From 2264e7b087ae796695979d2d5c75cd5eef1e03b7 Mon Sep 17 00:00:00 2001 From: comex Date: Thu, 23 Apr 2015 01:22:35 -0400 Subject: [PATCH] Use a fake exception to exit early in case of memory breakpoints. Change TMemCheck::Action to return whether to break rather than calling PPCDebugInterface::BreakNow, as this simplified the implementation; then remove said method, as that was its only caller. One "interface" method down, many to go... --- Source/Core/Common/BreakPoints.cpp | 6 +++--- Source/Core/Common/BreakPoints.h | 3 ++- Source/Core/Common/DebugInterface.h | 1 - .../Core/Core/Debugger/PPCDebugInterface.cpp | 5 ----- Source/Core/Core/Debugger/PPCDebugInterface.h | 1 - Source/Core/Core/HW/CPU.cpp | 10 +++++++++- Source/Core/Core/PowerPC/Gekko.h | 4 +++- Source/Core/Core/PowerPC/MMU.cpp | 20 ++++++++++++++++++- Source/Core/Core/PowerPC/PowerPC.cpp | 6 ++++++ 9 files changed, 42 insertions(+), 14 deletions(-) diff --git a/Source/Core/Common/BreakPoints.cpp b/Source/Core/Common/BreakPoints.cpp index 2ee89389d3..277b956e61 100644 --- a/Source/Core/Common/BreakPoints.cpp +++ b/Source/Core/Common/BreakPoints.cpp @@ -207,7 +207,7 @@ TMemCheck *MemChecks::GetMemCheck(u32 address) return nullptr; } -void TMemCheck::Action(DebugInterface *debug_interface, u32 iValue, u32 addr, bool write, int size, u32 pc) +bool TMemCheck::Action(DebugInterface *debug_interface, u32 iValue, u32 addr, bool write, int size, u32 pc) { if ((write && OnWrite) || (!write && OnRead)) { @@ -220,9 +220,9 @@ void TMemCheck::Action(DebugInterface *debug_interface, u32 iValue, u32 addr, bo ); } - if (Break) - debug_interface->BreakNow(); + return true; } + return false; } diff --git a/Source/Core/Common/BreakPoints.h b/Source/Core/Common/BreakPoints.h index 370f4c96e0..91dd74ae20 100644 --- a/Source/Core/Common/BreakPoints.h +++ b/Source/Core/Common/BreakPoints.h @@ -40,7 +40,8 @@ struct TMemCheck u32 numHits; - void Action(DebugInterface *dbg_interface, u32 _iValue, u32 addr, + // returns whether to break + bool Action(DebugInterface *dbg_interface, u32 _iValue, u32 addr, bool write, int size, u32 pc); }; diff --git a/Source/Core/Common/DebugInterface.h b/Source/Core/Common/DebugInterface.h index a21921d496..9e30870eff 100644 --- a/Source/Core/Common/DebugInterface.h +++ b/Source/Core/Common/DebugInterface.h @@ -30,7 +30,6 @@ public: virtual void SetPC(unsigned int /*address*/) {} virtual void Step() {} virtual void RunToBreakpoint() {} - virtual void BreakNow() {} virtual void InsertBLR(unsigned int /*address*/, unsigned int /*value*/) {} virtual int GetColor(unsigned int /*address*/){return 0xFFFFFFFF;} virtual std::string GetDescription(unsigned int /*address*/) = 0; diff --git a/Source/Core/Core/Debugger/PPCDebugInterface.cpp b/Source/Core/Core/Debugger/PPCDebugInterface.cpp index 2a70213d35..81ffa1bd0e 100644 --- a/Source/Core/Core/Debugger/PPCDebugInterface.cpp +++ b/Source/Core/Core/Debugger/PPCDebugInterface.cpp @@ -169,11 +169,6 @@ void PPCDebugInterface::InsertBLR(unsigned int address, unsigned int value) PowerPC::HostWrite_U32(value, address); } -void PPCDebugInterface::BreakNow() -{ - CCPU::Break(); -} - // ======================================================= // Separate the blocks with colors. diff --git a/Source/Core/Core/Debugger/PPCDebugInterface.h b/Source/Core/Core/Debugger/PPCDebugInterface.h index 0cecef0ea6..2a4753cb96 100644 --- a/Source/Core/Core/Debugger/PPCDebugInterface.h +++ b/Source/Core/Core/Debugger/PPCDebugInterface.h @@ -39,7 +39,6 @@ public: virtual unsigned int GetPC() override; virtual void SetPC(unsigned int address) override; virtual void Step() override {} - virtual void BreakNow() override; virtual void RunToBreakpoint() override; virtual void InsertBLR(unsigned int address, unsigned int value) override; virtual int GetColor(unsigned int address) override; diff --git a/Source/Core/Core/HW/CPU.cpp b/Source/Core/Core/HW/CPU.cpp index 953a4c9633..f583cc3dfe 100644 --- a/Source/Core/Core/HW/CPU.cpp +++ b/Source/Core/Core/HW/CPU.cpp @@ -13,6 +13,7 @@ #include "Core/Movie.h" #include "Core/HW/CPU.h" #include "Core/HW/DSP.h" +#include "Core/HW/Memmap.h" #include "Core/PowerPC/PowerPC.h" #include "VideoCommon/VideoBackendBase.h" @@ -117,7 +118,14 @@ void CCPU::EnableStepping(const bool _bStepping) { // SingleStep so that the "continue", "step over" and "step out" debugger functions // work when the PC is at a breakpoint at the beginning of the block - if (PowerPC::breakpoints.IsAddressBreakPoint(PC) && PowerPC::GetMode() != PowerPC::MODE_INTERPRETER) + // If watchpoints are enabled, any instruction could be a breakpoint. + bool could_be_bp; +#ifdef ENABLE_MEM_CHECK + could_be_bp = true; +#else + could_be_bp = PowerPC::breakpoints.IsAddressBreakPoint(PC); +#endif + if (could_be_bp && PowerPC::GetMode() != PowerPC::MODE_INTERPRETER) { PowerPC::CoreMode oldMode = PowerPC::GetMode(); PowerPC::SetMode(PowerPC::MODE_INTERPRETER); diff --git a/Source/Core/Core/PowerPC/Gekko.h b/Source/Core/Core/PowerPC/Gekko.h index 14f4083af6..4b8921c3e4 100644 --- a/Source/Core/Core/PowerPC/Gekko.h +++ b/Source/Core/Core/PowerPC/Gekko.h @@ -831,7 +831,9 @@ enum EXCEPTION_ALIGNMENT = 0x00000020, EXCEPTION_FPU_UNAVAILABLE = 0x00000040, EXCEPTION_PROGRAM = 0x00000080, - EXCEPTION_PERFORMANCE_MONITOR = 0x00000100 + EXCEPTION_PERFORMANCE_MONITOR = 0x00000100, + + EXCEPTION_FAKE_MEMCHECK_HIT = 0x00000200, }; inline s32 SignExt16(s16 x) {return (s32)(s16)x;} diff --git a/Source/Core/Core/PowerPC/MMU.cpp b/Source/Core/Core/PowerPC/MMU.cpp index 4fc09c7f19..b283354e72 100644 --- a/Source/Core/Core/PowerPC/MMU.cpp +++ b/Source/Core/Core/PowerPC/MMU.cpp @@ -21,6 +21,7 @@ #include "Core/ConfigManager.h" #include "Core/Core.h" +#include "Core/HW/CPU.h" #include "Core/HW/GPFifo.h" #include "Core/HW/Memmap.h" #include "Core/HW/MMIO.h" @@ -455,8 +456,25 @@ static __forceinline void Memcheck(u32 address, u32 var, bool write, int size) TMemCheck *mc = PowerPC::memchecks.GetMemCheck(address); if (mc) { + if (CCPU::IsStepping()) + { + // Disable when stepping so that resume works. + return; + } mc->numHits++; - mc->Action(&PowerPC::debug_interface, var, address, write, size, PC); + bool pause = mc->Action(&PowerPC::debug_interface, var, address, write, size, PC); + if (pause) + { + CCPU::Break(); + // Fake a DSI so that all the code that tests for it in order to skip + // the rest of the instruction will apply. (This means that + // watchpoints will stop the emulator before the offending load/store, + // not after like GDB does, but that's better anyway. Just need to + // make sure resuming after that works.) + // It doesn't matter if ReadFromHardware triggers its own DSI because + // we'll take it after resuming. + PowerPC::ppcState.Exceptions |= EXCEPTION_DSI | EXCEPTION_FAKE_MEMCHECK_HIT; + } } #endif } diff --git a/Source/Core/Core/PowerPC/PowerPC.cpp b/Source/Core/Core/PowerPC/PowerPC.cpp index ce69bd7d01..b9ec4ca085 100644 --- a/Source/Core/Core/PowerPC/PowerPC.cpp +++ b/Source/Core/Core/PowerPC/PowerPC.cpp @@ -375,6 +375,12 @@ void CheckExceptions() INFO_LOG(POWERPC, "EXCEPTION_FPU_UNAVAILABLE"); ppcState.Exceptions &= ~EXCEPTION_FPU_UNAVAILABLE; } +#ifdef ENABLE_MEM_CHECK + else if (exceptions & EXCEPTION_FAKE_MEMCHECK_HIT) + { + ppcState.Exceptions &= ~EXCEPTION_DSI & ~EXCEPTION_FAKE_MEMCHECK_HIT; + } +#endif else if (exceptions & EXCEPTION_DSI) { SRR0 = PC;