diff --git a/ares/component/processor/arm7tdmi/instruction.cpp b/ares/component/processor/arm7tdmi/instruction.cpp index 4d93d0d4e..60377f4f7 100644 --- a/ares/component/processor/arm7tdmi/instruction.cpp +++ b/ares/component/processor/arm7tdmi/instruction.cpp @@ -83,11 +83,8 @@ auto ARM7TDMI::armInitialize() -> void { opcode.bit( 0, 3), /* m */ \ opcode.bit(12,15), /* d */ \ opcode.bit(16,19) /* field */ - for(n4 m : range(16)) - for(n2 _ : range(4)) - for(n4 d : range(16)) - for(n4 field : range(16)) { - auto opcode = pattern(".... 0001 0010 ???? ???? ---- 0??1 ????") | m << 0 | _ << 5 | d << 12 | field << 16; + for(n2 _ : range(4)) { + auto opcode = pattern(".... 0001 0010 ???? ???? ---- 0??1 ????") | _ << 5; bind(opcode, BranchExchangeRegister); } #undef arguments diff --git a/ares/component/processor/sh2/exceptions.cpp b/ares/component/processor/sh2/exceptions.cpp index 9d4e8c475..6b6a988db 100644 --- a/ares/component/processor/sh2/exceptions.cpp +++ b/ares/component/processor/sh2/exceptions.cpp @@ -40,6 +40,9 @@ auto SH2::interrupt(u8 level, u8 vector) -> void { } auto SH2::addressErrorCPU() -> void { + if (GDB::server.hasActiveClient) { + GDB::server.reportSignal(GDB::Signal::BUS, PC - 4); + } static constexpr u8 vector = 0x09; SP &= ~3; //not accurate; but prevents infinite recursion push(SR); @@ -48,6 +51,9 @@ auto SH2::addressErrorCPU() -> void { } auto SH2::addressErrorDMA() -> void { + if (GDB::server.hasActiveClient) { + GDB::server.reportSignal(GDB::Signal::BUS, PC - 4); + } static constexpr u8 vector = 0x0a; SP &= ~3; //not accurate; but prevents infinite recursion push(SR); @@ -57,6 +63,9 @@ auto SH2::addressErrorDMA() -> void { auto SH2::illegalInstruction() -> void { if(inDelaySlot()) return illegalSlotInstruction(); + if (GDB::server.hasActiveClient) { + GDB::server.reportSignal(GDB::Signal::ILL, PC - 4); + } debug(unusual, "[SH2] illegal instruction: 0x", hex(busReadWord(PC - 4), 4L), " @ 0x", hex(PC - 4)); static constexpr u8 vector = 0x04; push(SR); @@ -65,6 +74,9 @@ auto SH2::illegalInstruction() -> void { } auto SH2::illegalSlotInstruction() -> void { + if (GDB::server.hasActiveClient) { + GDB::server.reportSignal(GDB::Signal::ILL, PC - 4); + } debug(unusual, "[SH2] illegal slot instruction: 0x", hex(busReadWord(PC - 4), 4L)); static constexpr u8 vector = 0x06; push(SR); diff --git a/ares/component/processor/sh2/sh2.hpp b/ares/component/processor/sh2/sh2.hpp index a409023aa..72af80eb5 100644 --- a/ares/component/processor/sh2/sh2.hpp +++ b/ares/component/processor/sh2/sh2.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include //Hitachi SH-2 diff --git a/ares/md/m32x/m32x.cpp b/ares/md/m32x/m32x.cpp index cf15389a5..a581b58b6 100644 --- a/ares/md/m32x/m32x.cpp +++ b/ares/md/m32x/m32x.cpp @@ -26,6 +26,8 @@ auto M32X::load(Node::Object parent) -> void { vectors.allocate(fp->size() >> 1); for(auto address : range(vectors.size())) vectors.program(address, fp->readm(2L)); } + + initDebugHooks(); } auto M32X::unload() -> void { @@ -92,4 +94,94 @@ auto M32X::hblank(bool line) -> void { } } +auto M32X::initDebugHooks() -> void { + + // See: https://sourceware.org/gdb/onlinedocs/gdb/Target-Description-Format.html#Target-Description-Format + GDB::server.hooks.targetXML = []() -> string { + return "" + "sh2" + ""; + }; + + GDB::server.hooks.normalizeAddress = [](u64 address) -> u64 { + return address & 0x00FFFFFF; + }; + + GDB::server.hooks.read = [](u64 address, u32 byteCount) -> string { + address = (s32)address; + + string res{}; + res.resize(byteCount * 2); + char* resPtr = res.begin(); + + for(u32 i : range(byteCount)) { + auto val = m32x.shm.readByte(address++); + hexByte(resPtr, val); + resPtr += 2; + } + + return res; + }; + + GDB::server.hooks.regRead = [this](u32 regIdx) { + if(regIdx < 16) { + return hex(shm.regs.R[regIdx], 8, '0'); + } + + switch (regIdx) + { + case 16: return hex(shm.regs.PC - 4, 8, '0'); + case 17: return hex(shm.regs.PR, 8, '0'); + case 18: return hex(shm.regs.GBR, 8, '0'); + case 19: return hex(shm.regs.VBR, 8, '0'); + case 20: return hex(shm.regs.MACH, 8, '0'); + case 21: return hex(shm.regs.MACL, 8, '0'); + case 22: return hex((u32)shm.regs.SR, 8, '0'); + } + + return string{"00000000"}; + }; + + GDB::server.hooks.regWrite = [this](u32 regIdx, u64 regValue) -> bool { + if(regIdx < 16) { + shm.regs.R[regIdx] = (u32)regValue; return true; + } + + switch (regIdx) + { + case 16: shm.regs.PC = (u32)regValue; return true; + case 17: shm.regs.PR = (u32)regValue; return true; + case 18: shm.regs.GBR = (u32)regValue; return true; + case 19: shm.regs.VBR = (u32)regValue; return true; + case 20: shm.regs.MACH = (u32)regValue; return true; + case 21: shm.regs.MACL = (u32)regValue; return true; + case 22: shm.regs.SR = (u32)regValue; return true; + } + + return false; + }; + + GDB::server.hooks.regReadGeneral = []() { + string res{}; + for(auto i : range(23)) { + res.append(GDB::server.hooks.regRead(i)); + } + return res; + }; + + GDB::server.hooks.regWriteGeneral = [](const string ®Data) { + u32 regIdx{0}; + for(auto i=0; i void; auto hblank(bool) -> void; + auto initDebugHooks() -> void; + //bus-internal.cpp auto readInternal(n1 upper, n1 lower, n32 address, n16 data = 0) -> n16; auto writeInternal(n1 upper, n1 lower, n32 address, n16 data) -> void; diff --git a/ares/md/m32x/sh7604.cpp b/ares/md/m32x/sh7604.cpp index 8cb084d75..8da29c8e1 100644 --- a/ares/md/m32x/sh7604.cpp +++ b/ares/md/m32x/sh7604.cpp @@ -14,6 +14,21 @@ auto M32X::SH7604::unload() -> void { } auto M32X::SH7604::main() -> void { + if (GDB::server.hasActiveClient && m32x.shm.active()) { + updateLoopCounter--; + + if (!GDB::server.reportDelayedPC(regs.PC)) { + if (!updateLoopCounter) { + GDB::server.updateLoop(); + updateLoopCounter = 23000000 / 60 / 240; + } + return; + } else if (!updateLoopCounter) { + GDB::server.updateLoop(); + updateLoopCounter = 23000000 / 60; + } + } + if(!m32x.io.adapterReset) return step(1000); if(!regs.ID) { @@ -93,6 +108,7 @@ auto M32X::SH7604::power(bool reset) -> void { SH2::power(reset); irq = {}; irq.vres.enable = 1; + updateLoopCounter = 23000000 / 60; } auto M32X::SH7604::restart() -> void { @@ -134,6 +150,9 @@ auto M32X::SH7604::syncM68k(bool force) -> void { } auto M32X::SH7604::busReadByte(u32 address) -> u32 { + if (GDB::server.hasActiveClient && m32x.shm.active()) { + GDB::server.reportMemRead(address, 1); + } if(address & 1) { return m32x.readInternal(0, 1, address & ~1).byte(0); } else { @@ -142,15 +161,24 @@ auto M32X::SH7604::busReadByte(u32 address) -> u32 { } auto M32X::SH7604::busReadWord(u32 address) -> u32 { + if (GDB::server.hasActiveClient && m32x.shm.active()) { + GDB::server.reportMemRead(address, 2); + } return m32x.readInternal(1, 1, address & ~1); } auto M32X::SH7604::busReadLong(u32 address) -> u32 { + if (GDB::server.hasActiveClient && m32x.shm.active()) { + GDB::server.reportMemRead(address, 4); + } u32 data = m32x.readInternal(1, 1, address & ~3 | 0) << 16; return data | m32x.readInternal(1, 1, address & ~3 | 2) << 0; } auto M32X::SH7604::busWriteByte(u32 address, u32 data) -> void { + if (GDB::server.hasActiveClient && m32x.shm.active()) { + GDB::server.reportMemWrite(address, 1); + } debugger.tracer.instruction->invalidate(address & ~1); if(address & 1) { m32x.writeInternal(0, 1, address & ~1, data << 8 | (u8)data << 0); @@ -160,11 +188,17 @@ auto M32X::SH7604::busWriteByte(u32 address, u32 data) -> void { } auto M32X::SH7604::busWriteWord(u32 address, u32 data) -> void { + if (GDB::server.hasActiveClient && m32x.shm.active()) { + GDB::server.reportMemWrite(address, 2); + } debugger.tracer.instruction->invalidate(address & ~1); m32x.writeInternal(1, 1, address & ~1, data); } auto M32X::SH7604::busWriteLong(u32 address, u32 data) -> void { + if (GDB::server.hasActiveClient && m32x.shm.active()) { + GDB::server.reportMemWrite(address, 4); + } debugger.tracer.instruction->invalidate(address & ~3 | 0); debugger.tracer.instruction->invalidate(address & ~3 | 2); m32x.writeInternal(1, 1, address & ~3 | 0, data >> 16); diff --git a/ares/md/md.hpp b/ares/md/md.hpp index 4689cb80f..b5267ae65 100644 --- a/ares/md/md.hpp +++ b/ares/md/md.hpp @@ -10,6 +10,7 @@ #include #include #include +#include namespace ares::MegaDrive { #include diff --git a/nall/nall/gdb/server.cpp b/nall/nall/gdb/server.cpp index 2c415f2cf..d616e1be2 100644 --- a/nall/nall/gdb/server.cpp +++ b/nall/nall/gdb/server.cpp @@ -105,6 +105,29 @@ namespace nall::GDB { return !needHalts; } + auto Server::reportDelayedPC(u64 pc) -> bool { + if(!hasActiveClient)return true; + + currentPC = pc; + bool needHalts = forceHalt || breakpoints.contains(pc - 4); + + if(needHalts) { + forceHalt = true; // breakpoints may get deleted after a signal, but we have to stay stopped + + if(!haltSignalSent) { + haltSignalSent = true; + sendSignal(Signal::TRAP); + } + } + + if(singleStepActive) { + singleStepActive = false; + forceHalt = true; + } + + return !needHalts; + } + /** * NOTE: please read the comment in the header server.hpp file before making any changes here! */ @@ -115,7 +138,7 @@ namespace nall::GDB { char cmdPrefix = cmdName.size() > 0 ? cmdName(0) : ' '; if constexpr(GDB_LOG_MESSAGES) { - print("GDB <: %s\n", cmdBuffer.data()); + printf("GDB <: %s\n", cmdBuffer.data()); } switch(cmdPrefix) diff --git a/nall/nall/gdb/server.hpp b/nall/nall/gdb/server.hpp index 8acc45906..d2cab7ca7 100644 --- a/nall/nall/gdb/server.hpp +++ b/nall/nall/gdb/server.hpp @@ -88,6 +88,7 @@ class Server : public nall::TCPText::Server { // PC / Memory State Updates auto reportPC(u64 pc) -> bool; + auto reportDelayedPC(u64 pc) -> bool; auto reportMemRead(u64 address, u32 size) -> void; auto reportMemWrite(u64 address, u32 size) -> void; @@ -101,6 +102,8 @@ class Server : public nall::TCPText::Server { auto updateLoop() -> void; auto getStatusText(u32 port, bool useIPv4) -> string; + + bool hasActiveClient{false}; protected: auto onText(string_view text) -> void override; @@ -120,7 +123,6 @@ class Server : public nall::TCPText::Server { bool handshakeDone{false}; // set to true after a few handshake commands, used to prevent exception-reporting until client is ready bool requestDisconnect{false}; // set to true if the client decides it wants to disconnect - bool hasActiveClient{false}; u32 messageCount{0}; // message count per update loop s32 currentThreadC{-1}; // selected thread for the next 'c' command