diff --git a/higan/emulator/emulator.hpp b/higan/emulator/emulator.hpp index 5f287915..6c792040 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.07"; + static const string Version = "100.08"; 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 7c31f216..ed133c21 100644 --- a/higan/processor/m68k/disassembler.cpp +++ b/higan/processor/m68k/disassembler.cpp @@ -11,7 +11,7 @@ auto M68K::_readLong(uint32 addr) -> uint32 { return data |= _readWord(addr + 2) << 0; } -auto M68K::_readPC(uint size) -> uint32 { +auto M68K::_readPC(uint2 size) -> uint32 { uint32 data = _readWord(_pc); _pc += 2; if(size == Byte) return (uint8)data; @@ -21,21 +21,29 @@ auto M68K::_readPC(uint size) -> uint32 { return data; } -auto M68K::_immediate(uint size) -> string { +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::_address(uint2 size, uint3 mode, uint3 reg) -> string { +auto M68K::_address(uint8 ea) -> string { + uint3 mode = ea >> 5; + uint3 reg = ea >> 2; + uint2 size = ea >> 0; + if(mode == 7) { if(reg == 2) return {"$", hex(_pc + (int16)_readPC(Word), 6L)}; } return "???"; } -auto M68K::_read(uint2 size, uint3 mode, uint3 reg) -> string { +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, ")"}; @@ -53,8 +61,8 @@ auto M68K::_read(uint2 size, uint3 mode, uint3 reg) -> string { return "???"; } -auto M68K::_write(uint2 size, uint3 mode, uint3 reg) -> string { - return _read(size, mode, reg); +auto M68K::_write(uint8 ea) -> string { + return _read(ea); } auto M68K::_branch(uint8 displacement) -> string { @@ -64,7 +72,7 @@ auto M68K::_branch(uint8 displacement) -> string { return {"$", hex(_pc + displacement, 6L)}; } -auto M68K::_suffix(uint size) -> string { +auto M68K::_suffix(uint2 size) -> string { if(size == Byte) return ".b"; if(size == Word) return ".w"; if(size == Long) return ".l"; @@ -103,28 +111,39 @@ auto M68K::disassembleRegisters() -> string { // -auto M68K::disassembleANDI(uint2 size, uint3 mode, uint3 reg) -> string { - return {"andi", _suffix(size), " ", _immediate(size), ",", _read(size, mode, reg)}; +template auto M68K::disassembleADD(uint3 reg, uint1 direction, EA ea) -> string { + string op{"add", _suffix(ea.reg), " "}; +return op; + + if(direction == 0) { +// return {op, _read(ea), ",d", reg}; + } else { +// return {op, "d", reg, ",", _read(ea)}; + } +} + +auto M68K::disassembleANDI(uint8 ea) -> string { + return {"andi", _suffix(ea), " ", _immediate(ea), ",", _read(ea)}; } auto M68K::disassembleBCC(uint4 condition, uint8 displacement) -> string { return {"b", _condition(condition), " ", _branch(displacement)}; } -auto M68K::disassembleLEA(uint3 target, uint3 mode, uint3 reg) -> string { - return {"lea ", _address(Long, mode, reg), ",a", target}; +auto M68K::disassembleLEA(uint3 to, uint8 ea) -> string { + return {"lea ", _address(ea), ",a", to}; } -auto M68K::disassembleMOVE(uint2 size, uint3 targetReg, uint3 targetMode, uint3 sourceMode, uint3 sourceReg) -> string { - return {"move", _suffix(size), " ", _read(size, sourceMode, sourceReg), ",", _write(size, targetMode, targetReg)}; +auto M68K::disassembleMOVE(uint8 to, uint8 from) -> string { + return {"move", _suffix(from), " ", _read(from), ",", _write(to)}; } -auto M68K::disassembleMOVEA(uint2 size, uint3 target, uint3 mode, uint3 reg) -> string { - return {"movea ", _read(size, mode, reg), ",a", target}; +auto M68K::disassembleMOVEA(uint3 to, uint8 from) -> string { + return {"movea ", _read(from), ",a", to}; } -auto M68K::disassembleMOVEM(uint1 direction, uint2 size, uint3 mode, uint3 reg) -> string { - string op{"movem", _suffix(size), " "}; +auto M68K::disassembleMOVEM(uint1 direction, uint8 ea) -> string { + string op{"movem", _suffix(ea), " "}; uint16 list = _readPC(); string regs; @@ -135,9 +154,9 @@ auto M68K::disassembleMOVEM(uint1 direction, uint2 size, uint3 mode, uint3 reg) regs.trimRight(","); if(direction == 0) { - return {op, regs, ",", _read(size, mode, reg)}; + return {op, regs, ",", _read(ea)}; } else { - return {op, _read(size, mode, reg), ",", regs}; + return {op, _read(ea), ",", regs}; } } @@ -157,6 +176,6 @@ auto M68K::disassembleNOP() -> string { return {"nop "}; } -auto M68K::disassembleTST(uint2 size, uint3 mode, uint3 reg) -> string { - return {"tst", _suffix(size), " ", _read(size, mode, reg)}; +auto M68K::disassembleTST(uint8 ea) -> string { + return {"tst", _suffix(ea), " ", _read(ea)}; } diff --git a/higan/processor/m68k/ea.cpp b/higan/processor/m68k/ea.cpp index e74a8488..c34a0954 100644 --- a/higan/processor/m68k/ea.cpp +++ b/higan/processor/m68k/ea.cpp @@ -1,137 +1,423 @@ -M68K::EA::EA(M68K* self, uint2 size, uint3 mode, uint3 reg) : self(self), size(size), mode(mode), reg(reg) { - if(this->mode == 7) this->mode += this->reg; //speed hack: convert cases {7; 0-4} to {8-12} for switch jump table - address = fetch(); -} +//effective addressing -M68K::EA::~EA() { - flush(); -} +//encoding: +// d7-d5: mode +// d4-d2: register +// d1-d0: size (0 = byte, 1 = word, 2 = long) -auto M68K::EA::pc() -> uint32& { return self->r.pc; } -auto M68K::EA::d(uint3 reg) -> uint32& { return self->r.d(reg); } -auto M68K::EA::a(uint3 reg) -> uint32& { return self->r.a(reg); } -auto M68K::EA::readPC(uint2 size) -> uint32 { return self->readPC(size); } -auto M68K::EA::read(uint32 addr) -> uint32 { return self->readAbsolute(size, addr); } -auto M68K::EA::write(uint32 addr, uint32 data) -> void { return self->writeAbsolute(size, addr, data); } - -auto M68K::EA::fetch() -> uint32 { - switch(mode) { +auto M68K::address(uint8 ea) -> uint32 { + switch(ea) { //data register direct - case 0: return d(reg); + case 0b000'000'00 ... 0b000'111'11: + return r.d(ea >> 2); //address register direct - case 1: return a(reg); + case 0b001'000'00 ... 0b001'111'11: + return r.a(ea >> 2); //address register indirect - case 2: return a(reg); + case 0b010'000'00 ... 0b010'111'11: + return r.a(ea >> 2); //address register indirect with post-increment - case 3: return a(reg); + case 0b011'000'00 ... 0b011'111'11: + return r.a(ea >> 2); //address register indirect with pre-decrement - case 4: return a(reg); + case 0b100'000'00 ... 0b100'111'11: + return r.a(ea >> 2); - //address register with displacement - case 5: return a(reg) + (int16)readPC(Word); + //address register indirect with displacement + case 0b101'000'00 ... 0b101'111'11: + return r.a(ea >> 2) + (int16)readPC(); - //address register with index - case 6: { - auto word = readPC(Word); - auto index = word & 0x8000 ? a(word >> 12) : d(word >> 12); + //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 a(reg) + index + (int8)word; + return r.a(ea >> 2) + index + (int8)word; } - //absolute short - case 7: return (int16)readPC(Word); + //absolute short indirect + case 0b111'000'00 ... 0b111'000'11: + return (int16)readPC(); - //absolute long - case 8: return readPC(Long); - - //program counter with displacement - case 9: { - auto base = pc(); - return base + (int16)readPC(Word); + //absolute long indirect + case 0b111'001'00 ... 0b111'001'11: { + uint32 address = readPC() << 16; + return address | readPC() << 0; } - //program counter with index - case 10: { - auto base = pc(); - auto word = readPC(Word); - auto index = word & 0x8000 ? a(word >> 12) : d(word >> 12); + //program counter indirect with displacement + case 0b111'010'00 ... 0b111'010'11: { + auto base = r.pc; + return base + (int16)readPC(); + } + + //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 base + index + (int8)word; } - //immediate - case 11: { - if(size == Byte) return (uint8)readPC(Word); - if(size == Word) return readPC(Word); - if(size == Long) return readPC(Long); + //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; } - } + //invalid + default: + return 0; - return 0; + } } -auto M68K::EA::read() -> uint32 { - switch(mode) { - case 0: return address; - case 1: return address; - case 2: return read(address); - case 3: { - auto data = read(address); - address += size == Long ? 4 : 2; +template auto M68K::read(EA ea) -> uint32 { + switch(ea.mode) { + + case 0: { //data register direct + return clip(r.d(ea.reg)); + } + + case 1: { //address register direct + return clip(r.a(ea.reg)); + } + + case 2: { //address register indirect + auto& address = r.a(ea.reg); + return read(address); + } + + case 3: { //address register indirect with post-increment + auto& address = r.a(ea.reg); + auto data = read(address); + address += Size == Long ? 4 : 2; return data; } - case 4: { - address -= size == Long ? 4 : 2; - return read(address); - } - case 5: return read(address); - case 6: return read(address); - case 7: return read(address); - case 8: return read(address); - case 9: return read(address); - case 10: return read(address); - case 11: return address; + + case 4: { //address register indirect with pre-decrement + auto& address = r.a(ea.reg); + address -= Size == Long ? 4 : 2; + return read(address); } - return 0; + } } -auto M68K::EA::write(uint32 data) -> void { - switch(mode) { - case 0: address = data; return; - case 1: address = data; return; - case 2: return write(address, data); - case 3: { - write(address, data); - address += size == Long ? 4 : 2; +template auto M68K::write(EA ea, uint32 data) -> void { + switch(ea.mode) { + + case 0: { //data register direct + r.d(ea.reg) = data; return; } - case 4: { - address -= size == Long ? 4 : 2; - return write(address, data); + + case 1: { //address register direct + r.a(ea.reg) = data; + return; } - case 5: return write(address, data); - case 6: return write(address, data); - case 7: return write(address, data); - case 8: return write(address, data); - case 9: return write(address, data); - case 10: return write(address, data); - case 11: address = data; return; + } } -auto M68K::EA::flush() -> void { +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 - if(mode == 3) a(reg) = address; + case 0b011'000'00 ... 0b011'111'11: { + auto& address = r.a(ea >> 2); + auto data = readAbsolute(ea, address); + address += 2 + (ea & 2); + return data; + } //address register indirect with pre-decrement - if(mode == 4) a(reg) = address; + case 0b100'000'00 ... 0b100'111'11: { + auto& address = r.a(ea >> 2); + address -= 2 + (ea & 2); + return readAbsolute(ea, address); + } - mode = 15; + //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); + } + + //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()); + } + + //program counter indirect with displacement + case 0b111'010'00 ... 0b111'010'11: { + auto base = r.pc; + return readAbsolute(ea, base + (int16)readPC()); + } + + //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); + } + + //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; + } + + //invalid + default: + return 0; + + } +} + +auto M68K::write(uint8 ea, uint32 data) -> void { + switch(ea) { + + //data register direct + case 0b000'000'00 ... 0b000'111'11: + r.d(ea >> 2) = data; + return; + + //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); + } + + //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); + 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); + } + + //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); + } + + //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); + } + + //program counter indirect with displacement + case 0b111'010'00 ... 0b111'010'11: { + auto base = r.pc; + return writeAbsolute(ea, base + (int16)readPC(), 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); + } + + } +} + +auto M68K::modify(uint8 ea, uint32 data, const function& op) -> uint32 { + switch(ea) { + + //data register direct + case 0b000'000'00 ... 0b000'111'11: { + auto& address = r.d(ea >> 2); + return address = op(address, data); + } + + //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); + } + + } +} + +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 109d99c7..b0af621a 100644 --- a/higan/processor/m68k/instruction.cpp +++ b/higan/processor/m68k/instruction.cpp @@ -15,12 +15,34 @@ auto M68K::instruction() -> void { } M68K::M68K() { + #define bind(id, name, ...) \ + assert(!instructionTable[id]); \ + instructionTable[id] = [=] { return instruction##name(__VA_ARGS__); }; \ + disassembleTable[id] = [=] { return disassemble##name(__VA_ARGS__); }; \ + + //ADD + for(uint3 d : 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; + if(direction == 1 && (mode == 0 || mode == 1 || (mode == 7 && reg >= 2))) continue; + + 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); + } + + #undef bind + #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__); }; \ @@ -29,15 +51,31 @@ M68K::M68K() { 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); - size = size == 0 ? Byte : size == 1 ? Word : size == 2 ? Long : 0; - if(size && mode != 1) { - bind(ANDI, size, mode, reg); + if(size != 3 && mode != 1) { + uint8 ea = mode << 5 | reg << 2 | size; + bind(ANDI, ea); } } @@ -58,48 +96,50 @@ M68K::M68K() { uint3 reg = bits(2,0); if(mode == 2 || mode == 5 || mode == 6 || (mode == 7 && reg <= 4)) { - bind(LEA, target, mode, reg); + uint8 ea = mode << 5 | reg << 2 | Long; + bind(LEA, target, ea); } } //MOVE match("00-- ---- ---- ----") { - uint2 size = bits(13,12); + 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); - size = size == 1 ? Byte : size == 3 ? Word : size == 2 ? Long : 0; - if(size && targetMode != 1) { - bind(MOVE, size, targetReg, targetMode, sourceMode, sourceReg); + 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); - uint3 target = bits(11,9); + 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); - size = size == 3 ? Word : size == 2 ? Long : 0; - if(size) { - bind(MOVEA, size, target, mode, reg); + 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 = bit(6); + uint2 size = 1 + bit(6); uint3 mode = bits(5,3); uint3 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); + uint8 ea = mode << 5 | reg << 2 | size; + bind(MOVEM, direction, ea); } } @@ -136,22 +176,22 @@ M68K::M68K() { uint3 mode = bits(5,3); uint3 reg = bits(2,0); - size = size == 0 ? Byte : size == 1 ? Word : size == 2 ? Long : 0; - if(size) { - bind(TST, size, mode, reg); + if(size != 3) { + uint8 ea = mode << 5 | reg << 2 | size << 0; + bind(TST, ea); } } } - for(uint16 opcode : range(65536)) { - if(instructionTable[opcode]) continue; - instructionTable[opcode] = [=] { trap(); }; - disassembleTable[opcode] = [=] { return string{"???"}; }; - } - #undef match #undef bind #undef bit #undef bits + + for(uint16 opcode : range(65536)) { + if(instructionTable[opcode]) continue; + instructionTable[opcode] = [=] { trap(); }; + disassembleTable[opcode] = [=] { return string{"???"}; }; + } } diff --git a/higan/processor/m68k/instructions.cpp b/higan/processor/m68k/instructions.cpp index 6a11b0d6..8bbe7c7a 100644 --- a/higan/processor/m68k/instructions.cpp +++ b/higan/processor/m68k/instructions.cpp @@ -22,15 +22,75 @@ auto M68K::testCondition(uint4 condition) -> bool { // -auto M68K::instructionANDI(uint2 size, uint3 mode, uint3 reg) -> void { - auto data = readPC(size); - EA modify{this, size, mode, reg}; - modify.write(data = modify.read() & data); +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; } + +template<> auto M68K::sign(uint32 data) -> int32 { return (int8)data; } +template<> auto M68K::sign(uint32 data) -> int32 { return (int16)data; } +template<> auto M68K::sign(uint32 data) -> int32 { return (int32)data; } + +template auto M68K::carry(uint32 result, uint32 source) -> bool { + return clip(result) < clip(source); +} + +template auto M68K::overflow(uint32 result, uint32 source, uint32 target) -> bool { + return sign((target ^ source) & (target ^ result)) < 0; +} + +template auto M68K::zero(uint32 result) -> bool { + return clip(result) == 0; +} + +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 { + uint32 source; + uint32 target; + uint32 result; + + if(direction == 0) { + source = read(ea); + target = r.d(reg); + result = source + target; + r.d(reg) = result; + } else { + source = r.d(reg); + target = read(ea); + result = source + target; + write(ea, result); + } + + r.c = carry(result, source); + r.v = overflow(result, source, target); + r.z = zero(result); + r.n = negative(result); + r.x = r.c; +} + +auto M68K::instructionANDI(uint8 ea) -> void { + auto result = modify(ea, readPC(ea), [&](auto x, auto y) -> uint32 { + return x & y; + }); r.c = 0; r.v = 0; - r.z = data == 0; - r.n = sign(size, data) < 0; + r.z = zero(ea, result); + r.n = negative(ea, result); } auto M68K::instructionBCC(uint4 condition, uint8 displacement) -> void { @@ -44,41 +104,45 @@ auto M68K::instructionBCC(uint4 condition, uint8 displacement) -> void { if(testCondition(condition)) r.pc += displacement; } -auto M68K::instructionLEA(uint3 target, uint3 mode, uint3 reg) -> void { - EA source{this, Long, mode, reg}; - r.a(target) = source.address; +auto M68K::instructionLEA(uint3 target, uint8 ea) -> void { + r.a(target) = address(ea); } -auto M68K::instructionMOVE(uint2 size, uint3 targetReg, uint3 targetMode, uint3 sourceMode, uint3 sourceReg) -> void { - EA source{this, size, sourceMode, sourceReg}; - EA target{this, size, targetMode, targetReg}; - - auto data = source.read(); - source.flush(); - target.write(data); +auto M68K::instructionMOVE(uint8 to, uint8 from) -> void { + auto data = read(from); + write(to, data); r.c = 0; r.v = 0; - r.z = data == 0; - r.n = sign(size, data) < 0; + r.z = zero(from, data); + r.n = negative(from, data); } -auto M68K::instructionMOVEA(uint2 size, uint3 target, uint3 mode, uint3 reg) -> void { - EA source{this, size, mode, reg}; - r.a(target) = source.read(); +auto M68K::instructionMOVEA(uint3 to, uint8 from) -> void { + auto data = read(from); + if(from & 1) data = (int16)data; + r.a(to) = data; } -auto M68K::instructionMOVEM(uint1 direction, uint2 size, uint3 mode, uint3 reg) -> void { +auto M68K::instructionMOVEM(uint1 direction, uint8 ea) -> void { auto list = readPC(); - EA source{this, size, mode, reg}; + auto addr = address(ea); for(uint n : range(8)) { - if(list.bit(0 + n)) r.d(n) = source.read(); + if(list.bit(0 + n)) { + r.d(n) = readAbsolute(ea, addr); + addr += 2 + (ea & 2); + } } for(uint n : range(8)) { - if(list.bit(8 + n)) r.a(n) = source.read(); + if(list.bit(8 + n)) { + r.a(n) = readAbsolute(ea, addr); + addr += 2 + (ea & 2); + } } + + flush(ea, addr); } auto M68K::instructionMOVEQ(uint3 target, uint8 immediate) -> void { @@ -87,7 +151,7 @@ auto M68K::instructionMOVEQ(uint3 target, uint8 immediate) -> void { r.c = 0; r.v = 0; r.z = immediate == 0; - r.v = sign(Byte, immediate) < 0; + r.n = negative(Byte, immediate); } auto M68K::instructionMOVE_USP(uint1 direction, uint3 reg) -> void { @@ -102,12 +166,11 @@ auto M68K::instructionMOVE_USP(uint1 direction, uint3 reg) -> void { auto M68K::instructionNOP() -> void { } -auto M68K::instructionTST(uint2 size, uint3 mode, uint3 reg) -> void { - EA source{this, size, mode, reg}; - auto data = source.read(); +auto M68K::instructionTST(uint8 ea) -> void { + auto data = read(ea); r.c = 0; r.v = 0; - r.z = data == 0; - r.n = sign(size, data) < 0; + r.z = zero(ea, data); + r.n = negative(ea, data); } diff --git a/higan/processor/m68k/m68k.cpp b/higan/processor/m68k/m68k.cpp index a8b77fcd..fed475b3 100644 --- a/higan/processor/m68k/m68k.cpp +++ b/higan/processor/m68k/m68k.cpp @@ -3,6 +3,8 @@ namespace Processor { +enum : uint { Byte, Word, Long }; + #include "registers.cpp" #include "memory.cpp" #include "ea.cpp" @@ -24,11 +26,4 @@ auto M68K::reset() -> void { r.sr = 0x2000; } -auto M68K::sign(uint2 size, uint32 data) -> int32 { - if(size == Byte) return (int8)data; - if(size == Word) return (int16)data; - if(size == Long) return (int32)data; - return 0; -} - } diff --git a/higan/processor/m68k/m68k.hpp b/higan/processor/m68k/m68k.hpp index 58694685..210f9d13 100644 --- a/higan/processor/m68k/m68k.hpp +++ b/higan/processor/m68k/m68k.hpp @@ -5,7 +5,7 @@ namespace Processor { struct M68K { - enum : uint { Byte = 1, Word = 2, Long = 3 }; + enum : uint { Byte, Word, Long }; M68K(); @@ -16,39 +16,33 @@ struct M68K { auto power() -> void; auto reset() -> void; - auto sign(uint2 size, uint32 data) -> int32; - //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; + //ea.cpp struct EA { - EA(M68K* self, uint2 size, uint3 mode, uint3 reg); - ~EA(); + EA(uint3 mode, uint3 reg) : mode(mode), reg(reg) { + if(mode == 7) mode += reg; //optimization: convert modes {7; 0-4} to {8-11} + } - auto pc() -> uint32&; - auto d(uint3 reg) -> uint32&; - auto a(uint3 reg) -> uint32&; - auto readPC(uint2 size) -> uint32; - auto read(uint32 addr) -> uint32; - auto write(uint32 addr, uint32 data) -> void; - - auto fetch() -> uint32; - auto read() -> uint32; - auto write(uint32 data) -> void; - auto flush() -> void; - - uint2 size; uint4 mode; uint3 reg; - - uint32 address; - M68K* self; }; + 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; + //instruction.cpp auto trap() -> void; auto instruction() -> void; @@ -56,16 +50,27 @@ struct M68K { //instructions.cpp auto testCondition(uint4 condition) -> bool; - auto instructionANDI(uint2 size, uint3 mode, uint3 reg) -> void; + template auto clip(uint32 data) -> uint32; + template auto sign(uint32 data) -> int32; + + template auto carry(uint32 result, uint32 source) -> bool; + 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, uint3 mode, uint3 reg) -> void; - auto instructionMOVE(uint2 size, uint3 targetReg, uint3 targetMode, uint3 sourceMode, uint3 sourceReg) -> void; - auto instructionMOVEA(uint2 size, uint3 target, uint3 mode, uint3 reg) -> void; - auto instructionMOVEM(uint1 direction, uint2 size, uint3 mode, uint3 reg) -> 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(uint2 size, uint3 mode, uint3 reg) -> void; + auto instructionTST(uint8 ea) -> void; //disassembler.cpp auto disassemble(uint32 pc) -> string; @@ -101,27 +106,28 @@ struct M68K { private: //disassembler.cpp - auto disassembleANDI(uint2 size, uint3 mode, uint3 reg) -> string; + 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, uint3 mode, uint3 reg) -> string; - auto disassembleMOVE(uint2 size, uint3 targetReg, uint3 targetMode, uint3 sourceMode, uint3 sourceReg) -> string; - auto disassembleMOVEA(uint2 size, uint3 target, uint3 mode, uint3 reg) -> string; - auto disassembleMOVEM(uint1 direction, uint2 size, uint3 mode, uint3 reg) -> 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(uint2 size, uint3 mode, uint3 reg) -> string; + auto disassembleTST(uint8 ea) -> 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(uint2 size, uint3 mode, uint3 reg) -> string; - auto _read(uint2 size, uint3 mode, uint3 reg) -> string; - auto _write(uint2 size, uint3 mode, uint3 reg) -> string; + 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; auto _branch(uint8 displacement) -> string; - auto _suffix(uint size) -> string; + auto _suffix(uint2 size) -> string; auto _condition(uint4 condition) -> string; uint32 _pc; diff --git a/higan/processor/m68k/memory.cpp b/higan/processor/m68k/memory.cpp index de9b512d..1021964b 100644 --- a/higan/processor/m68k/memory.cpp +++ b/higan/processor/m68k/memory.cpp @@ -30,3 +30,22 @@ auto M68K::readPC(uint2 size) -> uint32 { r.pc += 2; return data; } + +// + +template<> auto M68K::read(uint32 addr) -> uint32 { + step(4); + return read(0, addr); +} + +template<> auto M68K::read(uint32 addr) -> uint32 { + step(4); + return read(1, addr); +} + +template<> auto M68K::read(uint32 addr) -> uint32 { + step(4); + uint32 data = read(1, addr + 0) << 16; + step(4); + return data | read(1, addr + 2) << 0; +} diff --git a/nall/function.hpp b/nall/function.hpp index 14eebb49..37691866 100644 --- a/nall/function.hpp +++ b/nall/function.hpp @@ -14,7 +14,7 @@ template struct function R> { static constexpr bool value = decltype(exists(0))::value; }; - function() = default; + function() {} function(const function& source) { operator=(source); } function(void* function) { if(function) callback = new global((auto (*)(P...) -> R)function); } function(auto (*function)(P...) -> R) { callback = new global(function); }