diff --git a/higan/emulator/emulator.hpp b/higan/emulator/emulator.hpp index 3dd5714a..4981fd4e 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.04"; + static const string Version = "100.05"; 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 17d7b0f9..ea37cbc1 100644 --- a/higan/processor/m68k/disassembler.cpp +++ b/higan/processor/m68k/disassembler.cpp @@ -20,7 +20,7 @@ auto M68K::disassemble(uint32 pc) -> string { return data |= readWordPC() << 0; }; - auto suffix = [&](uint2 size) -> string { + auto size = [&](uint2 size) -> string { if(size == 0) return ".b"; if(size == 1) return ".w"; if(size == 2) return ".l"; @@ -56,15 +56,28 @@ auto M68K::disassemble(uint32 pc) -> string { }; 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), ")", suffix(size)}; - if(reg == 1) return {"($", hex(readLongPC(), 6L), ")", suffix(size)}; + 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 "???"; }; - string s, op; + 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(); @@ -72,25 +85,76 @@ auto M68K::disassemble(uint32 pc) -> string { if(0); - //bcc - else if(opcode >> 12 == 0b0110) { - op = {"b", cc(opcode >> 8), " ", branch(opcode >> 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"}; } - //nop - else if(opcode == 0b0100'1110'0111'0001) { - op = {"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 - else if(opcode >> 8 == 0b0100'1010) { - op = {"tst", suffix(opcode >> 6), " ", ea(opcode >> 6, opcode >> 3, opcode >> 0)}; + //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 { - op = {"???"}; + name = {"???"}; } - s.append(op); + s.append(name.size(-8), args); return s; } + +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.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) + }; +} diff --git a/higan/processor/m68k/ea.cpp b/higan/processor/m68k/ea.cpp index c3de8727..0f12cd25 100644 --- a/higan/processor/m68k/ea.cpp +++ b/higan/processor/m68k/ea.cpp @@ -5,21 +5,30 @@ auto M68K::signExtend(uint2 size, uint32 data) -> int32 { return 0; } -auto M68K::readEA(uint2 size, uint3 mode, uint3 reg) -> uint32 { - if(mode == 7) { - if(reg == 0) { - uint32 addr = (int16)readWordPC(); - return readAbsolute(size, addr); - } +// - if(reg == 1) { - uint32 addr = readLongPC(); - return readAbsolute(size, addr); - } +auto M68K::address(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 == 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(); } - return 0; + return ea.address = 0; } -auto M68K::writeEA(uint2 size, uint3 mode, uint3 reg, uint32 data) -> void { +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::write(EA& ea, uint32 data) -> void { + address(ea); } diff --git a/higan/processor/m68k/instruction.cpp b/higan/processor/m68k/instruction.cpp index e02c7464..d54ac5ab 100644 --- a/higan/processor/m68k/instruction.cpp +++ b/higan/processor/m68k/instruction.cpp @@ -8,27 +8,52 @@ auto M68K::trap() -> void { auto M68K::instruction() -> void { instructionsExecuted++; - print(disassemble(r.pc), "\n"); + print(disassembleRegisters(), "\n", disassemble(r.pc), "\n\n"); opcode = readWordPC(); - - //bcc - //0110 cccc dddd dddd - if(opcode >> 12 == 0b0110) { - return instructionBCC(opcode >> 8, opcode >> 0); - } - - //nop - //0100 1110 0111 0001 - if(opcode == 0b0100'1110'0111'0001) { - return instructionNOP(); - } - - //tst - //0100 1010 ssmm mrrr - if(opcode >> 8 == 0b0100'1010) { - return instructionTST(opcode >> 6, opcode >> 3, opcode >> 0); - } - - trap(); + return instructionTable[opcode](); +} + +M68K::M68K() { + for(uint opcode : range(65536)) instructionTable[opcode] = [=] { trap(); }; + + #define match(pattern) else 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); + + //NOP + match("0100 1110 0111 0001") { + instructionNOP(); + }; + + //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) + match("0100 1010 ---- ----") { + instructionTST(EA{bits(7,6), bits(5,3), bits(2,0)}); + }; + + //LEA (An, mode, register) + match("0100 ---1 11-- ----") { + instructionLEA(bits(11,9), EA{Long, bits(5,3), bits(2,0)}); + }; + + //BCC (condition, displacement) + match("0110 ---- ---- ----") { + instructionBCC(bits(11,8), bits(7,0)); + }; + } + + #undef match + #undef bit + #undef bits } diff --git a/higan/processor/m68k/instructions.cpp b/higan/processor/m68k/instructions.cpp index 121e0267..6d69df8e 100644 --- a/higan/processor/m68k/instructions.cpp +++ b/higan/processor/m68k/instructions.cpp @@ -34,14 +34,22 @@ auto M68K::instructionBCC(uint4 condition, uint8 displacementByte) -> void { } } +auto M68K::instructionLEA(uint3 wr, EA ea) -> void { + r.a(wr) = address(ea); +} + +auto M68K::instructionMOVEM(uint1 direction, EA ea) -> void { + auto list = readWordPC(); +} + auto M68K::instructionNOP() -> void { } -auto M68K::instructionTST(uint2 size, uint3 rdMode, uint3 rdReg) -> void { - auto data = readEA(size, rdMode, rdReg); +auto M68K::instructionTST(EA ea) -> void { + auto data = read(ea); r.c = 0; r.v = 0; r.z = data == 0; - r.n = signExtend(size, data) < 0; + r.n = signExtend(ea.size, data) < 0; } diff --git a/higan/processor/m68k/m68k.cpp b/higan/processor/m68k/m68k.cpp index 6829dd38..35419d00 100644 --- a/higan/processor/m68k/m68k.cpp +++ b/higan/processor/m68k/m68k.cpp @@ -21,4 +21,34 @@ auto M68K::reset() -> void { 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; +} + } diff --git a/higan/processor/m68k/m68k.hpp b/higan/processor/m68k/m68k.hpp index 1b160b02..36ec66bb 100644 --- a/higan/processor/m68k/m68k.hpp +++ b/higan/processor/m68k/m68k.hpp @@ -5,6 +5,8 @@ namespace Processor { struct M68K { + M68K(); + virtual auto step(uint clocks) -> void = 0; virtual auto read(uint32 addr) -> uint8 = 0; virtual auto write(uint32 addr, uint8 data) -> void = 0; @@ -23,9 +25,22 @@ struct M68K { auto readAbsolute(uint2 size, uint32 addr) -> uint32; //ea.cpp + struct EA { + EA(uint2 size, uint3 mode, uint3 reg) : size(size), mode(mode), reg(reg) {} + + uint2 size; + uint3 mode; + uint3 reg; + + boolean valid; + uint32 address; + }; + auto signExtend(uint2 size, uint32 data) -> int32; - auto readEA(uint2 size, uint3 mode, uint3 reg) -> uint32; - auto writeEA(uint2 size, uint3 mode, uint3 reg, uint32 data) -> void; + + auto address(EA& ea) -> uint32; + auto read(EA& ea) -> uint32; + auto write(EA& ea, uint32 data) -> void; //instruction.cpp auto trap() -> void; @@ -33,14 +48,23 @@ 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 instructionNOP() -> void; - auto instructionTST(uint2 size, uint3 rdMode, uint3 rdReg) -> void; + auto instructionTST(EA ea) -> 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&; + uint32 d0, d1, d2, d3, d4, d5, d6, d7; uint32 a0, a1, a2, a3, a4, a5, a6, usp, ssp; uint32 pc; @@ -59,6 +83,8 @@ struct M68K { uint16 opcode = 0; uint instructionsExecuted = 0; + + function instructionTable[65536]; }; } diff --git a/higan/sfc/cpu/memory.cpp b/higan/sfc/cpu/memory.cpp index 7edf90fd..17fe1dae 100644 --- a/higan/sfc/cpu/memory.cpp +++ b/higan/sfc/cpu/memory.cpp @@ -35,8 +35,8 @@ auto CPU::write(uint24 addr, uint8 data) -> void { auto CPU::speed(uint24 addr) const -> uint { if(addr & 0x408000) return addr & 0x800000 ? io.romSpeed : 8; - if((addr + 0x6000) & 0x4000) return 8; - if((addr - 0x4000) & 0x7e00) return 6; + if(addr + 0x6000 & 0x4000) return 8; + if(addr - 0x4000 & 0x7e00) return 6; return 12; } diff --git a/nall/primitives.hpp b/nall/primitives.hpp index f44734f0..07b502d5 100644 --- a/nall/primitives.hpp +++ b/nall/primitives.hpp @@ -79,6 +79,10 @@ template struct Natural { inline auto bit(uint index) -> Reference { return {*this, index, index}; } inline auto byte(uint index) -> Reference { return {*this, index * 8 + 0, index * 8 + 7}; } + inline auto bits(uint lo, uint hi) const -> const Reference { return {(Natural&)*this, lo < hi ? lo : hi, hi > lo ? hi : lo}; } + inline auto bit(uint index) const -> const Reference { return {(Natural&)*this, index, index}; } + inline auto byte(uint index) const -> const Reference { return {(Natural&)*this, index * 8 + 0, index * 8 + 7}; } + inline auto clamp(uint bits) -> uintmax_t { const uintmax_t b = 1ull << (bits - 1); const uintmax_t m = b * 2 - 1; @@ -157,10 +161,14 @@ template struct Integer { const uint Hi; }; - inline auto bits(uint lo, uint hi) -> Reference { return {*this, lo, hi}; } + inline auto bits(uint lo, uint hi) -> Reference { return {*this, lo < hi ? lo : hi, hi > lo ? hi : lo}; } inline auto bit(uint index) -> Reference { return {*this, index, index}; } inline auto byte(uint index) -> Reference { return {*this, index * 8 + 0, index * 8 + 7}; } + inline auto bits(uint lo, uint hi) const -> const Reference { return {(Integer&)*this, lo < hi ? lo : hi, hi > lo ? hi : lo}; } + inline auto bit(uint index) const -> const Reference { return {(Integer&)*this, index, index}; } + inline auto byte(uint index) const -> const Reference { return {(Integer&)*this, index * 8 + 0, index * 8 + 7}; } + inline auto clamp(uint bits) -> intmax_t { const intmax_t b = 1ull << (bits - 1); const intmax_t m = b - 1;