diff --git a/ares/component/processor/mos6502/mos6502.hpp b/ares/component/processor/mos6502/mos6502.hpp index f22ae2d06a..9bf8f68fd2 100644 --- a/ares/component/processor/mos6502/mos6502.hpp +++ b/ares/component/processor/mos6502/mos6502.hpp @@ -11,6 +11,7 @@ struct MOS6502 { virtual auto write(n16 addr, n8 data) -> void = 0; virtual auto lastCycle() -> void = 0; virtual auto nmi(n16& vector) -> void = 0; + virtual auto debugAddress(n16 address) -> n32 { return address; } virtual auto readDebugger(n16 addr) -> n8 { return 0; } //mos6502.cpp diff --git a/ares/fc/cartridge/board/action53.cpp b/ares/fc/cartridge/board/action53.cpp index 14bce8bf80..d98e1a874f 100644 --- a/ares/fc/cartridge/board/action53.cpp +++ b/ares/fc/cartridge/board/action53.cpp @@ -66,6 +66,27 @@ struct Action53 : Interface { } } + auto debugAddress(n32 address) -> n32 override { + if(address < 0x8000) return address; + + n32 result; + n8 programBankMask = (1 << programBankWidth) - 1; + if (programBankMode < 2) { + n8 outerBank = programOuterBank & ~programBankMask; + n8 innerBank = programBank & programBankMask; + result = (outerBank | innerBank) << 16; + } else { + n9 outerBank = (programOuterBank & ~programBankMask) << 1; + n9 innerBank = programBank & ((2 << programBankWidth) - 1); + n9 offset = (address >> 14) & 1; + if(offset == (programBankMode & 1)) + result = programOuterBank << 16; + else + result = (outerBank | innerBank) << 16; + } + return (result | (n16)address) & ((bit::round(programROM.size()) << 1) - 1); + } + inline auto addressCIRAM(n32 address) -> n11 { if(mirror) { return ((address >> nametableBank) & 0x0400) | (n10)address; diff --git a/ares/fc/cartridge/board/board.hpp b/ares/fc/cartridge/board/board.hpp index f456d07362..cdd0b8d1ce 100644 --- a/ares/fc/cartridge/board/board.hpp +++ b/ares/fc/cartridge/board/board.hpp @@ -15,6 +15,7 @@ struct Interface { virtual auto readPRG(n32 address, n8 data) -> n8 { return data; } virtual auto writePRG(n32 address, n8 data) -> void {} + virtual auto debugAddress(n32 address) -> n32 { return address; } virtual auto readCHR(n32 address, n8 data) -> n8 { return data; } virtual auto writeCHR(n32 address, n8 data) -> void {} diff --git a/ares/fc/cartridge/board/gtrom.cpp b/ares/fc/cartridge/board/gtrom.cpp index 5135051725..fd5697873f 100644 --- a/ares/fc/cartridge/board/gtrom.cpp +++ b/ares/fc/cartridge/board/gtrom.cpp @@ -32,6 +32,11 @@ struct GTROM : Interface { } } + auto debugAddress(n32 address) -> n32 override { + if(address < 0x8000) return address; + return (programBank << 16 | (n16)address) & ((bit::round(programROM.size()) << 1) - 1); + } + auto readCHR(n32 address, n8 data) -> n8 override { if(address & 0x2000) return videoRAM.read(videoBank << 13 | (n13)address); if(characterRAM) return characterRAM.read(characterBank << 13 | (n13)address); diff --git a/ares/fc/cartridge/board/hvc-axrom.cpp b/ares/fc/cartridge/board/hvc-axrom.cpp index 926d72d1ff..5d4fe84ff3 100644 --- a/ares/fc/cartridge/board/hvc-axrom.cpp +++ b/ares/fc/cartridge/board/hvc-axrom.cpp @@ -41,6 +41,11 @@ struct HVC_AxROM : Interface { mirror = data.bit(4); } + auto debugAddress(n32 address) -> n32 override { + if(address < 0x8000) return address; + return (programBank << 16 | (n16)address) & ((bit::round(programROM.size()) << 1) - 1); + } + auto readCHR(n32 address, n8 data) -> n8 override { if(address & 0x2000) return ppu.readCIRAM(mirror << 10 | (n10)address); if(characterROM) return characterROM.read(address); diff --git a/ares/fc/cartridge/board/hvc-bnrom.cpp b/ares/fc/cartridge/board/hvc-bnrom.cpp index 01995bc2f3..20b8a9171a 100644 --- a/ares/fc/cartridge/board/hvc-bnrom.cpp +++ b/ares/fc/cartridge/board/hvc-bnrom.cpp @@ -29,6 +29,11 @@ struct HVC_BNROM : Interface { programBank = data; } + auto debugAddress(n32 address) -> n32 override { + if(address < 0x8000) return address; + return (programBank << 16 | (n16)address) & ((bit::round(programROM.size()) << 1) - 1); + } + auto readCHR(n32 address, n8 data) -> n8 override { if(address & 0x2000) { address = address >> !mirror & 0x0400 | (n10)address; diff --git a/ares/fc/cartridge/board/hvc-exrom.cpp b/ares/fc/cartridge/board/hvc-exrom.cpp index 1eb6f2c904..5f63d36d53 100644 --- a/ares/fc/cartridge/board/hvc-exrom.cpp +++ b/ares/fc/cartridge/board/hvc-exrom.cpp @@ -192,7 +192,7 @@ struct HVC_ExROM : Interface { //MMC5 return ramBank << 13 | (n13)address; } - auto programRomAddress(n32 address) -> n32 { + auto programRomBank(n32 address) -> n8 { n8 bank; if(programMode == 0) { @@ -216,7 +216,11 @@ struct HVC_ExROM : Interface { //MMC5 address &= 0x1fff; } - return bank << 13 | address; + return bank; + } + + auto programRomAddress(n32 address) -> n32 { + return programRomBank(address) << 13 | address; } auto readPRG(n32 address, n8 data) -> n8 override { @@ -569,6 +573,11 @@ struct HVC_ExROM : Interface { //MMC5 } } + auto debugAddress(n32 address) -> n32 override { + if(address < 0x8000) return address; + return programRomBank(address) << 16 | (n16)address; + } + auto readCIRAM(n32 address) -> n8 { if(vsplitFetch && (hcounter & 2) == 0) return exram[vsplitVoffset / 8 * 32 + vsplitHoffset / 8]; if(vsplitFetch && (hcounter & 2) != 0) return exram[vsplitVoffset / 32 * 8 + vsplitHoffset / 32 + 0x03c0]; diff --git a/ares/fc/cartridge/board/hvc-sxrom.cpp b/ares/fc/cartridge/board/hvc-sxrom.cpp index 7b15b9cd8d..4006a9bf45 100644 --- a/ares/fc/cartridge/board/hvc-sxrom.cpp +++ b/ares/fc/cartridge/board/hvc-sxrom.cpp @@ -92,7 +92,7 @@ struct HVC_SxROM : Interface { //MMC1 if(writeDelay) writeDelay--; } - auto addressProgramROM(n32 address) -> n32 { + auto bankPRG(n32 address) -> n5 { bool region = address & 0x4000; n5 bank = programBank & ~1 | region; if(programSize == 1) { @@ -102,7 +102,11 @@ struct HVC_SxROM : Interface { //MMC1 if(revision == Revision::SXROM) { bank.bit(4) = characterBank[0].bit(4); } - return bank << 14 | (n14)address; + return bank; + } + + auto addressProgramROM(n32 address) -> n32 { + return bankPRG(address) << 14 | (n14)address; } auto addressProgramRAM(n32 address) -> n32 { @@ -158,6 +162,11 @@ struct HVC_SxROM : Interface { //MMC1 if(address & 0x8000) return writeIO(address, data); } + auto debugAddress(n32 address) -> n32 override { + if(address < 0x8000) return address; + return (bankPRG(address) << 16 | (n16)address) & ((bit::round(programROM.size()) << 2) - 1); + } + auto writeIO(n32 address, n8 data) -> void { if(writeDelay) return; writeDelay = 2; diff --git a/ares/fc/cartridge/board/hvc-txrom.cpp b/ares/fc/cartridge/board/hvc-txrom.cpp index 3881facb92..66d6720930 100644 --- a/ares/fc/cartridge/board/hvc-txrom.cpp +++ b/ares/fc/cartridge/board/hvc-txrom.cpp @@ -79,6 +79,15 @@ struct HVC_TxROM : Interface { //MMC3 characterAddress = address; } + inline auto bankPRG(n32 address) -> n6 { + switch(address >> 13 & 3) { + case 0: return (programMode == 0 ? programBank[0] : (n6)0x3e); break; + case 1: return programBank[1]; break; + case 2: return (programMode == 1 ? programBank[0] : (n6)0x3e); break; + case 3: default: return 0x3f; break; + } + } + auto readPRG(n32 address, n8 data) -> n8 override { if(address < 0x6000) return data; @@ -87,14 +96,7 @@ struct HVC_TxROM : Interface { //MMC3 return programRAM.read((n13)address); } - n6 bank; - switch(address >> 13 & 3) { - case 0: bank = (programMode == 0 ? programBank[0] : (n6)0x3e); break; - case 1: bank = programBank[1]; break; - case 2: bank = (programMode == 1 ? programBank[0] : (n6)0x3e); break; - case 3: bank = 0x3f; break; - } - + n6 bank = bankPRG(address); address = bank << 13 | (n13)address; if(revision == Revision::NESQJ) { address = outerBank.bit(0) << 17 | (n17)address; @@ -159,6 +161,11 @@ struct HVC_TxROM : Interface { //MMC3 } } + auto debugAddress(n32 address) -> n32 override { + if(address < 0x8000) return address; + return (bankPRG(address) << 16 | (n16)address) & ((bit::round(programROM.size()) << 2) - 1); + } + auto addressCHR(n32 address) const -> n32 { if(characterMode == 0) { if(address <= 0x07ff) return characterBank[0] << 10 | (n11)address; diff --git a/ares/fc/cartridge/board/hvc-uxrom.cpp b/ares/fc/cartridge/board/hvc-uxrom.cpp index 7713c01b30..114134c3d0 100644 --- a/ares/fc/cartridge/board/hvc-uxrom.cpp +++ b/ares/fc/cartridge/board/hvc-uxrom.cpp @@ -31,14 +31,16 @@ struct HVC_UxROM : Interface { Interface::save(characterRAM, "character.ram"); } - auto readPRG(n32 address, n8 data) -> n8 override { - if(address < 0x8000) return data; - n8 bank; + inline auto bankPRG(n32 address) -> n8 { switch(address >> 14 & 1) { - case 0: bank = (revision == Revision::UNROMA ? (n8)0x00 : programBank); break; - case 1: bank = (revision == Revision::UNROMA ? programBank : (n8)0xff); break; + case 0: return (revision == Revision::UNROMA ? (n8)0x00 : programBank); break; + case 1: default: return (revision == Revision::UNROMA ? programBank : (n8)0xff); break; } - return programROM.read(bank << 14 | (n14)address); + } + + auto readPRG(n32 address, n8 data) -> n8 override { + if(address < 0x8000) return data; + return programROM.read(bankPRG(address) << 14 | (n14)address); } auto writePRG(n32 address, n8 data) -> void override { @@ -47,6 +49,11 @@ struct HVC_UxROM : Interface { if(revision == Revision::UN1ROM) programBank >>= 2; } + auto debugAddress(n32 address) -> n32 override { + if(address < 0x8000) return address; + return (bankPRG(address) << 16 | (n16)address) & ((bit::round(programROM.size()) << 2) - 1); + } + auto readCHR(n32 address, n8 data) -> n8 override { if(address & 0x2000) { address = address >> !mirror & 0x0400 | (n10)address; diff --git a/ares/fc/cartridge/board/unrom-512.cpp b/ares/fc/cartridge/board/unrom-512.cpp index f9f69e3b3a..d4270ba14c 100644 --- a/ares/fc/cartridge/board/unrom-512.cpp +++ b/ares/fc/cartridge/board/unrom-512.cpp @@ -21,14 +21,16 @@ struct UNROM512 : Interface { Interface::save(characterRAM, "character.ram"); } - auto readPRG(n32 address, n8 data) -> n8 override { - if(address < 0x8000) return data; - n5 bank; + inline auto bankPRG(n32 address) -> n5 { switch(address >> 14 & 1) { - case 0: bank = programBank; break; - case 1: bank = (n5)0x1f; break; + case 0: return programBank; break; + case 1: default: return (n5)0x1f; break; } - return programROM.read(bank << 14 | (n14)address); + } + + auto readPRG(n32 address, n8 data) -> n8 override { + if(address < 0x8000) return data; + return programROM.read(bankPRG(address) << 14 | (n14)address); } auto writePRG(n32 address, n8 data) -> void override { @@ -38,6 +40,11 @@ struct UNROM512 : Interface { nametableBank = data.bit(7); } + auto debugAddress(n32 address) -> n32 override { + if(address < 0x8000) return address; + return (bankPRG(address) << 16 | (n16)address) & ((bit::round(programROM.size()) << 2) - 1); + } + inline auto addressCIRAM(n32 address) -> n11 { if(mirror & 2) { return (nametableBank << 10) | (n10)address; diff --git a/ares/fc/cartridge/cartridge.cpp b/ares/fc/cartridge/cartridge.cpp index 6c4e38b4dd..2a24138cc3 100644 --- a/ares/fc/cartridge/cartridge.cpp +++ b/ares/fc/cartridge/cartridge.cpp @@ -70,6 +70,10 @@ auto Cartridge::writeCHR(n32 address, n8 data) -> void { return board->writeCHR(address, data); } +auto Cartridge::debugAddress(n32 address) -> n32 { + return board->debugAddress(address); +} + auto Cartridge::scanline(n32 y) -> void { return board->scanline(y); } diff --git a/ares/fc/cartridge/cartridge.hpp b/ares/fc/cartridge/cartridge.hpp index 9abac217b7..7f7b0dd071 100644 --- a/ares/fc/cartridge/cartridge.hpp +++ b/ares/fc/cartridge/cartridge.hpp @@ -34,6 +34,7 @@ struct Cartridge : Thread { auto readCHR(n32 address, n8 data = 0x00) -> n8; auto writeCHR(n32 address, n8 data) -> void; + auto debugAddress(n32 address) -> n32; //scanline() is for debugging purposes only: //boards must detect scanline edges on their own diff --git a/ares/fc/cpu/cpu.cpp b/ares/fc/cpu/cpu.cpp index 0b0cbf758d..8392ec58ad 100644 --- a/ares/fc/cpu/cpu.cpp +++ b/ares/fc/cpu/cpu.cpp @@ -1,4 +1,5 @@ #include +#include namespace ares::Famicom { diff --git a/ares/fc/cpu/cpu.hpp b/ares/fc/cpu/cpu.hpp index b9e3d907d1..448bd7a80d 100644 --- a/ares/fc/cpu/cpu.hpp +++ b/ares/fc/cpu/cpu.hpp @@ -36,6 +36,7 @@ struct CPU : MOS6502, Thread { auto readIO(n16 address) -> n8; auto writeIO(n16 address, n8 data) -> void; + auto debugAddress(n16 address) -> n32 override; auto readDebugger(n16 address) -> n8 override; auto serialize(serializer&) -> void; diff --git a/ares/fc/cpu/memory.cpp b/ares/fc/cpu/memory.cpp index 2d569e56d0..3e09b07cf1 100644 --- a/ares/fc/cpu/memory.cpp +++ b/ares/fc/cpu/memory.cpp @@ -21,6 +21,11 @@ inline auto CPU::writeBus(n16 address, n8 data) -> void { if(address <= 0x4017) return cpu.writeIO(address, data); } +inline auto CPU::debugAddress(n16 address) -> n32 { + if(address <= 0x4017) return address; + return cartridge.debugAddress(address); +} + auto CPU::readIO(n16 address) -> n8 { n8 data = MDR; diff --git a/ares/fc/cpu/timing.cpp b/ares/fc/cpu/timing.cpp index 2b4aa42db6..e84a730cbc 100644 --- a/ares/fc/cpu/timing.cpp +++ b/ares/fc/cpu/timing.cpp @@ -1,4 +1,6 @@ auto CPU::read(n16 address) -> n8 { + GDB::server.reportMemRead(address, 1); + if(io.oamDMAPending) { io.oamDMAPending = 0; read(address); @@ -16,6 +18,8 @@ auto CPU::read(n16 address) -> n8 { } auto CPU::write(n16 address, n8 data) -> void { + GDB::server.reportMemWrite(address, 1); + writeBus(address, MDR = data); step(rate()); } diff --git a/ares/fc/system/gdb.cpp b/ares/fc/system/gdb.cpp new file mode 100644 index 0000000000..782450e0b3 --- /dev/null +++ b/ares/fc/system/gdb.cpp @@ -0,0 +1,91 @@ +auto System::initGdbDebugHooks() -> void { + // See: https://sourceware.org/gdb/onlinedocs/gdb/Target-Description-Format.html#Target-Description-Format + GDB::server.hooks.targetXML = []() -> string { + return "" + "mos" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + ""; + }; + + GDB::server.hooks.normalizeAddress = [](u64 address) -> u64 { + return cpu.debugAddress(address & 0xFFFF); + }; + + GDB::server.hooks.read = [](u64 address, u32 byteCount) -> string { + string res{}; + res.resize(byteCount * 2); + char* resPtr = res.begin(); + + for(u32 i : range(byteCount)) { + auto val = cpu.readDebugger(address++); + hexByte(resPtr, val); + resPtr += 2; + } + + return res; + }; + + GDB::server.hooks.write = [](u64 address, u32 unitSize, u64 value) { + for(u32 i : range(unitSize)) { + cpu.writeBus(address++, value); + value >>= 8; + } + }; + + GDB::server.hooks.regRead = [](u32 regIdx) { + switch(regIdx) { + case 0: return hex(cpu.A, 2, '0'); + case 1: return hex(cpu.X, 2, '0'); + case 2: return hex(cpu.Y, 2, '0'); + case 3: return hex(cpu.S, 2, '0'); + case 4: return hex(cpu.P|0, 2, '0'); + case 5: return hex(bswap32(cpu.debugAddress(cpu.PC)), 8, '0'); + } + return string{"00"}; + }; + + GDB::server.hooks.regWrite = [](u32 regIdx, u64 regValue) -> bool { + switch(regIdx) { + case 0: cpu.A = regValue; return true; + case 1: cpu.X = regValue; return true; + case 2: cpu.Y = regValue; return true; + case 3: cpu.S = regValue; return true; + case 4: cpu.P = regValue | 0x30; return true; + case 5: cpu.PC = bswap32(regValue) & 0xFFFF; return true; + } + return false; + }; + + GDB::server.hooks.regReadGeneral = []() { + string res{}; + for(auto i : range(6)) { + res.append(GDB::server.hooks.regRead(i)); + } + return res; + }; + + GDB::server.hooks.regWriteGeneral = [](const string ®Data) { + u32 regIdx{0}; + GDB::server.hooks.regWrite(0, regData.slice(0, 2).hex()); + GDB::server.hooks.regWrite(1, regData.slice(2, 2).hex()); + GDB::server.hooks.regWrite(2, regData.slice(4, 2).hex()); + GDB::server.hooks.regWrite(3, regData.slice(6, 2).hex()); + GDB::server.hooks.regWrite(4, regData.slice(8, 2).hex()); + GDB::server.hooks.regWrite(5, regData.slice(10, 4).hex()); // 8 + }; +} diff --git a/ares/fc/system/system.cpp b/ares/fc/system/system.cpp index 88934bdfa3..a7a21294fe 100644 --- a/ares/fc/system/system.cpp +++ b/ares/fc/system/system.cpp @@ -1,4 +1,5 @@ #include +#include namespace ares::Famicom { @@ -19,6 +20,7 @@ Random random; Scheduler scheduler; System system; #include "controls.cpp" +#include "gdb.cpp" #include "serialization.cpp" auto System::game() -> string { @@ -79,6 +81,8 @@ auto System::load(Node::System& root, string name) -> bool { controllerPort1.load(node); controllerPort2.load(node); expansionPort.load(node); + + initGdbDebugHooks(); return true; } diff --git a/ares/fc/system/system.hpp b/ares/fc/system/system.hpp index 03734604ea..fb19741a37 100644 --- a/ares/fc/system/system.hpp +++ b/ares/fc/system/system.hpp @@ -28,6 +28,9 @@ struct System { auto unload() -> void; auto power(bool reset) -> void; + //gdb.cpp + auto initGdbDebugHooks() -> void; + //serialization.cpp auto serialize(bool synchronize) -> serializer; auto unserialize(serializer&) -> bool;