From 059347e5752e644ca0dabcb5d2b0521c04cf6be7 Mon Sep 17 00:00:00 2001 From: Tim Allen Date: Sun, 17 Jul 2016 13:24:28 +1000 Subject: [PATCH] Update to v100r07 release. byuu says: Four and a half hours of work and ... zero new opcodes implemented. This was the best job I could do refining the effective address computations. Should have all twelve 68000 modes implemented now. Still have a billion questions about when and how I'm supposed to perform certain edge case operations, though. --- higan/emulator/emulator.hpp | 2 +- higan/md/cartridge/cartridge.cpp | 8 +- higan/md/cartridge/cartridge.hpp | 4 +- higan/md/cpu/cpu.cpp | 18 +-- higan/md/cpu/cpu.hpp | 4 +- higan/processor/m68k/disassembler.cpp | 73 ++++++----- higan/processor/m68k/ea.cpp | 179 ++++++++++++++++++-------- higan/processor/m68k/instruction.cpp | 68 +++++----- higan/processor/m68k/instructions.cpp | 45 ++++--- higan/processor/m68k/m68k.cpp | 7 + higan/processor/m68k/m68k.hpp | 92 +++++++------ higan/processor/m68k/memory.cpp | 44 +++---- higan/processor/r65816/r65816.cpp | 28 ++-- higan/processor/r65816/r65816.hpp | 2 +- higan/sfc/coprocessor/sa1/sa1.cpp | 14 ++ higan/sfc/coprocessor/sa1/sa1.hpp | 1 + nall/primitives.hpp | 3 + 17 files changed, 348 insertions(+), 244 deletions(-) diff --git a/higan/emulator/emulator.hpp b/higan/emulator/emulator.hpp index a6e5e069..5f287915 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.06"; + static const string Version = "100.07"; static const string Author = "byuu"; static const string License = "GPLv3"; static const string Website = "http://byuu.org/"; diff --git a/higan/md/cartridge/cartridge.cpp b/higan/md/cartridge/cartridge.cpp index 7ba76cd2..060d5c1e 100644 --- a/higan/md/cartridge/cartridge.cpp +++ b/higan/md/cartridge/cartridge.cpp @@ -70,11 +70,13 @@ auto Cartridge::power() -> void { auto Cartridge::reset() -> void { } -auto Cartridge::read(uint24 addr) -> uint8 { - return rom.data[addr & rom.mask]; +auto Cartridge::read(bool word, uint24 addr) -> uint16 { + uint16 data = rom.data[addr & rom.mask]; + if(!word) return data; + return data << 8 | rom.data[addr + 1 & rom.mask]; } -auto Cartridge::write(uint24 addr, uint8 data) -> void { +auto Cartridge::write(bool word, uint24 addr, uint16 data) -> void { } } diff --git a/higan/md/cartridge/cartridge.hpp b/higan/md/cartridge/cartridge.hpp index efdb400d..317ff0b1 100644 --- a/higan/md/cartridge/cartridge.hpp +++ b/higan/md/cartridge/cartridge.hpp @@ -10,8 +10,8 @@ struct Cartridge { auto power() -> void; auto reset() -> void; - auto read(uint24 addr) -> uint8; - auto write(uint24 addr, uint8 data) -> void; + auto read(bool word, uint24 addr) -> uint16; + auto write(bool word, uint24 addr, uint16 data) -> void; struct Information { uint pathID = 0; diff --git a/higan/md/cpu/cpu.cpp b/higan/md/cpu/cpu.cpp index afeb5340..f030a2b7 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 = readLong(0); - r.pc = readLong(4); + r.ssp = readAbsolute(Long, 0); + r.pc = readAbsolute(Long, 4); } auto CPU::main() -> void { @@ -35,17 +35,13 @@ auto CPU::reset() -> void { create(CPU::Enter, system.colorburst() * 15.0 / 7.0); } -auto CPU::read(uint32 addr) -> uint8 { - addr = (uint24)addr; - - if(addr < 0x400000) return cartridge.read(addr); - return 0x00; +auto CPU::read(bool word, uint24 addr) -> uint16 { + if(addr < 0x400000) return cartridge.read(word, addr); + return 0x0000; } -auto CPU::write(uint32 addr, uint8 data) -> void { - addr = (uint24)addr; - - if(addr < 0x400000) return cartridge.write(addr, data); +auto CPU::write(bool word, uint24 addr, uint16 data) -> void { + if(addr < 0x400000) return cartridge.write(word, addr, data); } } diff --git a/higan/md/cpu/cpu.hpp b/higan/md/cpu/cpu.hpp index b2f099c7..298d89b7 100644 --- a/higan/md/cpu/cpu.hpp +++ b/higan/md/cpu/cpu.hpp @@ -9,8 +9,8 @@ struct CPU : Processor::M68K, Thread { auto power() -> void; auto reset() -> void; - auto read(uint32 addr) -> uint8 override; - auto write(uint32 addr, uint8 data) -> void override; + auto read(bool word, uint24 addr) -> uint16 override; + auto write(bool word, uint24 addr, uint16 data) -> void override; }; extern CPU cpu; diff --git a/higan/processor/m68k/disassembler.cpp b/higan/processor/m68k/disassembler.cpp index 9909005c..7c31f216 100644 --- a/higan/processor/m68k/disassembler.cpp +++ b/higan/processor/m68k/disassembler.cpp @@ -1,10 +1,9 @@ auto M68K::_readByte(uint32 addr) -> uint8 { - return read(addr); + return read(0, addr); } auto M68K::_readWord(uint32 addr) -> uint16 { - uint16 data = _readByte(addr + 0) << 8; - return data |= _readByte(addr + 1) << 0; + return read(1, addr); } auto M68K::_readLong(uint32 addr) -> uint32 { @@ -29,23 +28,23 @@ auto M68K::_immediate(uint size) -> string { return "#???"; } -auto M68K::_address(uint size, EA& ea) -> string { - if(ea.mode == 7) { - if(ea.reg == 2) return {"$", hex(_pc + (int16)_readPC(Word), 6L)}; +auto M68K::_address(uint2 size, uint3 mode, uint3 reg) -> string { + if(mode == 7) { + if(reg == 2) return {"$", hex(_pc + (int16)_readPC(Word), 6L)}; } return "???"; } -auto M68K::_read(uint size, EA& ea) -> string { - if(ea.mode == 0) return {"d", ea.reg}; - if(ea.mode == 1) return {"a", ea.reg}; - if(ea.mode == 2) return {"(a", ea.reg, ")"}; - if(ea.mode == 3) return {"(a", ea.reg, ")+"}; - if(ea.mode == 4) return {"-(a", ea.reg, ")"}; - if(ea.mode == 5) return {"($", hex(r.a(ea.reg) + (int16)_readPC(Word), 6L), ")"}; - if(ea.mode == 7) { - if(ea.reg == 1) return {"($", hex(_readPC(Long), 6L), ")"}; - if(ea.reg == 4) { +auto M68K::_read(uint2 size, uint3 mode, uint3 reg) -> string { + 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)}; @@ -54,11 +53,11 @@ auto M68K::_read(uint size, EA& ea) -> string { return "???"; } -auto M68K::_write(uint size, EA& ea) -> string { - return _read(size, ea); +auto M68K::_write(uint2 size, uint3 mode, uint3 reg) -> string { + return _read(size, mode, reg); } -auto M68K::_branch(uint displacement) -> string { +auto M68K::_branch(uint8 displacement) -> string { uint16 word = _readPC(); if(displacement) displacement = (int8)displacement, _pc -= 2; else displacement = (int16)displacement; @@ -72,12 +71,12 @@ auto M68K::_suffix(uint size) -> string { return ".?"; } -auto M68K::_condition(uint condition) -> string { +auto M68K::_condition(uint4 condition) -> string { static const string conditions[16] = { "ra", "sr", "hi", "ls", "cc", "cs", "ne", "eq", "vc", "vs", "pl", "mi", "ge", "lt", "gt", "le", }; - return conditions[(uint4)condition]; + return conditions[condition]; } auto M68K::disassemble(uint32 pc) -> string { @@ -104,27 +103,27 @@ auto M68K::disassembleRegisters() -> string { // -auto M68K::disassembleANDI(uint size, EA modify) -> string { - return {"andi", _suffix(size), " ", _immediate(size), ",", _read(size, modify)}; +auto M68K::disassembleANDI(uint2 size, uint3 mode, uint3 reg) -> string { + return {"andi", _suffix(size), " ", _immediate(size), ",", _read(size, mode, reg)}; } -auto M68K::disassembleBCC(uint condition, uint displacement) -> string { +auto M68K::disassembleBCC(uint4 condition, uint8 displacement) -> string { return {"b", _condition(condition), " ", _branch(displacement)}; } -auto M68K::disassembleLEA(uint target, EA source) -> string { - return {"lea ", _address(Long, source), ",a", target}; +auto M68K::disassembleLEA(uint3 target, uint3 mode, uint3 reg) -> string { + return {"lea ", _address(Long, mode, reg), ",a", target}; } -auto M68K::disassembleMOVE(uint size, EA target, EA source) -> string { - return {"move", _suffix(size), " ", _read(size, source), ",", _write(size, target)}; +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::disassembleMOVEA(uint size, uint target, EA source) -> string { - return {"movea ", _read(size, source), ",a", target}; +auto M68K::disassembleMOVEA(uint2 size, uint3 target, uint3 mode, uint3 reg) -> string { + return {"movea ", _read(size, mode, reg), ",a", target}; } -auto M68K::disassembleMOVEM(uint direction, uint size, EA source) -> string { +auto M68K::disassembleMOVEM(uint1 direction, uint2 size, uint3 mode, uint3 reg) -> string { string op{"movem", _suffix(size), " "}; uint16 list = _readPC(); @@ -136,17 +135,17 @@ auto M68K::disassembleMOVEM(uint direction, uint size, EA source) -> string { regs.trimRight(","); if(direction == 0) { - return {op, regs, ",", _read(size, source)}; + return {op, regs, ",", _read(size, mode, reg)}; } else { - return {op, _read(size, source), ",", regs}; + return {op, _read(size, mode, reg), ",", regs}; } } -auto M68K::disassembleMOVEQ(uint target, uint immediate) -> string { +auto M68K::disassembleMOVEQ(uint3 target, uint8 immediate) -> string { return {"moveq #$", hex(immediate, 2L), ",d", target}; } -auto M68K::disassembleMOVE_USP(uint direction, uint reg) -> string { +auto M68K::disassembleMOVE_USP(uint1 direction, uint3 reg) -> string { if(direction == 0) { return {"move a", reg, ",usp"}; } else { @@ -158,6 +157,6 @@ auto M68K::disassembleNOP() -> string { return {"nop "}; } -auto M68K::disassembleTST(uint size, EA source) -> string { - return {"tst", _suffix(size), " ", _read(size, source)}; +auto M68K::disassembleTST(uint2 size, uint3 mode, uint3 reg) -> string { + return {"tst", _suffix(size), " ", _read(size, mode, reg)}; } diff --git a/higan/processor/m68k/ea.cpp b/higan/processor/m68k/ea.cpp index 6762deab..e74a8488 100644 --- a/higan/processor/m68k/ea.cpp +++ b/higan/processor/m68k/ea.cpp @@ -1,72 +1,137 @@ -auto M68K::sign(uint size, uint32 data) -> int32 { - if(size == Byte) return (int8)data; - if(size == Word) return (int16)data; - if(size == Long) return (int32)data; +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(); +} + +M68K::EA::~EA() { + flush(); +} + +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) { + + //data register direct + case 0: return d(reg); + + //address register direct + case 1: return a(reg); + + //address register indirect + case 2: return a(reg); + + //address register indirect with post-increment + case 3: return a(reg); + + //address register indirect with pre-decrement + case 4: return a(reg); + + //address register with displacement + case 5: return a(reg) + (int16)readPC(Word); + + //address register with index + case 6: { + auto word = readPC(Word); + auto index = word & 0x8000 ? a(word >> 12) : d(word >> 12); + if(word & 0x800) index = (int16)index; + return a(reg) + index + (int8)word; + } + + //absolute short + case 7: return (int16)readPC(Word); + + //absolute long + case 8: return readPC(Long); + + //program counter with displacement + case 9: { + auto base = pc(); + return base + (int16)readPC(Word); + } + + //program counter with index + case 10: { + auto base = pc(); + auto word = readPC(Word); + auto index = word & 0x8000 ? a(word >> 12) : 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); + } + + } + return 0; } -// - -auto M68K::address(uint size, EA& ea) -> uint32 { - if(ea.valid) return ea.address; - ea.valid = true; - - if(ea.mode == 0) return ea.address = r.d(ea.reg); - if(ea.mode == 1) return ea.address = r.a(ea.reg); - if(ea.mode == 2) return ea.address = r.a(ea.reg); - if(ea.mode == 3) return ea.address = r.a(ea.reg); - if(ea.mode == 4) return ea.address = r.a(ea.reg); - if(ea.mode == 5) return ea.address = r.a(ea.reg) + (int16)readPC(Word); - if(ea.mode == 7) { - if(ea.reg == 0) return ea.address = (int16)readPC(Word); - if(ea.reg == 1) return ea.address = readPC(Long); - if(ea.reg == 2) return ea.address = r.pc, ea.address += (int16)readPC(Word); - if(ea.reg == 4) { - if(size == Byte) return ea.address = readPC(Byte); - if(size == Word) return ea.address = readPC(Word); - if(size == Long) return ea.address = readPC(Long); - } - } - - return ea.address = 0; -} - -auto M68K::read(uint size, EA& ea) -> uint32 { - address(size, ea); - - if(ea.mode == 0) return r.d(ea.reg); - if(ea.mode == 1) return r.a(ea.reg); - if(ea.mode == 2) return read(size, ea.address); - if(ea.mode == 3) { - auto data = read(size, ea.address); - ea.address += size, r.a(ea.reg) += size; +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; return data; } - if(ea.mode == 4) { - ea.address -= size, r.a(ea.reg) -= size; - return read(size, ea.address); + case 4: { + address -= size == Long ? 4 : 2; + return read(address); } - if(ea.mode == 5) return read(size, ea.address); - if(ea.mode == 7) { - if(ea.reg == 0) return read(size, ea.address); - if(ea.reg == 1) return read(size, ea.address); - if(ea.reg == 2) return read(size, ea.address); - if(ea.reg == 4) return ea.address; + 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; } return 0; } -auto M68K::write(uint size, EA& ea, uint32 data) -> void { - address(size, ea); - - if(ea.mode == 0) { - r.d(ea.reg) = data; +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; return; } - - if(ea.mode == 1) { - r.a(ea.reg) = data; - return; + case 4: { + address -= size == Long ? 4 : 2; + return write(address, data); + } + 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 { + //address register indirect with post-increment + if(mode == 3) a(reg) = address; + + //address register indirect with pre-decrement + if(mode == 4) a(reg) = address; + + mode = 15; +} diff --git a/higan/processor/m68k/instruction.cpp b/higan/processor/m68k/instruction.cpp index b8771f01..109d99c7 100644 --- a/higan/processor/m68k/instruction.cpp +++ b/higan/processor/m68k/instruction.cpp @@ -31,20 +31,20 @@ M68K::M68K() { //ANDI match("0000 0010 ---- ----") { - auto size = bits(7,6); - auto mode = bits(5,3); - auto reg = bits(2,0); + 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}); + bind(ANDI, size, mode, reg); } } //BCC match("0110 ---- ---- ----") { - auto condition = bits(11,8); - auto displacement = bits(7,0); + uint4 condition = bits(11,8); + uint8 displacement = bits(7,0); if(true) { bind(BCC, condition, displacement); @@ -53,60 +53,60 @@ M68K::M68K() { //LEA match("0100 ---1 11-- ----") { - auto target = bits(11,9); - auto mode = bits(5,3); - auto reg = bits(2,0); + 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)) { - bind(LEA, target, {mode, reg}); + bind(LEA, target, mode, reg); } } //MOVE match("00-- ---- ---- ----") { - auto size = bits(13,12); - auto targetReg = bits(11,9); - auto targetMode = bits(8,6); - auto sourceMode = bits(5,3); - auto sourceReg = bits(2,0); + uint2 size = bits(13,12); + 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, {targetMode, targetReg}, {sourceMode, sourceReg}); + bind(MOVE, size, targetReg, targetMode, sourceMode, sourceReg); } } //MOVEA match("00-- ---0 01-- ----") { - auto size = bits(13,12); - auto target = bits(11,9); - auto sourceMode = bits(5,3); - auto sourceReg = bits(2,0); + uint2 size = bits(13,12); + uint3 target = 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, {sourceMode, sourceReg}); + bind(MOVEA, size, target, mode, reg); } } //MOVEM match("0100 1-00 1--- ----") { - auto direction = bit(10); - auto size = bit(6); - auto mode = bits(5,3); - auto reg = bits(2,0); + uint1 direction = bit(10); + uint2 size = 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}); + bind(MOVEM, direction, size, mode, reg); } } //MOVEQ match("0111 ---0 ---- ----") { - auto target = bits(11,9); - auto immediate = bits(7,0); + uint3 target = bits(11,9); + uint8 immediate = bits(7,0); if(true) { bind(MOVEQ, target, immediate); @@ -115,8 +115,8 @@ M68K::M68K() { //MOVE_USP match("0100 1110 0110 ----") { - auto direction = bit(3); - auto reg = bits(2,0); + uint1 direction = bit(3); + uint3 reg = bits(2,0); if(true) { bind(MOVE_USP, direction, reg); @@ -132,13 +132,13 @@ M68K::M68K() { //TST match("0100 1010 ---- ----") { - auto size = bits(7,6); - auto mode = bits(5,3); - auto reg = bits(2,0); + 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) { - bind(TST, size, {mode, reg}); + bind(TST, size, mode, reg); } } diff --git a/higan/processor/m68k/instructions.cpp b/higan/processor/m68k/instructions.cpp index eba80c43..6a11b0d6 100644 --- a/higan/processor/m68k/instructions.cpp +++ b/higan/processor/m68k/instructions.cpp @@ -22,9 +22,10 @@ auto M68K::testCondition(uint4 condition) -> bool { // -auto M68K::instructionANDI(uint size, EA modify) -> void { +auto M68K::instructionANDI(uint2 size, uint3 mode, uint3 reg) -> void { auto data = readPC(size); - write(size, modify, data = read(size, modify) & data); + EA modify{this, size, mode, reg}; + modify.write(data = modify.read() & data); r.c = 0; r.v = 0; @@ -32,7 +33,7 @@ auto M68K::instructionANDI(uint size, EA modify) -> void { r.n = sign(size, data) < 0; } -auto M68K::instructionBCC(uint condition, uint displacement) -> void { +auto M68K::instructionBCC(uint4 condition, uint8 displacement) -> void { auto word = readPC(); if(displacement) displacement = (int8)displacement, r.pc -= 2; else displacement = (int16)word; @@ -43,13 +44,18 @@ auto M68K::instructionBCC(uint condition, uint displacement) -> void { if(testCondition(condition)) r.pc += displacement; } -auto M68K::instructionLEA(uint target, EA source) -> void { - r.a(target) = address(Long, source); +auto M68K::instructionLEA(uint3 target, uint3 mode, uint3 reg) -> void { + EA source{this, Long, mode, reg}; + r.a(target) = source.address; } -auto M68K::instructionMOVE(uint size, EA target, EA source) -> void { - auto data = read(size, source); - write(size, target, data); +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); r.c = 0; r.v = 0; @@ -57,23 +63,25 @@ auto M68K::instructionMOVE(uint size, EA target, EA source) -> void { r.n = sign(size, data) < 0; } -auto M68K::instructionMOVEA(uint size, uint target, EA source) -> void { - r.d(target) = read(size, source); +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::instructionMOVEM(uint direction, uint size, EA source) -> void { +auto M68K::instructionMOVEM(uint1 direction, uint2 size, uint3 mode, uint3 reg) -> void { auto list = readPC(); + EA source{this, size, mode, reg}; for(uint n : range(8)) { - if(list.bit(0 + n)) r.d(n) = read(size, source); + if(list.bit(0 + n)) r.d(n) = source.read(); } for(uint n : range(8)) { - if(list.bit(8 + n)) r.a(n) = read(size, source); + if(list.bit(8 + n)) r.a(n) = source.read(); } } -auto M68K::instructionMOVEQ(uint target, uint immediate) -> void { +auto M68K::instructionMOVEQ(uint3 target, uint8 immediate) -> void { r.d(target) = immediate; r.c = 0; @@ -82,8 +90,8 @@ auto M68K::instructionMOVEQ(uint target, uint immediate) -> void { r.v = sign(Byte, immediate) < 0; } -auto M68K::instructionMOVE_USP(uint direction, uint reg) -> void { - if(!r.s) trap(); +auto M68K::instructionMOVE_USP(uint1 direction, uint3 reg) -> void { + if(!r.s) trap(); //todo: proper trap if(direction == 0) { r.usp = r.a(reg); } else { @@ -94,8 +102,9 @@ auto M68K::instructionMOVE_USP(uint direction, uint reg) -> void { auto M68K::instructionNOP() -> void { } -auto M68K::instructionTST(uint size, EA source) -> void { - auto data = read(size, source); +auto M68K::instructionTST(uint2 size, uint3 mode, uint3 reg) -> void { + EA source{this, size, mode, reg}; + auto data = source.read(); r.c = 0; r.v = 0; diff --git a/higan/processor/m68k/m68k.cpp b/higan/processor/m68k/m68k.cpp index 31c9842c..a8b77fcd 100644 --- a/higan/processor/m68k/m68k.cpp +++ b/higan/processor/m68k/m68k.cpp @@ -24,4 +24,11 @@ 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 ad3afbf0..58694685 100644 --- a/higan/processor/m68k/m68k.hpp +++ b/higan/processor/m68k/m68k.hpp @@ -5,40 +5,50 @@ namespace Processor { struct M68K { - enum : uint { Byte = 1, Word = 2, Long = 4 }; + enum : uint { Byte = 1, Word = 2, Long = 3 }; M68K(); virtual auto step(uint clocks) -> void = 0; - virtual auto read(uint32 addr) -> uint8 = 0; - virtual auto write(uint32 addr, uint8 data) -> void = 0; + virtual auto read(bool word, uint24 addr) -> uint16 = 0; + virtual auto write(bool word, uint24 addr, uint16 data) -> void = 0; auto power() -> void; auto reset() -> void; - //memory.cpp - auto readByte(uint32 addr) -> uint8; - auto readWord(uint32 addr) -> uint16; - auto readLong(uint32 addr) -> uint32; + auto sign(uint2 size, uint32 data) -> int32; - auto read(uint size, uint32 addr) -> uint32; - auto readPC(uint size = Word) -> uint32; + //memory.cpp + auto readAbsolute(uint2 size, uint32 addr) -> uint32; + auto writeAbsolute(uint2 size, uint32 addr, uint32 data) -> void; + + auto readPC(uint2 size = Word) -> uint32; //ea.cpp struct EA { - uint mode; - uint reg; + EA(M68K* self, uint2 size, uint3 mode, uint3 reg); + ~EA(); + + 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; - boolean valid; uint32 address; + M68K* self; }; - auto sign(uint size, uint32 data) -> int32; - - auto address(uint size, EA& ea) -> uint32; - auto read(uint size, EA& ea) -> uint32; - auto write(uint size, EA& ea, uint32 data) -> void; - //instruction.cpp auto trap() -> void; auto instruction() -> void; @@ -46,16 +56,16 @@ struct M68K { //instructions.cpp auto testCondition(uint4 condition) -> bool; - auto instructionANDI(uint size, EA modify) -> void; - auto instructionBCC(uint condition, uint displacement) -> void; - auto instructionLEA(uint target, EA source) -> void; - auto instructionMOVE(uint size, EA target, EA source) -> void; - auto instructionMOVEA(uint size, uint target, EA source) -> void; - auto instructionMOVEM(uint direction, uint size, EA source) -> void; - auto instructionMOVEQ(uint target, uint immediate) -> void; - auto instructionMOVE_USP(uint direction, uint reg) -> void; + auto instructionANDI(uint2 size, uint3 mode, uint3 reg) -> 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 instructionMOVEQ(uint3 target, uint8 immediate) -> void; + auto instructionMOVE_USP(uint1 direction, uint3 reg) -> void; auto instructionNOP() -> void; - auto instructionTST(uint size, EA source) -> void; + auto instructionTST(uint2 size, uint3 mode, uint3 reg) -> void; //disassembler.cpp auto disassemble(uint32 pc) -> string; @@ -91,28 +101,28 @@ struct M68K { private: //disassembler.cpp - auto disassembleANDI(uint size, EA modify) -> string; - auto disassembleBCC(uint condition, uint displacement) -> string; - auto disassembleLEA(uint target, EA source) -> string; - auto disassembleMOVE(uint size, EA target, EA source) -> string; - auto disassembleMOVEA(uint size, uint target, EA source) -> string; - auto disassembleMOVEM(uint direction, uint size, EA source) -> string; - auto disassembleMOVEQ(uint target, uint immediate) -> string; - auto disassembleMOVE_USP(uint direction, uint reg) -> string; + auto disassembleANDI(uint2 size, uint3 mode, uint3 reg) -> 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 disassembleMOVEQ(uint3 target, uint8 immediate) -> string; + auto disassembleMOVE_USP(uint1 direction, uint3 reg) -> string; auto disassembleNOP() -> string; - auto disassembleTST(uint size, EA source) -> string; + auto disassembleTST(uint2 size, uint3 mode, uint3 reg) -> string; auto _readByte(uint32 addr) -> uint8; auto _readWord(uint32 addr) -> uint16; auto _readLong(uint32 addr) -> uint32; auto _readPC(uint size = Word) -> uint32; auto _immediate(uint size) -> string; - auto _address(uint size, EA& ea) -> string; - auto _read(uint size, EA& ea) -> string; - auto _write(uint size, EA& ea) -> string; - auto _branch(uint displacement) -> string; + auto _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 _branch(uint8 displacement) -> string; auto _suffix(uint size) -> string; - auto _condition(uint condition) -> string; + auto _condition(uint4 condition) -> string; uint32 _pc; function disassembleTable[65536]; diff --git a/higan/processor/m68k/memory.cpp b/higan/processor/m68k/memory.cpp index 785f5bce..de9b512d 100644 --- a/higan/processor/m68k/memory.cpp +++ b/higan/processor/m68k/memory.cpp @@ -1,34 +1,32 @@ -auto M68K::readByte(uint32 addr) -> uint8 { +auto M68K::readAbsolute(uint2 size, uint32 addr) -> uint32 { step(4); - return read(addr); + uint32 data = read(size != Byte, addr); + if(size != Long) return data; + + step(4); + data = data << 16 | read(1, addr + 2); + return data; } -auto M68K::readWord(uint32 addr) -> uint16 { - step(4); - uint16 data = read(addr + 0) << 8; - return data |= read(addr + 1) << 0; -} - -auto M68K::readLong(uint32 addr) -> uint32 { - uint32 data = readWord(addr + 0) << 16; - return data |= readWord(addr + 2) << 0; +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::read(uint size, uint32 addr) -> uint32 { - if(size == Byte) return readByte(addr); - if(size == Word) return readWord(addr); - if(size == Long) return readLong(addr); - return 0; -} - -auto M68K::readPC(uint size) -> uint32 { - uint32 data = readWord(r.pc); +auto M68K::readPC(uint2 size) -> uint32 { + step(4); + uint32 data = read(size != Byte, r.pc); r.pc += 2; - if(size == Byte) return (uint8)data; - if(size == Word) return data; - data = data << 16 | readWord(r.pc); + if(size != Long) return data; + + step(4); + data = data << 16 | read(1, r.pc); r.pc += 2; return data; } diff --git a/higan/processor/r65816/r65816.cpp b/higan/processor/r65816/r65816.cpp index 9df96622..e261a1dd 100644 --- a/higan/processor/r65816/r65816.cpp +++ b/higan/processor/r65816/r65816.cpp @@ -19,6 +19,20 @@ namespace Processor { #include "instructions-misc.cpp" #include "switch.cpp" +auto R65816::interrupt() -> void { + read(r.pc.d); + idle(); +N writeSP(r.pc.b); + writeSP(r.pc.h); + writeSP(r.pc.l); + writeSP(r.e ? (r.p & ~0x10) : r.p); + r.pc.l = read(r.vector + 0); + r.p.i = 1; + r.p.d = 0; + r.pc.h = read(r.vector + 1); + r.pc.b = 0x00; +} + //immediate, 2-cycle opcodes with idle cycle will become bus read //when an IRQ is to be triggered immediately after opcode completion. //this affects the following opcodes: @@ -54,20 +68,6 @@ auto R65816::idle6(uint16 addr) -> void { } } -auto R65816::interrupt() -> void { - read(r.pc.d); - idle(); -N writeSP(r.pc.b); - writeSP(r.pc.h); - writeSP(r.pc.l); - writeSP(r.e ? (r.p & ~0x10) : r.p); - r.pc.l = read(r.vector + 0); - r.p.i = 1; - r.p.d = 0; - r.pc.h = read(r.vector + 1); - r.pc.b = 0x00; -} - #undef E #undef N #undef L diff --git a/higan/processor/r65816/r65816.hpp b/higan/processor/r65816/r65816.hpp index 1aedcacf..c1827a69 100644 --- a/higan/processor/r65816/r65816.hpp +++ b/higan/processor/r65816/r65816.hpp @@ -18,6 +18,7 @@ struct R65816 { virtual auto write(uint24 addr, uint8 data) -> void = 0; virtual auto lastCycle() -> void = 0; virtual auto interruptPending() const -> bool = 0; + virtual auto interrupt() -> void; virtual auto readDisassembler(uint24 addr) -> uint8 { return 0; } @@ -26,7 +27,6 @@ struct R65816 { alwaysinline auto idle2() -> void; alwaysinline auto idle4(uint16 x, uint16 y) -> void; alwaysinline auto idle6(uint16 addr) -> void; - auto interrupt() -> void; //algorithms.cpp auto op_adc_b(); diff --git a/higan/sfc/coprocessor/sa1/sa1.cpp b/higan/sfc/coprocessor/sa1/sa1.cpp index e4bcb688..d2981ddc 100644 --- a/higan/sfc/coprocessor/sa1/sa1.cpp +++ b/higan/sfc/coprocessor/sa1/sa1.cpp @@ -30,6 +30,20 @@ auto SA1::main() -> void { instruction(); } +//override R65816::interrupt() to support SA-1 vector location IO registers +auto SA1::interrupt() -> void { + read(r.pc.d); + idle(); + if(!r.e) writeSP(r.pc.b); + writeSP(r.pc.h); + writeSP(r.pc.l); + writeSP(r.e ? (r.p & ~0x10) : r.p); + r.pc.w = r.vector; + r.pc.b = 0x00; + r.p.i = 1; + r.p.d = 0; +} + auto SA1::lastCycle() -> void { if(mmio.sa1_nmi && !mmio.sa1_nmicl) { status.interruptPending = true; diff --git a/higan/sfc/coprocessor/sa1/sa1.hpp b/higan/sfc/coprocessor/sa1/sa1.hpp index f770eb53..3df28bc3 100644 --- a/higan/sfc/coprocessor/sa1/sa1.hpp +++ b/higan/sfc/coprocessor/sa1/sa1.hpp @@ -3,6 +3,7 @@ struct SA1 : Processor::R65816, Cothread { static auto Enter() -> void; auto main() -> void; auto tick() -> void; + auto interrupt() -> void override; alwaysinline auto triggerIRQ() -> void; alwaysinline auto lastCycle() -> void override; diff --git a/nall/primitives.hpp b/nall/primitives.hpp index 07b502d5..299ee070 100644 --- a/nall/primitives.hpp +++ b/nall/primitives.hpp @@ -12,6 +12,9 @@ struct Boolean { inline operator bool() const { return data; } template inline auto& operator=(const T& value) { data = value; return *this; } + inline auto raise() { return data == 0 ? data = 1, true : false; } + inline auto lower() { return data == 1 ? data = 0, true : false; } + inline auto serialize(serializer& s) { s(data); } private: