diff --git a/Core/Debugger/DebugTypes.h b/Core/Debugger/DebugTypes.h index ec480394..604427ef 100644 --- a/Core/Debugger/DebugTypes.h +++ b/Core/Debugger/DebugTypes.h @@ -302,17 +302,19 @@ enum class BreakSource CpuStep, PpuStep, + Irq, + Nmi, + //Used by DebugBreakHelper, prevents debugger getting focus InternalOperation, + //Everything after InternalOperation is treated as an "Exception" + //Forbid breakpoints can block these, but not the other types above BreakOnBrk, BreakOnCop, BreakOnWdm, BreakOnStp, BreakOnUninitMemoryRead, - - Irq, - Nmi, GbInvalidOamAccess, GbInvalidVramAccess, @@ -363,6 +365,14 @@ enum class StepType StepBack }; +enum class BreakType +{ + None = 0, + User = 1, + Exception = 2, + Both = 3 +}; + struct StepRequest { int64_t BreakAddress = -1; @@ -374,8 +384,9 @@ struct StepRequest bool HasRequest = false; - bool BreakNeeded = false; + BreakType BreakNeeded = BreakType::None; BreakSource Source = BreakSource::Unspecified; + BreakSource ExSource = BreakSource::Unspecified; StepRequest() { @@ -397,27 +408,61 @@ struct StepRequest HasRequest = (StepCount != -1 || PpuStepCount != -1 || BreakAddress != -1 || BreakScanline != INT32_MIN || CpuCycleStepCount != -1); } - __forceinline void SetBreakSource(BreakSource source) + void ClearException() { - if(Source == BreakSource::Unspecified) { - Source = source; + ExSource = BreakSource::Unspecified; + ClearBreakType(BreakType::Exception); + } + + __forceinline void SetBreakSource(BreakSource source, bool breakNeeded) + { + if(source > BreakSource::InternalOperation) { + if(ExSource == BreakSource::Unspecified) { + ExSource = source; + } + + if(breakNeeded) { + SetBreakType(BreakType::Exception); + } + } else { + if(Source == BreakSource::Unspecified) { + Source = source; + } + + if(breakNeeded) { + SetBreakType(BreakType::User); + } } } BreakSource GetBreakSource() { + if(ExSource != BreakSource::Unspecified) { + return ExSource; + } + if(Source == BreakSource::Unspecified) { if(BreakScanline != INT32_MIN || PpuStepCount >= 0) { return BreakSource::PpuStep; } } + return Source; } + __forceinline void SetBreakType(BreakType type) + { + BreakNeeded = (BreakType)((int)BreakNeeded | (int)type); + } + + __forceinline void ClearBreakType(BreakType type) + { + BreakNeeded = (BreakType)((int)BreakNeeded & ~(int)type); + } + __forceinline void Break(BreakSource src) { - BreakNeeded = true; - SetBreakSource(src); + SetBreakSource(src, true); } __forceinline void ProcessCpuExec() @@ -425,8 +470,7 @@ struct StepRequest if(StepCount > 0) { StepCount--; if(StepCount == 0) { - BreakNeeded = true; - SetBreakSource(BreakSource::CpuStep); + SetBreakSource(BreakSource::CpuStep, true); } } } @@ -436,8 +480,7 @@ struct StepRequest if(CpuCycleStepCount > 0) { CpuCycleStepCount--; if(CpuCycleStepCount == 0) { - BreakNeeded = true; - SetBreakSource(BreakSource::CpuStep); + SetBreakSource(BreakSource::CpuStep, true); return true; } } @@ -448,13 +491,11 @@ struct StepRequest { if(forNmi) { if(Type == StepType::RunToNmi) { - BreakNeeded = true; - SetBreakSource(BreakSource::Nmi); + SetBreakSource(BreakSource::Nmi, true); } } else { if(Type == StepType::RunToIrq) { - BreakNeeded = true; - SetBreakSource(BreakSource::Irq); + SetBreakSource(BreakSource::Irq, true); } } } diff --git a/Core/Debugger/Debugger.cpp b/Core/Debugger/Debugger.cpp index 5aa79a88..b787f732 100644 --- a/Core/Debugger/Debugger.cpp +++ b/Core/Debugger/Debugger.cpp @@ -368,7 +368,7 @@ void Debugger::ProcessHaltedCpu() //Process cpu step requests as if each call to ProcessHaltedCpu is an instruction StepRequest* req = dbg->GetStepRequest(); req->ProcessCpuExec(); - if(req->BreakNeeded) { + if((int)req->BreakNeeded) { SleepUntilResume(type, req->GetBreakSource()); } else { //Also check if a debugger break request is pending @@ -457,7 +457,7 @@ void Debugger::SleepUntilResume(CpuType sourceCpu, BreakSource source, MemoryOpe //If SleepUntilResume was called outside of ProcessInstruction, keep running return; } else if(IsBreakpointForbidden(source, sourceCpu, operation)) { - ClearPendingBreakRequests(); + ClearPendingBreakExceptions(); return; } @@ -503,7 +503,7 @@ void Debugger::SleepUntilResume(CpuType sourceCpu, BreakSource source, MemoryOpe bool Debugger::IsBreakpointForbidden(BreakSource source, CpuType sourceCpu, MemoryOperationInfo* operation) { - if(source != BreakSource::Unspecified && source != BreakSource::CpuStep && source != BreakSource::PpuStep && source != BreakSource::Pause && _breakRequestCount == 0) { + if((source > BreakSource::InternalOperation || source == BreakSource::Breakpoint) && _breakRequestCount == 0) { BreakpointManager* bp = _debuggers[(int)sourceCpu].Debugger->GetBreakpointManager(); uint32_t pc = GetProgramCounter(sourceCpu, true); AddressInfo relAddr = { (int32_t)pc, DebugUtilities::GetCpuMemoryType(sourceCpu) }; @@ -518,8 +518,8 @@ template void Debugger::ProcessBreakConditions(CpuType sourceCpu, StepRequest& step, BreakpointManager* bpManager, MemoryOperationInfo& operation, AddressInfo& addressInfo) { int breakpointId = bpManager->CheckBreakpoint(operation, addressInfo, true); - if(_breakRequestCount || _waitForBreakResume || (step.BreakNeeded && (!_debuggers[(int)sourceCpu].Debugger->IgnoreBreakpoints || step.Type == StepType::CpuCycleStep))) { - SleepUntilResume(sourceCpu, step.Source); + if(_breakRequestCount || _waitForBreakResume || ((int)step.BreakNeeded && (!_debuggers[(int)sourceCpu].Debugger->IgnoreBreakpoints || step.Type == StepType::CpuCycleStep))) { + SleepUntilResume(sourceCpu, step.GetBreakSource()); } else { if(breakpointId >= 0 && !_debuggers[(int)sourceCpu].Debugger->IgnoreBreakpoints) { SleepUntilResume(sourceCpu, BreakSource::Breakpoint, &operation, breakpointId); @@ -656,11 +656,11 @@ void Debugger::Run() _waitForBreakResume = false; } -void Debugger::ClearPendingBreakRequests() +void Debugger::ClearPendingBreakExceptions() { for(int i = 0; i <= (int)DebugUtilities::GetLastCpuType(); i++) { if(_debuggers[i].Debugger) { - _debuggers[i].Debugger->Run(); + _debuggers[i].Debugger->GetStepRequest()->ClearException(); } } } @@ -692,7 +692,7 @@ void Debugger::Step(CpuType cpuType, int32_t stepCount, StepType type, BreakSour } debugger->Step(stepCount, type); - debugger->GetStepRequest()->SetBreakSource(source); + debugger->GetStepRequest()->SetBreakSource(source, false); } for(int i = 0; i <= (int)DebugUtilities::GetLastCpuType(); i++) { diff --git a/Core/Debugger/Debugger.h b/Core/Debugger/Debugger.h index 112b9dd7..b38d2e94 100644 --- a/Core/Debugger/Debugger.h +++ b/Core/Debugger/Debugger.h @@ -99,7 +99,7 @@ private: bool IsBreakOptionEnabled(BreakSource src); template void SleepOnBreakRequest(); - void ClearPendingBreakRequests(); + void ClearPendingBreakExceptions(); bool IsBreakpointForbidden(BreakSource source, CpuType sourceCpu, MemoryOperationInfo* operation); diff --git a/UI/Interop/DebugApi.cs b/UI/Interop/DebugApi.cs index e23dfc94..0466bb7d 100644 --- a/UI/Interop/DebugApi.cs +++ b/UI/Interop/DebugApi.cs @@ -1529,6 +1529,8 @@ namespace Mesen.Interop Pause, CpuStep, PpuStep, + Irq, + Nmi, InternalOperation, BreakOnBrk, @@ -1537,9 +1539,6 @@ namespace Mesen.Interop BreakOnStp, BreakOnUninitMemoryRead, - Irq, - Nmi, - GbInvalidOamAccess, GbInvalidVramAccess, GbDisableLcdOutsideVblank,