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...
This commit is contained in:
comex 2015-04-23 01:22:35 -04:00
parent dd7ab4812b
commit 2264e7b087
9 changed files with 42 additions and 14 deletions

View File

@ -207,7 +207,7 @@ TMemCheck *MemChecks::GetMemCheck(u32 address)
return nullptr; 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)) if ((write && OnWrite) || (!write && OnRead))
{ {
@ -220,9 +220,9 @@ void TMemCheck::Action(DebugInterface *debug_interface, u32 iValue, u32 addr, bo
); );
} }
if (Break) return true;
debug_interface->BreakNow();
} }
return false;
} }

View File

@ -40,7 +40,8 @@ struct TMemCheck
u32 numHits; 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); bool write, int size, u32 pc);
}; };

View File

@ -30,7 +30,6 @@ public:
virtual void SetPC(unsigned int /*address*/) {} virtual void SetPC(unsigned int /*address*/) {}
virtual void Step() {} virtual void Step() {}
virtual void RunToBreakpoint() {} virtual void RunToBreakpoint() {}
virtual void BreakNow() {}
virtual void InsertBLR(unsigned int /*address*/, unsigned int /*value*/) {} virtual void InsertBLR(unsigned int /*address*/, unsigned int /*value*/) {}
virtual int GetColor(unsigned int /*address*/){return 0xFFFFFFFF;} virtual int GetColor(unsigned int /*address*/){return 0xFFFFFFFF;}
virtual std::string GetDescription(unsigned int /*address*/) = 0; virtual std::string GetDescription(unsigned int /*address*/) = 0;

View File

@ -169,11 +169,6 @@ void PPCDebugInterface::InsertBLR(unsigned int address, unsigned int value)
PowerPC::HostWrite_U32(value, address); PowerPC::HostWrite_U32(value, address);
} }
void PPCDebugInterface::BreakNow()
{
CCPU::Break();
}
// ======================================================= // =======================================================
// Separate the blocks with colors. // Separate the blocks with colors.

View File

@ -39,7 +39,6 @@ public:
virtual unsigned int GetPC() override; virtual unsigned int GetPC() override;
virtual void SetPC(unsigned int address) override; virtual void SetPC(unsigned int address) override;
virtual void Step() override {} virtual void Step() override {}
virtual void BreakNow() override;
virtual void RunToBreakpoint() override; virtual void RunToBreakpoint() override;
virtual void InsertBLR(unsigned int address, unsigned int value) override; virtual void InsertBLR(unsigned int address, unsigned int value) override;
virtual int GetColor(unsigned int address) override; virtual int GetColor(unsigned int address) override;

View File

@ -13,6 +13,7 @@
#include "Core/Movie.h" #include "Core/Movie.h"
#include "Core/HW/CPU.h" #include "Core/HW/CPU.h"
#include "Core/HW/DSP.h" #include "Core/HW/DSP.h"
#include "Core/HW/Memmap.h"
#include "Core/PowerPC/PowerPC.h" #include "Core/PowerPC/PowerPC.h"
#include "VideoCommon/VideoBackendBase.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 // 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 // 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::CoreMode oldMode = PowerPC::GetMode();
PowerPC::SetMode(PowerPC::MODE_INTERPRETER); PowerPC::SetMode(PowerPC::MODE_INTERPRETER);

View File

@ -831,7 +831,9 @@ enum
EXCEPTION_ALIGNMENT = 0x00000020, EXCEPTION_ALIGNMENT = 0x00000020,
EXCEPTION_FPU_UNAVAILABLE = 0x00000040, EXCEPTION_FPU_UNAVAILABLE = 0x00000040,
EXCEPTION_PROGRAM = 0x00000080, 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;} inline s32 SignExt16(s16 x) {return (s32)(s16)x;}

View File

@ -21,6 +21,7 @@
#include "Core/ConfigManager.h" #include "Core/ConfigManager.h"
#include "Core/Core.h" #include "Core/Core.h"
#include "Core/HW/CPU.h"
#include "Core/HW/GPFifo.h" #include "Core/HW/GPFifo.h"
#include "Core/HW/Memmap.h" #include "Core/HW/Memmap.h"
#include "Core/HW/MMIO.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); TMemCheck *mc = PowerPC::memchecks.GetMemCheck(address);
if (mc) if (mc)
{ {
if (CCPU::IsStepping())
{
// Disable when stepping so that resume works.
return;
}
mc->numHits++; 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 #endif
} }

View File

@ -375,6 +375,12 @@ void CheckExceptions()
INFO_LOG(POWERPC, "EXCEPTION_FPU_UNAVAILABLE"); INFO_LOG(POWERPC, "EXCEPTION_FPU_UNAVAILABLE");
ppcState.Exceptions &= ~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) else if (exceptions & EXCEPTION_DSI)
{ {
SRR0 = PC; SRR0 = PC;