From 4e77e6caef68480a58c6ef2a420c3586e069d6f6 Mon Sep 17 00:00:00 2001 From: Sour Date: Sun, 7 Jun 2020 16:34:23 -0400 Subject: [PATCH] Debugger: GB - Added GB-specific "break on" options --- Core/Console.cpp | 7 +++ Core/Console.h | 1 + Core/DebugTypes.h | 9 ++- Core/Debugger.cpp | 12 ++++ Core/Debugger.h | 2 + Core/GbDebugger.cpp | 19 ++++++ Core/GbMemoryManager.cpp | 12 ++++ Core/GbMemoryManager.h | 1 + Core/GbPpu.cpp | 93 +++++++++++++++++++--------- Core/GbPpu.h | 6 ++ Core/SettingTypes.h | 7 +++ UI/Debugger/Config/DebuggerInfo.cs | 14 +++++ UI/Debugger/frmDebugger.Designer.cs | 95 +++++++++++++++++++++++++---- UI/Debugger/frmDebugger.cs | 23 +++++++ UI/Dependencies/resources.en.xml | 6 ++ UI/Interop/ConfigApi.cs | 7 +++ UI/Interop/DebugApi.cs | 9 ++- 17 files changed, 280 insertions(+), 43 deletions(-) diff --git a/Core/Console.cpp b/Core/Console.cpp index 3501cb2..6141b8f 100644 --- a/Core/Console.cpp +++ b/Core/Console.cpp @@ -957,6 +957,13 @@ void Console::ProcessEvent(EventType type) } } +void Console::BreakImmediately(BreakSource source) +{ + if(_debugger) { + _debugger->BreakImmediately(source); + } +} + template void Console::ProcessMemoryRead(uint32_t addr, uint8_t value, MemoryOperationType opType); template void Console::ProcessMemoryRead(uint32_t addr, uint8_t value, MemoryOperationType opType); template void Console::ProcessMemoryRead(uint32_t addr, uint8_t value, MemoryOperationType opType); diff --git a/Core/Console.h b/Core/Console.h index ddafeeb..2a11bc9 100644 --- a/Core/Console.h +++ b/Core/Console.h @@ -181,4 +181,5 @@ public: void ProcessPpuCycle(uint16_t scanline, uint16_t cycle); template void ProcessInterrupt(uint32_t originalPc, uint32_t currentPc, bool forNmi); void ProcessEvent(EventType type); + void BreakImmediately(BreakSource source); }; diff --git a/Core/DebugTypes.h b/Core/DebugTypes.h index a36f361..5666ae6 100644 --- a/Core/DebugTypes.h +++ b/Core/DebugTypes.h @@ -230,7 +230,14 @@ enum class BreakSource BreakOnCop = 4, BreakOnWdm = 5, BreakOnStp = 6, - BreakOnUninitMemoryRead = 7 + BreakOnUninitMemoryRead = 7, + + GbInvalidOamAccess = 8, + GbInvalidVramAccess = 9, + GbDisableLcdOutsideVblank = 10, + GbInvalidOpCode = 11, + GbNopLoad = 12, + GbOamCorruption = 13, }; struct BreakEvent diff --git a/Core/Debugger.cpp b/Core/Debugger.cpp index b4484fb..83655ed 100644 --- a/Core/Debugger.cpp +++ b/Core/Debugger.cpp @@ -434,6 +434,18 @@ void Debugger::SuspendDebugger(bool release) } } +void Debugger::BreakImmediately(BreakSource source) +{ + if(source == BreakSource::GbDisableLcdOutsideVblank && !_settings->CheckDebuggerFlag(DebuggerFlags::GbBreakOnDisableLcdOutsideVblank)) { + return; + } else if(source == BreakSource::GbInvalidVramAccess && !_settings->CheckDebuggerFlag(DebuggerFlags::GbBreakOnInvalidVramAccess)) { + return; + } else if(source == BreakSource::GbInvalidOamAccess && !_settings->CheckDebuggerFlag(DebuggerFlags::GbBreakOnInvalidOamAccess)) { + return; + } + SleepUntilResume(source); +} + void Debugger::GetState(DebugState &state, bool partialPpuState) { state.MasterClock = _memoryManager->GetMasterClock(); diff --git a/Core/Debugger.h b/Core/Debugger.h index 71bc1af..5d61d09 100644 --- a/Core/Debugger.h +++ b/Core/Debugger.h @@ -116,6 +116,8 @@ public: void BreakRequest(bool release); void SuspendDebugger(bool release); + void BreakImmediately(BreakSource source); + void ProcessBreakConditions(bool needBreak, BreakpointManager *bpManager, MemoryOperationInfo &operation, AddressInfo &addressInfo, BreakSource source = BreakSource::Unspecified); void GetState(DebugState &state, bool partialPpuState); diff --git a/Core/GbDebugger.cpp b/Core/GbDebugger.cpp index 4c363ca..1cb2768 100644 --- a/Core/GbDebugger.cpp +++ b/Core/GbDebugger.cpp @@ -95,6 +95,25 @@ void GbDebugger::ProcessRead(uint16_t addr, uint8_t value, MemoryOperationType t _step->StepCount = 0; } + if(_settings->CheckDebuggerFlag(DebuggerFlags::GbDebuggerEnabled)) { + bool needBreak = false; + switch(value) { + case 0x40: + needBreak = _settings->CheckDebuggerFlag(DebuggerFlags::GbBreakOnNopLoad); + breakSource = BreakSource::GbNopLoad; + break; + + case 0xD3: case 0xDB: case 0xDD: case 0xE3: case 0xE4: case 0xE8: case 0xEC: case 0xED: case 0xF4: case 0xFC: case 0xFD: + needBreak = _settings->CheckDebuggerFlag(DebuggerFlags::GbBreakOnInvalidOpCode); + breakSource = BreakSource::GbInvalidOpCode; + break; + } + + if(needBreak) { + _step->StepCount = 0; + } + } + _prevOpCode = value; _prevProgramCounter = gbState.PC; diff --git a/Core/GbMemoryManager.cpp b/Core/GbMemoryManager.cpp index 63d232f..8046a69 100644 --- a/Core/GbMemoryManager.cpp +++ b/Core/GbMemoryManager.cpp @@ -218,6 +218,18 @@ uint8_t* GbMemoryManager::GetMappedBlock(uint16_t addr) return nullptr; } +uint8_t GbMemoryManager::PeekRegister(uint16_t addr) +{ + //Peek on oam/vram to avoid triggering the invalid oam/vram access break options + if(addr >= 0xFE00 && addr <= 0xFE9F) { + return _ppu->PeekOam((uint8_t)addr); + } else if(addr >= 0x8000 && addr <= 0x9FFF) { + return _ppu->PeekVram(addr); + } else { + ReadRegister(addr); + } +} + uint8_t GbMemoryManager::ReadRegister(uint16_t addr) { if(addr >= 0xFF00) { diff --git a/Core/GbMemoryManager.h b/Core/GbMemoryManager.h index 2fdf493..9942596 100644 --- a/Core/GbMemoryManager.h +++ b/Core/GbMemoryManager.h @@ -60,6 +60,7 @@ public: template void Write(uint16_t addr, uint8_t value); + uint8_t PeekRegister(uint16_t addr); uint8_t ReadRegister(uint16_t addr); void WriteRegister(uint16_t addr, uint8_t value); diff --git a/Core/GbPpu.cpp b/Core/GbPpu.cpp index a6cda23..3bee098 100644 --- a/Core/GbPpu.cpp +++ b/Core/GbPpu.cpp @@ -677,6 +677,10 @@ void GbPpu::Write(uint16_t addr, uint8_t value) if(!_state.LcdEnabled) { //Reset LCD to top of screen when it gets turned off + if(_state.Mode != PpuMode::VBlank) { + _console->BreakImmediately(BreakSource::GbDisableLcdOutsideVblank); + } + _state.Cycle = 0; _state.Scanline = 0; _state.Ly = 0; @@ -752,41 +756,82 @@ void GbPpu::Write(uint16_t addr, uint8_t value) } } +bool GbPpu::IsVramReadAllowed() +{ + return _state.Mode <= PpuMode::VBlank || (_state.Mode == PpuMode::OamEvaluation && _state.Cycle < 80); +} + +bool GbPpu::IsVramWriteAllowed() +{ + return _state.Mode <= PpuMode::OamEvaluation; +} + uint8_t GbPpu::ReadVram(uint16_t addr) { - if(_state.Mode <= PpuMode::VBlank || (_state.Mode == PpuMode::OamEvaluation && _state.Cycle < 80)) { + if(IsVramReadAllowed()) { return _vram[(_state.CgbVramBank << 13) | (addr & 0x1FFF)]; } else { + _console->BreakImmediately(BreakSource::GbInvalidVramAccess); return 0xFF; } } +uint8_t GbPpu::PeekVram(uint8_t addr) +{ + return IsVramReadAllowed() ? _vram[(_state.CgbVramBank << 13) | (addr & 0x1FFF)] : 0xFF; +} + void GbPpu::WriteVram(uint16_t addr, uint8_t value) { - if(_state.Mode <= PpuMode::OamEvaluation) { + if(IsVramWriteAllowed()) { _vram[(_state.CgbVramBank << 13) | (addr & 0x1FFF)] = value; + } else { + _console->BreakImmediately(BreakSource::GbInvalidVramAccess); } } +bool GbPpu::IsOamWriteAllowed() +{ + if(_memoryManager->IsOamDmaRunning()) { + return false; + } + + if(_state.Scanline == 0 && _isFirstFrame) { + return _state.Mode == PpuMode::HBlank && _state.Cycle != 77 && _state.Cycle != 78; + } else { + return _state.Mode <= PpuMode::VBlank || (_state.Cycle >= 80 && _state.Cycle < 84); + } +} + +bool GbPpu::IsOamReadAllowed() +{ + if(_memoryManager->IsOamDmaRunning()) { + return false; + } + + if(_state.Scanline == 0 && _isFirstFrame) { + return _state.Mode == PpuMode::HBlank; + } else { + return _state.Mode == PpuMode::VBlank || (_state.Mode == PpuMode::HBlank && _state.Cycle != 3); + } +} + +uint8_t GbPpu::PeekOam(uint8_t addr) +{ + if(addr < 0xA0) { + return IsOamReadAllowed() ? _oam[addr] : 0xFF; + } + return 0; +} + uint8_t GbPpu::ReadOam(uint8_t addr) { if(addr < 0xA0) { - if(_memoryManager->IsOamDmaRunning()) { - return 0xFF; - } - - if(_state.Scanline == 0 && _isFirstFrame) { - if(_state.Mode == PpuMode::HBlank) { - return _oam[addr]; - } else { - return 0xFF; - } + if(IsOamReadAllowed()) { + return _oam[addr]; } else { - if(_state.Mode == PpuMode::VBlank || (_state.Mode == PpuMode::HBlank && _state.Cycle != 3)) { - return _oam[addr]; - } else { - return 0xFF; - } + _console->BreakImmediately(BreakSource::GbInvalidOamAccess); + return 0xFF; } } return 0; @@ -800,18 +845,10 @@ void GbPpu::WriteOam(uint8_t addr, uint8_t value, bool forDma) if(addr < 0xA0) { if(forDma) { _oam[addr] = value; - } else if(_memoryManager->IsOamDmaRunning()) { - return; - } - - if(_state.Scanline == 0 && _isFirstFrame) { - if(_state.Mode == PpuMode::HBlank && _state.Cycle != 77 && _state.Cycle != 78) { - _oam[addr] = value; - } + } else if(IsOamWriteAllowed()) { + _oam[addr] = value; } else { - if(_state.Mode <= PpuMode::VBlank || (_state.Cycle >= 80 && _state.Cycle < 84)) { - _oam[addr] = value; - } + _console->BreakImmediately(BreakSource::GbInvalidOamAccess); } } } diff --git a/Core/GbPpu.h b/Core/GbPpu.h index 258629f..b789a46 100644 --- a/Core/GbPpu.h +++ b/Core/GbPpu.h @@ -90,10 +90,16 @@ public: uint8_t Read(uint16_t addr); void Write(uint16_t addr, uint8_t value); + bool IsVramReadAllowed(); + bool IsVramWriteAllowed(); uint8_t ReadVram(uint16_t addr); + uint8_t PeekVram(uint8_t addr); void WriteVram(uint16_t addr, uint8_t value); + bool IsOamReadAllowed(); + bool IsOamWriteAllowed(); uint8_t ReadOam(uint8_t addr); + uint8_t PeekOam(uint8_t addr); void WriteOam(uint8_t addr, uint8_t value, bool forDma); uint8_t ReadCgbRegister(uint16_t addr); diff --git a/Core/SettingTypes.h b/Core/SettingTypes.h index 9a3c19b..9f855ca 100644 --- a/Core/SettingTypes.h +++ b/Core/SettingTypes.h @@ -504,6 +504,13 @@ enum class DebuggerFlags : uint32_t AutoResetCdl = 0x4000, + GbBreakOnInvalidOamAccess = 0x10000, + GbBreakOnInvalidVramAccess = 0x20000, + GbBreakOnDisableLcdOutsideVblank = 0x40000, + GbBreakOnInvalidOpCode = 0x80000, + GbBreakOnNopLoad = 0x100000, + GbBreakOnOamCorruption = 0x200000, + GbDebuggerEnabled = 0x02000000, Cx4DebuggerEnabled = 0x04000000, NecDspDebuggerEnabled = 0x08000000, diff --git a/UI/Debugger/Config/DebuggerInfo.cs b/UI/Debugger/Config/DebuggerInfo.cs index 94345a6..585f51a 100644 --- a/UI/Debugger/Config/DebuggerInfo.cs +++ b/UI/Debugger/Config/DebuggerInfo.cs @@ -25,6 +25,13 @@ namespace Mesen.GUI.Config public bool BreakOnStp = false; public bool BreakOnUninitRead = false; + public bool GbBreakOnInvalidOamAccess = false; + public bool GbBreakOnInvalidVramAccess = false; + public bool GbBreakOnDisableLcdOutsideVblank = false; + public bool GbBreakOnInvalidOpCode = false; + public bool GbBreakOnNopLoad = false; + public bool GbBreakOnOamCorruption = false; + public bool BreakOnOpen = true; public bool BreakOnPowerCycleReset = true; @@ -78,6 +85,13 @@ namespace Mesen.GUI.Config ConfigApi.SetDebuggerFlag(DebuggerFlags.BreakOnStp, BreakOnStp); ConfigApi.SetDebuggerFlag(DebuggerFlags.BreakOnUninitRead, BreakOnUninitRead); + ConfigApi.SetDebuggerFlag(DebuggerFlags.GbBreakOnInvalidOamAccess, GbBreakOnInvalidOamAccess); + ConfigApi.SetDebuggerFlag(DebuggerFlags.GbBreakOnInvalidVramAccess, GbBreakOnInvalidVramAccess); + ConfigApi.SetDebuggerFlag(DebuggerFlags.GbBreakOnDisableLcdOutsideVblank, GbBreakOnDisableLcdOutsideVblank); + ConfigApi.SetDebuggerFlag(DebuggerFlags.GbBreakOnInvalidOpCode, GbBreakOnInvalidOpCode); + ConfigApi.SetDebuggerFlag(DebuggerFlags.GbBreakOnNopLoad, GbBreakOnNopLoad); + ConfigApi.SetDebuggerFlag(DebuggerFlags.GbBreakOnOamCorruption, GbBreakOnOamCorruption); + ConfigApi.SetDebuggerFlag(DebuggerFlags.ShowUnidentifiedData, UnidentifiedBlockDisplay == CodeDisplayMode.Show); ConfigApi.SetDebuggerFlag(DebuggerFlags.DisassembleUnidentifiedData, UnidentifiedBlockDisplay == CodeDisplayMode.Disassemble); ConfigApi.SetDebuggerFlag(DebuggerFlags.ShowVerifiedData, VerifiedDataDisplay == CodeDisplayMode.Show); diff --git a/UI/Debugger/frmDebugger.Designer.cs b/UI/Debugger/frmDebugger.Designer.cs index bcd0b2c..9e47b8a 100644 --- a/UI/Debugger/frmDebugger.Designer.cs +++ b/UI/Debugger/frmDebugger.Designer.cs @@ -120,6 +120,13 @@ this.toolStripMenuItem10 = new System.Windows.Forms.ToolStripSeparator(); this.mnuBringToFrontOnBreak = new System.Windows.Forms.ToolStripMenuItem(); this.mnuBringToFrontOnPause = new System.Windows.Forms.ToolStripMenuItem(); + this.sepGameboyBreak = new System.Windows.Forms.ToolStripSeparator(); + this.mnuGbBreakOnOamCorruption = new System.Windows.Forms.ToolStripMenuItem(); + this.mnuGbBreakOnInvalidOamAccess = new System.Windows.Forms.ToolStripMenuItem(); + this.mnuGbBreakOnInvalidVramAccess = new System.Windows.Forms.ToolStripMenuItem(); + this.mnuGbBreakOnDisableLcdOutsideVblank = new System.Windows.Forms.ToolStripMenuItem(); + this.mnuGbBreakOnInvalidOpCode = new System.Windows.Forms.ToolStripMenuItem(); + this.mnuGbBreakOnNopLoad = new System.Windows.Forms.ToolStripMenuItem(); this.toolStripMenuItem5 = new System.Windows.Forms.ToolStripSeparator(); this.mnuFontOptions = new System.Windows.Forms.ToolStripMenuItem(); this.mnuIncreaseFontSize = new System.Windows.Forms.ToolStripMenuItem(); @@ -758,7 +765,14 @@ this.mnuBreakOnUnitRead, this.toolStripMenuItem10, this.mnuBringToFrontOnBreak, - this.mnuBringToFrontOnPause}); + this.mnuBringToFrontOnPause, + this.sepGameboyBreak, + this.mnuGbBreakOnOamCorruption, + this.mnuGbBreakOnInvalidOamAccess, + this.mnuGbBreakOnInvalidVramAccess, + this.mnuGbBreakOnDisableLcdOutsideVblank, + this.mnuGbBreakOnInvalidOpCode, + this.mnuGbBreakOnNopLoad}); this.mnuBreakOptions.Name = "mnuBreakOptions"; this.mnuBreakOptions.Size = new System.Drawing.Size(209, 22); this.mnuBreakOptions.Text = "Break Options"; @@ -767,73 +781,121 @@ // mnuBreakOnPowerCycleReset // this.mnuBreakOnPowerCycleReset.Name = "mnuBreakOnPowerCycleReset"; - this.mnuBreakOnPowerCycleReset.Size = new System.Drawing.Size(261, 22); + this.mnuBreakOnPowerCycleReset.Size = new System.Drawing.Size(265, 22); this.mnuBreakOnPowerCycleReset.Text = "Break on power/reset"; // // mnuBreakOnOpen // this.mnuBreakOnOpen.Name = "mnuBreakOnOpen"; - this.mnuBreakOnOpen.Size = new System.Drawing.Size(261, 22); + this.mnuBreakOnOpen.Size = new System.Drawing.Size(265, 22); this.mnuBreakOnOpen.Text = "Break when debugger is opened"; // // sepBrkCopStpWdm // this.sepBrkCopStpWdm.Name = "sepBrkCopStpWdm"; - this.sepBrkCopStpWdm.Size = new System.Drawing.Size(258, 6); + this.sepBrkCopStpWdm.Size = new System.Drawing.Size(262, 6); // // mnuBreakOnBrk // this.mnuBreakOnBrk.Name = "mnuBreakOnBrk"; - this.mnuBreakOnBrk.Size = new System.Drawing.Size(261, 22); + this.mnuBreakOnBrk.Size = new System.Drawing.Size(265, 22); this.mnuBreakOnBrk.Text = "Break on BRK"; // // mnuBreakOnCop // this.mnuBreakOnCop.Name = "mnuBreakOnCop"; - this.mnuBreakOnCop.Size = new System.Drawing.Size(261, 22); + this.mnuBreakOnCop.Size = new System.Drawing.Size(265, 22); this.mnuBreakOnCop.Text = "Break on COP"; // // mnuBreakOnStp // this.mnuBreakOnStp.Name = "mnuBreakOnStp"; - this.mnuBreakOnStp.Size = new System.Drawing.Size(261, 22); + this.mnuBreakOnStp.Size = new System.Drawing.Size(265, 22); this.mnuBreakOnStp.Text = "Break on STP"; // // mnuBreakOnWdm // this.mnuBreakOnWdm.Name = "mnuBreakOnWdm"; - this.mnuBreakOnWdm.Size = new System.Drawing.Size(261, 22); + this.mnuBreakOnWdm.Size = new System.Drawing.Size(265, 22); this.mnuBreakOnWdm.Text = "Break on WDM"; // // sepBreakOnUnitRead // this.sepBreakOnUnitRead.Name = "sepBreakOnUnitRead"; - this.sepBreakOnUnitRead.Size = new System.Drawing.Size(258, 6); + this.sepBreakOnUnitRead.Size = new System.Drawing.Size(262, 6); // // mnuBreakOnUnitRead // this.mnuBreakOnUnitRead.Name = "mnuBreakOnUnitRead"; - this.mnuBreakOnUnitRead.Size = new System.Drawing.Size(261, 22); + this.mnuBreakOnUnitRead.Size = new System.Drawing.Size(265, 22); this.mnuBreakOnUnitRead.Text = "Break on uninitialized memory read"; // // toolStripMenuItem10 // this.toolStripMenuItem10.Name = "toolStripMenuItem10"; - this.toolStripMenuItem10.Size = new System.Drawing.Size(258, 6); + this.toolStripMenuItem10.Size = new System.Drawing.Size(262, 6); // // mnuBringToFrontOnBreak // this.mnuBringToFrontOnBreak.Name = "mnuBringToFrontOnBreak"; - this.mnuBringToFrontOnBreak.Size = new System.Drawing.Size(261, 22); + this.mnuBringToFrontOnBreak.Size = new System.Drawing.Size(265, 22); this.mnuBringToFrontOnBreak.Text = "Bring debugger to front on break"; // // mnuBringToFrontOnPause // this.mnuBringToFrontOnPause.Name = "mnuBringToFrontOnPause"; - this.mnuBringToFrontOnPause.Size = new System.Drawing.Size(261, 22); + this.mnuBringToFrontOnPause.Size = new System.Drawing.Size(265, 22); this.mnuBringToFrontOnPause.Text = "Bring debugger to front on pause"; this.mnuBringToFrontOnPause.Visible = false; // + // sepGameboyBreak + // + this.sepGameboyBreak.Name = "sepGameboyBreak"; + this.sepGameboyBreak.Size = new System.Drawing.Size(262, 6); + this.sepGameboyBreak.Visible = false; + // + // mnuGbBreakOnOamCorruption + // + this.mnuGbBreakOnOamCorruption.Name = "mnuGbBreakOnOamCorruption"; + this.mnuGbBreakOnOamCorruption.Size = new System.Drawing.Size(265, 22); + this.mnuGbBreakOnOamCorruption.Text = "Break on OAM corruption"; + this.mnuGbBreakOnOamCorruption.Visible = false; + // + // mnuGbBreakOnInvalidOamAccess + // + this.mnuGbBreakOnInvalidOamAccess.Name = "mnuGbBreakOnInvalidOamAccess"; + this.mnuGbBreakOnInvalidOamAccess.Size = new System.Drawing.Size(265, 22); + this.mnuGbBreakOnInvalidOamAccess.Text = "Break on invalid OAM access"; + this.mnuGbBreakOnInvalidOamAccess.Visible = false; + // + // mnuGbBreakOnInvalidVramAccess + // + this.mnuGbBreakOnInvalidVramAccess.Name = "mnuGbBreakOnInvalidVramAccess"; + this.mnuGbBreakOnInvalidVramAccess.Size = new System.Drawing.Size(265, 22); + this.mnuGbBreakOnInvalidVramAccess.Text = "Break on invalid VRAM access"; + this.mnuGbBreakOnInvalidVramAccess.Visible = false; + // + // mnuGbBreakOnDisableLcdOutsideVblank + // + this.mnuGbBreakOnDisableLcdOutsideVblank.Name = "mnuGbBreakOnDisableLcdOutsideVblank"; + this.mnuGbBreakOnDisableLcdOutsideVblank.Size = new System.Drawing.Size(265, 22); + this.mnuGbBreakOnDisableLcdOutsideVblank.Text = "Break on LCD disable outside vblank"; + this.mnuGbBreakOnDisableLcdOutsideVblank.Visible = false; + // + // mnuGbBreakOnInvalidOpCode + // + this.mnuGbBreakOnInvalidOpCode.Name = "mnuGbBreakOnInvalidOpCode"; + this.mnuGbBreakOnInvalidOpCode.Size = new System.Drawing.Size(265, 22); + this.mnuGbBreakOnInvalidOpCode.Text = "Break on invalid instructions"; + this.mnuGbBreakOnInvalidOpCode.Visible = false; + // + // mnuGbBreakOnNopLoad + // + this.mnuGbBreakOnNopLoad.Name = "mnuGbBreakOnNopLoad"; + this.mnuGbBreakOnNopLoad.Size = new System.Drawing.Size(265, 22); + this.mnuGbBreakOnNopLoad.Text = "Break on LD B, B (nop)"; + this.mnuGbBreakOnNopLoad.Visible = false; + // // toolStripMenuItem5 // this.toolStripMenuItem5.Name = "toolStripMenuItem5"; @@ -1220,5 +1282,12 @@ private System.Windows.Forms.ToolStripMenuItem mnuAutoResetCdl; private System.Windows.Forms.ToolStripSeparator toolStripMenuItem12; private System.Windows.Forms.ToolStripMenuItem mnuShowMemoryMappings; + private System.Windows.Forms.ToolStripSeparator sepGameboyBreak; + private System.Windows.Forms.ToolStripMenuItem mnuGbBreakOnInvalidOamAccess; + private System.Windows.Forms.ToolStripMenuItem mnuGbBreakOnInvalidVramAccess; + private System.Windows.Forms.ToolStripMenuItem mnuGbBreakOnDisableLcdOutsideVblank; + private System.Windows.Forms.ToolStripMenuItem mnuGbBreakOnInvalidOpCode; + private System.Windows.Forms.ToolStripMenuItem mnuGbBreakOnNopLoad; + private System.Windows.Forms.ToolStripMenuItem mnuGbBreakOnOamCorruption; } } \ No newline at end of file diff --git a/UI/Debugger/frmDebugger.cs b/UI/Debugger/frmDebugger.cs index 78ed187..7e40134 100644 --- a/UI/Debugger/frmDebugger.cs +++ b/UI/Debugger/frmDebugger.cs @@ -154,6 +154,14 @@ namespace Mesen.GUI.Debugger mnuBreakOnStp.Visible = false; ctrlPpuStatus.Visible = false; + sepGameboyBreak.Visible = true; + mnuGbBreakOnDisableLcdOutsideVblank.Visible = true; + mnuGbBreakOnInvalidOamAccess.Visible = true; + mnuGbBreakOnInvalidOpCode.Visible = true; + mnuGbBreakOnInvalidVramAccess.Visible = true; + mnuGbBreakOnNopLoad.Visible = true; + mnuGbBreakOnOamCorruption.Visible = false; + this.ctrlGameboyStatus = new ctrlGameboyStatus(); this.ctrlGameboyStatus.Padding = new Padding(3, 0, 3, 0); this.ctrlGameboyStatus.Dock = DockStyle.Top; @@ -345,8 +353,17 @@ namespace Mesen.GUI.Debugger mnuBreakOnStp.Click += (s, e) => { InvertFlag(ref ConfigManager.Config.Debug.Debugger.BreakOnStp); }; mnuBreakOnWdm.Click += (s, e) => { InvertFlag(ref ConfigManager.Config.Debug.Debugger.BreakOnWdm); }; mnuBreakOnOpen.Click += (s, e) => { InvertFlag(ref ConfigManager.Config.Debug.Debugger.BreakOnOpen); }; + mnuBreakOnPowerCycleReset.Click += (s, e) => { InvertFlag(ref ConfigManager.Config.Debug.Debugger.BreakOnPowerCycleReset); }; mnuBreakOnUnitRead.Click += (s, e) => { InvertFlag(ref ConfigManager.Config.Debug.Debugger.BreakOnUninitRead); }; + + mnuGbBreakOnDisableLcdOutsideVblank.Click += (s, e) => { InvertFlag(ref ConfigManager.Config.Debug.Debugger.GbBreakOnDisableLcdOutsideVblank); }; + mnuGbBreakOnInvalidOamAccess.Click += (s, e) => { InvertFlag(ref ConfigManager.Config.Debug.Debugger.GbBreakOnInvalidOamAccess); }; + mnuGbBreakOnInvalidOpCode.Click += (s, e) => { InvertFlag(ref ConfigManager.Config.Debug.Debugger.GbBreakOnInvalidOpCode); }; + mnuGbBreakOnInvalidVramAccess.Click += (s, e) => { InvertFlag(ref ConfigManager.Config.Debug.Debugger.GbBreakOnInvalidVramAccess); }; + mnuGbBreakOnNopLoad.Click += (s, e) => { InvertFlag(ref ConfigManager.Config.Debug.Debugger.GbBreakOnNopLoad); }; + mnuGbBreakOnOamCorruption.Click += (s, e) => { InvertFlag(ref ConfigManager.Config.Debug.Debugger.GbBreakOnOamCorruption); }; + mnuBringToFrontOnBreak.Click += (s, e) => { InvertFlag(ref ConfigManager.Config.Debug.Debugger.BringToFrontOnBreak); }; mnuBringToFrontOnPause.Click += (s, e) => { InvertFlag(ref ConfigManager.Config.Debug.Debugger.BringToFrontOnPause); }; mnuAutoResetCdl.Click += (s, e) => { InvertFlag(ref ConfigManager.Config.Debug.Debugger.AutoResetCdl); }; @@ -389,6 +406,12 @@ namespace Mesen.GUI.Debugger mnuBreakOnOpen.Checked = cfg.BreakOnOpen; mnuBreakOnPowerCycleReset.Checked = cfg.BreakOnPowerCycleReset; mnuBreakOnUnitRead.Checked = cfg.BreakOnUninitRead; + mnuGbBreakOnDisableLcdOutsideVblank.Checked = cfg.GbBreakOnDisableLcdOutsideVblank; + mnuGbBreakOnInvalidOamAccess.Checked = cfg.GbBreakOnInvalidOamAccess; + mnuGbBreakOnInvalidOpCode.Checked = cfg.GbBreakOnInvalidOpCode; + mnuGbBreakOnInvalidVramAccess.Checked = cfg.GbBreakOnInvalidVramAccess; + mnuGbBreakOnNopLoad.Checked = cfg.GbBreakOnNopLoad; + mnuGbBreakOnOamCorruption.Checked = cfg.GbBreakOnOamCorruption; mnuBringToFrontOnBreak.Checked = cfg.BringToFrontOnBreak; mnuBringToFrontOnPause.Checked = cfg.BringToFrontOnPause; } diff --git a/UI/Dependencies/resources.en.xml b/UI/Dependencies/resources.en.xml index c211d74..ce8b19a 100644 --- a/UI/Dependencies/resources.en.xml +++ b/UI/Dependencies/resources.en.xml @@ -998,6 +998,12 @@ WDM STP Uninitialized memory read + Invalid OAM access + Invalid VRAM access + Disabled LCD outside vblank + Invalid instruction + LD B,B (NOP) + OAM corruption bug triggered Read diff --git a/UI/Interop/ConfigApi.cs b/UI/Interop/ConfigApi.cs index 028f9c2..02752f2 100644 --- a/UI/Interop/ConfigApi.cs +++ b/UI/Interop/ConfigApi.cs @@ -64,6 +64,13 @@ namespace Mesen.GUI AutoResetCdl = 0x4000, + GbBreakOnInvalidOamAccess = 0x10000, + GbBreakOnInvalidVramAccess = 0x20000, + GbBreakOnDisableLcdOutsideVblank = 0x40000, + GbBreakOnInvalidOpCode = 0x80000, + GbBreakOnNopLoad = 0x100000, + GbBreakOnOamCorruption = 0x200000, + GbDebuggerEnabled = 0x02000000, Cx4DebuggerEnabled = 0x04000000, NecDspDebuggerEnabled = 0x08000000, diff --git a/UI/Interop/DebugApi.cs b/UI/Interop/DebugApi.cs index 50a34bd..453b32e 100644 --- a/UI/Interop/DebugApi.cs +++ b/UI/Interop/DebugApi.cs @@ -597,7 +597,14 @@ namespace Mesen.GUI BreakOnCop = 4, BreakOnWdm = 5, BreakOnStp = 6, - BreakOnUninitMemoryRead = 7 + BreakOnUninitMemoryRead = 7, + + GbInvalidOamAccess = 8, + GbInvalidVramAccess = 9, + GbDisableLcdOutsideVblank = 10, + GbInvalidOpCode = 11, + GbNopLoad = 12, + GbOamCorruption = 13, } public struct BreakEvent