mirror of https://github.com/PCSX2/pcsx2.git
Add breakpoint support to R5900 interpreter
This commit is contained in:
parent
430c617a95
commit
a95e55dc54
|
@ -140,6 +140,7 @@ public:
|
||||||
|
|
||||||
static const std::vector<MemCheck> GetMemChecks();
|
static const std::vector<MemCheck> GetMemChecks();
|
||||||
static const std::vector<BreakPoint> GetBreakpoints();
|
static const std::vector<BreakPoint> GetBreakpoints();
|
||||||
|
static const size_t GetNumMemchecks() { return memChecks_.size(); }
|
||||||
|
|
||||||
static void Update(u32 addr = 0);
|
static void Update(u32 addr = 0);
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,8 @@
|
||||||
|
|
||||||
#include "Elfheader.h"
|
#include "Elfheader.h"
|
||||||
|
|
||||||
|
#include "../DebugTools/Breakpoints.h"
|
||||||
|
|
||||||
#include <float.h>
|
#include <float.h>
|
||||||
|
|
||||||
using namespace R5900; // for OPCODE and OpcodeImpl
|
using namespace R5900; // for OPCODE and OpcodeImpl
|
||||||
|
@ -45,8 +47,93 @@ static void debugI()
|
||||||
|
|
||||||
//long int runs=0;
|
//long int runs=0;
|
||||||
|
|
||||||
|
void intBreakpoint(bool memcheck)
|
||||||
|
{
|
||||||
|
u32 pc = cpuRegs.pc;
|
||||||
|
if (CBreakPoints::CheckSkipFirst(pc) != 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!memcheck)
|
||||||
|
{
|
||||||
|
auto cond = CBreakPoints::GetBreakPointCondition(pc);
|
||||||
|
if (cond && !cond->Evaluate())
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CBreakPoints::SetBreakpointTriggered(true);
|
||||||
|
GetCoreThread().PauseSelf();
|
||||||
|
throw Exception::ExitCpuExecute();
|
||||||
|
}
|
||||||
|
|
||||||
|
void intMemcheck(u32 op, u32 bits, bool store)
|
||||||
|
{
|
||||||
|
// compute accessed address
|
||||||
|
u32 start = cpuRegs.GPR.r[(op >> 21) & 0x1F].UD[0];
|
||||||
|
if ((s16)op != 0)
|
||||||
|
start += (s16)op;
|
||||||
|
if (bits == 128)
|
||||||
|
start &= ~0x0F;
|
||||||
|
|
||||||
|
start = standardizeBreakpointAddress(start);
|
||||||
|
u32 end = start + bits/8;
|
||||||
|
|
||||||
|
auto checks = CBreakPoints::GetMemChecks();
|
||||||
|
for (size_t i = 0; i < checks.size(); i++)
|
||||||
|
{
|
||||||
|
auto& check = checks[i];
|
||||||
|
|
||||||
|
if (check.result == 0)
|
||||||
|
continue;
|
||||||
|
if ((check.cond & MEMCHECK_WRITE) == 0 && store == true)
|
||||||
|
continue;
|
||||||
|
if ((check.cond & MEMCHECK_READ) == 0 && store == false)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (start < check.end && check.start < end)
|
||||||
|
intBreakpoint(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void intCheckMemcheck()
|
||||||
|
{
|
||||||
|
u32 pc = cpuRegs.pc;
|
||||||
|
int needed = isMemcheckNeeded(pc);
|
||||||
|
if (needed == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
u32 op = memRead32(needed == 2 ? pc+4 : pc);
|
||||||
|
const OPCODE& opcode = GetInstruction(op);
|
||||||
|
|
||||||
|
bool store = (opcode.flags & IS_STORE) != 0;
|
||||||
|
switch (opcode.flags & MEMTYPE_MASK)
|
||||||
|
{
|
||||||
|
case MEMTYPE_BYTE:
|
||||||
|
intMemcheck(op,8,store);
|
||||||
|
break;
|
||||||
|
case MEMTYPE_HALF:
|
||||||
|
intMemcheck(op,16,store);
|
||||||
|
break;
|
||||||
|
case MEMTYPE_WORD:
|
||||||
|
intMemcheck(op,32,store);
|
||||||
|
break;
|
||||||
|
case MEMTYPE_DWORD:
|
||||||
|
intMemcheck(op,64,store);
|
||||||
|
break;
|
||||||
|
case MEMTYPE_QWORD:
|
||||||
|
intMemcheck(op,128,store);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void execI()
|
static void execI()
|
||||||
{
|
{
|
||||||
|
// check if any breakpoints or memchecks are triggered by this instruction
|
||||||
|
if (isBreakpointNeeded(cpuRegs.pc))
|
||||||
|
intBreakpoint(false);
|
||||||
|
|
||||||
|
intCheckMemcheck();
|
||||||
|
|
||||||
|
// interprete instruction
|
||||||
cpuRegs.code = memRead32( cpuRegs.pc );
|
cpuRegs.code = memRead32( cpuRegs.pc );
|
||||||
if( IsDebugBuild )
|
if( IsDebugBuild )
|
||||||
debugI();
|
debugI();
|
||||||
|
|
|
@ -34,6 +34,9 @@
|
||||||
#include "Patch.h"
|
#include "Patch.h"
|
||||||
#include "GameDatabase.h"
|
#include "GameDatabase.h"
|
||||||
|
|
||||||
|
#include "../DebugTools/Breakpoints.h"
|
||||||
|
#include "R5900OpcodeTables.h"
|
||||||
|
|
||||||
using namespace R5900; // for R5900 disasm tools
|
using namespace R5900; // for R5900 disasm tools
|
||||||
|
|
||||||
s32 EEsCycle; // used to sync the IOP to the EE
|
s32 EEsCycle; // used to sync the IOP to the EE
|
||||||
|
@ -608,3 +611,44 @@ void __fastcall eeloadReplaceOSDSYS()
|
||||||
}
|
}
|
||||||
// else... uh...?
|
// else... uh...?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline bool isBranchOrJump(u32 addr)
|
||||||
|
{
|
||||||
|
u32 op = memRead32(addr);
|
||||||
|
const OPCODE& opcode = GetInstruction(op);
|
||||||
|
|
||||||
|
return (opcode.flags & IS_BRANCH) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The next two functions return 0 if no breakpoint is needed,
|
||||||
|
// 1 if it's needed on the current pc, 2 if it's needed in the delay slot
|
||||||
|
|
||||||
|
int isBreakpointNeeded(u32 addr)
|
||||||
|
{
|
||||||
|
if (CBreakPoints::IsAddressBreakPoint(addr))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
// there may be a breakpoint in the delay slot
|
||||||
|
if (isBranchOrJump(addr) && CBreakPoints::IsAddressBreakPoint(addr+4))
|
||||||
|
return 2;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int isMemcheckNeeded(u32 pc)
|
||||||
|
{
|
||||||
|
if (CBreakPoints::GetNumMemchecks() == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
u32 addr = pc;
|
||||||
|
if (isBranchOrJump(addr))
|
||||||
|
addr += 4;
|
||||||
|
|
||||||
|
u32 op = memRead32(addr);
|
||||||
|
const OPCODE& opcode = GetInstruction(op);
|
||||||
|
|
||||||
|
if (opcode.flags & IS_MEMORY)
|
||||||
|
return addr == pc ? 1 : 2;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
|
@ -436,6 +436,10 @@ extern void cpuTestINTCInts();
|
||||||
extern void cpuTestDMACInts();
|
extern void cpuTestDMACInts();
|
||||||
extern void cpuTestTIMRInts();
|
extern void cpuTestTIMRInts();
|
||||||
|
|
||||||
|
// breakpoint code shared between interpreter and recompiler
|
||||||
|
int isMemcheckNeeded(u32 pc);
|
||||||
|
int isBreakpointNeeded(u32 addr);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Exception Codes
|
// Exception Codes
|
||||||
|
|
||||||
|
|
|
@ -1356,47 +1356,6 @@ void recMemcheck(u32 op, u32 bits, bool store)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool isBranchOrJump(u32 addr)
|
|
||||||
{
|
|
||||||
u32 op = memRead32(addr);
|
|
||||||
const OPCODE& opcode = GetInstruction(op);
|
|
||||||
|
|
||||||
return (opcode.flags & IS_BRANCH) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The next two functions return 0 if no breakpoint is needed,
|
|
||||||
// 1 if it's needed on the current pc, 2 if it's needed in the delay slot
|
|
||||||
|
|
||||||
int isBreakpointNeeded(u32 addr)
|
|
||||||
{
|
|
||||||
if (CBreakPoints::IsAddressBreakPoint(addr))
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
// there may be a breakpoint in the delay slot
|
|
||||||
if (isBranchOrJump(addr) && CBreakPoints::IsAddressBreakPoint(addr+4))
|
|
||||||
return 2;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int isMemcheckNeeded(u32 pc)
|
|
||||||
{
|
|
||||||
if (CBreakPoints::GetMemChecks().size() == 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
u32 addr = pc;
|
|
||||||
if (isBranchOrJump(addr))
|
|
||||||
addr += 4;
|
|
||||||
|
|
||||||
u32 op = memRead32(addr);
|
|
||||||
const OPCODE& opcode = GetInstruction(op);
|
|
||||||
|
|
||||||
if ((opcode.flags & IS_MEMORY) && (opcode.flags & MEMTYPE_MASK) != 0)
|
|
||||||
return addr == pc ? 1 : 2;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void encodeBreakpoint()
|
void encodeBreakpoint()
|
||||||
{
|
{
|
||||||
if (isBreakpointNeeded(pc) != 0)
|
if (isBreakpointNeeded(pc) != 0)
|
||||||
|
|
Loading…
Reference in New Issue