diff --git a/higan/emulator/emulator.hpp b/higan/emulator/emulator.hpp index 6c792040..b427d189 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.08"; + static const string Version = "100.09"; 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 f030a2b7..72d86add 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 = readAbsolute(Long, 0); - r.pc = readAbsolute(Long, 4); + r.ssp = 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 ed133c21..410e119a 100644 --- a/higan/processor/m68k/disassembler.cpp +++ b/higan/processor/m68k/disassembler.cpp @@ -1,68 +1,53 @@ -auto M68K::_readByte(uint32 addr) -> uint8 { +template<> auto M68K::_read(uint32 addr) -> uint32 { return read(0, addr); } -auto M68K::_readWord(uint32 addr) -> uint16 { +template<> auto M68K::_read(uint32 addr) -> uint32 { return read(1, addr); } -auto M68K::_readLong(uint32 addr) -> uint32 { - uint32 data = _readWord(addr + 0) << 16; - return data |= _readWord(addr + 2) << 0; +template<> auto M68K::_read(uint32 addr) -> uint32 { + uint32 data = _read(addr + 0) << 16; + return data | _read(addr + 2) << 0; } -auto M68K::_readPC(uint2 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; +template auto M68K::_readPC() -> uint32 { + auto data = _read(_pc); + _pc += Size == Long ? 4 : 2; + return clip(data); } -auto M68K::_immediate(uint2 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::_register(Register r) -> string { + static const string registers[16] = { + "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", + "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7", + }; + return registers[r.number]; } -auto M68K::_address(uint8 ea) -> string { - uint3 mode = ea >> 5; - uint3 reg = ea >> 2; - uint2 size = ea >> 0; +template auto M68K::_immediate() -> string { + return {"#$", hex(_readPC(), 2 << Size)}; +} - if(mode == 7) { - if(reg == 2) return {"$", hex(_pc + (int16)_readPC(Word), 6L)}; - } +template auto M68K::_address(EA ea) -> string { + if(ea.mode == 9) return {"$", hex(_pc + (int16)_readPC(), 6L)}; return "???"; } -auto M68K::_read(uint8 ea) -> string { - uint3 mode = ea >> 5; - uint3 reg = ea >> 2; - uint2 size = ea >> 0; - - if(mode == 0) return {"d", reg}; - if(mode == 1) return {"a", reg}; - if(mode == 2) return {"(a", reg, ")"}; - if(mode == 3) return {"(a", reg, ")+"}; - if(mode == 4) return {"-(a", reg, ")"}; - if(mode == 5) return {"($", hex(r.a(reg) + (int16)_readPC(Word), 6L), ")"}; - if(mode == 7) { - if(reg == 1) return {"($", hex(_readPC(Long), 6L), ")"}; - if(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)}; - } - } +template auto M68K::_read(EA ea) -> string { + if(ea.mode == 0) return {_register(ea.reg)}; + if(ea.mode == 1) return {_register(ea.reg)}; + if(ea.mode == 2) return {"(", _register(ea.reg), ")"}; + if(ea.mode == 3) return {"(", _register(ea.reg), ")+"}; + if(ea.mode == 4) return {"-(", _register(ea.reg), ")"}; + if(ea.mode == 5) return {"($", hex(read(ea.reg) + (int16)_readPC(), 6L), ")"}; + if(ea.mode == 8) return {"($", hex(_readPC(), 6L), ")"}; + if(ea.mode == 11) return {"#$", hex(_readPC(), 2 << Size)}; return "???"; } -auto M68K::_write(uint8 ea) -> string { - return _read(ea); +template auto M68K::_write(EA ea) -> string { + return _read(ea); } auto M68K::_branch(uint8 displacement) -> string { @@ -72,11 +57,8 @@ auto M68K::_branch(uint8 displacement) -> string { return {"$", hex(_pc + displacement, 6L)}; } -auto M68K::_suffix(uint2 size) -> string { - if(size == Byte) return ".b"; - if(size == Word) return ".w"; - if(size == Long) return ".l"; - return ".?"; +template auto M68K::_suffix() -> string { + return Size == Byte ? ".b" : Size == Word ? ".w" : ".l"; } auto M68K::_condition(uint4 condition) -> string { @@ -111,64 +93,60 @@ auto M68K::disassembleRegisters() -> string { // -template auto M68K::disassembleADD(uint3 reg, uint1 direction, EA ea) -> string { - string op{"add", _suffix(ea.reg), " "}; -return op; +template auto M68K::disassembleADD(Register rd, uint1 direction, EA ea) -> string { + string op{"add", _suffix(), " "}; if(direction == 0) { -// return {op, _read(ea), ",d", reg}; + return {op, _read(ea), ",", _register(rd)}; } else { -// return {op, "d", reg, ",", _read(ea)}; + return {op, "", _register(rd), ",", _read(ea)}; } } -auto M68K::disassembleANDI(uint8 ea) -> string { - return {"andi", _suffix(ea), " ", _immediate(ea), ",", _read(ea)}; +template auto M68K::disassembleANDI(EA ea) -> string { + return {"andi", _suffix(), " ", _immediate(), ",", _read(ea)}; } auto M68K::disassembleBCC(uint4 condition, uint8 displacement) -> string { return {"b", _condition(condition), " ", _branch(displacement)}; } -auto M68K::disassembleLEA(uint3 to, uint8 ea) -> string { - return {"lea ", _address(ea), ",a", to}; +auto M68K::disassembleLEA(Register ra, EA ea) -> string { + return {"lea ", _address(ea), ",", _register(ra)}; } -auto M68K::disassembleMOVE(uint8 to, uint8 from) -> string { - return {"move", _suffix(from), " ", _read(from), ",", _write(to)}; +template auto M68K::disassembleMOVE(EA to, EA from) -> string { + return {"move", _suffix(), " ", _read(from), ",", _write(to)}; } -auto M68K::disassembleMOVEA(uint3 to, uint8 from) -> string { - return {"movea ", _read(from), ",a", to}; +template auto M68K::disassembleMOVEA(Register ra, EA ea) -> string { + return {"movea ", _read(ea), ",", _register(ra)}; } -auto M68K::disassembleMOVEM(uint1 direction, uint8 ea) -> string { - string op{"movem", _suffix(ea), " "}; +template auto M68K::disassembleMOVEM(uint1 direction, EA ea) -> string { + string op{"movem", _suffix(), " "}; 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, ","); + for(uint rn : range(16)) if(list.bit(rn)) regs.append(_register(Register{rn}), ","); regs.trimRight(","); if(direction == 0) { - return {op, regs, ",", _read(ea)}; + return {op, regs, ",", _read(ea)}; } else { - return {op, _read(ea), ",", regs}; + return {op, _read(ea), ",", regs}; } } -auto M68K::disassembleMOVEQ(uint3 target, uint8 immediate) -> string { - return {"moveq #$", hex(immediate, 2L), ",d", target}; +auto M68K::disassembleMOVEQ(Register rd, uint8 immediate) -> string { + return {"moveq #$", hex(immediate, 2L), ",", _register(rd)}; } -auto M68K::disassembleMOVE_USP(uint1 direction, uint3 reg) -> string { +auto M68K::disassembleMOVE_USP(uint1 direction, Register ra) -> string { if(direction == 0) { - return {"move a", reg, ",usp"}; + return {"move ", _register(ra), ",usp"}; } else { - return {"move usp,a", reg}; + return {"move usp,", _register(ra)}; } } @@ -176,6 +154,6 @@ auto M68K::disassembleNOP() -> string { return {"nop "}; } -auto M68K::disassembleTST(uint8 ea) -> string { - return {"tst", _suffix(ea), " ", _read(ea)}; +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 c34a0954..5cc2872a 100644 --- a/higan/processor/m68k/ea.cpp +++ b/higan/processor/m68k/ea.cpp @@ -1,423 +1,203 @@ -//effective addressing +template auto M68K::fetch(EA& ea) -> uint32 { + ea.valid = true; -//encoding: -// d7-d5: mode -// d4-d2: register -// d1-d0: size (0 = byte, 1 = word, 2 = long) + switch(ea.mode) { -auto M68K::address(uint8 ea) -> uint32 { - switch(ea) { - - //data register direct - case 0b000'000'00 ... 0b000'111'11: - return r.d(ea >> 2); - - //address register direct - case 0b001'000'00 ... 0b001'111'11: - return r.a(ea >> 2); - - //address register indirect - case 0b010'000'00 ... 0b010'111'11: - return r.a(ea >> 2); - - //address register indirect with post-increment - case 0b011'000'00 ... 0b011'111'11: - return r.a(ea >> 2); - - //address register indirect with pre-decrement - case 0b100'000'00 ... 0b100'111'11: - return r.a(ea >> 2); - - //address register indirect with displacement - case 0b101'000'00 ... 0b101'111'11: - return r.a(ea >> 2) + (int16)readPC(); - - //address register indirect with index - case 0b110'000'00 ... 0b110'111'11: { - auto word = readPC(); - auto index = word & 0x8000 ? r.a(word >> 12) : r.d(word >> 12); - if(word & 0x800) index = (int16)index; - return r.a(ea >> 2) + index + (int8)word; + case 0: { //data register direct + return read(ea.reg); } - //absolute short indirect - case 0b111'000'00 ... 0b111'000'11: + case 1: { //data register indirect + return read(ea.reg); + } + + case 2: { //address register indirect + return read(ea.reg); + } + + case 3: { //address register indirect with post-increment + return read(ea.reg); + } + + case 4: { //address register indirect with pre-decrement + return read(ea.reg); + } + + case 5: { //address register indirect with displacement + return read(ea.reg) + (int16)readPC(); + } + + case 6: { //address register indirect with index + 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 return (int16)readPC(); - - //absolute long indirect - case 0b111'001'00 ... 0b111'001'11: { - uint32 address = readPC() << 16; - return address | readPC() << 0; } - //program counter indirect with displacement - case 0b111'010'00 ... 0b111'010'11: { + case 8: { //absolute long indirect + return readPC(); + } + + case 9: { //program counter indirect with displacement auto base = r.pc; return base + (int16)readPC(); } - //program counter indirect with index - case 0b111'011'00 ... 0b111'011'11: { + case 10: { //program counter indirect with index auto base = r.pc; - auto word = readPC(); - auto index = word & 0x8000 ? r.a(word >> 12) : r.d(word >> 12); - if(word & 0x800) index = (int16)index; - return base + index + (int8)word; + auto extension = readPC(); + auto index = read(Register{extension >> 12}); + if(extension & 0x800) index = (int16)index; + return base + index + (int8)extension; } - //immediate byte - case 0b111'100'00: - return (uint8)readPC(); - - //immediate word - case 0b111'100'01: - return readPC(); - - //immediate long - case 0b111'100'10: { - uint32 address = readPC() << 16; - return address | readPC() << 0; + case 11: { //immediate + return readPC(); } - //invalid - default: - return 0; - } + + return 0; } -template auto M68K::read(EA ea) -> uint32 { +template auto M68K::read(EA& ea) -> uint32 { + if(!ea.valid) ea.address = fetch(ea); + switch(ea.mode) { case 0: { //data register direct - return clip(r.d(ea.reg)); + return clip(ea.address); } case 1: { //address register direct - return clip(r.a(ea.reg)); + return clip(ea.address); } case 2: { //address register indirect - auto& address = r.a(ea.reg); - return read(address); + return read(ea.address); } case 3: { //address register indirect with post-increment - auto& address = r.a(ea.reg); - auto data = read(address); - address += Size == Long ? 4 : 2; + 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& address = r.a(ea.reg); - address -= Size == Long ? 4 : 2; - return read(address); - } - - } -} - -template auto M68K::write(EA ea, uint32 data) -> void { - switch(ea.mode) { - - case 0: { //data register direct - r.d(ea.reg) = data; - return; - } - - case 1: { //address register direct - r.a(ea.reg) = data; - return; - } - - } -} - -auto M68K::read(uint8 ea) -> uint32 { - switch(ea) { - - //data register direct - case 0b000'000'00 ... 0b000'111'11: - return r.d(ea >> 2); - - //address register direct - case 0b001'000'00 ... 0b001'111'11: - return r.a(ea >> 2); - - //address register indirect - case 0b010'000'00 ... 0b010'111'11: { - auto address = r.a(ea >> 2); - return readAbsolute(ea, address); - } - - //address register indirect with post-increment - case 0b011'000'00 ... 0b011'111'11: { - auto& address = r.a(ea >> 2); - auto data = readAbsolute(ea, address); - address += 2 + (ea & 2); + auto data = read((uint32)(ea.address - (Size == Long ? 4 : 2))); + if(Update) write(ea.reg, ea.address -= (Size == Long ? 4 : 2)); return data; } - //address register indirect with pre-decrement - case 0b100'000'00 ... 0b100'111'11: { - auto& address = r.a(ea >> 2); - address -= 2 + (ea & 2); - return readAbsolute(ea, address); + case 5: { //address register indirect with displacement + return read(ea.address); } - //address register indirect with displacement - case 0b101'000'00 ... 0b101'111'11: - return readAbsolute(ea, r.a(ea >> 2) + (int16)readPC()); - - //address register indirect with index - case 0b110'000'00 ... 0b110'111'11: { - auto word = readPC(); - auto index = word & 0x8000 ? r.a(word >> 12) : r.d(word >> 12); - if(word & 0x800) index = (int16)index; - return readAbsolute(ea, r.a(ea >> 2) + index + (int8)word); + case 6: { //address register indirect with index + return read(ea.address); } - //absolute short indirect - case 0b111'000'00 ... 0b111'000'11: - return readAbsolute(ea, (int16)readPC()); - - //absolute long indirect - case 0b111'001'00 ... 0b111'001'11: { - uint32 address = readPC() << 16; - return readAbsolute(ea, address | readPC()); + case 7: { //absolute short indirect + return read(ea.address); } - //program counter indirect with displacement - case 0b111'010'00 ... 0b111'010'11: { - auto base = r.pc; - return readAbsolute(ea, base + (int16)readPC()); + case 8: { //absolute long indirect + return read(ea.address); } - //program counter indirect with index - case 0b111'011'00 ... 0b111'011'11: { - auto base = r.pc; - auto word = readPC(); - auto index = word & 0x8000 ? r.a(word >> 12) : r.d(word >> 12); - if(word & 0x800) index = (int16)index; - return readAbsolute(ea, base + index + (int8)word); + case 9: { //program counter indirect with displacement + return read(ea.address); } - //immediate byte - case 0b111'100'00: - return (uint8)readPC(); - - //immediate word - case 0b111'100'01: - return readPC(); - - //immediate long - case 0b111'100'10: { - uint32 address = readPC() << 16; - return address | readPC() << 0; + case 10: { //program counter indirect with index + return read(ea.address); } - //invalid - default: - return 0; + case 11: { //immediate + return clip(ea.address); + } } + + return 0; } -auto M68K::write(uint8 ea, uint32 data) -> void { - switch(ea) { +template auto M68K::write(EA& ea, uint32 data) -> void { + if(!ea.valid) ea.address = fetch(ea); - //data register direct - case 0b000'000'00 ... 0b000'111'11: - r.d(ea >> 2) = data; - return; + switch(ea.mode) { - //address register direct - case 0b001'000'00 ... 0b001'111'11: - r.a(ea >> 2) = data; - return; - - //address register indirect - case 0b010'000'00 ... 0b010'111'11: { - auto address = r.a(ea >> 2); - return writeAbsolute(ea, address, data); + case 0: { //data register direct + return write(ea.reg, data); } - //address register indirect with post-increment - case 0b011'000'00 ... 0b011'111'11: { - auto& address = r.a(ea >> 2); - writeAbsolute(ea, address, data); - address += 2 + (ea & 2); + case 1: { //address register direct + return write(ea.reg, data); + } + + case 2: { //address register indirect + return write(ea.address, data); + } + + case 3: { //address register indirect with post-increment + write(ea.address, data); + if(Update) write(ea.reg, ea.address += (Size == Long ? 4 : 2)); return; } - //address register indirect with pre-decrement - case 0b100'000'00 ... 0b100'111'11: { - auto& address = r.a(ea >> 2); - address -= 2 + (ea & 2); - return writeAbsolute(ea, address, data); + case 4: { //address register indirect with pre-decrement + write((uint32)(ea.address - (Size == Long ? 4 : 2)), data); + if(Update) write(ea.reg, ea.address -= (Size == Long ? 4 : 2)); + return; } - //address register indirect with displacement - case 0b101'000'00 ... 0b101'111'11: - return writeAbsolute(ea, r.a(ea >> 2) + (int16)readPC(), data); - - //address register indirect with index - case 0b110'000'00 ... 0b110'111'11: { - auto word = readPC(); - auto index = word & 0x8000 ? r.a(word >> 12) : r.d(word >> 12); - if(word & 0x800) index = (int16)index; - return writeAbsolute(ea, r.a(ea >> 2) + index + (int8)word, data); + case 5: { //address register indirect with displacement + return write(ea.address, data); } - //absolute short indirect - case 0b111'000'00 ... 0b111'000'11: - return writeAbsolute(ea, (int16)readPC(), data); - - //absolute long indirect - case 0b111'001'00 ... 0b111'001'11: { - uint32 address = readPC() << 16; - return writeAbsolute(ea, address | readPC(), data); + case 6: { //address register indirect with index + return write(ea.address, data); } - //program counter indirect with displacement - case 0b111'010'00 ... 0b111'010'11: { - auto base = r.pc; - return writeAbsolute(ea, base + (int16)readPC(), data); + case 7: { //absolute short indirect + return write(ea.address, data); } - //program counter indirect with index - case 0b111'011'00 ... 0b111'011'11: { - auto base = r.pc; - auto word = readPC(); - auto index = word & 0x8000 ? r.a(word >> 12) : r.d(word >> 12); - if(word & 0x800) index = (int16)index; - return writeAbsolute(ea, base + index + (int8)word, data); + case 8: { //absolute long indirect + return write(ea.address, data); + } + + case 9: { //program counter indirect with displacement + return write(ea.address, data); + } + + case 10: { //program counter indirect with index + return write(ea.address, data); + } + + case 11: { //immediate + return; } } } -auto M68K::modify(uint8 ea, uint32 data, const function& op) -> uint32 { - switch(ea) { +template auto M68K::flush(EA& ea, uint32 data) -> void { + switch(ea.mode) { - //data register direct - case 0b000'000'00 ... 0b000'111'11: { - auto& address = r.d(ea >> 2); - return address = op(address, data); + case 3: { //address register indirect with post-increment + write(ea.reg, data); + return; } - //address register direct - case 0b001'000'00 ... 0b001'111'11: { - auto& address = r.a(ea >> 2); - return address = op(address, data); - } - - //address register indirect - case 0b010'000'00 ... 0b010'111'11: { - auto address = r.a(ea >> 2); - auto memory = readAbsolute(ea, address); - writeAbsolute(ea, address, memory = op(memory, data)); - return memory; - } - - //address register indirect with post-increment - case 0b011'000'00 ... 0b011'111'11: { - auto& address = r.a(ea >> 2); - auto memory = readAbsolute(ea, address); - writeAbsolute(ea, address, memory = op(memory, data)); - address += 2 + (ea & 2); - return memory; - } - - //address register indirect with pre-decrement - case 0b100'000'00 ... 0b100'111'11: { - auto& address = r.a(ea >> 2); - address -= 2 + (ea & 2); - auto memory = readAbsolute(ea, address); - writeAbsolute(ea, address, memory = op(memory, data)); - return memory; - } - - //address register indirect with displacement - case 0b101'000'00 ... 0b101'111'11: { - auto address = r.a(ea >> 2) + (int16)readPC(); - auto memory = readAbsolute(ea, address); - writeAbsolute(ea, address, memory = op(memory, data)); - return memory; - } - - //address register indirect with index - case 0b110'000'00 ... 0b110'111'11: { - auto word = readPC(); - auto index = word & 0x8000 ? r.a(word >> 12) : r.d(word >> 12); - if(word & 0x800) index = (int16)index; - auto address = r.a(ea >> 2) + index + (int8)word; - auto memory = readAbsolute(ea, address); - writeAbsolute(ea, address, memory = op(memory, data)); - return memory; - } - - //absolute short indirect - case 0b111'000'00 ... 0b111'000'11: { - auto address = (int16)readPC(); - auto memory = readAbsolute(ea, address); - writeAbsolute(ea, address, memory = op(memory, data)); - return memory; - } - - //absolute long indirect - case 0b111'001'00 ... 0b111'001'11: { - auto word = readPC(); - uint32 address = word << 16 | readPC(); - auto memory = readAbsolute(ea, address); - writeAbsolute(ea, address, memory = op(memory, data)); - return memory; - } - - //program counter indirect with displacement - case 0b111'010'00 ... 0b111'010'11: { - auto address = r.pc; - address += (int16)readPC(); - auto memory = readAbsolute(ea, address); - writeAbsolute(ea, address, memory = op(memory, data)); - return memory; - } - - //program counter indirect with index - case 0b111'011'00 ... 0b111'011'11: { - auto address = r.pc; - auto word = readPC(); - auto index = word & 0x8000 ? r.a(word >> 12) : r.d(word >> 12); - if(word & 0x8000) index = (int16)index; - address += index + (int8)word; - auto memory = readAbsolute(ea, address); - writeAbsolute(ea, address, memory = op(memory, data)); - return memory; - } - - //immediate byte - case 0b111'100'00: - return op((uint8)readPC(), data); - - //immediate word - case 0b111'100'01: - return op(readPC(), data); - - //immediate long - case 0b111'100'10: { - uint32 immediate = readPC() << 16; - immediate |= readPC(); - return op(immediate, data); + case 4: { //address register indirect with pre-decrement + write(ea.reg, data); + return; } } } - -auto M68K::flush(uint8 ea, uint32 address) -> void { - //address register indirect with post-increment - //address register indirect with pre-decrement - if(ea >= 0b011'000'00 && ea <= 0b100'111'11) { - r.a(ea >> 2) = address; - } -} diff --git a/higan/processor/m68k/instruction.cpp b/higan/processor/m68k/instruction.cpp index b0af621a..11bd9937 100644 --- a/higan/processor/m68k/instruction.cpp +++ b/higan/processor/m68k/instruction.cpp @@ -8,7 +8,9 @@ auto M68K::trap() -> void { auto M68K::instruction() -> void { instructionsExecuted++; - print(disassembleRegisters(), "\n", disassemble(r.pc), "\n\n"); + print(disassembleRegisters(), "\n"); + print(disassemble(r.pc), "\n"); + print("\n"); opcode = readPC(); return instructionTable[opcode](); @@ -18,180 +20,141 @@ M68K::M68K() { #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 pattern(s) \ + std::integral_constant::value //ADD - for(uint3 d : range(8)) + for(uint3 dreg : range(8)) for(uint1 direction : range(2)) for(uint3 mode : range(8)) for(uint3 reg : range(8)) { - auto opcode = 0b1101'0000'0000'0000 | d << 9 | direction << 8 | mode << 3 | reg << 0; + 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}; EA ea{mode, reg}; - bind(opcode | 0 << 6, ADD, d, direction, ea); - bind(opcode | 1 << 6, ADD, d, direction, ea); - bind(opcode | 2 << 6, ADD, d, direction, ea); + bind(opcode | 0 << 6, ADD, rd, direction, ea); + bind(opcode | 1 << 6, ADD, rd, direction, ea); + bind(opcode | 2 << 6, ADD, rd, direction, ea); + } + + //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; + + EA ea{mode, reg}; + bind(opcode | 0 << 6, ANDI, ea); + bind(opcode | 1 << 6, ANDI, ea); + bind(opcode | 2 << 6, ANDI, ea); + } + + //BCC + for(uint4 condition : range( 16)) + for(uint8 displacement : range(256)) { + auto opcode = pattern("0110 ---- ---- ----") | condition << 8 | displacement << 0; + + bind(opcode, BCC, condition, displacement); + } + + //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; + + Register ra{8u + areg}; + EA ea{mode, reg}; + bind(opcode, LEA, ra, ea); + } + + //MOVE + for(uint3 toReg : range(8)) + for(uint3 toMode : range(8)) + 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; + + 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); + } + + //MOVEA + for(uint3 areg : range(8)) + for(uint3 mode : range(8)) + for(uint3 reg : range(8)) { + auto opcode = pattern("00++ ---0 01-- ----") | areg << 9 | mode << 3 | reg << 0; + + Register ra{8u + areg}; + EA ea{mode, reg}; + bind(opcode | 3 << 12, MOVEA, ra, ea); + bind(opcode | 2 << 12, MOVEA, ra, ea); + } + + //MOVEM + for(uint1 direction : range(2)) + 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)); + + EA ea{mode, reg}; + bind(opcode | 0 << 6, MOVEM, direction, ea); + bind(opcode | 1 << 6, MOVEM, direction, ea); + } + + //MOVEQ + for(uint3 dreg : range( 8)) + for(uint8 immediate : range(256)) { + auto opcode = pattern("0111 ---0 ---- ----") | dreg << 9 | immediate << 0; + + Register rd{0u + dreg}; + bind(opcode, MOVEQ, rd, immediate); + } + + //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}; + bind(opcode, MOVE_USP, direction, ra); + } + + //NOP + { auto opcode = pattern("0100 1110 0111 0001"); + + bind(opcode, NOP); + } + + //TST + for(uint3 mode : range(8)) + for(uint3 reg : range(8)) { + auto opcode = pattern("0100 1010 ++-- ----") | mode << 3 | reg << 0; + + EA ea{mode, reg}; + bind(opcode | 0 << 6, TST, ea); + bind(opcode | 1 << 6, TST, ea); + bind(opcode | 2 << 6, TST, ea); } #undef bind + #undef pattern - #define match(pattern) if( \ - (opcode & std::integral_constant::value) \ - == std::integral_constant::value \ - ) - - #define bind(name, ...) \ - assert(!instructionTable[opcode]); \ - 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)) { - -/* - //ADD - match("1101 ---- ---- ----") { - uint3 r = bits(11,9); - uint1 direction = bit(8); - uint2 size = bits(7,6); - uint3 mode = bits(5,3); - uint3 reg = bits(2,0); - - if(size != 3 && (direction == 0 || (mode == 2 || mode == 3 || mode == 4 || mode == 5 || mode == 6 || (mode == 7 && reg <= 1)))) { - uint8 ea = mode << 5 | reg << 2 | size; - bind(ADD, r, direction, ea); - } - } -*/ - - //ANDI - match("0000 0010 ---- ----") { - uint2 size = bits(7,6); - uint3 mode = bits(5,3); - uint3 reg = bits(2,0); - - if(size != 3 && mode != 1) { - uint8 ea = mode << 5 | reg << 2 | size; - bind(ANDI, ea); - } - } - - //BCC - match("0110 ---- ---- ----") { - uint4 condition = bits(11,8); - uint8 displacement = bits(7,0); - - if(true) { - bind(BCC, condition, displacement); - } - } - - //LEA - match("0100 ---1 11-- ----") { - uint3 target = bits(11,9); - uint3 mode = bits(5,3); - uint3 reg = bits(2,0); - - if(mode == 2 || mode == 5 || mode == 6 || (mode == 7 && reg <= 4)) { - uint8 ea = mode << 5 | reg << 2 | Long; - bind(LEA, target, ea); - } - } - - //MOVE - match("00-- ---- ---- ----") { - uint2 size = bits(13,12) == 1 ? Byte : bits(13,12) == 3 ? Word : bits(13,12) == 2 ? Long : 3; - uint3 targetReg = bits(11,9); - uint3 targetMode = bits(8,6); - uint3 sourceMode = bits(5,3); - uint3 sourceReg = bits(2,0); - - if(size != 3 && targetMode != 1) { - uint8 to = targetMode << 5 | targetReg << 2 | size; - uint8 from = sourceMode << 5 | sourceReg << 2 | size; - bind(MOVE, to, from); - } - } - - //MOVEA - match("00-- ---0 01-- ----") { - uint2 size = bits(13,12) == 3 ? Word : bits(13,12) == 2 ? Long : 3; - uint3 to = bits(11,9); - uint3 mode = bits(5,3); - uint3 reg = bits(2,0); - - if(size != 3) { - uint8 from = mode << 5 | reg << 2 | size; - bind(MOVEA, to, from); - } - } - - //MOVEM - match("0100 1-00 1--- ----") { - uint1 direction = bit(10); - uint2 size = 1 + bit(6); - uint3 mode = bits(5,3); - uint3 reg = bits(2,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)))) { - uint8 ea = mode << 5 | reg << 2 | size; - bind(MOVEM, direction, ea); - } - } - - //MOVEQ - match("0111 ---0 ---- ----") { - uint3 target = bits(11,9); - uint8 immediate = bits(7,0); - - if(true) { - bind(MOVEQ, target, immediate); - } - } - - //MOVE_USP - match("0100 1110 0110 ----") { - uint1 direction = bit(3); - uint3 reg = bits(2,0); - - if(true) { - bind(MOVE_USP, direction, reg); - } - } - - //NOP - match("0100 1110 0111 0001") { - if(true) { - bind(NOP); - } - } - - //TST - match("0100 1010 ---- ----") { - uint2 size = bits(7,6); - uint3 mode = bits(5,3); - uint3 reg = bits(2,0); - - if(size != 3) { - uint8 ea = mode << 5 | reg << 2 | size << 0; - bind(TST, ea); - } - } - - } - - #undef match - #undef bind - #undef bit - #undef bits - + uint unimplemented = 0; for(uint16 opcode : range(65536)) { if(instructionTable[opcode]) continue; instructionTable[opcode] = [=] { trap(); }; disassembleTable[opcode] = [=] { return string{"???"}; }; + unimplemented++; } +//print("[M68K] unimplemented opcodes: ", unimplemented, "\n"); } diff --git a/higan/processor/m68k/instructions.cpp b/higan/processor/m68k/instructions.cpp index 8bbe7c7a..79278ed5 100644 --- a/higan/processor/m68k/instructions.cpp +++ b/higan/processor/m68k/instructions.cpp @@ -46,30 +46,20 @@ template auto M68K::negative(uint32 result) -> bool { return sign(result) < 0; } -auto M68K::zero(uint2 size, uint32 result) -> bool { - static const uint32 mask[4] = {0xff, 0xffff, 0xffffffff}; - return (result & mask[size]) == 0; -} - -auto M68K::negative(uint2 size, uint32 result) -> bool { - static const uint32 mask[4] = {0x80, 0x8000, 0x80000000}; - return result & mask[size]; -} - // -template auto M68K::instructionADD(uint3 reg, uint1 direction, EA ea) -> void { +template auto M68K::instructionADD(Register rd, uint1 direction, EA ea) -> void { uint32 source; uint32 target; uint32 result; if(direction == 0) { source = read(ea); - target = r.d(reg); + target = read(rd); result = source + target; - r.d(reg) = result; + write(rd, result); } else { - source = r.d(reg); + source = read(rd); target = read(ea); result = source + target; write(ea, result); @@ -82,95 +72,86 @@ template auto M68K::instructionADD(uint3 reg, uint1 direction, EA ea) r.x = r.c; } -auto M68K::instructionANDI(uint8 ea) -> void { - auto result = modify(ea, readPC(ea), [&](auto x, auto y) -> uint32 { - return x & y; - }); +template auto M68K::instructionANDI(EA ea) -> void { + auto source = readPC(); + auto target = read(ea); + auto result = target & source; + write(ea, result); r.c = 0; r.v = 0; - r.z = zero(ea, result); - r.n = negative(ea, result); + r.z = zero(result); + r.n = negative(result); } auto M68K::instructionBCC(uint4 condition, uint8 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 += displacement; + auto extension = readPC(); + if(condition == 1); //push(r.pc); + r.pc -= 2; + if(!testCondition(condition == 1 ? (uint4)0 : condition)) return; + r.pc += displacement ? sign(displacement) : sign(extension); } -auto M68K::instructionLEA(uint3 target, uint8 ea) -> void { - r.a(target) = address(ea); +auto M68K::instructionLEA(Register ra, EA ea) -> void { + write(ra, fetch(ea)); } -auto M68K::instructionMOVE(uint8 to, uint8 from) -> void { - auto data = read(from); - write(to, data); +template auto M68K::instructionMOVE(EA to, EA from) -> void { + auto data = read(from); + write(to, data); r.c = 0; r.v = 0; - r.z = zero(from, data); - r.n = negative(from, data); + r.z = zero(data); + r.n = negative(data); } -auto M68K::instructionMOVEA(uint3 to, uint8 from) -> void { - auto data = read(from); - if(from & 1) data = (int16)data; - r.a(to) = data; +template auto M68K::instructionMOVEA(Register ra, EA ea) -> void { + auto data = read(ea); + if(Size == Word) data = (int16)data; + write(ra, data); } -auto M68K::instructionMOVEM(uint1 direction, uint8 ea) -> void { +template auto M68K::instructionMOVEM(uint1 direction, EA ea) -> void { auto list = readPC(); - auto addr = address(ea); + auto addr = fetch(ea); - for(uint n : range(8)) { - if(list.bit(0 + n)) { - r.d(n) = readAbsolute(ea, addr); - addr += 2 + (ea & 2); + for(uint rn : range(16)) { + if(list.bit(rn)) { + write(Register{rn}, read(addr)); + addr += Size == Long ? 4 : 2; } } - for(uint n : range(8)) { - if(list.bit(8 + n)) { - r.a(n) = readAbsolute(ea, addr); - addr += 2 + (ea & 2); - } - } - - flush(ea, addr); + flush(ea, addr); } -auto M68K::instructionMOVEQ(uint3 target, uint8 immediate) -> void { - r.d(target) = immediate; +auto M68K::instructionMOVEQ(Register rd, uint8 immediate) -> void { + write(rd, immediate); r.c = 0; r.v = 0; - r.z = immediate == 0; - r.n = negative(Byte, immediate); + r.z = zero(immediate); + r.n = negative(immediate); } -auto M68K::instructionMOVE_USP(uint1 direction, uint3 reg) -> void { +auto M68K::instructionMOVE_USP(uint1 direction, Register ra) -> void { if(!r.s) trap(); //todo: proper trap if(direction == 0) { - r.usp = r.a(reg); + r.usp = read(ra); } else { - r.a(reg) = r.usp; + write(ra, r.usp); } } auto M68K::instructionNOP() -> void { } -auto M68K::instructionTST(uint8 ea) -> void { - auto data = read(ea); +template auto M68K::instructionTST(EA ea) -> void { + auto data = read(ea); r.c = 0; r.v = 0; - r.z = zero(ea, data); - r.n = negative(ea, data); + r.z = zero(data); + r.n = negative(data); } diff --git a/higan/processor/m68k/m68k.cpp b/higan/processor/m68k/m68k.cpp index fed475b3..9e101a24 100644 --- a/higan/processor/m68k/m68k.cpp +++ b/higan/processor/m68k/m68k.cpp @@ -18,8 +18,7 @@ auto M68K::power() -> void { auto M68K::reset() -> void { instructionsExecuted = 0; - for(uint n : range(8)) r.d(n) = 0; - for(uint n : range(7)) r.a(n) = 0; + for(uint rn : range(15)) write(Register{rn}, 0); r.ssp = 0; r.usp = 0; r.pc = 0; diff --git a/higan/processor/m68k/m68k.hpp b/higan/processor/m68k/m68k.hpp index 210f9d13..e0579bac 100644 --- a/higan/processor/m68k/m68k.hpp +++ b/higan/processor/m68k/m68k.hpp @@ -6,6 +6,7 @@ namespace Processor { struct M68K { enum : uint { Byte, Word, Long }; + enum : bool { NoUpdate = 0 }; M68K(); @@ -16,32 +17,39 @@ struct M68K { auto power() -> void; auto reset() -> void; + //registers.cpp + struct Register { + Register(uint number) : number(number) {} + + uint4 number; + }; + + template auto read(Register reg) -> uint32; + template auto write(Register reg, uint32 value) -> void; + //memory.cpp - auto readAbsolute(uint2 size, uint32 addr) -> uint32; - auto writeAbsolute(uint2 size, uint32 addr, uint32 data) -> void; - - auto readPC(uint2 size = Word) -> uint32; - template auto read(uint32 addr) -> uint32; + template auto write(uint32 addr, uint32 data) -> void; + template auto readPC() -> uint32; //ea.cpp struct EA { - EA(uint3 mode, uint3 reg) : mode(mode), reg(reg) { - if(mode == 7) mode += reg; //optimization: convert modes {7; 0-4} to {8-11} + 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 } uint4 mode; - uint3 reg; + Register reg; + + boolean valid; + uint32 address; }; - template auto read(EA ea) -> uint32; - template auto write(EA ea, uint32 data) -> void; - - auto address(uint8 ea) -> uint32; - auto read(uint8 ea) -> uint32; - auto write(uint8 ea, uint32 data) -> void; - auto modify(uint8 ea, uint32 data, const function& op) -> uint32; - auto flush(uint8 ea, uint32 address) -> void; + template auto fetch(EA& ea) -> uint32; + template auto read(EA& ea) -> uint32; + template auto write(EA& ea, uint32 data) -> void; + template auto flush(EA& ea, uint32 data) -> void; //instruction.cpp auto trap() -> void; @@ -57,29 +65,24 @@ struct M68K { template auto overflow(uint32 result, uint32 source, uint32 target) -> bool; template auto zero(uint32 result) -> bool; template auto negative(uint32 result) -> bool; - auto zero(uint2 size, uint32 result) -> bool; - auto negative(uint2 size, uint32 result) -> bool; - template auto instructionADD(uint3 reg, uint1 direction, EA ea) -> void; - auto instructionANDI(uint8 ea) -> void; - auto instructionBCC(uint4 condition, uint8 displacement) -> void; - auto instructionLEA(uint3 target, uint8 source) -> void; - auto instructionMOVE(uint8 to, uint8 from) -> void; - auto instructionMOVEA(uint3 to, uint8 ea) -> void; - auto instructionMOVEM(uint1 direction, uint8 ea) -> void; - auto instructionMOVEQ(uint3 target, uint8 immediate) -> void; - auto instructionMOVE_USP(uint1 direction, uint3 reg) -> void; - auto instructionNOP() -> void; - auto instructionTST(uint8 ea) -> void; + template auto instructionADD(Register rd, uint1 direction, EA ea) -> void; + template auto instructionANDI(EA ea) -> void; + auto instructionBCC(uint4 condition, uint8 displacement) -> 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_USP(uint1 direction, Register ra) -> void; + auto instructionNOP() -> void; + template auto instructionTST(EA ea) -> void; //disassembler.cpp auto disassemble(uint32 pc) -> string; auto disassembleRegisters() -> string; struct Registers { - 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, ssp, usp; uint32 pc; @@ -106,28 +109,27 @@ struct M68K { private: //disassembler.cpp - template auto disassembleADD(uint3 reg, uint1 direction, EA ea) -> string; - auto disassembleANDI(uint8 ea) -> string; - auto disassembleBCC(uint4 condition, uint8 displacement) -> string; - auto disassembleLEA(uint3 target, uint8 ea) -> string; - auto disassembleMOVE(uint8 to, uint8 from) -> string; - auto disassembleMOVEA(uint3 to, uint8 from) -> string; - auto disassembleMOVEM(uint1 direction, uint8 ea) -> string; - auto disassembleMOVEQ(uint3 target, uint8 immediate) -> string; - auto disassembleMOVE_USP(uint1 direction, uint3 reg) -> string; - auto disassembleNOP() -> string; - auto disassembleTST(uint8 ea) -> string; + template auto disassembleADD(Register rd, uint1 direction, EA ea) -> string; + template auto disassembleANDI(EA ea) -> string; + auto disassembleBCC(uint4 condition, uint8 displacement) -> 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_USP(uint1 direction, Register ra) -> string; + auto disassembleNOP() -> string; + template auto disassembleTST(EA ea) -> string; - auto _readByte(uint32 addr) -> uint8; - auto _readWord(uint32 addr) -> uint16; - auto _readLong(uint32 addr) -> uint32; - auto _readPC(uint2 size = Word) -> uint32; - auto _immediate(uint2 size) -> string; - auto _address(uint8 ea) -> string; - auto _read(uint8 ea) -> string; - auto _write(uint8 ea) -> string; + template auto _read(uint32 addr) -> uint32; + template auto _readPC() -> uint32; + auto _register(Register r) -> string; + template auto _immediate() -> string; + template auto _address(EA ea) -> string; + template auto _read(EA ea) -> string; + template auto _write(EA ea) -> string; auto _branch(uint8 displacement) -> string; - auto _suffix(uint2 size) -> string; + template auto _suffix() -> string; auto _condition(uint4 condition) -> string; uint32 _pc; diff --git a/higan/processor/m68k/memory.cpp b/higan/processor/m68k/memory.cpp index 1021964b..13723890 100644 --- a/higan/processor/m68k/memory.cpp +++ b/higan/processor/m68k/memory.cpp @@ -1,24 +1,4 @@ -auto M68K::readAbsolute(uint2 size, uint32 addr) -> uint32 { - step(4); - uint32 data = read(size != Byte, addr); - if(size != Long) return data; - - step(4); - data = data << 16 | read(1, addr + 2); - return data; -} - -auto M68K::writeAbsolute(uint2 size, uint32 addr, uint32 data) -> void { - if(size == Long) { - write(1, addr + 0, data >> 16); - write(1, addr + 2, data >> 0); - } else { - write(size != Byte, addr, data >> 0); - } -} - -// - +/* auto M68K::readPC(uint2 size) -> uint32 { step(4); uint32 data = read(size != Byte, r.pc); @@ -30,8 +10,7 @@ auto M68K::readPC(uint2 size) -> uint32 { r.pc += 2; return data; } - -// +*/ template<> auto M68K::read(uint32 addr) -> uint32 { step(4); @@ -49,3 +28,40 @@ template<> auto M68K::read(uint32 addr) -> uint32 { step(4); return data | read(1, addr + 2) << 0; } + +// + +template<> auto M68K::write(uint32 addr, uint32 data) -> void { +} + +template<> auto M68K::write(uint32 addr, uint32 data) -> void { +} + +template<> auto M68K::write(uint32 addr, uint32 data) -> void { +} + +// + +template<> auto M68K::readPC() -> uint32 { + step(4); + uint32 data = read(1, r.pc); + r.pc += 2; + return (uint8)data; +} + +template<> auto M68K::readPC() -> uint32 { + step(4); + uint32 data = read(1, r.pc); + r.pc += 2; + return data; +} + +template<> auto M68K::readPC() -> uint32 { + step(4); + uint32 data = read(1, r.pc) << 16; + r.pc += 2; + step(4); + data |= read(1, r.pc); + r.pc += 2; + return data; +} diff --git a/higan/processor/m68k/registers.cpp b/higan/processor/m68k/registers.cpp index b31f1faa..6b381315 100644 --- a/higan/processor/m68k/registers.cpp +++ b/higan/processor/m68k/registers.cpp @@ -1,26 +1,42 @@ -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; +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; } -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; +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; } }