diff --git a/higan/emulator/emulator.hpp b/higan/emulator/emulator.hpp index 4981fd4e..a6e5e069 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.05"; + static const string Version = "100.06"; static const string Author = "byuu"; static const string License = "GPLv3"; static const string Website = "http://byuu.org/"; diff --git a/higan/processor/m68k/disassembler.cpp b/higan/processor/m68k/disassembler.cpp index ea37cbc1..9909005c 100644 --- a/higan/processor/m68k/disassembler.cpp +++ b/higan/processor/m68k/disassembler.cpp @@ -1,160 +1,163 @@ +auto M68K::_readByte(uint32 addr) -> uint8 { + return read(addr); +} + +auto M68K::_readWord(uint32 addr) -> uint16 { + uint16 data = _readByte(addr + 0) << 8; + return data |= _readByte(addr + 1) << 0; +} + +auto M68K::_readLong(uint32 addr) -> uint32 { + uint32 data = _readWord(addr + 0) << 16; + return data |= _readWord(addr + 2) << 0; +} + +auto M68K::_readPC(uint size) -> uint32 { + uint32 data = _readWord(_pc); + _pc += 2; + if(size == Byte) return (uint8)data; + if(size == Word) return data; + data = (data << 16) | _readWord(_pc); + _pc += 2; + return data; +} + +auto M68K::_immediate(uint size) -> string { + if(size == Byte) return {"#$", hex(_readPC(Byte), 2L)}; + if(size == Word) return {"#$", hex(_readPC(Word), 4L)}; + if(size == Long) return {"#$", hex(_readPC(Long), 8L)}; + return "#???"; +} + +auto M68K::_address(uint size, EA& ea) -> string { + if(ea.mode == 7) { + if(ea.reg == 2) return {"$", hex(_pc + (int16)_readPC(Word), 6L)}; + } + return "???"; +} + +auto M68K::_read(uint size, EA& ea) -> string { + if(ea.mode == 0) return {"d", ea.reg}; + if(ea.mode == 1) return {"a", ea.reg}; + if(ea.mode == 2) return {"(a", ea.reg, ")"}; + if(ea.mode == 3) return {"(a", ea.reg, ")+"}; + if(ea.mode == 4) return {"-(a", ea.reg, ")"}; + if(ea.mode == 5) return {"($", hex(r.a(ea.reg) + (int16)_readPC(Word), 6L), ")"}; + if(ea.mode == 7) { + if(ea.reg == 1) return {"($", hex(_readPC(Long), 6L), ")"}; + if(ea.reg == 4) { + if(size == Byte) return {"#$", hex(_readPC(Byte), 2L)}; + if(size == Word) return {"#$", hex(_readPC(Word), 4L)}; + if(size == Long) return {"#$", hex(_readPC(Long), 8L)}; + } + } + return "???"; +} + +auto M68K::_write(uint size, EA& ea) -> string { + return _read(size, ea); +} + +auto M68K::_branch(uint displacement) -> string { + uint16 word = _readPC(); + if(displacement) displacement = (int8)displacement, _pc -= 2; + else displacement = (int16)displacement; + return {"$", hex(_pc + displacement, 6L)}; +} + +auto M68K::_suffix(uint size) -> string { + if(size == Byte) return ".b"; + if(size == Word) return ".w"; + if(size == Long) return ".l"; + return ".?"; +} + +auto M68K::_condition(uint condition) -> string { + static const string conditions[16] = { + "ra", "sr", "hi", "ls", "cc", "cs", "ne", "eq", + "vc", "vs", "pl", "mi", "ge", "lt", "gt", "le", + }; + return conditions[(uint4)condition]; +} + auto M68K::disassemble(uint32 pc) -> string { - auto readByte = [&](uint32 addr) -> uint8 { - return read(addr); - }; - auto readWord = [&](uint32 addr) -> uint16 { - uint16 data = read(addr + 0) << 8; - return data |= read(addr + 1) << 0; - }; - auto readLong = [&](uint32 addr) -> uint32 { - uint32 data = readWord(addr + 0) << 16; - return data |= readWord(addr + 2) << 0; - }; - auto readWordPC = [&]() -> uint16 { - auto data = readWord(pc); - pc += 2; - return data; - }; - auto readLongPC = [&]() -> uint32 { - uint32 data = readWordPC() << 16; - return data |= readWordPC() << 0; - }; - - auto size = [&](uint2 size) -> string { - if(size == 0) return ".b"; - if(size == 1) return ".w"; - if(size == 2) return ".l"; - return ".?"; - }; - - auto branch = [&](uint8 displacementByte) -> string { - uint16 displacementWord = readWordPC(); - if(displacementByte) pc -= 2; - return {"$", hex(pc + (displacementByte ? (int8_t)displacementByte : ((int16_t)displacementWord - 2)), 6L)}; - }; - - auto cc = [&](uint4 condition) -> string { - switch(condition) { - case 0: return "ra"; - case 1: return "sr"; - case 2: return "hi"; - case 3: return "ls"; - case 4: return "cc"; - case 5: return "cs"; - case 6: return "ne"; - case 7: return "eq"; - case 8: return "vc"; - case 9: return "vs"; - case 10: return "pl"; - case 11: return "mi"; - case 12: return "ge"; - case 13: return "lt"; - case 14: return "gt"; - case 15: return "le"; - } - unreachable; - }; - - auto ea = [&](uint2 size, uint3 mode, uint3 reg) -> string { - if(mode == 3) return {"(a", reg, ")+"}; - - if(mode == 7) { - if(reg == 0) return {"($", hex((int16)readWordPC(), 6L), ")"}; - if(reg == 1) return {"($", hex(readLongPC(), 6L), ")"}; - if(reg == 2) return {"($", hex(pc + (int16)readWordPC(), 6L), ")"}; - } - - return "???"; - }; - - auto rd = [&](uint3 reg) -> string { - static const string name[8] = {"d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7"}; - return name[reg]; - }; - - auto ra = [&](uint3 reg) -> string { - static const string name[8] = {"a0", "a1", "a2", "a3", "a4", "a5", "a6", "sp"}; - return name[reg]; - }; - - string s, name, args; - s.append(hex(pc, 6L), " "); - - auto opcode = readWordPC(); - s.append(hex(opcode, 4L), " "); - - if(0); - - #define match(pattern) else if( \ - (opcode & std::integral_constant::value) \ - == std::integral_constant::value \ - ) - #define bit(n) (opcode >> n & 1) - #define bits(hi, lo) ((opcode >> lo) & ((1 << (hi - lo + 1)) - 1)) - - //NOP - match("0100 1110 0111 0001") { - name = {"nop"}; - } - - //MOVEM - match("0100 1-00 1--- ----") { - name = {"movem", size(1 + bit(6))}; - bool direction = bit(10); - uint16 list = readWordPC(); - - string regs; - for(auto n : range(8)) if(list & 1 << (0 + n)) regs.append("d", n, ","); - for(auto n : range(8)) if(list & 1 << (8 + n)) regs.append("a", n, ","); - regs.trimRight(","); - - if(direction == 0) { - args = {regs, ",", ea(1 + bit(6), bits(5,3), bits(2,0))}; - } else { - args = {ea(1 + bit(6), bits(5,3), bits(2,0)), ",", regs}; - } - } - - //TST - match("0100 1010 ---- ----") { - name = {"tst", size(bits(7,6))}; - args = {ea(bits(7,6), bits(5,3), bits(2,0))}; - } - - //LEA - match("0100 ---1 11-- ----") { - name = {"lea"}; - args = {ea(Long, bits(5,3), bits(2,0)), ",", ra(bits(11,9))}; - } - - //BCC - match("0110 ---- ---- ----") { - name = {"b", cc(bits(11,8))}; - args = {branch(bits(7,0))}; - } - - #undef match - #undef bit - #undef bits - - else { - name = {"???"}; - } - - s.append(name.size(-8), args); - return s; + uint16 opcode; + return {hex(_pc = pc, 6L), " ", hex(opcode = _readPC(), 4L), " ", disassembleTable[opcode]()}; } 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), " ", + r.t ? "T" : "t", + r.s ? "S" : "s", + (uint)r.i, r.c ? "C" : "c", r.v ? "V" : "v", 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.usp, 8L), " ", hex(r.ssp, 8L) + hex(r.a4, 8L), " ", hex(r.a5, 8L), " ", hex(r.a6, 8L), " ", hex(r.ssp, 8L), " ", hex(r.usp, 8L) }; } + +// + +auto M68K::disassembleANDI(uint size, EA modify) -> string { + return {"andi", _suffix(size), " ", _immediate(size), ",", _read(size, modify)}; +} + +auto M68K::disassembleBCC(uint condition, uint displacement) -> string { + return {"b", _condition(condition), " ", _branch(displacement)}; +} + +auto M68K::disassembleLEA(uint target, EA source) -> string { + return {"lea ", _address(Long, source), ",a", target}; +} + +auto M68K::disassembleMOVE(uint size, EA target, EA source) -> string { + return {"move", _suffix(size), " ", _read(size, source), ",", _write(size, target)}; +} + +auto M68K::disassembleMOVEA(uint size, uint target, EA source) -> string { + return {"movea ", _read(size, source), ",a", target}; +} + +auto M68K::disassembleMOVEM(uint direction, uint size, EA source) -> string { + string op{"movem", _suffix(size), " "}; + + uint16 list = _readPC(); + string regs; + for(auto n : range(8)) if(list.bit(0 + n)) regs.append("d", n, ","); + regs.trimRight(","); + if(regs && list >> 8) regs.append("/"); + for(auto n : range(8)) if(list.bit(8 + n)) regs.append("a", n, ","); + regs.trimRight(","); + + if(direction == 0) { + return {op, regs, ",", _read(size, source)}; + } else { + return {op, _read(size, source), ",", regs}; + } +} + +auto M68K::disassembleMOVEQ(uint target, uint immediate) -> string { + return {"moveq #$", hex(immediate, 2L), ",d", target}; +} + +auto M68K::disassembleMOVE_USP(uint direction, uint reg) -> string { + if(direction == 0) { + return {"move a", reg, ",usp"}; + } else { + return {"move usp,a", reg}; + } +} + +auto M68K::disassembleNOP() -> string { + return {"nop "}; +} + +auto M68K::disassembleTST(uint size, EA source) -> string { + return {"tst", _suffix(size), " ", _read(size, source)}; +} diff --git a/higan/processor/m68k/ea.cpp b/higan/processor/m68k/ea.cpp index 0f12cd25..6762deab 100644 --- a/higan/processor/m68k/ea.cpp +++ b/higan/processor/m68k/ea.cpp @@ -1,34 +1,72 @@ -auto M68K::signExtend(uint2 size, uint32 data) -> int32 { - if(size == 0) return (int8)data; - if(size == 1) return (int16)data; - if(size == 2) return (int32)data; +auto M68K::sign(uint size, uint32 data) -> int32 { + if(size == Byte) return (int8)data; + if(size == Word) return (int16)data; + if(size == Long) return (int32)data; return 0; } // -auto M68K::address(EA& ea) -> uint32 { +auto M68K::address(uint size, EA& ea) -> uint32 { if(ea.valid) return ea.address; ea.valid = true; if(ea.mode == 0) return ea.address = r.d(ea.reg); if(ea.mode == 1) return ea.address = r.a(ea.reg); - + if(ea.mode == 2) return ea.address = r.a(ea.reg); + if(ea.mode == 3) return ea.address = r.a(ea.reg); + if(ea.mode == 4) return ea.address = r.a(ea.reg); + if(ea.mode == 5) return ea.address = r.a(ea.reg) + (int16)readPC(Word); if(ea.mode == 7) { - if(ea.reg == 0) return ea.address = (int16)readWordPC(); - if(ea.reg == 1) return ea.address = readLongPC(); - if(ea.reg == 2) return ea.address = r.pc, ea.address += (int16)readWordPC(); + if(ea.reg == 0) return ea.address = (int16)readPC(Word); + if(ea.reg == 1) return ea.address = readPC(Long); + if(ea.reg == 2) return ea.address = r.pc, ea.address += (int16)readPC(Word); + if(ea.reg == 4) { + if(size == Byte) return ea.address = readPC(Byte); + if(size == Word) return ea.address = readPC(Word); + if(size == Long) return ea.address = readPC(Long); + } } return ea.address = 0; } -auto M68K::read(EA& ea) -> uint32 { - address(ea); - if(ea.mode < 2 || (ea.mode == 7 && ea.reg == 4)) return ea.address; - return readAbsolute(ea.size, ea.address); +auto M68K::read(uint size, EA& ea) -> uint32 { + address(size, ea); + + if(ea.mode == 0) return r.d(ea.reg); + if(ea.mode == 1) return r.a(ea.reg); + if(ea.mode == 2) return read(size, ea.address); + if(ea.mode == 3) { + auto data = read(size, ea.address); + ea.address += size, r.a(ea.reg) += size; + return data; + } + if(ea.mode == 4) { + ea.address -= size, r.a(ea.reg) -= size; + return read(size, ea.address); + } + if(ea.mode == 5) return read(size, ea.address); + if(ea.mode == 7) { + if(ea.reg == 0) return read(size, ea.address); + if(ea.reg == 1) return read(size, ea.address); + if(ea.reg == 2) return read(size, ea.address); + if(ea.reg == 4) return ea.address; + } + + return 0; } -auto M68K::write(EA& ea, uint32 data) -> void { - address(ea); +auto M68K::write(uint size, EA& ea, uint32 data) -> void { + address(size, ea); + + if(ea.mode == 0) { + r.d(ea.reg) = data; + return; + } + + if(ea.mode == 1) { + r.a(ea.reg) = data; + return; + } } diff --git a/higan/processor/m68k/instruction.cpp b/higan/processor/m68k/instruction.cpp index d54ac5ab..b8771f01 100644 --- a/higan/processor/m68k/instruction.cpp +++ b/higan/processor/m68k/instruction.cpp @@ -10,50 +10,148 @@ auto M68K::instruction() -> void { instructionsExecuted++; print(disassembleRegisters(), "\n", disassemble(r.pc), "\n\n"); - opcode = readWordPC(); + opcode = readPC(); return instructionTable[opcode](); } M68K::M68K() { - for(uint opcode : range(65536)) instructionTable[opcode] = [=] { trap(); }; - - #define match(pattern) else if( \ + #define match(pattern) if( \ (opcode & std::integral_constant::value) \ == std::integral_constant::value \ - ) instructionTable[opcode] = [=] - #define bit(n) (opcode >> n & 1) - #define bits(hi, lo) ((opcode >> lo) & ((1 << (hi - lo + 1)) - 1)) + ) - for(uint opcode : range(65536)) { - if(0); + #define bind(name, ...) \ + instructionTable[opcode] = [=] { return instruction##name(__VA_ARGS__); }; \ + disassembleTable[opcode] = [=] { return disassemble##name(__VA_ARGS__); }; \ + + #define bit(x) (uint)opcode.bit(x) + #define bits(x, y) (uint)opcode.bits(x, y) + + for(uint16 opcode : range(65536)) { + + //ANDI + match("0000 0010 ---- ----") { + auto size = bits(7,6); + auto mode = bits(5,3); + auto reg = bits(2,0); + + size = size == 0 ? Byte : size == 1 ? Word : size == 2 ? Long : 0; + if(size && mode != 1) { + bind(ANDI, size, {mode, reg}); + } + } + + //BCC + match("0110 ---- ---- ----") { + auto condition = bits(11,8); + auto displacement = bits(7,0); + + if(true) { + bind(BCC, condition, displacement); + } + } + + //LEA + match("0100 ---1 11-- ----") { + auto target = bits(11,9); + auto mode = bits(5,3); + auto reg = bits(2,0); + + if(mode == 2 || mode == 5 || mode == 6 || (mode == 7 && reg <= 4)) { + bind(LEA, target, {mode, reg}); + } + } + + //MOVE + match("00-- ---- ---- ----") { + auto size = bits(13,12); + auto targetReg = bits(11,9); + auto targetMode = bits(8,6); + auto sourceMode = bits(5,3); + auto sourceReg = bits(2,0); + + size = size == 1 ? Byte : size == 3 ? Word : size == 2 ? Long : 0; + if(size && targetMode != 1) { + bind(MOVE, size, {targetMode, targetReg}, {sourceMode, sourceReg}); + } + } + + //MOVEA + match("00-- ---0 01-- ----") { + auto size = bits(13,12); + auto target = bits(11,9); + auto sourceMode = bits(5,3); + auto sourceReg = bits(2,0); + + size = size == 3 ? Word : size == 2 ? Long : 0; + if(size) { + bind(MOVEA, size, target, {sourceMode, sourceReg}); + } + } + + //MOVEM + match("0100 1-00 1--- ----") { + auto direction = bit(10); + auto size = bit(6); + auto mode = bits(5,3); + auto reg = bits(2,0); + + size = size == 0 ? Word : size == 1 ? Long : 0; + if((direction == 0 && (mode == 2 || mode == 4 || mode == 5 || mode == 6 || (mode == 7 && reg <= 3))) + || (direction == 1 && (mode == 2 || mode == 3 || mode == 5 || mode == 6 || (mode == 7 && reg <= 3)))) { + bind(MOVEM, direction, size, {mode, reg}); + } + } + + //MOVEQ + match("0111 ---0 ---- ----") { + auto target = bits(11,9); + auto immediate = bits(7,0); + + if(true) { + bind(MOVEQ, target, immediate); + } + } + + //MOVE_USP + match("0100 1110 0110 ----") { + auto direction = bit(3); + auto reg = bits(2,0); + + if(true) { + bind(MOVE_USP, direction, reg); + } + } //NOP match("0100 1110 0111 0001") { - instructionNOP(); - }; + if(true) { + bind(NOP); + } + } - //MOVEM (direction, size, mode, register) - match("0100 1-00 1--- ----") { - instructionMOVEM(bit(10), EA{1 + bit(6), bits(5,3), bits(2,0)}); - }; - - //TST (size, mode, register) + //TST match("0100 1010 ---- ----") { - instructionTST(EA{bits(7,6), bits(5,3), bits(2,0)}); - }; + auto size = bits(7,6); + auto mode = bits(5,3); + auto reg = bits(2,0); - //LEA (An, mode, register) - match("0100 ---1 11-- ----") { - instructionLEA(bits(11,9), EA{Long, bits(5,3), bits(2,0)}); - }; + size = size == 0 ? Byte : size == 1 ? Word : size == 2 ? Long : 0; + if(size) { + bind(TST, size, {mode, reg}); + } + } - //BCC (condition, displacement) - match("0110 ---- ---- ----") { - instructionBCC(bits(11,8), bits(7,0)); - }; + } + + for(uint16 opcode : range(65536)) { + if(instructionTable[opcode]) continue; + instructionTable[opcode] = [=] { trap(); }; + disassembleTable[opcode] = [=] { return string{"???"}; }; } #undef match + #undef bind #undef bit #undef bits } diff --git a/higan/processor/m68k/instructions.cpp b/higan/processor/m68k/instructions.cpp index 6d69df8e..eba80c43 100644 --- a/higan/processor/m68k/instructions.cpp +++ b/higan/processor/m68k/instructions.cpp @@ -22,34 +22,83 @@ auto M68K::testCondition(uint4 condition) -> bool { // -auto M68K::instructionBCC(uint4 condition, uint8 displacementByte) -> void { - uint16 displacementWord = readWordPC(); - if(displacementByte) r.pc -= 2; +auto M68K::instructionANDI(uint size, EA modify) -> void { + auto data = readPC(size); + write(size, modify, data = read(size, modify) & data); + + r.c = 0; + r.v = 0; + r.z = data == 0; + r.n = sign(size, data) < 0; +} + +auto M68K::instructionBCC(uint condition, uint displacement) -> void { + auto word = readPC(); + if(displacement) displacement = (int8)displacement, r.pc -= 2; + else displacement = (int16)word; if(condition == 1) { condition = 0; //pushLong(r.pc); } - if(testCondition(condition)) { - r.pc += displacementByte ? (int8_t)displacementByte : ((int16_t)displacementWord - 2); + if(testCondition(condition)) r.pc += displacement; +} + +auto M68K::instructionLEA(uint target, EA source) -> void { + r.a(target) = address(Long, source); +} + +auto M68K::instructionMOVE(uint size, EA target, EA source) -> void { + auto data = read(size, source); + write(size, target, data); + + r.c = 0; + r.v = 0; + r.z = data == 0; + r.n = sign(size, data) < 0; +} + +auto M68K::instructionMOVEA(uint size, uint target, EA source) -> void { + r.d(target) = read(size, source); +} + +auto M68K::instructionMOVEM(uint direction, uint size, EA source) -> void { + auto list = readPC(); + + for(uint n : range(8)) { + if(list.bit(0 + n)) r.d(n) = read(size, source); + } + + for(uint n : range(8)) { + if(list.bit(8 + n)) r.a(n) = read(size, source); } } -auto M68K::instructionLEA(uint3 wr, EA ea) -> void { - r.a(wr) = address(ea); +auto M68K::instructionMOVEQ(uint target, uint immediate) -> void { + r.d(target) = immediate; + + r.c = 0; + r.v = 0; + r.z = immediate == 0; + r.v = sign(Byte, immediate) < 0; } -auto M68K::instructionMOVEM(uint1 direction, EA ea) -> void { - auto list = readWordPC(); +auto M68K::instructionMOVE_USP(uint direction, uint reg) -> void { + if(!r.s) trap(); + if(direction == 0) { + r.usp = r.a(reg); + } else { + r.a(reg) = r.usp; + } } auto M68K::instructionNOP() -> void { } -auto M68K::instructionTST(EA ea) -> void { - auto data = read(ea); +auto M68K::instructionTST(uint size, EA source) -> void { + auto data = read(size, source); r.c = 0; r.v = 0; r.z = data == 0; - r.n = signExtend(ea.size, data) < 0; + r.n = sign(size, data) < 0; } diff --git a/higan/processor/m68k/m68k.cpp b/higan/processor/m68k/m68k.cpp index 35419d00..31c9842c 100644 --- a/higan/processor/m68k/m68k.cpp +++ b/higan/processor/m68k/m68k.cpp @@ -3,6 +3,7 @@ namespace Processor { +#include "registers.cpp" #include "memory.cpp" #include "ea.cpp" #include "instruction.cpp" @@ -15,40 +16,12 @@ auto M68K::power() -> void { auto M68K::reset() -> void { instructionsExecuted = 0; - r.d0 = r.d1 = r.d2 = r.d3 = r.d4 = r.d5 = r.d6 = r.d7 = 0; - r.a0 = r.a1 = r.a2 = r.a3 = r.a4 = r.a5 = r.a6 = r.usp = r.ssp = 0; + for(uint n : range(8)) r.d(n) = 0; + for(uint n : range(7)) r.a(n) = 0; + r.ssp = 0; + r.usp = 0; r.pc = 0; - r.ccr = 0; -} - -// - -auto M68K::Registers::d(uint3 reg) -> uint32& { - switch(reg) { - case 0: return d0; - case 1: return d1; - case 2: return d2; - case 3: return d3; - case 4: return d4; - case 5: return d5; - case 6: return d6; - case 7: return d7; - } - unreachable; -} - -auto M68K::Registers::a(uint3 reg) -> uint32& { - switch(reg) { - case 0: return a0; - case 1: return a1; - case 2: return a2; - case 3: return a3; - case 4: return a4; - case 5: return a5; - case 6: return a6; - case 7: return ssp; - } - unreachable; + r.sr = 0x2000; } } diff --git a/higan/processor/m68k/m68k.hpp b/higan/processor/m68k/m68k.hpp index 36ec66bb..ad3afbf0 100644 --- a/higan/processor/m68k/m68k.hpp +++ b/higan/processor/m68k/m68k.hpp @@ -5,6 +5,8 @@ namespace Processor { struct M68K { + enum : uint { Byte = 1, Word = 2, Long = 4 }; + M68K(); virtual auto step(uint clocks) -> void = 0; @@ -19,28 +21,23 @@ struct M68K { auto readWord(uint32 addr) -> uint16; auto readLong(uint32 addr) -> uint32; - auto readWordPC() -> uint16; - auto readLongPC() -> uint32; - - auto readAbsolute(uint2 size, uint32 addr) -> uint32; + auto read(uint size, uint32 addr) -> uint32; + auto readPC(uint size = Word) -> uint32; //ea.cpp struct EA { - EA(uint2 size, uint3 mode, uint3 reg) : size(size), mode(mode), reg(reg) {} - - uint2 size; - uint3 mode; - uint3 reg; + uint mode; + uint reg; boolean valid; uint32 address; }; - auto signExtend(uint2 size, uint32 data) -> int32; + auto sign(uint size, uint32 data) -> int32; - auto address(EA& ea) -> uint32; - auto read(EA& ea) -> uint32; - auto write(EA& ea, uint32 data) -> void; + auto address(uint size, EA& ea) -> uint32; + auto read(uint size, EA& ea) -> uint32; + auto write(uint size, EA& ea, uint32 data) -> void; //instruction.cpp auto trap() -> void; @@ -49,42 +46,76 @@ struct M68K { //instructions.cpp auto testCondition(uint4 condition) -> bool; - auto instructionBCC(uint4 condition, uint8 displacementByte) -> void; - auto instructionLEA(uint3 wr, EA ea) -> void; - auto instructionMOVEM(uint1 direction, EA ea) -> void; + auto instructionANDI(uint size, EA modify) -> void; + auto instructionBCC(uint condition, uint displacement) -> void; + auto instructionLEA(uint target, EA source) -> void; + auto instructionMOVE(uint size, EA target, EA source) -> void; + auto instructionMOVEA(uint size, uint target, EA source) -> void; + auto instructionMOVEM(uint direction, uint size, EA source) -> void; + auto instructionMOVEQ(uint target, uint immediate) -> void; + auto instructionMOVE_USP(uint direction, uint reg) -> void; auto instructionNOP() -> void; - auto instructionTST(EA ea) -> void; + auto instructionTST(uint size, EA source) -> void; //disassembler.cpp auto disassemble(uint32 pc) -> string; auto disassembleRegisters() -> string; - enum : uint { Byte = 0, Word = 1, Long = 2 }; - struct Registers { - auto d(uint3 reg) -> uint32&; - auto a(uint3 reg) -> uint32&; + auto d(uint3 r) -> uint32&; + auto a(uint3 r) -> uint32&; uint32 d0, d1, d2, d3, d4, d5, d6, d7; - uint32 a0, a1, a2, a3, a4, a5, a6, usp, ssp; + uint32 a0, a1, a2, a3, a4, a5, a6, ssp, usp; uint32 pc; union { - uint8 ccr; - BooleanBitField c; //carry - BooleanBitField v; //overflow - BooleanBitField z; //zero - BooleanBitField n; //negative - BooleanBitField x; //extend + uint16 sr; + BooleanBitField c; //carry + BooleanBitField v; //overflow + BooleanBitField z; //zero + BooleanBitField n; //negative + BooleanBitField x; //extend + NaturalBitField i; //interrupt mask + BooleanBitField s; //supervisor mode + BooleanBitField t; //trace mode }; - Registers() : ccr(0) {} + Registers() : sr(0) {} } r; uint16 opcode = 0; uint instructionsExecuted = 0; function instructionTable[65536]; + +private: + //disassembler.cpp + auto disassembleANDI(uint size, EA modify) -> string; + auto disassembleBCC(uint condition, uint displacement) -> string; + auto disassembleLEA(uint target, EA source) -> string; + auto disassembleMOVE(uint size, EA target, EA source) -> string; + auto disassembleMOVEA(uint size, uint target, EA source) -> string; + auto disassembleMOVEM(uint direction, uint size, EA source) -> string; + auto disassembleMOVEQ(uint target, uint immediate) -> string; + auto disassembleMOVE_USP(uint direction, uint reg) -> string; + auto disassembleNOP() -> string; + auto disassembleTST(uint size, EA source) -> string; + + auto _readByte(uint32 addr) -> uint8; + auto _readWord(uint32 addr) -> uint16; + auto _readLong(uint32 addr) -> uint32; + auto _readPC(uint size = Word) -> uint32; + auto _immediate(uint size) -> string; + auto _address(uint size, EA& ea) -> string; + auto _read(uint size, EA& ea) -> string; + auto _write(uint size, EA& ea) -> string; + auto _branch(uint displacement) -> string; + auto _suffix(uint size) -> string; + auto _condition(uint condition) -> string; + + uint32 _pc; + function disassembleTable[65536]; }; } diff --git a/higan/processor/m68k/memory.cpp b/higan/processor/m68k/memory.cpp index bd247a08..785f5bce 100644 --- a/higan/processor/m68k/memory.cpp +++ b/higan/processor/m68k/memory.cpp @@ -16,22 +16,19 @@ auto M68K::readLong(uint32 addr) -> uint32 { // -auto M68K::readWordPC() -> uint16 { - uint16 data = readWord(r.pc); +auto M68K::read(uint size, uint32 addr) -> uint32 { + if(size == Byte) return readByte(addr); + if(size == Word) return readWord(addr); + if(size == Long) return readLong(addr); + return 0; +} + +auto M68K::readPC(uint size) -> uint32 { + uint32 data = readWord(r.pc); + r.pc += 2; + if(size == Byte) return (uint8)data; + if(size == Word) return data; + data = data << 16 | readWord(r.pc); r.pc += 2; return data; } - -auto M68K::readLongPC() -> uint32 { - uint32 data = readWordPC() << 16; - return data |= readWordPC() << 0; -} - -// - -auto M68K::readAbsolute(uint2 size, uint32 addr) -> uint32 { - if(size == 0) return readByte(addr); - if(size == 1) return readWord(addr); - if(size == 2) return readLong(addr); - return 0; -} diff --git a/higan/processor/m68k/registers.cpp b/higan/processor/m68k/registers.cpp new file mode 100644 index 00000000..b31f1faa --- /dev/null +++ b/higan/processor/m68k/registers.cpp @@ -0,0 +1,26 @@ +auto M68K::Registers::d(uint3 r) -> uint32& { + switch(r) { + case 0: return d0; + case 1: return d1; + case 2: return d2; + case 3: return d3; + case 4: return d4; + case 5: return d5; + case 6: return d6; + case 7: return d7; + } + unreachable; +} + +auto M68K::Registers::a(uint3 r) -> uint32& { + switch(r) { + case 0: return a0; + case 1: return a1; + case 2: return a2; + case 3: return a3; + case 4: return a4; + case 5: return a5; + case 6: return a6; + case 7: return s ? ssp : usp; + } +}