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; }