diff --git a/pcsx2/DebugTools/Breakpoints.h b/pcsx2/DebugTools/Breakpoints.h index 024bdb841f..48f79f5563 100644 --- a/pcsx2/DebugTools/Breakpoints.h +++ b/pcsx2/DebugTools/Breakpoints.h @@ -140,6 +140,7 @@ public: static const std::vector GetMemChecks(); static const std::vector GetBreakpoints(); + static const size_t GetNumMemchecks() { return memChecks_.size(); } static void Update(u32 addr = 0); diff --git a/pcsx2/Interpreter.cpp b/pcsx2/Interpreter.cpp index f4484ae540..59a90181c1 100644 --- a/pcsx2/Interpreter.cpp +++ b/pcsx2/Interpreter.cpp @@ -23,6 +23,8 @@ #include "Elfheader.h" +#include "../DebugTools/Breakpoints.h" + #include using namespace R5900; // for OPCODE and OpcodeImpl @@ -45,8 +47,93 @@ static void debugI() //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() { + // 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 ); if( IsDebugBuild ) debugI(); diff --git a/pcsx2/R5900.cpp b/pcsx2/R5900.cpp index 29ff799766..3febf42454 100644 --- a/pcsx2/R5900.cpp +++ b/pcsx2/R5900.cpp @@ -34,6 +34,9 @@ #include "Patch.h" #include "GameDatabase.h" +#include "../DebugTools/Breakpoints.h" +#include "R5900OpcodeTables.h" + using namespace R5900; // for R5900 disasm tools s32 EEsCycle; // used to sync the IOP to the EE @@ -608,3 +611,44 @@ void __fastcall eeloadReplaceOSDSYS() } // 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; +} diff --git a/pcsx2/R5900.h b/pcsx2/R5900.h index b9f97aaf8a..4504a6fed7 100644 --- a/pcsx2/R5900.h +++ b/pcsx2/R5900.h @@ -436,6 +436,10 @@ extern void cpuTestINTCInts(); extern void cpuTestDMACInts(); extern void cpuTestTIMRInts(); +// breakpoint code shared between interpreter and recompiler +int isMemcheckNeeded(u32 pc); +int isBreakpointNeeded(u32 addr); + //////////////////////////////////////////////////////////////////// // Exception Codes diff --git a/pcsx2/x86/ix86-32/iR5900-32.cpp b/pcsx2/x86/ix86-32/iR5900-32.cpp index a3edc40a54..c754aec6b8 100644 --- a/pcsx2/x86/ix86-32/iR5900-32.cpp +++ b/pcsx2/x86/ix86-32/iR5900-32.cpp @@ -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() { if (isBreakpointNeeded(pc) != 0)