diff --git a/Core/BreakpointManager.cpp b/Core/BreakpointManager.cpp index 41f4c58..4b36306 100644 --- a/Core/BreakpointManager.cpp +++ b/Core/BreakpointManager.cpp @@ -64,13 +64,13 @@ BreakpointType BreakpointManager::GetBreakpointType(MemoryOperationType type) } } -bool BreakpointManager::CheckBreakpoint(MemoryOperationInfo operationInfo, AddressInfo &address) +int BreakpointManager::CheckBreakpoint(MemoryOperationInfo operationInfo, AddressInfo &address) { BreakpointCategory category = Breakpoint::GetBreakpointCategory(address.Type); BreakpointType type = GetBreakpointType(operationInfo.Type); if(!_hasBreakpoint[(int)category][(int)type]) { - return false; + return -1; } CpuType cpuType = category == BreakpointCategory::Spc ? CpuType::Spc : CpuType::Cpu; @@ -82,10 +82,10 @@ bool BreakpointManager::CheckBreakpoint(MemoryOperationInfo operationInfo, Addre for(size_t i = 0; i < breakpoints.size(); i++) { if(breakpoints[i].Matches(operationInfo.Address, address)) { if(!breakpoints[i].HasCondition() || _bpExpEval[(int)cpuType]->Evaluate(_rpnList[(int)category][(int)type][i], state, resultType, operationInfo)) { - return true; + return breakpoints[i].GetId(); } } } - return false; + return -1; } diff --git a/Core/BreakpointManager.h b/Core/BreakpointManager.h index c3b3bb9..c62dca7 100644 --- a/Core/BreakpointManager.h +++ b/Core/BreakpointManager.h @@ -29,5 +29,5 @@ public: BreakpointManager(Debugger *debugger); void SetBreakpoints(Breakpoint breakpoints[], uint32_t count); - bool CheckBreakpoint(MemoryOperationInfo operationInfo, AddressInfo &address); + int CheckBreakpoint(MemoryOperationInfo operationInfo, AddressInfo &address); }; \ No newline at end of file diff --git a/Core/DebugTypes.h b/Core/DebugTypes.h index cd004e6..e25169e 100644 --- a/Core/DebugTypes.h +++ b/Core/DebugTypes.h @@ -38,15 +38,6 @@ struct MemoryOperationInfo uint32_t Address; int32_t Value; MemoryOperationType Type; - - MemoryOperationInfo() { } - - MemoryOperationInfo(uint32_t address, int32_t value, MemoryOperationType type) - { - Address = address; - Value = value; - Type = type; - } }; enum class BreakpointTypeFlags @@ -211,6 +202,25 @@ struct StackFrameInfo StackFrameFlags Flags; }; +enum class BreakSource +{ + Unspecified = -1, + Breakpoint = 0, + CpuStep = 1, + PpuStep = 2, + BreakOnBrk = 3, + BreakOnCop = 4, + BreakOnWdm = 5, + BreakOnStp = 6 +}; + +struct BreakEvent +{ + BreakSource Source; + MemoryOperationInfo Operation; + int32_t BreakpointId; +}; + enum class StepType { CpuStep, diff --git a/Core/Debugger.cpp b/Core/Debugger.cpp index c3f70a1..6de3d47 100644 --- a/Core/Debugger.cpp +++ b/Core/Debugger.cpp @@ -95,6 +95,7 @@ void Debugger::ProcessCpuRead(uint32_t addr, uint8_t value, MemoryOperationType AddressInfo addressInfo = _memoryManager->GetAbsoluteAddress(addr); MemoryOperationInfo operation = { addr, value, type }; CpuState state = _cpu->GetState(); + BreakSource breakSource = BreakSource::Unspecified; if(type == MemoryOperationType::ExecOpCode) { if(addressInfo.Address >= 0) { @@ -138,12 +139,16 @@ void Debugger::ProcessCpuRead(uint32_t addr, uint8_t value, MemoryOperationType if(value == 0x00 || value == 0x02 || value == 0x42 || value == 0xDB) { //Break on BRK/STP/WDM/COP if(value == 0x00 && _settings->CheckDebuggerFlag(DebuggerFlags::BreakOnBrk)) { + breakSource = BreakSource::BreakOnBrk; _cpuStepCount = 0; } else if(value == 0x02 && _settings->CheckDebuggerFlag(DebuggerFlags::BreakOnCop)) { + breakSource = BreakSource::BreakOnCop; _cpuStepCount = 0; } else if(value == 0x42 && _settings->CheckDebuggerFlag(DebuggerFlags::BreakOnWdm)) { + breakSource = BreakSource::BreakOnWdm; _cpuStepCount = 0; } else if(value == 0xDB && _settings->CheckDebuggerFlag(DebuggerFlags::BreakOnStp)) { + breakSource = BreakSource::BreakOnStp; _cpuStepCount = 0; } } @@ -164,7 +169,7 @@ void Debugger::ProcessCpuRead(uint32_t addr, uint8_t value, MemoryOperationType _eventManager->AddEvent(DebugEventType::Register, operation); } - ProcessBreakConditions(operation, addressInfo); + ProcessBreakConditions(operation, addressInfo, breakSource); } void Debugger::ProcessCpuWrite(uint32_t addr, uint8_t value, MemoryOperationType type) @@ -188,7 +193,7 @@ void Debugger::ProcessWorkRamRead(uint32_t addr, uint8_t value) { AddressInfo addressInfo { (int32_t)addr, SnesMemoryType::WorkRam }; //TODO Make this more flexible/accurate - MemoryOperationInfo operation(0x7E0000 | addr, value, MemoryOperationType::Read); + MemoryOperationInfo operation { 0x7E0000 | addr, value, MemoryOperationType::Read }; ProcessBreakConditions(operation, addressInfo); } @@ -196,7 +201,7 @@ void Debugger::ProcessWorkRamWrite(uint32_t addr, uint8_t value) { AddressInfo addressInfo { (int32_t)addr, SnesMemoryType::WorkRam }; //TODO Make this more flexible/accurate - MemoryOperationInfo operation(0x7E0000 | addr, value, MemoryOperationType::Write); + MemoryOperationInfo operation { 0x7E0000 | addr, value, MemoryOperationType::Write }; ProcessBreakConditions(operation, addressInfo); } @@ -208,7 +213,7 @@ void Debugger::ProcessSpcRead(uint16_t addr, uint8_t value, MemoryOperationType } AddressInfo addressInfo = _spc->GetAbsoluteAddress(addr); - MemoryOperationInfo operation(addr, value, type); + MemoryOperationInfo operation { addr, value, type }; if(type == MemoryOperationType::ExecOpCode) { _disassembler->BuildCache(addressInfo, 0, CpuType::Spc); @@ -254,7 +259,7 @@ void Debugger::ProcessSpcRead(uint16_t addr, uint8_t value, MemoryOperationType void Debugger::ProcessSpcWrite(uint16_t addr, uint8_t value, MemoryOperationType type) { AddressInfo addressInfo { addr, SnesMemoryType::SpcRam }; //Writes never affect the SPC ROM - MemoryOperationInfo operation(addr, value, type); + MemoryOperationInfo operation { addr, value, type }; ProcessBreakConditions(operation, addressInfo); _disassembler->InvalidateCache(addressInfo); @@ -265,7 +270,7 @@ void Debugger::ProcessSpcWrite(uint16_t addr, uint8_t value, MemoryOperationType void Debugger::ProcessPpuRead(uint16_t addr, uint8_t value, SnesMemoryType memoryType) { AddressInfo addressInfo { addr, memoryType }; - MemoryOperationInfo operation(addr, value, MemoryOperationType::Read); + MemoryOperationInfo operation { addr, value, MemoryOperationType::Read }; ProcessBreakConditions(operation, addressInfo); _memoryAccessCounter->ProcessMemoryAccess(addressInfo, MemoryOperationType::Read, _memoryManager->GetMasterClock()); @@ -274,7 +279,7 @@ void Debugger::ProcessPpuRead(uint16_t addr, uint8_t value, SnesMemoryType memor void Debugger::ProcessPpuWrite(uint16_t addr, uint8_t value, SnesMemoryType memoryType) { AddressInfo addressInfo { addr, memoryType }; - MemoryOperationInfo operation(addr, value, MemoryOperationType::Write); + MemoryOperationInfo operation { addr, value, MemoryOperationType::Write }; ProcessBreakConditions(operation, addressInfo); _memoryAccessCounter->ProcessMemoryAccess(addressInfo, MemoryOperationType::Write, _memoryManager->GetMasterClock()); @@ -290,18 +295,18 @@ void Debugger::ProcessPpuCycle() _ppuStepCount--; if(_ppuStepCount == 0) { _cpuStepCount = 0; - SleepUntilResume(); + SleepUntilResume(BreakSource::PpuStep); } } if(cycle == 0 && scanline == _breakScanline) { _cpuStepCount = 0; _breakScanline = -1; - SleepUntilResume(); + SleepUntilResume(BreakSource::PpuStep); } } -void Debugger::SleepUntilResume() +void Debugger::SleepUntilResume(BreakSource source, MemoryOperationInfo *operation, int breakpointId) { if(_suspendRequestCount) { return; @@ -313,9 +318,15 @@ void Debugger::SleepUntilResume() _executionStopped = true; - if(_cpuStepCount == 0) { + if(_cpuStepCount == 0 && _breakRequestCount == 0) { //Only trigger code break event if the pause was caused by user action - _console->GetNotificationManager()->SendNotification(ConsoleNotificationType::CodeBreak); + BreakEvent evt = {}; + evt.BreakpointId = breakpointId; + evt.Source = source; + if(operation) { + evt.Operation = *operation; + } + _console->GetNotificationManager()->SendNotification(ConsoleNotificationType::CodeBreak, &evt); } while((_cpuStepCount == 0 && !_suspendRequestCount) || _breakRequestCount) { @@ -333,14 +344,16 @@ void Debugger::ProcessStepConditions(uint8_t opCode, uint32_t currentPc) } } -void Debugger::ProcessBreakConditions(MemoryOperationInfo &operation, AddressInfo &addressInfo) +void Debugger::ProcessBreakConditions(MemoryOperationInfo &operation, AddressInfo &addressInfo, BreakSource source) { - if(_breakpointManager->CheckBreakpoint(operation, addressInfo)) { - _cpuStepCount = 0; - } - if(_cpuStepCount == 0 || _breakRequestCount) { - SleepUntilResume(); + SleepUntilResume(source); + } else { + int breakpointId = _breakpointManager->CheckBreakpoint(operation, addressInfo); + if(breakpointId >= 0) { + _cpuStepCount = 0; + SleepUntilResume(BreakSource::Breakpoint, &operation, breakpointId); + } } } diff --git a/Core/Debugger.h b/Core/Debugger.h index 24051a4..ee8e97e 100644 --- a/Core/Debugger.h +++ b/Core/Debugger.h @@ -71,9 +71,9 @@ private: uint32_t _spcPrevProgramCounter = 0; void Reset(); - void SleepUntilResume(); + void SleepUntilResume(BreakSource source, MemoryOperationInfo *operation = nullptr, int breakpointId = -1); void ProcessStepConditions(uint8_t opCode, uint32_t currentPc); - void ProcessBreakConditions(MemoryOperationInfo &operation, AddressInfo &addressInfo); + void ProcessBreakConditions(MemoryOperationInfo &operation, AddressInfo &addressInfo, BreakSource source = BreakSource::Unspecified); public: Debugger(shared_ptr console); diff --git a/Core/ExpressionEvaluator.cpp b/Core/ExpressionEvaluator.cpp index a6f6f66..0ddade8 100644 --- a/Core/ExpressionEvaluator.cpp +++ b/Core/ExpressionEvaluator.cpp @@ -556,7 +556,7 @@ void ExpressionEvaluator::RunTests() //Some basic unit tests to run in debug mode auto test = [=](string expr, EvalResultType expectedType, int expectedResult) { DebugState state = { 0 }; - MemoryOperationInfo opInfo(0, 0, MemoryOperationType::Read); + MemoryOperationInfo opInfo { 0, 0, MemoryOperationType::Read }; EvalResultType type; int32_t result = Evaluate(expr, state, type, opInfo); diff --git a/UI/Debugger/Breakpoints/BreakpointManager.cs b/UI/Debugger/Breakpoints/BreakpointManager.cs index 39b2303..6b63267 100644 --- a/UI/Debugger/Breakpoints/BreakpointManager.cs +++ b/UI/Debugger/Breakpoints/BreakpointManager.cs @@ -125,5 +125,13 @@ namespace Mesen.GUI.Debugger } DebugApi.SetBreakpoints(breakpoints.ToArray(), (UInt32)breakpoints.Count); } + + public static Breakpoint GetBreakpointById(int breakpointId) + { + if(breakpointId < 0 || breakpointId >= _breakpoints.Count) { + return null; + } + return _breakpoints[breakpointId]; + } } } diff --git a/UI/Debugger/Controls/ctrlDisassemblyView.cs b/UI/Debugger/Controls/ctrlDisassemblyView.cs index 368f9af..068a9bb 100644 --- a/UI/Debugger/Controls/ctrlDisassemblyView.cs +++ b/UI/Debugger/Controls/ctrlDisassemblyView.cs @@ -141,7 +141,7 @@ namespace Mesen.GUI.Debugger.Controls public void SetActiveAddress(int? address) { - if(_styleProvider.ActiveAddress == address) { + if(_styleProvider.ActiveAddress == null && address == null) { return; } @@ -275,5 +275,10 @@ namespace Mesen.GUI.Debugger.Controls UpdateCode(); } } + + public void SetMessage(TextboxMessageInfo msg) + { + ctrlCode.SetMessage(msg); + } } } diff --git a/UI/Debugger/frmDebugger.cs b/UI/Debugger/frmDebugger.cs index 8c99d90..1d2aeeb 100644 --- a/UI/Debugger/frmDebugger.cs +++ b/UI/Debugger/frmDebugger.cs @@ -1,5 +1,6 @@ using Mesen.GUI.Config; using Mesen.GUI.Debugger.Code; +using Mesen.GUI.Debugger.Controls; using Mesen.GUI.Debugger.Workspace; using Mesen.GUI.Forms; using System; @@ -8,6 +9,7 @@ using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; +using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; @@ -295,6 +297,27 @@ namespace Mesen.GUI.Debugger ctrlCallstack.UpdateCallstack(_cpuType); } + void ProcessBreakEvent(BreakEvent evt, DebugState state, int activeAddress) + { + if(ConfigManager.Config.Debug.Debugger.BringToFrontOnBreak) { + Breakpoint bp = BreakpointManager.GetBreakpointById(evt.BreakpointId); + if(bp?.MemoryType.ToCpuType() == _cpuType || evt.Source > BreakSource.PpuStep) { + DebugWindowManager.BringToFront(this); + } + } + + UpdateContinueAction(); + UpdateDebugger(state, activeAddress); + + if(evt.Source == BreakSource.Breakpoint || evt.Source > BreakSource.PpuStep) { + string message = ResourceHelper.GetEnumText(evt.Source); + if(evt.Source == BreakSource.Breakpoint) { + message += ": " + ResourceHelper.GetEnumText(evt.Operation.Type) + " ($" + evt.Operation.Address.ToString("X4") + ":$" + evt.Operation.Value.ToString("X2") + ")"; + } + ctrlDisassemblyView.SetMessage(new TextboxMessageInfo() { Message = message }); + } + } + private void OnNotificationReceived(NotificationEventArgs e) { switch(e.NotificationType) { @@ -326,16 +349,12 @@ namespace Mesen.GUI.Debugger break; case ConsoleNotificationType.CodeBreak: { + BreakEvent evt = (BreakEvent)Marshal.PtrToStructure(e.Parameter, typeof(BreakEvent)); DebugState state = DebugApi.GetState(); int activeAddress = _cpuType == CpuType.Cpu ? (int)((state.Cpu.K << 16) | state.Cpu.PC) : (int)state.Spc.PC; this.BeginInvoke((MethodInvoker)(() => { - if(ConfigManager.Config.Debug.Debugger.BringToFrontOnBreak) { - DebugWindowManager.BringToFront(this); - } - - UpdateContinueAction(); - UpdateDebugger(state, activeAddress); + ProcessBreakEvent(evt, state, activeAddress); if(_firstBreak && !ConfigManager.Config.Debug.Debugger.BreakOnOpen) { DebugApi.ResumeExecution(); diff --git a/UI/Dependencies/resources.en.xml b/UI/Dependencies/resources.en.xml index ede71f6..61172da 100644 --- a/UI/Dependencies/resources.en.xml +++ b/UI/Dependencies/resources.en.xml @@ -1098,158 +1098,24 @@ Text Text (Active only) - - None - 128 bytes - 256 bytes - 512 bytes - 1 KB - 2 KB - 4 KB - 8 KB - 16 KB - 32 KB - 64 KB - 128 KB - 256 KB - 512 KB - 1024 KB - Reserved - - - NTSC - PAL - NTSC and PAL - Dendy - - - NES / Famicom / Dendy - VS System - Playchoice-10 - Bit Corporation Creator - VT01 Monochrome - VT01 Red/Cyan - VT02 - VT03 - VT09 - VT3x - VT36x - - - Horizontal - Vertical - Four Screens - - - Horizontal - Vertical - Screen A - Screen B - Four Screens - - - PPU Register Write - PPU Register Read - Mapper Register Write - Mapper Register Read - NMI - IRQ - Sprite 0 Hit - - - Global - Execute - CPU Read - CPU Write - PPU Read - PPU Write - (Dummy) CPU Read - (Dummy) CPU Write - Breakpoint CPU Step PPU Step BRK - Unofficial OP code - Reset event - Debugger focused + COP + WDM + STP Uninitialized memory read - Decayed OAM read - CPU crashed - - RP2C03B - RP2C03G - RP2C04-0001 - RP2C04-0002 - RP2C04-0003 - RP2C04-0004 - RC2C03B - RC2C03C - RC2C05-01 - RC2C05-02 - RC2C05-03 - RC2C05-04 - RC2C05-05 - Undefined - Undefined (2) - Undefined (3) - - - Default - RBI Baseball - TKO Boxing - Super Xevious - Ice Climber - VS. Dual System - Raid on Bungeling Bay - - - Unspecified - Standard Controllers - Four Score (NES) - Four Player Adapter (Famicom) - VS System - VS System - Swap P1/P2 - VS System - Swap A/B buttons - VS Zapper - Zapper - 2 zappers - Bandai Hypershot - Power Pad Side A - Power Pad Side B - Family Trainer Side A - Family Trainer Side B - Arkanoid Controller (NES) - Arkanoid Controller (Famicom) - 2x Arkanoid Controllers (NES) - Konami Hyper Shot - Pachinko Controller - Exciting Boxing - Jissen Mahjong - Party Tap - Oeka Kids Tablet - Barcode Battler - Miracle Piano - Pokkun Moguraa - Top Rider - Double Fisted - Famicom 3D System - Doremikko Keyboard - ROB - Family Data Recorder - Turbo File - Battle Box - Family Basic Keyboard - PEC-586 Keyboard - Bit-79 Keyboard - Subor Keyboard - Subor Keyboard+Mouse (Type A) - Subor Keyboard+Mouse (Type B) - SNES Mouse - Generic Multicart - SNES Controllers + + Read + Write + Exec + Exec + DMA Read + DMA Write + Dummy Read \ No newline at end of file diff --git a/UI/Interop/DebugApi.cs b/UI/Interop/DebugApi.cs index 2d8b823..a733f63 100644 --- a/UI/Interop/DebugApi.cs +++ b/UI/Interop/DebugApi.cs @@ -572,6 +572,25 @@ namespace Mesen.GUI SpecificScanline, } + public enum BreakSource + { + Unspecified = -1, + Breakpoint = 0, + CpuStep = 1, + PpuStep = 2, + BreakOnBrk = 3, + BreakOnCop = 4, + BreakOnWdm = 5, + BreakOnStp = 6 + } + + public struct BreakEvent + { + public BreakSource Source; + public MemoryOperationInfo Operation; + public Int32 BreakpointId; + } + public enum CdlFlags : byte { None = 0x00,