From 4b897ba791055ab1ff5db9c2f4dc817418200ef5 Mon Sep 17 00:00:00 2001 From: Tim Allen Date: Fri, 22 Jul 2016 22:03:25 +1000 Subject: [PATCH] Update to v100r10 release. byuu says: Redesigned the handling of reading/writing registers to be about eight times faster than the old system. More work may be needed ... it seems data registers tend to preserve their upper bits upon assignment; whereas address registers tend to sign-extend values into them. It may make sense to have DataRegister and AddressRegister classes with separate read/write handlers. I'd have to hold two Register objects inside the EffectiveAddress (EA) class if we do that. Implemented 19 opcodes now (out of somewhere between 60 and 90.) That gets the first ~530,000 instructions in Sonic the Hedgehog running (though probably wrong. But we can run a lot thanks to large initialization loops.) If I force the core to loop back to the reset vector on an invalid opcode, I'm getting about 1500fps with a dumb 320x240 blit 60 times a second and just the 68K running alone (no Z80, PSG, VDP, YM2612.) I don't know if that's good or not. I guess we'll find out. I had to stop tonight because the final opcode I execute is an RTS (return from subroutine) that's branching back to address 0; which is invalid ... meaning something went terribly wrong and the system crashed. --- higan/emulator/emulator.hpp | 2 +- higan/md/cpu/cpu.cpp | 4 +- higan/processor/m68k/disassembler.cpp | 49 ++++++++-- higan/processor/m68k/ea.cpp | 86 ++++++++--------- higan/processor/m68k/instruction.cpp | 131 +++++++++++++++++++++++--- higan/processor/m68k/instructions.cpp | 85 +++++++++++++++-- higan/processor/m68k/m68k.cpp | 12 ++- higan/processor/m68k/m68k.hpp | 51 ++++++++-- higan/processor/m68k/memory.cpp | 60 ++++++++---- higan/processor/m68k/registers.cpp | 45 ++------- 10 files changed, 386 insertions(+), 139 deletions(-) diff --git a/higan/emulator/emulator.hpp b/higan/emulator/emulator.hpp index b427d189..6dd1fcfc 100644 --- a/higan/emulator/emulator.hpp +++ b/higan/emulator/emulator.hpp @@ -11,7 +11,7 @@ using namespace nall; namespace Emulator { static const string Name = "higan"; - static const string Version = "100.09"; + static const string Version = "100.10"; static const string Author = "byuu"; static const string License = "GPLv3"; static const string Website = "http://byuu.org/"; diff --git a/higan/md/cpu/cpu.cpp b/higan/md/cpu/cpu.cpp index 72d86add..8a0b6ca2 100644 --- a/higan/md/cpu/cpu.cpp +++ b/higan/md/cpu/cpu.cpp @@ -10,8 +10,8 @@ auto CPU::Enter() -> void { } auto CPU::boot() -> void { - r.ssp = read(1, 0) << 16 | read(1, 2) << 0; - r.pc = read(1, 4) << 16 | read(1, 6) << 0; + r.da[A7] = read(1, 0) << 16 | read(1, 2) << 0; + r.pc = read(1, 4) << 16 | read(1, 6) << 0; } auto CPU::main() -> void { diff --git a/higan/processor/m68k/disassembler.cpp b/higan/processor/m68k/disassembler.cpp index 410e119a..ccd6b0d6 100644 --- a/higan/processor/m68k/disassembler.cpp +++ b/higan/processor/m68k/disassembler.cpp @@ -63,7 +63,7 @@ template auto M68K::_suffix() -> string { auto M68K::_condition(uint4 condition) -> string { static const string conditions[16] = { - "ra", "sr", "hi", "ls", "cc", "cs", "ne", "eq", + "t ", "f ", "hi", "ls", "cc", "cs", "ne", "eq", "vc", "vs", "pl", "mi", "ge", "lt", "gt", "le", }; return conditions[condition]; @@ -76,8 +76,8 @@ auto M68K::disassemble(uint32 pc) -> string { auto M68K::disassembleRegisters() -> string { return { - hex(r.d0, 8L), " ", hex(r.d1, 8L), " ", hex(r.d2, 8L), " ", hex(r.d3, 8L), " ", - hex(r.d4, 8L), " ", hex(r.d5, 8L), " ", hex(r.d6, 8L), " ", hex(r.d7, 8L), " ", + hex(r.da[D0], 8L), " ", hex(r.da[D1], 8L), " ", hex(r.da[D2], 8L), " ", hex(r.da[D3], 8L), " ", + hex(r.da[D4], 8L), " ", hex(r.da[D5], 8L), " ", hex(r.da[D6], 8L), " ", hex(r.da[D7], 8L), " ", r.t ? "T" : "t", r.s ? "S" : "s", (uint)r.i, @@ -86,8 +86,8 @@ auto M68K::disassembleRegisters() -> string { r.z ? "Z" : "z", r.n ? "N" : "n", r.x ? "X" : "x", "\n", - hex(r.a0, 8L), " ", hex(r.a1, 8L), " ", hex(r.a2, 8L), " ", hex(r.a3, 8L), " ", - hex(r.a4, 8L), " ", hex(r.a5, 8L), " ", hex(r.a6, 8L), " ", hex(r.ssp, 8L), " ", hex(r.usp, 8L) + hex(r.da[A0], 8L), " ", hex(r.da[A1], 8L), " ", hex(r.da[A2], 8L), " ", hex(r.da[A3], 8L), " ", + hex(r.da[A4], 8L), " ", hex(r.da[A5], 8L), " ", hex(r.da[A6], 8L), " ", hex(r.da[A7], 8L), " ", hex(r.sp, 8L) }; } @@ -108,7 +108,32 @@ template auto M68K::disassembleANDI(EA ea) -> string { } auto M68K::disassembleBCC(uint4 condition, uint8 displacement) -> string { - return {"b", _condition(condition), " ", _branch(displacement)}; + auto cc = _condition(condition); + if(condition == 0) cc = "ra"; + if(condition == 1) cc = "sr"; + return {"b", cc, " ", _branch(displacement)}; +} + +template auto M68K::disassembleBTST(Register rd, EA ea) -> string { + return {"btst ", _register(rd), ",", _read(ea)}; +} + +template auto M68K::disassembleBTST(EA ea) -> string { + return {"btst ", _immediate(), ",", _read(ea)}; +} + +template auto M68K::disassembleCLR(EA ea) -> string { + return {"clr", _suffix(), " ", _read(ea)}; +} + +template auto M68K::disassembleCMP(Register rd, EA ea) -> string { + return {"cmp", _suffix(), " ", _read(ea), ",", _register(rd)}; +} + +auto M68K::disassembleDBCC(uint4 condition, Register rd) -> string { + auto base = _pc; + auto displacement = (int16)_readPC(); + return {"db", _condition(condition), " ", _register(rd), ",$", hex(base + displacement, 6L)}; } auto M68K::disassembleLEA(Register ra, EA ea) -> string { @@ -142,6 +167,14 @@ auto M68K::disassembleMOVEQ(Register rd, uint8 immediate) -> string { return {"moveq #$", hex(immediate, 2L), ",", _register(rd)}; } +auto M68K::disassembleMOVE_FROM_SR(EA ea) -> string { + return {"move sr,", _read(ea)}; +} + +auto M68K::disassembleMOVE_TO_SR(EA ea) -> string { + return {"move ", _read(ea), ",sr"}; +} + auto M68K::disassembleMOVE_USP(uint1 direction, Register ra) -> string { if(direction == 0) { return {"move ", _register(ra), ",usp"}; @@ -154,6 +187,10 @@ auto M68K::disassembleNOP() -> string { return {"nop "}; } +auto M68K::disassembleRTS() -> string { + return {"rts "}; +} + template auto M68K::disassembleTST(EA ea) -> string { return {"tst", _suffix(), " ", _read(ea)}; } diff --git a/higan/processor/m68k/ea.cpp b/higan/processor/m68k/ea.cpp index 5cc2872a..58ab4c0f 100644 --- a/higan/processor/m68k/ea.cpp +++ b/higan/processor/m68k/ea.cpp @@ -1,53 +1,53 @@ template auto M68K::fetch(EA& ea) -> uint32 { - ea.valid = true; + if(!ea.valid.raise()) return ea.address; switch(ea.mode) { - case 0: { //data register direct + case DataRegisterDirect: { return read(ea.reg); } - case 1: { //data register indirect + case AddressRegisterDirect: { return read(ea.reg); } - case 2: { //address register indirect + case AddressRegisterIndirect: { return read(ea.reg); } - case 3: { //address register indirect with post-increment + case AddressRegisterIndirectWithPostIncrement: { return read(ea.reg); } - case 4: { //address register indirect with pre-decrement + case AddressRegisterIndirectWithPreDecrement: { return read(ea.reg); } - case 5: { //address register indirect with displacement + case AddressRegisterIndirectWithDisplacement: { return read(ea.reg) + (int16)readPC(); } - case 6: { //address register indirect with index + case AddressRegisterIndirectWithIndex: { auto extension = readPC(); auto index = read(Register{extension >> 12}); if(extension & 0x800) index = (int16)index; return read(ea.reg) + index + (int8)extension; } - case 7: { //absolute short indirect + case AbsoluteShortIndirect: { return (int16)readPC(); } - case 8: { //absolute long indirect + case AbsoluteLongIndirect: { return readPC(); } - case 9: { //program counter indirect with displacement + case ProgramCounterIndirectWithDisplacement: { auto base = r.pc; return base + (int16)readPC(); } - case 10: { //program counter indirect with index + case ProgramCounterIndirectWithIndex: { auto base = r.pc; auto extension = readPC(); auto index = read(Register{extension >> 12}); @@ -55,7 +55,7 @@ template auto M68K::fetch(EA& ea) -> uint32 { return base + index + (int8)extension; } - case 11: { //immediate + case Immediate: { return readPC(); } @@ -65,59 +65,59 @@ template auto M68K::fetch(EA& ea) -> uint32 { } template auto M68K::read(EA& ea) -> uint32 { - if(!ea.valid) ea.address = fetch(ea); + ea.address = fetch(ea); switch(ea.mode) { - case 0: { //data register direct + case DataRegisterDirect: { return clip(ea.address); } - case 1: { //address register direct + case AddressRegisterDirect: { return clip(ea.address); } - case 2: { //address register indirect + case AddressRegisterIndirect: { return read(ea.address); } - case 3: { //address register indirect with post-increment + case AddressRegisterIndirectWithPostIncrement: { auto data = read(ea.address); if(Update) write(ea.reg, ea.address += (Size == Long ? 4 : 2)); return data; } - case 4: { //address register indirect with pre-decrement - auto data = read((uint32)(ea.address - (Size == Long ? 4 : 2))); + case AddressRegisterIndirectWithPreDecrement: { + auto data = read(ea.address - (Size == Long ? 4 : 2)); if(Update) write(ea.reg, ea.address -= (Size == Long ? 4 : 2)); return data; } - case 5: { //address register indirect with displacement + case AddressRegisterIndirectWithDisplacement: { return read(ea.address); } - case 6: { //address register indirect with index + case AddressRegisterIndirectWithIndex: { return read(ea.address); } - case 7: { //absolute short indirect + case AbsoluteShortIndirect: { return read(ea.address); } - case 8: { //absolute long indirect + case AbsoluteLongIndirect: { return read(ea.address); } - case 9: { //program counter indirect with displacement + case ProgramCounterIndirectWithDisplacement: { return read(ea.address); } - case 10: { //program counter indirect with index + case ProgramCounterIndirectWithIndex: { return read(ea.address); } - case 11: { //immediate + case Immediate: { return clip(ea.address); } @@ -127,59 +127,59 @@ template auto M68K::read(EA& ea) -> uint32 { } template auto M68K::write(EA& ea, uint32 data) -> void { - if(!ea.valid) ea.address = fetch(ea); + ea.address = fetch(ea); switch(ea.mode) { - case 0: { //data register direct + case DataRegisterDirect: { return write(ea.reg, data); } - case 1: { //address register direct + case AddressRegisterDirect: { return write(ea.reg, data); } - case 2: { //address register indirect + case AddressRegisterIndirect: { return write(ea.address, data); } - case 3: { //address register indirect with post-increment + case AddressRegisterIndirectWithPostIncrement: { write(ea.address, data); if(Update) write(ea.reg, ea.address += (Size == Long ? 4 : 2)); return; } - case 4: { //address register indirect with pre-decrement - write((uint32)(ea.address - (Size == Long ? 4 : 2)), data); + case AddressRegisterIndirectWithPreDecrement: { + write(ea.address - (Size == Long ? 4 : 2), data); if(Update) write(ea.reg, ea.address -= (Size == Long ? 4 : 2)); return; } - case 5: { //address register indirect with displacement + case AddressRegisterIndirectWithDisplacement: { return write(ea.address, data); } - case 6: { //address register indirect with index + case AddressRegisterIndirectWithIndex: { return write(ea.address, data); } - case 7: { //absolute short indirect + case AbsoluteShortIndirect: { return write(ea.address, data); } - case 8: { //absolute long indirect + case AbsoluteLongIndirect: { return write(ea.address, data); } - case 9: { //program counter indirect with displacement + case ProgramCounterIndirectWithDisplacement: { return write(ea.address, data); } - case 10: { //program counter indirect with index + case ProgramCounterIndirectWithIndex: { return write(ea.address, data); } - case 11: { //immediate + case Immediate: { return; } @@ -189,12 +189,12 @@ template auto M68K::write(EA& ea, uint32 data) -> void { template auto M68K::flush(EA& ea, uint32 data) -> void { switch(ea.mode) { - case 3: { //address register indirect with post-increment + case AddressRegisterIndirectWithPostIncrement: { write(ea.reg, data); return; } - case 4: { //address register indirect with pre-decrement + case AddressRegisterIndirectWithPreDecrement: { write(ea.reg, data); return; } diff --git a/higan/processor/m68k/instruction.cpp b/higan/processor/m68k/instruction.cpp index 11bd9937..5b0f7ecf 100644 --- a/higan/processor/m68k/instruction.cpp +++ b/higan/processor/m68k/instruction.cpp @@ -8,19 +8,25 @@ auto M68K::trap() -> void { auto M68K::instruction() -> void { instructionsExecuted++; - print(disassembleRegisters(), "\n"); - print(disassemble(r.pc), "\n"); - print("\n"); +//print(disassembleRegisters(), "\n"); +//print(disassemble(r.pc), "\n"); +//print("\n"); opcode = readPC(); return instructionTable[opcode](); } M68K::M68K() { - #define bind(id, name, ...) \ + #define bind(id, name, ...) { \ assert(!instructionTable[id]); \ instructionTable[id] = [=] { return instruction##name(__VA_ARGS__); }; \ - disassembleTable[id] = [=] { return disassemble##name(__VA_ARGS__); }; + disassembleTable[id] = [=] { return disassemble##name(__VA_ARGS__); }; \ + } + + #define unbind(id) { \ + instructionTable[id].reset(); \ + disassembleTable[id].reset(); \ + } #define pattern(s) \ std::integral_constant::value @@ -33,18 +39,20 @@ M68K::M68K() { auto opcode = pattern("1101 ---- ++-- ----") | dreg << 9 | direction << 8 | mode << 3 | reg << 0; if(direction == 1 && (mode == 0 || mode == 1 || (mode == 7 && reg >= 2))) continue; - Register rd{0u + dreg}; + Register rd{D0 + dreg}; EA ea{mode, reg}; bind(opcode | 0 << 6, ADD, rd, direction, ea); bind(opcode | 1 << 6, ADD, rd, direction, ea); bind(opcode | 2 << 6, ADD, rd, direction, ea); + + if(direction == 0 && mode == 1) unbind(opcode | 0 << 6); } //ANDI for(uint3 mode : range(8)) for(uint3 reg : range(8)) { auto opcode = pattern("0000 0010 ++-- ----") | mode << 3 | reg << 0; - if(mode == 1 || (mode == 7 && reg >= 4)) continue; + if(mode == 1 || (mode == 7 && reg >= 2)) continue; EA ea{mode, reg}; bind(opcode | 0 << 6, ANDI, ea); @@ -60,14 +68,74 @@ M68K::M68K() { bind(opcode, BCC, condition, displacement); } + //BTST (register) + for(uint3 dreg : range(8)) + for(uint3 mode : range(8)) + for(uint3 reg : range(8)) { + auto opcode = pattern("0000 ---1 00-- ----") | dreg << 9 | mode << 3 | reg << 0; + if(mode == 1) continue; + + Register rd{D0 + dreg}; + EA ea{mode, reg}; + if(mode == 0) bind(opcode, BTST, rd, ea); + if(mode != 0) bind(opcode, BTST, rd, ea); + } + + //BTST (immediate) + for(uint3 mode : range(8)) + for(uint3 reg : range(8)) { + auto opcode = pattern("0000 1000 00-- ----") | mode << 3 | reg << 0; + if(mode == 1 || (mode == 7 && reg == 2)) continue; + + EA ea{mode, reg}; + if(mode == 0) bind(opcode, BTST, ea); + if(mode != 0) bind(opcode, BTST, ea); + } + + //CLR + for(uint3 mode : range(8)) + for(uint3 reg : range(8)) { + auto opcode = pattern("0100 0010 ++-- ----") | mode << 3 | reg << 0; + if(mode == 1 || (mode == 7 && reg >= 2)) continue; + + EA ea{mode, reg}; + bind(opcode | 0 << 6, CLR, ea); + bind(opcode | 1 << 6, CLR, ea); + bind(opcode | 2 << 6, CLR, ea); + } + + //CMP + for(uint3 dreg : range(8)) + for(uint3 mode : range(8)) + for(uint3 reg : range(8)) { + auto opcode = pattern("1011 ---0 ++-- ----") | dreg << 9 | mode << 3 | reg << 0; + + Register rd{D0 + dreg}; + EA ea{mode, reg}; + bind(opcode | 0 << 6, CMP, rd, ea); + bind(opcode | 1 << 6, CMP, rd, ea); + bind(opcode | 2 << 6, CMP, rd, ea); + + if(mode == 1) unbind(opcode | 0 << 6); + } + + //DBCC + for(uint4 condition : range(16)) + for(uint3 dreg : range( 8)) { + auto opcode = pattern("0101 ---- 1100 1---") | condition << 8 | dreg << 0; + + Register rd{D0 + dreg}; + bind(opcode, DBCC, condition, rd); + } + //LEA for(uint3 areg : range(8)) for(uint3 mode : range(8)) for(uint3 reg : range(8)) { auto opcode = pattern("0100 ---1 11-- ----") | areg << 9 | mode << 3 | reg << 0; - if(mode <= 1 || mode == 3 || mode == 4 || (mode == 7 && reg >= 4)) continue; + if(mode <= 1 || mode == 3 || mode == 4 || (mode == 7 && reg == 4)) continue; - Register ra{8u + areg}; + Register ra{A0 + areg}; EA ea{mode, reg}; bind(opcode, LEA, ra, ea); } @@ -78,13 +146,15 @@ M68K::M68K() { for(uint3 fromMode : range(8)) for(uint3 fromReg : range(8)) { auto opcode = pattern("00++ ---- ---- ----") | toReg << 9 | toMode << 6 | fromMode << 3 | fromReg << 0; - if(toMode == 1 || (toMode == 7 && toReg >= 4)) continue; + if(toMode == 1 || (toMode == 7 && toReg >= 2)) continue; EA to{toMode, toReg}; EA from{fromMode, fromReg}; bind(opcode | 1 << 12, MOVE, to, from); bind(opcode | 3 << 12, MOVE, to, from); bind(opcode | 2 << 12, MOVE, to, from); + + if(fromMode == 1) unbind(opcode | 1 << 12); } //MOVEA @@ -93,7 +163,7 @@ M68K::M68K() { for(uint3 reg : range(8)) { auto opcode = pattern("00++ ---0 01-- ----") | areg << 9 | mode << 3 | reg << 0; - Register ra{8u + areg}; + Register ra{A0 + areg}; EA ea{mode, reg}; bind(opcode | 3 << 12, MOVEA, ra, ea); bind(opcode | 2 << 12, MOVEA, ra, ea); @@ -104,7 +174,8 @@ M68K::M68K() { for(uint3 mode : range(8)) for(uint3 reg : range(8)) { auto opcode = pattern("0100 1-00 1+-- ----") | direction << 10 | mode << 3 | reg << 0; - if(mode <= 1 || mode == 3 || (mode == 7 && reg >= 4)); + if(direction == 0 && (mode <= 1 || mode == 3 || (mode == 7 && reg >= 2))); + if(direction == 1 && (mode <= 1 || mode == 4 || (mode == 7 && reg == 4))); EA ea{mode, reg}; bind(opcode | 0 << 6, MOVEM, direction, ea); @@ -116,16 +187,36 @@ M68K::M68K() { for(uint8 immediate : range(256)) { auto opcode = pattern("0111 ---0 ---- ----") | dreg << 9 | immediate << 0; - Register rd{0u + dreg}; + Register rd{D0 + dreg}; bind(opcode, MOVEQ, rd, immediate); } + //MOVE_FROM_SR + for(uint3 mode : range(8)) + for(uint3 reg : range(8)) { + auto opcode = pattern("0100 0000 11-- ----") | mode << 3 | reg << 0; + if(mode == 1 || (mode == 7 && reg >= 2)) continue; + + EA ea{mode, reg}; + bind(opcode, MOVE_FROM_SR, ea); + } + + //MOVE_TO_SR + for(uint3 mode : range(8)) + for(uint3 reg : range(8)) { + auto opcode = pattern("0100 0110 11-- ----") | mode << 3 | reg << 0; + if(mode == 1) continue; + + EA ea{mode, reg}; + bind(opcode, MOVE_TO_SR, ea); + } + //MOVE_USP for(uint1 direction : range(2)) for(uint3 areg : range(8)) { auto opcode = pattern("0100 1110 0110 ----") | direction << 3 | areg << 0; - Register ra{8u + areg}; + Register ra{A0 + areg}; bind(opcode, MOVE_USP, direction, ra); } @@ -135,18 +226,28 @@ M68K::M68K() { bind(opcode, NOP); } + //RTS + { auto opcode = pattern("0100 1110 0111 0101"); + + bind(opcode, RTS); + } + //TST for(uint3 mode : range(8)) for(uint3 reg : range(8)) { auto opcode = pattern("0100 1010 ++-- ----") | mode << 3 | reg << 0; + if(mode == 7 && reg >= 2) continue; EA ea{mode, reg}; bind(opcode | 0 << 6, TST, ea); bind(opcode | 1 << 6, TST, ea); bind(opcode | 2 << 6, TST, ea); + + if(mode == 1) unbind(opcode | 0 << 6); } #undef bind + #undef unbind #undef pattern uint unimplemented = 0; @@ -156,5 +257,5 @@ M68K::M68K() { disassembleTable[opcode] = [=] { return string{"???"}; }; unimplemented++; } -//print("[M68K] unimplemented opcodes: ", unimplemented, "\n"); + print("[M68K] unimplemented opcodes: ", unimplemented, "\n"); } diff --git a/higan/processor/m68k/instructions.cpp b/higan/processor/m68k/instructions.cpp index 79278ed5..16ff6603 100644 --- a/higan/processor/m68k/instructions.cpp +++ b/higan/processor/m68k/instructions.cpp @@ -1,7 +1,7 @@ auto M68K::testCondition(uint4 condition) -> bool { switch(condition) { - case 0: return true; //RA - case 1: return false; //NV,SR + case 0: return true; //T + case 1: return false; //F case 2: return !r.c && !r.z; //HI case 3: return r.c || r.z; //LS case 4: return !r.c; //CC,HS @@ -22,6 +22,14 @@ auto M68K::testCondition(uint4 condition) -> bool { // +template<> auto M68K::bits() -> uint { return 8; } +template<> auto M68K::bits() -> uint { return 16; } +template<> auto M68K::bits() -> uint { return 32; } + +template<> auto M68K::mask() -> uint32 { return 0xff; } +template<> auto M68K::mask() -> uint32 { return 0xffff; } +template<> auto M68K::mask() -> uint32 { return 0xffffffff; } + template<> auto M68K::clip(uint32 data) -> uint32 { return data & 0xff; } template<> auto M68K::clip(uint32 data) -> uint32 { return data & 0xffff; } template<> auto M68K::clip(uint32 data) -> uint32 { return data & 0xffffffff; } @@ -86,12 +94,58 @@ template auto M68K::instructionANDI(EA ea) -> void { auto M68K::instructionBCC(uint4 condition, uint8 displacement) -> void { auto extension = readPC(); - if(condition == 1); //push(r.pc); + if(condition == 1) push(r.pc); r.pc -= 2; - if(!testCondition(condition == 1 ? (uint4)0 : condition)) return; + if(condition >= 2 && !testCondition(condition)) return; //0 = BRA; 1 = BSR r.pc += displacement ? sign(displacement) : sign(extension); } +template auto M68K::instructionBTST(Register rd, EA ea) -> void { + auto bit = read(rd); + auto test = read(ea); + bit &= bits() - 1; + + r.z = test.bit(bit) == 0; +} + +template auto M68K::instructionBTST(EA ea) -> void { + auto bit = (uint8)readPC(); + auto test = read(ea); + bit &= bits() - 1; + + r.z = test.bit(bit) == 0; +} + +template auto M68K::instructionCLR(EA ea) -> void { + read(ea); + write(ea, 0); + + r.c = 0; + r.v = 0; + r.z = 1; + r.n = 0; +} + +template auto M68K::instructionCMP(Register rd, EA ea) -> void { + auto source = read(ea); + auto target = read(rd); + auto result = target - source; + + r.c = carry(result, source); + r.v = overflow(result, source, target); + r.z = zero(result); + r.n = negative(result); +} + +auto M68K::instructionDBCC(uint4 condition, Register rd) -> void { + auto displacement = (int16)readPC(); + if(!testCondition(condition)) { + uint16 result = read(rd); + write(rd, result - 1); + if(result) r.pc -= 2, r.pc += displacement; + } +} + auto M68K::instructionLEA(Register ra, EA ea) -> void { write(ra, fetch(ea)); } @@ -109,7 +163,7 @@ template auto M68K::instructionMOVE(EA to, EA from) -> void { template auto M68K::instructionMOVEA(Register ra, EA ea) -> void { auto data = read(ea); if(Size == Word) data = (int16)data; - write(ra, data); + write(ra, data); } template auto M68K::instructionMOVEM(uint1 direction, EA ea) -> void { @@ -135,18 +189,33 @@ auto M68K::instructionMOVEQ(Register rd, uint8 immediate) -> void { r.n = negative(immediate); } +auto M68K::instructionMOVE_FROM_SR(EA ea) -> void { + write(ea, r.sr); +} + +auto M68K::instructionMOVE_TO_SR(EA ea) -> void { + if(!supervisor()) return; + + setSR(read(ea)); +} + auto M68K::instructionMOVE_USP(uint1 direction, Register ra) -> void { - if(!r.s) trap(); //todo: proper trap + if(!supervisor()) return; + if(direction == 0) { - r.usp = read(ra); + r.sp = read(ra); } else { - write(ra, r.usp); + write(ra, r.sp); } } auto M68K::instructionNOP() -> void { } +auto M68K::instructionRTS() -> void { + r.pc = pop(); +} + template auto M68K::instructionTST(EA ea) -> void { auto data = read(ea); diff --git a/higan/processor/m68k/m68k.cpp b/higan/processor/m68k/m68k.cpp index 9e101a24..df2b94bf 100644 --- a/higan/processor/m68k/m68k.cpp +++ b/higan/processor/m68k/m68k.cpp @@ -4,6 +4,7 @@ namespace Processor { enum : uint { Byte, Word, Long }; +enum : bool { Reverse = 1 }; #include "registers.cpp" #include "memory.cpp" @@ -18,11 +19,16 @@ auto M68K::power() -> void { auto M68K::reset() -> void { instructionsExecuted = 0; - for(uint rn : range(15)) write(Register{rn}, 0); - r.ssp = 0; - r.usp = 0; + for(auto& da : r.da) da = 0; + r.sp = 0; r.pc = 0; r.sr = 0x2000; } +auto M68K::supervisor() -> bool { + if(r.s) return true; + //todo: raise TRAP exception + return false; +} + } diff --git a/higan/processor/m68k/m68k.hpp b/higan/processor/m68k/m68k.hpp index e0579bac..9036b852 100644 --- a/higan/processor/m68k/m68k.hpp +++ b/higan/processor/m68k/m68k.hpp @@ -5,8 +5,25 @@ namespace Processor { struct M68K { + enum : bool { User, Supervisor }; enum : uint { Byte, Word, Long }; - enum : bool { NoUpdate = 0 }; + enum : bool { NoUpdate = 0, Reverse = 1 }; + enum : uint { D0, D1, D2, D3, D4, D5, D6, D7, A0, A1, A2, A3, A4, A5, A6, A7 }; + + enum : uint { + DataRegisterDirect, + AddressRegisterDirect, + AddressRegisterIndirect, + AddressRegisterIndirectWithPostIncrement, + AddressRegisterIndirectWithPreDecrement, + AddressRegisterIndirectWithDisplacement, + AddressRegisterIndirectWithIndex, + AbsoluteShortIndirect, + AbsoluteLongIndirect, + ProgramCounterIndirectWithDisplacement, + ProgramCounterIndirectWithIndex, + Immediate, + }; M68K(); @@ -16,25 +33,29 @@ struct M68K { auto power() -> void; auto reset() -> void; + auto supervisor() -> bool; //registers.cpp struct Register { - Register(uint number) : number(number) {} + explicit Register(uint number_) : number(number_) {} uint4 number; }; template auto read(Register reg) -> uint32; template auto write(Register reg, uint32 value) -> void; + auto setSR(uint16 sr) -> void; //memory.cpp template auto read(uint32 addr) -> uint32; - template auto write(uint32 addr, uint32 data) -> void; + template auto write(uint32 addr, uint32 data) -> void; template auto readPC() -> uint32; + template auto pop() -> uint32; + template auto push(uint32 data) -> void; //ea.cpp struct EA { - EA(uint mode_, uint reg_) : mode(mode_), reg(reg_) { + explicit EA(uint mode_, uint reg_) : mode(mode_), reg(reg_) { if(mode == 7) mode += reg.number; //optimization: convert modes {7; 0-4} to {8-11} if(mode != 0) reg.number += 8; //optimization: linear index to all registers: d0-d7; a0-a7 } @@ -58,6 +79,8 @@ struct M68K { //instructions.cpp auto testCondition(uint4 condition) -> bool; + template auto bits() -> uint; + template auto mask() -> uint32; template auto clip(uint32 data) -> uint32; template auto sign(uint32 data) -> int32; @@ -69,13 +92,21 @@ struct M68K { template auto instructionADD(Register rd, uint1 direction, EA ea) -> void; template auto instructionANDI(EA ea) -> void; auto instructionBCC(uint4 condition, uint8 displacement) -> void; + template auto instructionBTST(Register rd, EA ea) -> void; + template auto instructionBTST(EA ea) -> void; + template auto instructionCLR(EA ea) -> void; + template auto instructionCMP(Register rd, EA ea) -> void; + auto instructionDBCC(uint4 condition, Register rd) -> void; auto instructionLEA(Register ra, EA ea) -> void; template auto instructionMOVE(EA to, EA from) -> void; template auto instructionMOVEA(Register ra, EA ea) -> void; template auto instructionMOVEM(uint1 direction, EA ea) -> void; auto instructionMOVEQ(Register rd, uint8 immediate) -> void; + auto instructionMOVE_FROM_SR(EA ea) -> void; + auto instructionMOVE_TO_SR(EA ea) -> void; auto instructionMOVE_USP(uint1 direction, Register ra) -> void; auto instructionNOP() -> void; + auto instructionRTS() -> void; template auto instructionTST(EA ea) -> void; //disassembler.cpp @@ -83,8 +114,8 @@ struct M68K { auto disassembleRegisters() -> string; struct Registers { - uint32 d0, d1, d2, d3, d4, d5, d6, d7; - uint32 a0, a1, a2, a3, a4, a5, a6, ssp, usp; + uint32 da[16]; //a7 = primary stack pointer + uint32 sp; //sp = secondary stack pointer uint32 pc; union { @@ -112,13 +143,21 @@ private: template auto disassembleADD(Register rd, uint1 direction, EA ea) -> string; template auto disassembleANDI(EA ea) -> string; auto disassembleBCC(uint4 condition, uint8 displacement) -> string; + template auto disassembleBTST(Register rd, EA ea) -> string; + template auto disassembleBTST(EA ea) -> string; + template auto disassembleCLR(EA ea) -> string; + template auto disassembleCMP(Register rd, EA ea) -> string; + auto disassembleDBCC(uint4 condition, Register rd) -> string; auto disassembleLEA(Register ra, EA ea) -> string; template auto disassembleMOVE(EA to, EA from) -> string; template auto disassembleMOVEA(Register ra, EA ea) -> string; template auto disassembleMOVEM(uint1 direction, EA ea) -> string; auto disassembleMOVEQ(Register rd, uint8 immediate) -> string; + auto disassembleMOVE_FROM_SR(EA ea) -> string; + auto disassembleMOVE_TO_SR(EA ea) -> string; auto disassembleMOVE_USP(uint1 direction, Register ra) -> string; auto disassembleNOP() -> string; + auto disassembleRTS() -> string; template auto disassembleTST(EA ea) -> string; template auto _read(uint32 addr) -> uint32; diff --git a/higan/processor/m68k/memory.cpp b/higan/processor/m68k/memory.cpp index 13723890..7d2bc58b 100644 --- a/higan/processor/m68k/memory.cpp +++ b/higan/processor/m68k/memory.cpp @@ -1,17 +1,3 @@ -/* -auto M68K::readPC(uint2 size) -> uint32 { - step(4); - uint32 data = read(size != Byte, r.pc); - r.pc += 2; - if(size != Long) return data; - - step(4); - data = data << 16 | read(1, r.pc); - r.pc += 2; - return data; -} -*/ - template<> auto M68K::read(uint32 addr) -> uint32 { step(4); return read(0, addr); @@ -32,36 +18,74 @@ template<> auto M68K::read(uint32 addr) -> uint32 { // template<> auto M68K::write(uint32 addr, uint32 data) -> void { + step(4); + return write(0, addr, data); } template<> auto M68K::write(uint32 addr, uint32 data) -> void { + step(4); + return write(1, addr, data); } template<> auto M68K::write(uint32 addr, uint32 data) -> void { + step(4); + write(1, addr + 0, data >> 16); + step(4); + write(1, addr + 2, data >> 0); +} + +template<> auto M68K::write(uint32 addr, uint32 data) -> void { + step(4); + return write(0, addr, data); +} + +template<> auto M68K::write(uint32 addr, uint32 data) -> void { + step(4); + return write(1, addr, data); +} + +template<> auto M68K::write(uint32 addr, uint32 data) -> void { + step(4); + write(1, addr + 2, data >> 0); + step(4); + write(1, addr + 0, data >> 16); } // template<> auto M68K::readPC() -> uint32 { step(4); - uint32 data = read(1, r.pc); + auto data = read(1, r.pc); r.pc += 2; return (uint8)data; } template<> auto M68K::readPC() -> uint32 { step(4); - uint32 data = read(1, r.pc); + auto data = read(1, r.pc); r.pc += 2; return data; } template<> auto M68K::readPC() -> uint32 { step(4); - uint32 data = read(1, r.pc) << 16; + auto hi = read(1, r.pc); r.pc += 2; step(4); - data |= read(1, r.pc); + auto lo = read(1, r.pc); r.pc += 2; + return hi << 16 | lo << 0; +} + +// + +template auto M68K::pop() -> uint32 { + auto data = read((uint32)r.da[A7]); + r.da[A7] += Size == Long ? 4 : 2; return data; } + +template auto M68K::push(uint32 data) -> void { + r.da[A7] -= Size == Long ? 4 : 2; + return write((uint32)r.da[A7], data); +} diff --git a/higan/processor/m68k/registers.cpp b/higan/processor/m68k/registers.cpp index 6b381315..7e76b248 100644 --- a/higan/processor/m68k/registers.cpp +++ b/higan/processor/m68k/registers.cpp @@ -1,42 +1,13 @@ template auto M68K::read(Register reg) -> uint32 { - switch(reg.number) { - case 0: return clip(r.d0); - case 1: return clip(r.d1); - case 2: return clip(r.d2); - case 3: return clip(r.d3); - case 4: return clip(r.d4); - case 5: return clip(r.d5); - case 6: return clip(r.d6); - case 7: return clip(r.d7); - case 8: return clip(r.a0); - case 9: return clip(r.a1); - case 10: return clip(r.a2); - case 11: return clip(r.a3); - case 12: return clip(r.a4); - case 13: return clip(r.a5); - case 14: return clip(r.a6); - case 15: return r.s ? clip(r.ssp) : clip(r.usp); - } - unreachable; + return clip(r.da[reg.number]); } template auto M68K::write(Register reg, uint32 data) -> void { - switch(reg.number) { - case 0: r.d0 = clip(data); return; - case 1: r.d1 = clip(data); return; - case 2: r.d2 = clip(data); return; - case 3: r.d3 = clip(data); return; - case 4: r.d4 = clip(data); return; - case 5: r.d5 = clip(data); return; - case 6: r.d6 = clip(data); return; - case 7: r.d7 = clip(data); return; - case 8: r.a0 = clip(data); return; - case 9: r.a1 = clip(data); return; - case 10: r.a2 = clip(data); return; - case 11: r.a3 = clip(data); return; - case 12: r.a4 = clip(data); return; - case 13: r.a5 = clip(data); return; - case 14: r.a6 = clip(data); return; - case 15: r.s ? r.ssp = clip(data) : r.usp = clip(data); return; - } + r.da[reg.number] = (r.da[reg.number] & ~mask()) | (data & mask()); +} + +auto M68K::setSR(uint16 sr) -> void { + //when entering or exiting supervisor mode; swap SSP and USP into A7 + if(r.sr.bit(13) != sr.bit(13)) swap(r.da[A7], r.sp); + r.sr = sr; }