Implements IOP breakpoints (#3011)

IOP: Implement IOP Breakpoints
This commit is contained in:
Maxim Nikitin 2021-01-08 18:34:08 -05:00 committed by GitHub
parent 170d1cb94c
commit 7dbf01b024
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 423 additions and 146 deletions

View File

@ -22,14 +22,24 @@
#include "../System.h"
std::vector<BreakPoint> CBreakPoints::breakPoints_;
u32 CBreakPoints::breakSkipFirstAt_ = 0;
u64 CBreakPoints::breakSkipFirstTicks_ = 0;
u32 CBreakPoints::breakSkipFirstAtEE_ = 0;
u64 CBreakPoints::breakSkipFirstTicksEE_ = 0;
u32 CBreakPoints::breakSkipFirstAtIop_ = 0;
u64 CBreakPoints::breakSkipFirstTicksIop_ = 0;
std::vector<MemCheck> CBreakPoints::memChecks_;
std::vector<MemCheck *> CBreakPoints::cleanupMemChecks_;
bool CBreakPoints::breakpointTriggered_ = false;
// called from the dynarec
u32 __fastcall standardizeBreakpointAddress(u32 addr)
u32 __fastcall standardizeBreakpointAddress(BreakPointCpu cpu, u32 addr)
{
if (cpu == BREAKPOINT_IOP)
return standardizeBreakpointAddressIop(addr);
else
return standardizeBreakpointAddressEE(addr);
}
u32 __fastcall standardizeBreakpointAddressEE(u32 addr)
{
if (addr >= 0xFFFF8000)
return addr;
@ -38,14 +48,19 @@ u32 __fastcall standardizeBreakpointAddress(u32 addr)
addr &= 0x1FFFFFFF;
addr &= 0x7FFFFFFF;
if ((addr >> 28) == 2 || (addr >> 28) == 3)
addr &= ~(0xF << 28);
return addr;
}
u32 __fastcall standardizeBreakpointAddressIop(u32 addr)
{
return addr;
}
MemCheck::MemCheck() :
cpu(BREAKPOINT_EE),
start(0),
end(0),
cond(MEMCHECK_READWRITE),
@ -120,104 +135,105 @@ void MemCheck::JitCleanup()
host->SetDebugMode(true);*/
}
size_t CBreakPoints::FindBreakpoint(u32 addr, bool matchTemp, bool temp)
size_t CBreakPoints::FindBreakpoint(BreakPointCpu cpu, u32 addr, bool matchTemp, bool temp)
{
addr = standardizeBreakpointAddress(addr);
addr = standardizeBreakpointAddress(cpu, addr);
for (size_t i = 0; i < breakPoints_.size(); ++i)
{
u32 cmp = standardizeBreakpointAddress(breakPoints_[i].addr);
if (cmp == addr && (!matchTemp || breakPoints_[i].temporary == temp))
u32 cmp = standardizeBreakpointAddress(cpu, breakPoints_[i].addr);
if (cpu == breakPoints_[i].cpu && cmp == addr && (!matchTemp || breakPoints_[i].temporary == temp))
return i;
}
return INVALID_BREAKPOINT;
}
size_t CBreakPoints::FindMemCheck(u32 start, u32 end)
size_t CBreakPoints::FindMemCheck(BreakPointCpu cpu, u32 start, u32 end)
{
start = standardizeBreakpointAddress(start);
end = standardizeBreakpointAddress(end);
start = standardizeBreakpointAddress(cpu, start);
end = standardizeBreakpointAddress(cpu, end);
for (size_t i = 0; i < memChecks_.size(); ++i)
{
u32 cmpStart = standardizeBreakpointAddress(memChecks_[i].start);
u32 cmpEnd = standardizeBreakpointAddress(memChecks_[i].end);
if (cmpStart == start && cmpEnd == end)
u32 cmpStart = standardizeBreakpointAddress(cpu, memChecks_[i].start);
u32 cmpEnd = standardizeBreakpointAddress(cpu, memChecks_[i].end);
if (memChecks_[i].cpu == cpu && cmpStart == start && cmpEnd == end)
return i;
}
return INVALID_MEMCHECK;
}
bool CBreakPoints::IsAddressBreakPoint(u32 addr)
bool CBreakPoints::IsAddressBreakPoint(BreakPointCpu cpu, u32 addr)
{
size_t bp = FindBreakpoint(addr);
size_t bp = FindBreakpoint(cpu, addr);
if (bp != INVALID_BREAKPOINT && breakPoints_[bp].enabled)
return true;
// Check again for overlapping temp breakpoint
bp = FindBreakpoint(addr, true, true);
bp = FindBreakpoint(cpu, addr, true, true);
return bp != INVALID_BREAKPOINT && breakPoints_[bp].enabled;
}
bool CBreakPoints::IsAddressBreakPoint(u32 addr, bool* enabled)
bool CBreakPoints::IsAddressBreakPoint(BreakPointCpu cpu, u32 addr, bool* enabled)
{
size_t bp = FindBreakpoint(addr);
size_t bp = FindBreakpoint(cpu, addr);
if (bp == INVALID_BREAKPOINT) return false;
if (enabled != NULL) *enabled = breakPoints_[bp].enabled;
return true;
}
bool CBreakPoints::IsTempBreakPoint(u32 addr)
bool CBreakPoints::IsTempBreakPoint(BreakPointCpu cpu, u32 addr)
{
size_t bp = FindBreakpoint(addr, true, true);
size_t bp = FindBreakpoint(cpu, addr, true, true);
return bp != INVALID_BREAKPOINT;
}
void CBreakPoints::AddBreakPoint(u32 addr, bool temp)
void CBreakPoints::AddBreakPoint(BreakPointCpu cpu, u32 addr, bool temp)
{
size_t bp = FindBreakpoint(addr, true, temp);
size_t bp = FindBreakpoint(cpu, addr, true, temp);
if (bp == INVALID_BREAKPOINT)
{
BreakPoint pt;
pt.enabled = true;
pt.temporary = temp;
pt.addr = addr;
pt.cpu = cpu;
breakPoints_.push_back(pt);
Update(addr);
Update(cpu, addr);
}
else if (!breakPoints_[bp].enabled)
{
breakPoints_[bp].enabled = true;
breakPoints_[bp].hasCond = false;
Update(addr);
Update(cpu, addr);
}
}
void CBreakPoints::RemoveBreakPoint(u32 addr)
void CBreakPoints::RemoveBreakPoint(BreakPointCpu cpu, u32 addr)
{
size_t bp = FindBreakpoint(addr);
size_t bp = FindBreakpoint(cpu, addr);
if (bp != INVALID_BREAKPOINT)
{
breakPoints_.erase(breakPoints_.begin() + bp);
// Check again, there might've been an overlapping temp breakpoint.
bp = FindBreakpoint(addr);
bp = FindBreakpoint(cpu, addr);
if (bp != INVALID_BREAKPOINT)
breakPoints_.erase(breakPoints_.begin() + bp);
Update(addr);
Update(cpu, addr);
}
}
void CBreakPoints::ChangeBreakPoint(u32 addr, bool status)
void CBreakPoints::ChangeBreakPoint(BreakPointCpu cpu, u32 addr, bool status)
{
size_t bp = FindBreakpoint(addr);
size_t bp = FindBreakpoint(cpu, addr);
if (bp != INVALID_BREAKPOINT)
{
breakPoints_[bp].enabled = status;
Update(addr);
Update(cpu, addr);
}
}
@ -239,15 +255,15 @@ void CBreakPoints::ClearTemporaryBreakPoints()
{
if (breakPoints_[i].temporary)
{
Update(breakPoints_[i].addr);
Update(breakPoints_[i].cpu, breakPoints_[i].addr);
breakPoints_.erase(breakPoints_.begin() + i);
}
}
}
void CBreakPoints::ChangeBreakPointAddCond(u32 addr, const BreakPointCond &cond)
void CBreakPoints::ChangeBreakPointAddCond(BreakPointCpu cpu, u32 addr, const BreakPointCond &cond)
{
size_t bp = FindBreakpoint(addr, true, false);
size_t bp = FindBreakpoint(cpu, addr, true, false);
if (bp != INVALID_BREAKPOINT)
{
breakPoints_[bp].hasCond = true;
@ -256,9 +272,9 @@ void CBreakPoints::ChangeBreakPointAddCond(u32 addr, const BreakPointCond &cond)
}
}
void CBreakPoints::ChangeBreakPointRemoveCond(u32 addr)
void CBreakPoints::ChangeBreakPointRemoveCond(BreakPointCpu cpu, u32 addr)
{
size_t bp = FindBreakpoint(addr, true, false);
size_t bp = FindBreakpoint(cpu, addr, true, false);
if (bp != INVALID_BREAKPOINT)
{
breakPoints_[bp].hasCond = false;
@ -266,25 +282,25 @@ void CBreakPoints::ChangeBreakPointRemoveCond(u32 addr)
}
}
BreakPointCond *CBreakPoints::GetBreakPointCondition(u32 addr)
BreakPointCond *CBreakPoints::GetBreakPointCondition(BreakPointCpu cpu, u32 addr)
{
size_t bp = FindBreakpoint(addr, true, true);
size_t bp = FindBreakpoint(cpu, addr, true, true);
//temp breakpoints are unconditional
if (bp != INVALID_BREAKPOINT)
return NULL;
bp = FindBreakpoint(addr, true, false);
bp = FindBreakpoint(cpu, addr, true, false);
if (bp != INVALID_BREAKPOINT && breakPoints_[bp].hasCond)
return &breakPoints_[bp].cond;
return NULL;
}
void CBreakPoints::AddMemCheck(u32 start, u32 end, MemCheckCondition cond, MemCheckResult result)
void CBreakPoints::AddMemCheck(BreakPointCpu cpu, u32 start, u32 end, MemCheckCondition cond, MemCheckResult result)
{
// This will ruin any pending memchecks.
cleanupMemChecks_.clear();
size_t mc = FindMemCheck(start, end);
size_t mc = FindMemCheck(cpu, start, end);
if (mc == INVALID_MEMCHECK)
{
MemCheck check;
@ -292,39 +308,40 @@ void CBreakPoints::AddMemCheck(u32 start, u32 end, MemCheckCondition cond, MemCh
check.end = end;
check.cond = cond;
check.result = result;
check.cpu = cpu;
memChecks_.push_back(check);
Update();
Update(cpu);
}
else
{
memChecks_[mc].cond = (MemCheckCondition)(memChecks_[mc].cond | cond);
memChecks_[mc].result = (MemCheckResult)(memChecks_[mc].result | result);
Update();
Update(cpu);
}
}
void CBreakPoints::RemoveMemCheck(u32 start, u32 end)
void CBreakPoints::RemoveMemCheck(BreakPointCpu cpu, u32 start, u32 end)
{
// This will ruin any pending memchecks.
cleanupMemChecks_.clear();
size_t mc = FindMemCheck(start, end);
size_t mc = FindMemCheck(cpu, start, end);
if (mc != INVALID_MEMCHECK)
{
memChecks_.erase(memChecks_.begin() + mc);
Update();
Update(cpu);
}
}
void CBreakPoints::ChangeMemCheck(u32 start, u32 end, MemCheckCondition cond, MemCheckResult result)
void CBreakPoints::ChangeMemCheck(BreakPointCpu cpu, u32 start, u32 end, MemCheckCondition cond, MemCheckResult result)
{
size_t mc = FindMemCheck(start, end);
size_t mc = FindMemCheck(cpu, start, end);
if (mc != INVALID_MEMCHECK)
{
memChecks_[mc].cond = cond;
memChecks_[mc].result = result;
Update();
Update(cpu);
}
}
@ -340,18 +357,27 @@ void CBreakPoints::ClearAllMemChecks()
}
}
void CBreakPoints::SetSkipFirst(u32 pc)
void CBreakPoints::SetSkipFirst(BreakPointCpu cpu, u32 pc)
{
breakSkipFirstAt_ = standardizeBreakpointAddress(pc);
breakSkipFirstTicks_ = r5900Debug.getCycles();
if (cpu == BREAKPOINT_EE)
{
breakSkipFirstAtEE_ = standardizeBreakpointAddress(cpu, pc);
breakSkipFirstTicksEE_ = r5900Debug.getCycles();
}
else if (cpu == BREAKPOINT_IOP)
{
breakSkipFirstAtIop_ = standardizeBreakpointAddress(cpu, pc);
breakSkipFirstTicksIop_ = r3000Debug.getCycles();
}
}
u32 CBreakPoints::CheckSkipFirst(u32 cmpPc)
u32 CBreakPoints::CheckSkipFirst(BreakPointCpu cpu, u32 cmpPc)
{
cmpPc = standardizeBreakpointAddress(cmpPc);
u32 pc = breakSkipFirstAt_;
if (breakSkipFirstTicks_ == r5900Debug.getCycles())
return pc;
cmpPc = standardizeBreakpointAddress(cpu, cmpPc);
if (cpu == BREAKPOINT_EE && breakSkipFirstTicksEE_ == r5900Debug.getCycles())
return breakSkipFirstAtEE_;
else if (cpu == BREAKPOINT_IOP && breakSkipFirstTicksIop_ == r3000Debug.getCycles())
return breakSkipFirstAtIop_;
return 0;
}
@ -385,7 +411,7 @@ const std::vector<BreakPoint> CBreakPoints::GetBreakpoints()
#include "App.h"
#include "Debugger/DisassemblyDialog.h"
void CBreakPoints::Update(u32 addr)
void CBreakPoints::Update(BreakPointCpu cpu, u32 addr)
{
bool resume = false;
if (!r5900Debug.isCpuPaused())

View File

@ -52,6 +52,7 @@ struct BreakPoint
bool hasCond;
BreakPointCond cond;
BreakPointCpu cpu;
bool operator == (const BreakPoint &other) const {
return addr == other.addr;
@ -87,6 +88,7 @@ struct MemCheck
MemCheckCondition cond;
MemCheckResult result;
BreakPointCpu cpu;
u32 numHits;
@ -114,27 +116,27 @@ public:
static const size_t INVALID_BREAKPOINT = -1;
static const size_t INVALID_MEMCHECK = -1;
static bool IsAddressBreakPoint(u32 addr);
static bool IsAddressBreakPoint(u32 addr, bool* enabled);
static bool IsTempBreakPoint(u32 addr);
static void AddBreakPoint(u32 addr, bool temp = false);
static void RemoveBreakPoint(u32 addr);
static void ChangeBreakPoint(u32 addr, bool enable);
static bool IsAddressBreakPoint(BreakPointCpu cpu, u32 addr);
static bool IsAddressBreakPoint(BreakPointCpu cpu, u32 addr, bool* enabled);
static bool IsTempBreakPoint(BreakPointCpu cpu, u32 addr);
static void AddBreakPoint(BreakPointCpu cpu, u32 addr, bool temp = false);
static void RemoveBreakPoint(BreakPointCpu cpu, u32 addr);
static void ChangeBreakPoint(BreakPointCpu cpu, u32 addr, bool enable);
static void ClearAllBreakPoints();
static void ClearTemporaryBreakPoints();
// Makes a copy. Temporary breakpoints can't have conditions.
static void ChangeBreakPointAddCond(u32 addr, const BreakPointCond &cond);
static void ChangeBreakPointRemoveCond(u32 addr);
static BreakPointCond *GetBreakPointCondition(u32 addr);
static void ChangeBreakPointAddCond(BreakPointCpu cpu, u32 addr, const BreakPointCond &cond);
static void ChangeBreakPointRemoveCond(BreakPointCpu cpu, u32 addr);
static BreakPointCond *GetBreakPointCondition(BreakPointCpu cpu, u32 addr);
static void AddMemCheck(u32 start, u32 end, MemCheckCondition cond, MemCheckResult result);
static void RemoveMemCheck(u32 start, u32 end);
static void ChangeMemCheck(u32 start, u32 end, MemCheckCondition cond, MemCheckResult result);
static void AddMemCheck(BreakPointCpu cpu, u32 start, u32 end, MemCheckCondition cond, MemCheckResult result);
static void RemoveMemCheck(BreakPointCpu cpu, u32 start, u32 end);
static void ChangeMemCheck(BreakPointCpu cpu, u32 start, u32 end, MemCheckCondition cond, MemCheckResult result);
static void ClearAllMemChecks();
static void SetSkipFirst(u32 pc);
static u32 CheckSkipFirst(u32 pc);
static void SetSkipFirst(BreakPointCpu cpu, u32 pc);
static u32 CheckSkipFirst(BreakPointCpu cpu, u32 pc);
// Includes uncached addresses.
static const std::vector<MemCheck> GetMemCheckRanges();
@ -143,19 +145,22 @@ public:
static const std::vector<BreakPoint> GetBreakpoints();
static size_t GetNumMemchecks() { return memChecks_.size(); }
static void Update(u32 addr = 0);
static void Update(BreakPointCpu cpu = BREAKPOINT_IOP_AND_EE, u32 addr = 0);
static void SetBreakpointTriggered(bool b) { breakpointTriggered_ = b; };
static bool GetBreakpointTriggered() { return breakpointTriggered_; };
private:
static size_t FindBreakpoint(u32 addr, bool matchTemp = false, bool temp = false);
static size_t FindBreakpoint(BreakPointCpu cpu, u32 addr, bool matchTemp = false, bool temp = false);
// Finds exactly, not using a range check.
static size_t FindMemCheck(u32 start, u32 end);
static size_t FindMemCheck(BreakPointCpu cpu, u32 start, u32 end);
static std::vector<BreakPoint> breakPoints_;
static u32 breakSkipFirstAt_;
static u64 breakSkipFirstTicks_;
static u32 breakSkipFirstAtEE_;
static u64 breakSkipFirstTicksEE_;
static u32 breakSkipFirstAtIop_;
static u64 breakSkipFirstTicksIop_;
static bool breakpointTriggered_;
static std::vector<MemCheck> memChecks_;
@ -164,4 +169,6 @@ private:
// called from the dynarec
u32 __fastcall standardizeBreakpointAddress(u32 addr);
u32 __fastcall standardizeBreakpointAddress(BreakPointCpu cpu, u32 addr);
u32 __fastcall standardizeBreakpointAddressEE(u32 addr);
u32 __fastcall standardizeBreakpointAddressIop(u32 addr);

View File

@ -232,6 +232,11 @@ bool DebugInterface::parseExpression(PostfixExpression& exp, u64& dest)
// R5900DebugInterface
//
BreakPointCpu R5900DebugInterface::getCpuType()
{
return BREAKPOINT_EE;
}
u32 R5900DebugInterface::read8(u32 address)
{
if (!isValidAddress(address))
@ -628,6 +633,11 @@ u32 R5900DebugInterface::getCycles()
//
BreakPointCpu R3000DebugInterface::getCpuType()
{
return BREAKPOINT_IOP;
}
u32 R3000DebugInterface::read8(u32 address)
{
if (!isValidAddress(address))

View File

@ -19,6 +19,12 @@
enum { EECAT_GPR, EECAT_CP0, EECAT_FPR, EECAT_FCR, EECAT_VU0F, EECAT_VU0I, EECAT_COUNT };
enum { IOPCAT_GPR, IOPCAT_COUNT };
enum BreakPointCpu
{
BREAKPOINT_EE = 0x01,
BREAKPOINT_IOP = 0x02,
BREAKPOINT_IOP_AND_EE = 0x03
};
class DebugInterface
{
@ -51,6 +57,7 @@ public:
virtual std::string disasm(u32 address, bool simplify) = 0;
virtual bool isValidAddress(u32 address) = 0;
virtual u32 getCycles() = 0;
virtual BreakPointCpu getCpuType() = 0;
bool initExpression(const char* exp, PostfixExpression& dest);
bool parseExpression(PostfixExpression& exp, u64& dest);
@ -90,6 +97,7 @@ public:
virtual std::string disasm(u32 address, bool simplify);
virtual bool isValidAddress(u32 address);
virtual u32 getCycles();
virtual BreakPointCpu getCpuType();
};
@ -122,6 +130,7 @@ public:
virtual std::string disasm(u32 address, bool simplify);
virtual bool isValidAddress(u32 address);
virtual u32 getCycles();
virtual BreakPointCpu getCpuType();
};
extern R5900DebugInterface r5900Debug;

View File

@ -49,12 +49,12 @@ static void debugI()
void intBreakpoint(bool memcheck)
{
u32 pc = cpuRegs.pc;
if (CBreakPoints::CheckSkipFirst(pc) != 0)
if (CBreakPoints::CheckSkipFirst(BREAKPOINT_EE, pc) != 0)
return;
if (!memcheck)
{
auto cond = CBreakPoints::GetBreakPointCondition(pc);
auto cond = CBreakPoints::GetBreakPointCondition(BREAKPOINT_EE, pc);
if (cond && !cond->Evaluate())
return;
}
@ -73,7 +73,7 @@ void intMemcheck(u32 op, u32 bits, bool store)
if (bits == 128)
start &= ~0x0F;
start = standardizeBreakpointAddress(start);
start = standardizeBreakpointAddress(BREAKPOINT_EE, start);
u32 end = start + bits/8;
auto checks = CBreakPoints::GetMemChecks();
@ -81,6 +81,8 @@ void intMemcheck(u32 op, u32 bits, bool store)
{
auto& check = checks[i];
if (check.cpu != BREAKPOINT_EE)
continue;
if (check.result == 0)
continue;
if ((check.cond & MEMCHECK_WRITE) == 0 && store)

View File

@ -19,6 +19,8 @@
#include "Sio.h"
#include "Sif.h"
#include "../DebugTools/Breakpoints.h"
#include "R5900OpcodeTables.h"
using namespace R3000A;
@ -41,6 +43,8 @@ s32 iopBreak = 0;
// control is returned to the EE.
s32 iopCycleEE = -1;
bool iopBreakpoint = 0;
// Used to signal to the EE when important actions that need IOP-attention have
// happened (hsyncs, vsyncs, IOP exceptions, etc). IOP runs code whenever this
// is true, even if it's already running ahead a bit.
@ -247,3 +251,45 @@ void iopTestIntc()
psxSetNextBranchDelta( 2 );
}
inline bool psxIsBranchOrJump(u32 addr)
{
u32 op = iopMemRead32(addr);
const R5900::OPCODE& opcode = R5900::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
// 3 if needed in both
int psxIsBreakpointNeeded(u32 addr)
{
int bpFlags = 0;
if (CBreakPoints::IsAddressBreakPoint(BREAKPOINT_IOP, addr))
bpFlags += 1;
// there may be a breakpoint in the delay slot
if (psxIsBranchOrJump(addr) && CBreakPoints::IsAddressBreakPoint(BREAKPOINT_IOP, addr + 4))
bpFlags += 2;
return bpFlags;
}
int psxIsMemcheckNeeded(u32 pc)
{
if (CBreakPoints::GetNumMemchecks() == 0)
return 0;
u32 addr = pc;
if (psxIsBranchOrJump(addr))
addr += 4;
u32 op = iopMemRead32(addr);
const R5900::OPCODE& opcode = R5900::GetInstruction(op);
if (opcode.flags & IS_MEMORY)
return addr == pc ? 1 : 2;
return 0;
}

View File

@ -120,6 +120,7 @@ extern __aligned16 psxRegisters psxRegs;
extern u32 g_iopNextEventCycle;
extern s32 iopBreak; // used when the IOP execution is broken and control returned to the EE
extern s32 iopCycleEE; // tracks IOP's current sych status with the EE
extern bool iopBreakpoint;
#ifndef _PC_
@ -203,6 +204,9 @@ extern void __fastcall psxException(u32 code, u32 step);
extern void iopEventTest();
extern void psxMemReset();
int psxIsBreakpointNeeded(u32 addr);
int psxIsMemcheckNeeded(u32 pc);
// Subsets
extern void (*psxBSC[64])();
extern void (*psxSPC[64])();

View File

@ -771,11 +771,11 @@ inline bool isBranchOrJump(u32 addr)
int isBreakpointNeeded(u32 addr)
{
int bpFlags = 0;
if (CBreakPoints::IsAddressBreakPoint(addr))
if (CBreakPoints::IsAddressBreakPoint(BREAKPOINT_EE, addr))
bpFlags += 1;
// there may be a breakpoint in the delay slot
if (isBranchOrJump(addr) && CBreakPoints::IsAddressBreakPoint(addr+4))
if (isBranchOrJump(addr) && CBreakPoints::IsAddressBreakPoint(BREAKPOINT_EE, addr+4))
bpFlags += 2;
return bpFlags;

View File

@ -1147,7 +1147,8 @@ protected:
CoreThread.ResetQuick();
symbolMap.Clear();
CBreakPoints::SetSkipFirst(0);
CBreakPoints::SetSkipFirst(BREAKPOINT_EE, 0);
CBreakPoints::SetSkipFirst(BREAKPOINT_IOP, 0);
CDVDsys_SetFile(CDVD_SourceType::Iso, g_Conf->CurrentIso );
if( m_UseCDVDsrc )

View File

@ -325,10 +325,10 @@ void BreakpointWindow::addBreakpoint()
else if (enabled) result = MEMCHECK_BREAK;
else result = MEMCHECK_IGNORE;
CBreakPoints::AddMemCheck(address, address + size, (MemCheckCondition)cond, result);
CBreakPoints::AddMemCheck(cpu->getCpuType(), address, address + size, (MemCheckCondition)cond, result);
} else {
// add breakpoint
CBreakPoints::AddBreakPoint(address,false);
CBreakPoints::AddBreakPoint(cpu->getCpuType(), address,false);
if (condition[0] != 0)
{
@ -336,12 +336,12 @@ void BreakpointWindow::addBreakpoint()
cond.debug = cpu;
strcpy(cond.expressionString,condition);
cond.expression = compiledCondition;
CBreakPoints::ChangeBreakPointAddCond(address,cond);
CBreakPoints::ChangeBreakPointAddCond(cpu->getCpuType(), address,cond);
}
if (!enabled)
{
CBreakPoints::ChangeBreakPoint(address,false);
CBreakPoints::ChangeBreakPoint(cpu->getCpuType(), address,false);
}
}
}

View File

@ -525,7 +525,7 @@ void CtrlDisassemblyView::render(wxDC& dc)
// display address/symbol
bool enabled;
if (CBreakPoints::IsAddressBreakPoint(address,&enabled))
if (CBreakPoints::IsAddressBreakPoint(cpu->getCpuType(),address,&enabled))
{
if (enabled)
textColor = 0x0000FF;
@ -933,26 +933,26 @@ void CtrlDisassemblyView::scrollbarEvent(wxScrollWinEvent& evt)
void CtrlDisassemblyView::toggleBreakpoint(bool toggleEnabled)
{
bool enabled;
if (CBreakPoints::IsAddressBreakPoint(curAddress,&enabled))
if (CBreakPoints::IsAddressBreakPoint(cpu->getCpuType(), curAddress,&enabled))
{
if (!enabled)
{
// enable disabled breakpoints
CBreakPoints::ChangeBreakPoint(curAddress,true);
} else if (!toggleEnabled && CBreakPoints::GetBreakPointCondition(curAddress) != NULL)
CBreakPoints::ChangeBreakPoint(cpu->getCpuType(), curAddress,true);
} else if (!toggleEnabled && CBreakPoints::GetBreakPointCondition(cpu->getCpuType(), curAddress) != NULL)
{
// don't just delete a breakpoint with a custom condition
CBreakPoints::RemoveBreakPoint(curAddress);
CBreakPoints::RemoveBreakPoint(cpu->getCpuType(), curAddress);
} else if (toggleEnabled)
{
// disable breakpoint
CBreakPoints::ChangeBreakPoint(curAddress,false);
CBreakPoints::ChangeBreakPoint(cpu->getCpuType(), curAddress,false);
} else {
// otherwise just remove breakpoint
CBreakPoints::RemoveBreakPoint(curAddress);
CBreakPoints::RemoveBreakPoint(cpu->getCpuType(), curAddress);
}
} else {
CBreakPoints::AddBreakPoint(curAddress);
CBreakPoints::AddBreakPoint(cpu->getCpuType(), curAddress);
}
}
@ -1266,7 +1266,7 @@ void CtrlDisassemblyView::editBreakpoint()
BreakpointWindow win(this,cpu);
bool exists = false;
if (CBreakPoints::IsAddressBreakPoint(curAddress))
if (CBreakPoints::IsAddressBreakPoint(cpu->getCpuType(), curAddress))
{
auto breakpoints = CBreakPoints::GetBreakpoints();
for (size_t i = 0; i < breakpoints.size(); i++)
@ -1286,7 +1286,7 @@ void CtrlDisassemblyView::editBreakpoint()
if (win.ShowModal() == wxID_OK)
{
if (exists)
CBreakPoints::RemoveBreakPoint(curAddress);
CBreakPoints::RemoveBreakPoint(cpu->getCpuType(), curAddress);
win.addBreakpoint();
postEvent(debEVT_UPDATE,0);
}

View File

@ -189,10 +189,14 @@ BreakpointList::BreakpointList(wxWindow* parent, DebugInterface* _cpu, CtrlDisas
int BreakpointList::getRowCount()
{
int count = (int)CBreakPoints::GetMemChecks().size();
int count = 0;
for (size_t i = 0; i < CBreakPoints::GetMemChecks().size(); i++)
{
if (displayedMemChecks_[i].cpu == cpu->getCpuType()) count++;
}
for (size_t i = 0; i < CBreakPoints::GetBreakpoints().size(); i++)
{
if (!displayedBreakPoints_[i].temporary) count++;
if (!displayedBreakPoints_[i].temporary && displayedBreakPoints_[i].cpu == cpu->getCpuType()) count++;
}
return count;
@ -327,18 +331,21 @@ void BreakpointList::onKeyDown(int key)
int BreakpointList::getBreakpointIndex(int itemIndex, bool& isMemory) const
{
// memory breakpoints first
if (itemIndex < (int)displayedMemChecks_.size())
for (size_t i = 0; i < displayedMemChecks_.size(); i++)
{
isMemory = true;
return itemIndex;
if (displayedMemChecks_[i].cpu != cpu->getCpuType()) continue;
if (itemIndex == 0)
{
isMemory = true;
return (int)i;
}
itemIndex--;
}
itemIndex -= (int)displayedMemChecks_.size();
size_t i = 0;
while (i < displayedBreakPoints_.size())
{
if (displayedBreakPoints_[i].temporary)
if (displayedBreakPoints_[i].temporary || displayedBreakPoints_[i].cpu != cpu->getCpuType())
{
i++;
continue;
@ -379,7 +386,7 @@ void BreakpointList::editBreakpoint(int itemIndex)
win.loadFromMemcheck(mem);
if (win.ShowModal() == wxID_OK)
{
CBreakPoints::RemoveMemCheck(mem.start,mem.end);
CBreakPoints::RemoveMemCheck(cpu->getCpuType(), mem.start,mem.end);
win.addBreakpoint();
}
} else {
@ -387,7 +394,7 @@ void BreakpointList::editBreakpoint(int itemIndex)
win.loadFromBreakpoint(bp);
if (win.ShowModal() == wxID_OK)
{
CBreakPoints::RemoveBreakPoint(bp.addr);
CBreakPoints::RemoveBreakPoint(cpu->getCpuType(), bp.addr);
win.addBreakpoint();
}
}
@ -401,10 +408,10 @@ void BreakpointList::toggleEnabled(int itemIndex)
if (isMemory) {
MemCheck mcPrev = displayedMemChecks_[index];
CBreakPoints::ChangeMemCheck(mcPrev.start, mcPrev.end, mcPrev.cond, MemCheckResult(mcPrev.result ^ MEMCHECK_BREAK));
CBreakPoints::ChangeMemCheck(cpu->getCpuType(), mcPrev.start, mcPrev.end, mcPrev.cond, MemCheckResult(mcPrev.result ^ MEMCHECK_BREAK));
} else {
BreakPoint bpPrev = displayedBreakPoints_[index];
CBreakPoints::ChangeBreakPoint(bpPrev.addr, !bpPrev.enabled);
CBreakPoints::ChangeBreakPoint(cpu->getCpuType(), bpPrev.addr, !bpPrev.enabled);
}
}
@ -433,10 +440,10 @@ void BreakpointList::removeBreakpoint(int itemIndex)
if (isMemory)
{
auto mc = displayedMemChecks_[index];
CBreakPoints::RemoveMemCheck(mc.start, mc.end);
CBreakPoints::RemoveMemCheck(cpu->getCpuType(), mc.start, mc.end);
} else {
u32 address = displayedBreakPoints_[index].addr;
CBreakPoints::RemoveBreakPoint(address);
CBreakPoints::RemoveBreakPoint(displayedBreakPoints_[index].cpu, address);
}
}

View File

@ -309,7 +309,8 @@ void DisassemblyDialog::onBreakRunClicked(wxCommandEvent& evt)
if (r5900Debug.isCpuPaused())
{
// If the current PC is on a breakpoint, the user doesn't want to do nothing.
CBreakPoints::SetSkipFirst(r5900Debug.getPC());
CBreakPoints::SetSkipFirst(BREAKPOINT_EE, r5900Debug.getPC());
CBreakPoints::SetSkipFirst(BREAKPOINT_IOP, r3000Debug.getPC());
r5900Debug.resumeCpu();
} else {
r5900Debug.pauseCpu();
@ -361,19 +362,15 @@ void DisassemblyDialog::stepOver()
{
if (!r5900Debug.isAlive() || !r5900Debug.isCpuPaused() || currentCpu == NULL)
return;
// todo: breakpoints for iop
if (currentCpu != eeTab)
return;
DebugInterface *debug = currentCpu->getCpu();
CtrlDisassemblyView* disassembly = currentCpu->getDisassembly();
// If the current PC is on a breakpoint, the user doesn't want to do nothing.
CBreakPoints::SetSkipFirst(r5900Debug.getPC());
u32 currentPc = r5900Debug.getPC();
CBreakPoints::SetSkipFirst(debug->getCpuType(), debug->getPC());
u32 currentPc = debug->getPC();
MIPSAnalyst::MipsOpcodeInfo info = MIPSAnalyst::GetOpcodeInfo(&r5900Debug,r5900Debug.getPC());
MIPSAnalyst::MipsOpcodeInfo info = MIPSAnalyst::GetOpcodeInfo(debug,debug->getPC());
u32 breakpointAddress = currentPc+disassembly->getInstructionSizeAt(currentPc);
if (info.isBranch)
{
@ -400,7 +397,7 @@ void DisassemblyDialog::stepOver()
disassembly->scrollStepping(breakpointAddress);
}
CBreakPoints::AddBreakPoint(breakpointAddress,true);
CBreakPoints::AddBreakPoint(debug->getCpuType(), breakpointAddress,true);
r5900Debug.resumeCpu();
}
@ -410,17 +407,14 @@ void DisassemblyDialog::stepInto()
if (!r5900Debug.isAlive() || !r5900Debug.isCpuPaused() || currentCpu == NULL)
return;
// todo: breakpoints for iop
if (currentCpu != eeTab)
return;
DebugInterface *debug = currentCpu->getCpu();
CtrlDisassemblyView* disassembly = currentCpu->getDisassembly();
// If the current PC is on a breakpoint, the user doesn't want to do nothing.
CBreakPoints::SetSkipFirst(r5900Debug.getPC());
u32 currentPc = r5900Debug.getPC();
CBreakPoints::SetSkipFirst(debug->getCpuType(), debug->getPC());
u32 currentPc = debug->getPC();
MIPSAnalyst::MipsOpcodeInfo info = MIPSAnalyst::GetOpcodeInfo(&r5900Debug,r5900Debug.getPC());
MIPSAnalyst::MipsOpcodeInfo info = MIPSAnalyst::GetOpcodeInfo(debug,debug->getPC());
u32 breakpointAddress = currentPc+disassembly->getInstructionSizeAt(currentPc);
if (info.isBranch)
{
@ -441,7 +435,7 @@ void DisassemblyDialog::stepInto()
if (info.isSyscall)
breakpointAddress = info.branchTarget;
CBreakPoints::AddBreakPoint(breakpointAddress,true);
CBreakPoints::AddBreakPoint(debug->getCpuType(), breakpointAddress,true);
r5900Debug.resumeCpu();
}
@ -449,14 +443,15 @@ void DisassemblyDialog::stepOut()
{
if (!r5900Debug.isAlive() || !r5900Debug.isCpuPaused() || currentCpu == NULL)
return;
DebugInterface *debug = currentCpu->getCpu();
// If the current PC is on a breakpoint, the user doesn't want to do nothing.
CBreakPoints::SetSkipFirst(r5900Debug.getPC());
CBreakPoints::SetSkipFirst(debug->getCpuType(), debug->getPC());
u32 addr = currentCpu->getStepOutAddress();
if (addr == (u32)-1)
return;
CBreakPoints::AddBreakPoint(addr,true);
CBreakPoints::AddBreakPoint(debug->getCpuType(), addr,true);
r5900Debug.resumeCpu();
}
@ -505,10 +500,7 @@ void DisassemblyDialog::onDebuggerEvent(wxCommandEvent& evt)
}
} else if (type == debEVT_RUNTOPOS)
{
// todo: breakpoints for iop
if (currentCpu != eeTab)
return;
CBreakPoints::AddBreakPoint(evt.GetInt(),true);
CBreakPoints::AddBreakPoint(currentCpu->getCpu()->getCpuType(), evt.GetInt(),true);
currentCpu->getCpu()->resumeCpu();
} else if (type == debEVT_GOTOINDISASM)
{
@ -633,7 +625,8 @@ void DisassemblyDialog::setDebugMode(bool debugMode, bool switchPC)
if (currentCpu != NULL)
currentCpu->getDisassembly()->SetFocus();
CBreakPoints::SetBreakpointTriggered(false);
CBreakPoints::SetSkipFirst(0);
CBreakPoints::SetSkipFirst(BREAKPOINT_EE, 0);
CBreakPoints::SetSkipFirst(BREAKPOINT_IOP, 0);
}
if (currentCpu != NULL)

View File

@ -23,6 +23,8 @@
#include "iR3000A.h"
#include "BaseblockEx.h"
#include "System/RecTypes.h"
#include "System/SysThreads.h"
#include "R5900OpcodeTables.h"
#include <time.h>
@ -36,6 +38,7 @@
#include "AppConfig.h"
#include "Utilities/Perf.h"
#include "../DebugTools/Breakpoints.h"
using namespace x86Emitter;
@ -434,6 +437,11 @@ void _psxFlushCall(int flushtype)
_freeX86reg( ecx );
_freeX86reg( edx );
if ((flushtype & FLUSH_PC)/*&& !g_cpuFlushedPC*/) {
xMOV(ptr32[&psxRegs.pc], psxpc);
//g_cpuFlushedPC = true;
}
if( flushtype & FLUSH_CACHED_REGS )
_psxFlushConstRegs();
}
@ -1030,11 +1038,167 @@ void rpsxBREAK()
//if (!psxbranch) psxbranch = 2;
}
void psxDynarecCheckBreakpoint()
{
u32 pc = psxRegs.pc;
if (CBreakPoints::CheckSkipFirst(BREAKPOINT_IOP, pc) == pc)
return;
int bpFlags = psxIsBreakpointNeeded(pc);
bool hit = false;
//check breakpoint at current pc
if (bpFlags & 1) {
auto cond = CBreakPoints::GetBreakPointCondition(BREAKPOINT_IOP, pc);
if (cond == NULL || cond->Evaluate()) {
hit = true;
}
}
//check breakpoint in delay slot
if (bpFlags & 2) {
auto cond = CBreakPoints::GetBreakPointCondition(BREAKPOINT_IOP, pc + 4);
if (cond == NULL || cond->Evaluate())
hit = true;
}
if (!hit)
return;
CBreakPoints::SetBreakpointTriggered(true);
GetCoreThread().PauseSelfDebug();
iopBreakpoint = true;
}
void psxDynarecMemcheck()
{
u32 pc = psxRegs.pc;
if (CBreakPoints::CheckSkipFirst(BREAKPOINT_IOP, pc) == pc)
return;
CBreakPoints::SetBreakpointTriggered(true);
GetCoreThread().PauseSelfDebug();
iopBreakpoint = true;
}
void __fastcall psxDynarecMemLogcheck(u32 start, bool store)
{
if (store)
DevCon.WriteLn("Hit store breakpoint @0x%x", start);
else
DevCon.WriteLn("Hit load breakpoint @0x%x", start);
}
void psxRecMemcheck(u32 op, u32 bits, bool store)
{
_psxFlushCall(FLUSH_EVERYTHING | FLUSH_PC);
// compute accessed address
_psxMoveGPRtoR(ecx, (op >> 21) & 0x1F);
if ((s16)op != 0)
xADD(ecx, (s16)op);
if (bits == 128)
xAND(ecx, ~0x0F);
xFastCall((void*)standardizeBreakpointAddressIop, ecx);
xMOV(ecx, eax);
xMOV(edx, eax);
xADD(edx, bits / 8);
// ecx = access address
// edx = access address+size
auto checks = CBreakPoints::GetMemChecks();
for (size_t i = 0; i < checks.size(); i++)
{
if (checks[i].cpu != BREAKPOINT_IOP)
continue;
if (checks[i].result == 0)
continue;
if ((checks[i].cond & MEMCHECK_WRITE) == 0 && store)
continue;
if ((checks[i].cond & MEMCHECK_READ) == 0 && !store)
continue;
// logic: memAddress < bpEnd && bpStart < memAddress+memSize
xMOV(eax, standardizeBreakpointAddress(BREAKPOINT_IOP, checks[i].end));
xCMP(ecx, eax); // address < end
xForwardJGE8 next1; // if address >= end then goto next1
xMOV(eax, standardizeBreakpointAddress(BREAKPOINT_IOP, checks[i].start));
xCMP(eax, edx); // start < address+size
xForwardJGE8 next2; // if start >= address+size then goto next2
// hit the breakpoint
if (checks[i].result & MEMCHECK_LOG) {
xMOV(edx, store);
xFastCall((void*)psxDynarecMemLogcheck, ecx, edx);
}
if (checks[i].result & MEMCHECK_BREAK) {
xFastCall((void*)psxDynarecMemcheck);
}
next1.SetTarget();
next2.SetTarget();
}
// get out of here
xCMP(ptr8[&iopBreakpoint], 0);
xJNE(iopExitRecompiledCode);
}
void psxEncodeBreakpoint()
{
if (psxIsBreakpointNeeded(psxpc) != 0)
{
_psxFlushCall(FLUSH_EVERYTHING | FLUSH_PC);
xFastCall((void*)psxDynarecCheckBreakpoint);
// get out of here
xCMP(ptr8[&iopBreakpoint], 0);
xJNE(iopExitRecompiledCode);
}
}
void psxEncodeMemcheck()
{
int needed = psxIsMemcheckNeeded(psxpc);
if (needed == 0)
return;
u32 op = iopMemRead32(needed == 2 ? psxpc + 4 : psxpc);
const R5900::OPCODE& opcode = R5900::GetInstruction(op);
bool store = (opcode.flags & IS_STORE) != 0;
switch (opcode.flags & MEMTYPE_MASK)
{
case MEMTYPE_BYTE:
psxRecMemcheck(op, 8, store);
break;
case MEMTYPE_HALF:
psxRecMemcheck(op, 16, store);
break;
case MEMTYPE_WORD:
psxRecMemcheck(op, 32, store);
break;
case MEMTYPE_DWORD:
psxRecMemcheck(op, 64, store);
break;
case MEMTYPE_QWORD:
psxRecMemcheck(op, 128, store);
break;
}
}
void psxRecompileNextInstruction(int delayslot)
{
// pblock isn't used elsewhere in this function.
//BASEBLOCK* pblock = PSX_GETBLOCK(psxpc);
// add breakpoint
if (!delayslot)
{
psxEncodeBreakpoint();
psxEncodeMemcheck();
}
if( IsDebugBuild ) {
xNOP();
xMOV(eax, psxpc);

View File

@ -113,6 +113,7 @@ static u32 dumplog = 0;
static void iBranchTest(u32 newpc = 0xffffffff);
static void ClearRecLUT(BASEBLOCK* base, int count);
static u32 scaleblockcycles();
static void recExitExecution();
void _eeFlushAllUnused()
{
@ -336,6 +337,11 @@ static DynGenFunc* DispatchPageReset = NULL;
static void recEventTest()
{
_cpuEventTest_Shared();
if (iopBreakpoint) {
iopBreakpoint = false;
recExitExecution();
}
}
// The address for all cleared blocks. It recompiles the current pc and then
@ -1167,21 +1173,21 @@ int cop2flags(u32 code)
void dynarecCheckBreakpoint()
{
u32 pc = cpuRegs.pc;
if (CBreakPoints::CheckSkipFirst(pc) != 0)
if (CBreakPoints::CheckSkipFirst(BREAKPOINT_EE, pc) != 0)
return;
int bpFlags = isBreakpointNeeded(pc);
bool hit = false;
//check breakpoint at current pc
if (bpFlags & 1) {
auto cond = CBreakPoints::GetBreakPointCondition(pc);
auto cond = CBreakPoints::GetBreakPointCondition(BREAKPOINT_EE, pc);
if (cond == NULL || cond->Evaluate()) {
hit = true;
}
}
//check breakpoint in delay slot
if (bpFlags & 2) {
auto cond = CBreakPoints::GetBreakPointCondition(pc + 4);
auto cond = CBreakPoints::GetBreakPointCondition(BREAKPOINT_EE, pc + 4);
if (cond == NULL || cond->Evaluate())
hit = true;
}
@ -1197,7 +1203,7 @@ void dynarecCheckBreakpoint()
void dynarecMemcheck()
{
u32 pc = cpuRegs.pc;
if (CBreakPoints::CheckSkipFirst(pc) != 0)
if (CBreakPoints::CheckSkipFirst(BREAKPOINT_EE, pc) != 0)
return;
CBreakPoints::SetBreakpointTriggered(true);
@ -1224,7 +1230,7 @@ void recMemcheck(u32 op, u32 bits, bool store)
if (bits == 128)
xAND(ecx, ~0x0F);
xFastCall((void*)standardizeBreakpointAddress, ecx);
xFastCall((void*)standardizeBreakpointAddressEE, ecx);
xMOV(ecx,eax);
xMOV(edx,eax);
xADD(edx,bits/8);
@ -1235,6 +1241,8 @@ void recMemcheck(u32 op, u32 bits, bool store)
auto checks = CBreakPoints::GetMemChecks();
for (size_t i = 0; i < checks.size(); i++)
{
if (checks[i].cpu != BREAKPOINT_EE)
continue;
if (checks[i].result == 0)
continue;
if ((checks[i].cond & MEMCHECK_WRITE) == 0 && store)
@ -1244,11 +1252,11 @@ void recMemcheck(u32 op, u32 bits, bool store)
// logic: memAddress < bpEnd && bpStart < memAddress+memSize
xMOV(eax,standardizeBreakpointAddress(checks[i].end));
xMOV(eax,standardizeBreakpointAddress(BREAKPOINT_EE, checks[i].end));
xCMP(ecx,eax); // address < end
xForwardJGE8 next1; // if address >= end then goto next1
xMOV(eax,standardizeBreakpointAddress(checks[i].start));
xMOV(eax,standardizeBreakpointAddress(BREAKPOINT_EE, checks[i].start));
xCMP(eax,edx); // start < address+size
xForwardJGE8 next2; // if start >= address+size then goto next2