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:
parent
dd7ab4812b
commit
2264e7b087
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue