mirror of
https://github.com/SourMesen/Mesen2.git
synced 2025-04-02 10:21:44 -04:00
Debugger: Added "bring to front on pause" option
This commit is contained in:
parent
89a2a46392
commit
7b394aa686
22 changed files with 71 additions and 46 deletions
|
@ -290,6 +290,7 @@ enum class BreakSource
|
|||
{
|
||||
Unspecified = -1,
|
||||
Breakpoint = 0,
|
||||
Pause,
|
||||
CpuStep,
|
||||
PpuStep,
|
||||
BreakOnBrk,
|
||||
|
@ -374,10 +375,27 @@ struct StepRequest
|
|||
HasRequest = (StepCount != -1 || PpuStepCount != -1 || BreakAddress != -1 || BreakScanline != INT32_MIN || CpuCycleStepCount != -1);
|
||||
}
|
||||
|
||||
__forceinline void SetBreakSource(BreakSource source)
|
||||
{
|
||||
if(Source == BreakSource::Unspecified) {
|
||||
Source = source;
|
||||
}
|
||||
}
|
||||
|
||||
BreakSource GetBreakSource()
|
||||
{
|
||||
if(Source == BreakSource::Unspecified) {
|
||||
if(BreakScanline != INT32_MIN || PpuStepCount >= 0) {
|
||||
return BreakSource::PpuStep;
|
||||
}
|
||||
}
|
||||
return Source;
|
||||
}
|
||||
|
||||
__forceinline void Break(BreakSource src)
|
||||
{
|
||||
BreakNeeded = true;
|
||||
Source = src;
|
||||
SetBreakSource(src);
|
||||
}
|
||||
|
||||
__forceinline void ProcessCpuExec()
|
||||
|
@ -386,7 +404,7 @@ struct StepRequest
|
|||
StepCount--;
|
||||
if(StepCount == 0) {
|
||||
BreakNeeded = true;
|
||||
Source = BreakSource::CpuStep;
|
||||
SetBreakSource(BreakSource::CpuStep);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -397,7 +415,7 @@ struct StepRequest
|
|||
CpuCycleStepCount--;
|
||||
if(CpuCycleStepCount == 0) {
|
||||
BreakNeeded = true;
|
||||
Source = BreakSource::CpuStep;
|
||||
SetBreakSource(BreakSource::CpuStep);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -409,12 +427,12 @@ struct StepRequest
|
|||
if(forNmi) {
|
||||
if(Type == StepType::RunToNmi) {
|
||||
BreakNeeded = true;
|
||||
Source = BreakSource::Nmi;
|
||||
SetBreakSource(BreakSource::Nmi);
|
||||
}
|
||||
} else {
|
||||
if(Type == StepType::RunToIrq) {
|
||||
BreakNeeded = true;
|
||||
Source = BreakSource::Irq;
|
||||
SetBreakSource(BreakSource::Irq);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -481,13 +481,25 @@ void Debugger::Run()
|
|||
_waitForBreakResume = false;
|
||||
}
|
||||
|
||||
void Debugger::Step(CpuType cpuType, int32_t stepCount, StepType type)
|
||||
void Debugger::PauseOnNextFrame()
|
||||
{
|
||||
//Use BreakSource::PpuStep to prevent "Run single frame" from triggering the "bring to front on pause" feature
|
||||
switch(_mainCpuType) {
|
||||
case CpuType::Snes: Step(CpuType::Snes, 240, StepType::SpecificScanline, BreakSource::PpuStep); break;
|
||||
case CpuType::Gameboy: Step(CpuType::Gameboy, 144, StepType::SpecificScanline, BreakSource::PpuStep); break;
|
||||
case CpuType::Nes: Step(CpuType::Nes, 240, StepType::SpecificScanline, BreakSource::PpuStep); break;
|
||||
case CpuType::Pce: Step(CpuType::Pce, 243, StepType::SpecificScanline, BreakSource::PpuStep); break;
|
||||
}
|
||||
}
|
||||
|
||||
void Debugger::Step(CpuType cpuType, int32_t stepCount, StepType type, BreakSource source)
|
||||
{
|
||||
DebugBreakHelper helper(this);
|
||||
IDebugger* debugger = _debuggers[(int)cpuType].Debugger.get();
|
||||
|
||||
if(debugger) {
|
||||
debugger->Step(stepCount, type);
|
||||
debugger->GetStepRequest()->SetBreakSource(source);
|
||||
}
|
||||
|
||||
for(int i = 0; i <= (int)DebugUtilities::GetLastCpuType(); i++) {
|
||||
|
|
|
@ -119,7 +119,8 @@ public:
|
|||
int32_t EvaluateExpression(string expression, CpuType cpuType, EvalResultType &resultType, bool useCache);
|
||||
|
||||
void Run();
|
||||
void Step(CpuType cpuType, int32_t stepCount, StepType type);
|
||||
void PauseOnNextFrame();
|
||||
void Step(CpuType cpuType, int32_t stepCount, StepType type, BreakSource source = BreakSource::Unspecified);
|
||||
bool IsPaused();
|
||||
bool IsExecutionStopped();
|
||||
|
||||
|
|
|
@ -17,6 +17,9 @@ enum class MemoryOperationType;
|
|||
|
||||
class IDebugger
|
||||
{
|
||||
protected:
|
||||
unique_ptr<StepRequest> _step;
|
||||
|
||||
public:
|
||||
bool IgnoreBreakpoints = false;
|
||||
bool AllowChangeProgramCounter = false;
|
||||
|
@ -24,6 +27,8 @@ public:
|
|||
|
||||
virtual ~IDebugger() = default;
|
||||
|
||||
StepRequest* GetStepRequest() { return _step.get(); }
|
||||
|
||||
virtual void Step(int32_t stepCount, StepType type) = 0;
|
||||
virtual void Reset() = 0;
|
||||
virtual void Run() = 0;
|
||||
|
|
|
@ -309,11 +309,11 @@ void GbDebugger::ProcessPpuCycle()
|
|||
|
||||
if(_step->HasRequest) {
|
||||
if(_step->HasScanlineBreakRequest() && _ppu->GetCycle() == 0 && _ppu->GetScanline() == _step->BreakScanline) {
|
||||
_debugger->SleepUntilResume(CpuType::Gameboy, BreakSource::PpuStep);
|
||||
_debugger->SleepUntilResume(CpuType::Gameboy, _step->GetBreakSource());
|
||||
} else if(_step->PpuStepCount > 0) {
|
||||
_step->PpuStepCount--;
|
||||
if(_step->PpuStepCount == 0) {
|
||||
_debugger->SleepUntilResume(CpuType::Gameboy, BreakSource::PpuStep);
|
||||
_debugger->SleepUntilResume(CpuType::Gameboy, _step->GetBreakSource());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,7 +38,6 @@ class GbDebugger final : public IDebugger
|
|||
unique_ptr<CallstackManager> _callstackManager;
|
||||
unique_ptr<CodeDataLogger> _codeDataLogger;
|
||||
unique_ptr<BreakpointManager> _breakpointManager;
|
||||
unique_ptr<StepRequest> _step;
|
||||
unique_ptr<GbAssembler> _assembler;
|
||||
unique_ptr<GbTraceLogger> _traceLogger;
|
||||
unique_ptr<GbPpuTools> _ppuTools;
|
||||
|
|
|
@ -347,11 +347,11 @@ void NesDebugger::ProcessPpuCycle()
|
|||
|
||||
if(_step->HasRequest) {
|
||||
if(_step->HasScanlineBreakRequest() && _ppu->GetCurrentCycle() == 0 && _ppu->GetCurrentScanline() == _step->BreakScanline) {
|
||||
_debugger->SleepUntilResume(CpuType::Nes, BreakSource::PpuStep);
|
||||
_debugger->SleepUntilResume(CpuType::Nes, _step->GetBreakSource());
|
||||
} else if(_step->PpuStepCount > 0) {
|
||||
_step->PpuStepCount--;
|
||||
if(_step->PpuStepCount == 0) {
|
||||
_debugger->SleepUntilResume(CpuType::Nes, BreakSource::PpuStep);
|
||||
_debugger->SleepUntilResume(CpuType::Nes, _step->GetBreakSource());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,7 +47,6 @@ class NesDebugger final : public IDebugger
|
|||
unique_ptr<CallstackManager> _callstackManager;
|
||||
unique_ptr<BreakpointManager> _breakpointManager;
|
||||
unique_ptr<NesTraceLogger> _traceLogger;
|
||||
unique_ptr<StepRequest> _step;
|
||||
unique_ptr<NesPpuTools> _ppuTools;
|
||||
|
||||
bool _enableBreakOnUninitRead = false;
|
||||
|
|
|
@ -317,12 +317,12 @@ void PceDebugger::ProcessPpuCycle()
|
|||
|
||||
if(_step->HasRequest) {
|
||||
if(_step->HasScanlineBreakRequest() && _vdc->GetHClock() == 0 && _vdc->GetScanline() == _step->BreakScanline) {
|
||||
_debugger->SleepUntilResume(CpuType::Pce, BreakSource::PpuStep);
|
||||
_debugger->SleepUntilResume(CpuType::Pce, _step->GetBreakSource());
|
||||
} else if(_step->PpuStepCount > 0) {
|
||||
_step->PpuStepCount -= 3;
|
||||
if(_step->PpuStepCount <= 0) {
|
||||
_step->PpuStepCount = 0;
|
||||
_debugger->SleepUntilResume(CpuType::Pce, BreakSource::PpuStep);
|
||||
_debugger->SleepUntilResume(CpuType::Pce, _step->GetBreakSource());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,7 +48,6 @@ class PceDebugger final : public IDebugger
|
|||
unique_ptr<CallstackManager> _callstackManager;
|
||||
unique_ptr<BreakpointManager> _breakpointManager;
|
||||
unique_ptr<PceTraceLogger> _traceLogger;
|
||||
unique_ptr<StepRequest> _step;
|
||||
unique_ptr<PceVdcTools> _ppuTools;
|
||||
|
||||
bool _enableBreakOnUninitRead = false;
|
||||
|
|
|
@ -28,7 +28,6 @@ class Cx4Debugger final : public IDebugger
|
|||
|
||||
unique_ptr<BreakpointManager> _breakpointManager;
|
||||
unique_ptr<CallstackManager> _callstackManager;
|
||||
unique_ptr<StepRequest> _step;
|
||||
unique_ptr<Cx4TraceLogger> _traceLogger;
|
||||
|
||||
uint32_t _prevProgramCounter = 0;
|
||||
|
|
|
@ -26,7 +26,6 @@ class GsuDebugger final : public IDebugger
|
|||
EmuSettings* _settings;
|
||||
|
||||
unique_ptr<BreakpointManager> _breakpointManager;
|
||||
unique_ptr<StepRequest> _step;
|
||||
unique_ptr<GsuTraceLogger> _traceLogger;
|
||||
|
||||
uint8_t _prevOpCode = 0xFF;
|
||||
|
|
|
@ -23,7 +23,6 @@ class NecDspDebugger final : public IDebugger
|
|||
EmuSettings* _settings;
|
||||
|
||||
unique_ptr<BreakpointManager> _breakpointManager;
|
||||
unique_ptr<StepRequest> _step;
|
||||
unique_ptr<NecDspTraceLogger> _traceLogger;
|
||||
unique_ptr<CallstackManager> _callstackManager;
|
||||
|
||||
|
|
|
@ -377,11 +377,11 @@ void SnesDebugger::ProcessPpuCycle()
|
|||
|
||||
if(_step->HasRequest) {
|
||||
if(_step->HasScanlineBreakRequest() && _ppu->GetScanline() == _step->BreakScanline && _memoryManager->GetHClock() == 0) {
|
||||
_debugger->SleepUntilResume(CpuType::Snes, BreakSource::PpuStep);
|
||||
_debugger->SleepUntilResume(CpuType::Snes, _step->GetBreakSource());
|
||||
} else if(_step->PpuStepCount > 0) {
|
||||
_step->PpuStepCount--;
|
||||
if(_step->PpuStepCount == 0) {
|
||||
_debugger->SleepUntilResume(CpuType::Snes, BreakSource::PpuStep);
|
||||
_debugger->SleepUntilResume(CpuType::Snes, _step->GetBreakSource());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,7 +51,6 @@ class SnesDebugger final : public IDebugger
|
|||
unique_ptr<SnesAssembler> _assembler;
|
||||
unique_ptr<CallstackManager> _callstackManager;
|
||||
unique_ptr<BreakpointManager> _breakpointManager;
|
||||
unique_ptr<StepRequest> _step;
|
||||
unique_ptr<SnesCpuTraceLogger> _traceLogger;
|
||||
unique_ptr<SnesPpuTools> _ppuTools;
|
||||
unique_ptr<DummySnesCpu> _dummyCpu;
|
||||
|
|
|
@ -28,7 +28,6 @@ class SpcDebugger final : public IDebugger
|
|||
unique_ptr<CallstackManager> _callstackManager;
|
||||
unique_ptr<BreakpointManager> _breakpointManager;
|
||||
unique_ptr<SpcTraceLogger> _traceLogger;
|
||||
unique_ptr<StepRequest> _step;
|
||||
unique_ptr<DummySpc> _dummyCpu;
|
||||
|
||||
uint8_t _prevOpCode = 0xFF;
|
||||
|
|
|
@ -665,27 +665,10 @@ double Emulator::GetFrameDelay()
|
|||
|
||||
void Emulator::PauseOnNextFrame()
|
||||
{
|
||||
//Used by "Run single frame" shortcut
|
||||
shared_ptr<Debugger> debugger = _debugger.lock();
|
||||
if(debugger) {
|
||||
//TODO move this logic to console classes?
|
||||
switch(GetConsoleType()) {
|
||||
case ConsoleType::Snes:
|
||||
debugger->Step(CpuType::Snes, 240, StepType::SpecificScanline);
|
||||
break;
|
||||
|
||||
case ConsoleType::Gameboy:
|
||||
case ConsoleType::GameboyColor:
|
||||
debugger->Step(CpuType::Gameboy, 144, StepType::SpecificScanline);
|
||||
break;
|
||||
|
||||
case ConsoleType::Nes:
|
||||
debugger->Step(CpuType::Nes, 240, StepType::SpecificScanline);
|
||||
break;
|
||||
|
||||
case ConsoleType::PcEngine:
|
||||
debugger->Step(CpuType::Pce, 243, StepType::SpecificScanline);
|
||||
break;
|
||||
}
|
||||
debugger->PauseOnNextFrame();
|
||||
} else {
|
||||
_pauseOnNextFrame = true;
|
||||
_paused = false;
|
||||
|
@ -696,7 +679,7 @@ void Emulator::Pause()
|
|||
{
|
||||
shared_ptr<Debugger> debugger = _debugger.lock();
|
||||
if(debugger) {
|
||||
debugger->Step(GetCpuTypes()[0], 1, StepType::Step);
|
||||
debugger->Step(GetCpuTypes()[0], 1, StepType::Step, BreakSource::Pause);
|
||||
} else {
|
||||
_paused = true;
|
||||
}
|
||||
|
|
|
@ -49,6 +49,7 @@ namespace Mesen.Config
|
|||
[Reactive] public bool RefreshWhileRunning { get; set; } = false;
|
||||
|
||||
[Reactive] public bool BringToFrontOnBreak { get; set; } = true;
|
||||
[Reactive] public bool BringToFrontOnPause { get; set; } = false;
|
||||
|
||||
[Reactive] public CodeDisplayMode UnidentifiedBlockDisplay { get; set; } = CodeDisplayMode.Hide;
|
||||
[Reactive] public CodeDisplayMode VerifiedDataDisplay { get; set; } = CodeDisplayMode.Hide;
|
||||
|
|
|
@ -175,7 +175,12 @@
|
|||
IsChecked="{CompiledBinding Config.BringToFrontOnBreak}"
|
||||
Content="{l:Translate chkBringToFrontOnBreak}"
|
||||
/>
|
||||
|
||||
|
||||
<CheckBox
|
||||
IsChecked="{CompiledBinding Config.BringToFrontOnPause}"
|
||||
Content="{l:Translate chkBringToFrontOnPause}"
|
||||
/>
|
||||
|
||||
<CheckBox
|
||||
IsChecked="{CompiledBinding Config.RefreshWhileRunning}"
|
||||
Content="{l:Translate chkRefreshWhileRunning}"
|
||||
|
|
|
@ -135,8 +135,13 @@ namespace Mesen.Debugger.Windows
|
|||
BreakEvent evt = Marshal.PtrToStructure<BreakEvent>(e.Parameter);
|
||||
Dispatcher.UIThread.Post(() => {
|
||||
_model.UpdateDebugger(true, evt);
|
||||
if(!_suppressBringToFront && _model.Config.BringToFrontOnBreak && evt.SourceCpu == _model.CpuType && evt.Source != BreakSource.PpuStep) {
|
||||
Activate();
|
||||
if(!_suppressBringToFront) {
|
||||
bool isPause = evt.Source == BreakSource.Pause;
|
||||
if(isPause && _model.Config.BringToFrontOnPause && evt.SourceCpu == _model.CpuType) {
|
||||
Activate();
|
||||
} else if(!isPause && _model.Config.BringToFrontOnBreak && evt.SourceCpu == _model.CpuType && evt.Source != BreakSource.PpuStep) {
|
||||
Activate();
|
||||
}
|
||||
}
|
||||
_suppressBringToFront = false;
|
||||
});
|
||||
|
|
|
@ -1207,6 +1207,7 @@ namespace Mesen.Interop
|
|||
{
|
||||
Unspecified = -1,
|
||||
Breakpoint = 0,
|
||||
Pause,
|
||||
CpuStep,
|
||||
PpuStep,
|
||||
BreakOnBrk,
|
||||
|
|
|
@ -1073,6 +1073,7 @@
|
|||
|
||||
<Control ID="lblMiscSettings">Misc. settings</Control>
|
||||
<Control ID="chkBringToFrontOnBreak">Bring to front on break</Control>
|
||||
<Control ID="chkBringToFrontOnPause">Bring to front on pause</Control>
|
||||
<Control ID="chkRefreshWhileRunning">Refresh while running</Control>
|
||||
<Control ID="chkDrawPartialFrame">Draw partial frame</Control>
|
||||
<Control ID="chkUsePredictiveBreakpoints">Use predictive breakpoints</Control>
|
||||
|
@ -2424,6 +2425,7 @@
|
|||
<Value ID="CompactText">Text (Active only)</Value>
|
||||
</Enum>
|
||||
<Enum ID="BreakSource">
|
||||
<Value ID="Pause">Pause</Value>
|
||||
<Value ID="Breakpoint">Breakpoint</Value>
|
||||
<Value ID="CpuStep">CPU Step</Value>
|
||||
<Value ID="PpuStep">PPU Step</Value>
|
||||
|
|
Loading…
Add table
Reference in a new issue