Add breakpoint support to R5900 interpreter

This commit is contained in:
Kingcom 2014-08-21 13:01:07 +02:00
parent 430c617a95
commit a95e55dc54
5 changed files with 136 additions and 41 deletions

View File

@ -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);

View File

@ -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();

View File

@ -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;
}

View File

@ -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

View File

@ -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)