IOP: Implement memchecks for the interpreter

This commit is contained in:
ty 2021-02-22 21:25:03 -05:00 committed by refractionpcsx2
parent e1df43703c
commit 10e995aa06
1 changed files with 77 additions and 7 deletions

View File

@ -17,6 +17,8 @@
#include "PrecompiledHeader.h"
#include "IopCommon.h"
#include "App.h" // For host irx injection hack
#include "R5900OpcodeTables.h"
#include "../DebugTools/Breakpoints.h"
using namespace R3000A;
@ -124,32 +126,100 @@ void psxJALR()
doBranch(_u32(_rRs_));
}
void psxBreakpoint()
void psxBreakpoint(bool memcheck)
{
u32 pc = psxRegs.pc;
if (CBreakPoints::CheckSkipFirst(BREAKPOINT_IOP, pc) != 0)
return;
auto cond = CBreakPoints::GetBreakPointCondition(BREAKPOINT_IOP, pc);
if (cond && !cond->Evaluate())
return;
if (!memcheck)
{
auto cond = CBreakPoints::GetBreakPointCondition(BREAKPOINT_IOP, pc);
if (cond && !cond->Evaluate())
return;
}
CBreakPoints::SetBreakpointTriggered(true);
GetCoreThread().PauseSelfDebug();
throw Exception::ExitCpuExecute();
}
void psxMemcheck(u32 op, u32 bits, bool store)
{
// compute accessed address
u32 start = psxRegs.GPR.r[(op >> 21) & 0x1F];
if ((s16)op != 0)
start += (s16)op;
if (bits == 128)
start &= ~0x0F;
start = standardizeBreakpointAddress(BREAKPOINT_IOP, 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.cpu != BREAKPOINT_IOP)
continue;
if (check.result == 0)
continue;
if ((check.cond & MEMCHECK_WRITE) == 0 && store)
continue;
if ((check.cond & MEMCHECK_READ) == 0 && !store)
continue;
if (start < check.end && check.start < end)
psxBreakpoint(true);
}
}
void psxCheckMemcheck()
{
u32 pc = psxRegs.pc;
int needed = psxIsMemcheckNeeded(pc);
if (needed == 0)
return;
u32 op = iopMemRead32(needed == 2 ? pc + 4 : pc);
// Yeah, we use the R5900 opcode table for the R3000
const R5900::OPCODE& opcode = R5900::GetInstruction(op);
bool store = (opcode.flags & IS_STORE) != 0;
switch (opcode.flags & MEMTYPE_MASK)
{
case MEMTYPE_BYTE:
psxMemcheck(op, 8, store);
break;
case MEMTYPE_HALF:
psxMemcheck(op, 16, store);
break;
case MEMTYPE_WORD:
psxMemcheck(op, 32, store);
break;
case MEMTYPE_DWORD:
psxMemcheck(op, 64, store);
break;
case MEMTYPE_QWORD:
psxMemcheck(op, 128, store);
break;
}
}
///////////////////////////////////////////
// These macros are used to assemble the repassembler functions
static __fi void execI()
{
// Called for every instruction.
// This function is called for every instruction.
// Enabling the define below will probably, no, will cause the interpretor to be slower.
//#define EXTRA_DEBUG
#ifdef EXTRA_DEBUG
if (psxIsBreakpointNeeded(psxRegs.pc))
psxBreakpoint();
psxBreakpoint(false);
psxCheckMemcheck();
#endif
// Inject IRX hack
@ -166,7 +236,7 @@ static __fi void execI()
psxRegs.pc+= 4;
psxRegs.cycle++;
if ((psxHu32(HW_ICFG) & (1 << 3)))
{
//One of the Iop to EE delta clocks to be set in PS1 mode.