From 51afb5ae3f31fb7b693c47e9076456b8d8c2b0ce Mon Sep 17 00:00:00 2001 From: Souryo Date: Thu, 2 Mar 2017 20:33:25 -0500 Subject: [PATCH] Debugger: Added several commands to right-click menu in hex editor (including freeze/unfreeze feature) --- Core/Debugger.cpp | 31 ++++- Core/Debugger.h | 9 +- Core/MemoryManager.cpp | 12 +- Core/MessageManager.cpp | 2 +- GUI.NET/Controls/MyListView.cs | 68 +++++----- GUI.NET/Debugger/BreakpointManager.cs | 22 +++- GUI.NET/Debugger/ByteColorProvider.cs | 8 +- GUI.NET/Debugger/Controls/ctrlDebuggerCode.cs | 5 +- GUI.NET/Debugger/Controls/ctrlHexViewer.cs | 7 + .../Debugger/Controls/ctrlWatch.Designer.cs | 21 ++- GUI.NET/Debugger/Controls/ctrlWatch.cs | 120 +++++------------- GUI.NET/Debugger/HexBox/HexBox.cs | 51 +++++--- GUI.NET/Debugger/WatchManager.cs | 84 ++++++++++++ GUI.NET/Debugger/frmDebugger.Designer.cs | 2 - GUI.NET/Debugger/frmDebugger.cs | 9 +- GUI.NET/Debugger/frmMemoryViewer.Designer.cs | 21 +-- GUI.NET/Debugger/frmMemoryViewer.cs | 115 +++++++++++++++++ GUI.NET/GUI.NET.csproj | 1 + GUI.NET/InteropEmu.cs | 17 +++ InteropDLL/DebugWrapper.cpp | 4 +- 20 files changed, 429 insertions(+), 180 deletions(-) create mode 100644 GUI.NET/Debugger/WatchManager.cs diff --git a/Core/Debugger.cpp b/Core/Debugger.cpp index 560e6f70..541b7ce9 100644 --- a/Core/Debugger.cpp +++ b/Core/Debugger.cpp @@ -60,6 +60,8 @@ Debugger::Debugger(shared_ptr console, shared_ptr cpu, shared_ptr< _bpUpdateNeeded = false; _executionStopped = false; + _frozenAddresses.insert(_frozenAddresses.end(), 0x10000, 0); + LoadCdlFile(FolderUtilities::CombinePath(FolderUtilities::GetDebuggerFolder(), FolderUtilities::GetFilename(_romName, false) + ".cdl")); Debugger::Instance = this; @@ -327,7 +329,7 @@ void Debugger::PrivateProcessPpuCycle() } } -void Debugger::PrivateProcessRamOperation(MemoryOperationType type, uint16_t &addr, uint8_t &value) +bool Debugger::PrivateProcessRamOperation(MemoryOperationType type, uint16_t &addr, uint8_t &value) { _currentReadAddr = &addr; _currentReadValue = &value; @@ -400,6 +402,14 @@ void Debugger::PrivateProcessRamOperation(MemoryOperationType type, uint16_t &ad } _currentReadAddr = nullptr; + + if(type == MemoryOperationType::Write) { + if(_frozenAddresses[addr]) { + return false; + } + } + + return true; } bool Debugger::SleepUntilResume() @@ -625,11 +635,12 @@ void Debugger::ProcessPpuCycle() } } -void Debugger::ProcessRamOperation(MemoryOperationType type, uint16_t &addr, uint8_t &value) +bool Debugger::ProcessRamOperation(MemoryOperationType type, uint16_t &addr, uint8_t &value) { if(Debugger::Instance) { - Debugger::Instance->PrivateProcessRamOperation(type, addr, value); + return Debugger::Instance->PrivateProcessRamOperation(type, addr, value); } + return true; } void Debugger::ProcessVramOperation(MemoryOperationType type, uint16_t addr, uint8_t value) @@ -735,4 +746,16 @@ void Debugger::SetLastFramePpuScroll(uint16_t x, uint16_t y) uint32_t Debugger::GetPpuScroll() { return (_ppuScrollY << 16) | _ppuScrollX; -} \ No newline at end of file +} + +void Debugger::SetFreezeState(uint16_t address, bool frozen) +{ + _frozenAddresses[address] = frozen ? 1 : 0; +} + +void Debugger::GetFreezeState(uint16_t startAddress, uint16_t length, bool* freezeState) +{ + for(uint16_t i = 0; i < length; i++) { + freezeState[i] = _frozenAddresses[startAddress + i] ? true : false; + } +} diff --git a/Core/Debugger.h b/Core/Debugger.h index d9486bde..1cefec61 100644 --- a/Core/Debugger.h +++ b/Core/Debugger.h @@ -56,6 +56,8 @@ private: vector _breakpoints[BreakpointTypeCount]; bool _hasBreakpoint[BreakpointTypeCount] = {}; + vector _frozenAddresses; + deque _callstackAbsolute; deque _callstackRelative; @@ -91,7 +93,7 @@ private: void UpdateBreakpoints(); void PrivateProcessPpuCycle(); - void PrivateProcessRamOperation(MemoryOperationType type, uint16_t &addr, uint8_t &value); + bool PrivateProcessRamOperation(MemoryOperationType type, uint16_t &addr, uint8_t &value); void PrivateProcessVramOperation(MemoryOperationType type, uint16_t addr, uint8_t value); bool HasMatchingBreakpoint(BreakpointType type, uint32_t addr, int16_t value); @@ -156,7 +158,7 @@ public: int32_t EvaluateExpression(string expression, EvalResultType &resultType); - static void ProcessRamOperation(MemoryOperationType type, uint16_t &addr, uint8_t &value); + static bool ProcessRamOperation(MemoryOperationType type, uint16_t &addr, uint8_t &value); static void ProcessVramOperation(MemoryOperationType type, uint16_t addr, uint8_t value); static void ProcessPpuCycle(); @@ -169,4 +171,7 @@ public: static void BreakIfDebugging(); int GetMemorySize(DebugMemoryType memoryType); + + void SetFreezeState(uint16_t address, bool frozen); + void GetFreezeState(uint16_t startAddress, uint16_t length, bool* freezeState); }; \ No newline at end of file diff --git a/Core/MemoryManager.cpp b/Core/MemoryManager.cpp index 7a6dcbbc..be86f76a 100644 --- a/Core/MemoryManager.cpp +++ b/Core/MemoryManager.cpp @@ -131,12 +131,12 @@ uint8_t MemoryManager::Read(uint16_t addr, MemoryOperationType operationType) void MemoryManager::Write(uint16_t addr, uint8_t value) { - Debugger::ProcessRamOperation(MemoryOperationType::Write, addr, value); - - if(addr <= 0x1FFF) { - _internalRAM[addr & 0x07FF] = value; - } else { - WriteRegister(addr, value); + if(Debugger::ProcessRamOperation(MemoryOperationType::Write, addr, value)) { + if(addr <= 0x1FFF) { + _internalRAM[addr & 0x07FF] = value; + } else { + WriteRegister(addr, value); + } } } diff --git a/Core/MessageManager.cpp b/Core/MessageManager.cpp index 1aefe2c4..b15f8fd5 100644 --- a/Core/MessageManager.cpp +++ b/Core/MessageManager.cpp @@ -1,4 +1,4 @@ -#include "stdafx.h" +#include "stdafx.h" #include #include "MessageManager.h" diff --git a/GUI.NET/Controls/MyListView.cs b/GUI.NET/Controls/MyListView.cs index ab4ac6db..985d4898 100644 --- a/GUI.NET/Controls/MyListView.cs +++ b/GUI.NET/Controls/MyListView.cs @@ -12,19 +12,12 @@ namespace Mesen.GUI.Controls class MyListView : ListView { private bool _preventCheck = false; - private int _editItemIndex = -1; - private string _originalText = null; public MyListView() { this.DoubleBuffered = true; } - public bool IsEditing - { - get { return _editItemIndex >= 0; } - } - protected override void OnItemCheck(ItemCheckEventArgs e) { if(this._preventCheck) { @@ -44,45 +37,60 @@ namespace Mesen.GUI.Controls base.OnMouseDown(e); } + protected override void OnKeyDown(KeyEventArgs e) + { + this._preventCheck = false; + base.OnKeyDown(e); + } + } + + class WatchList : MyListView + { + private int _editItemIndex = -1; + private string _originalText = null; + private bool _pressedEsc = false; + + public event LabelEditEventHandler AfterEdit; + + public WatchList() + { + this.DoubleBuffered = true; + } + + public bool IsEditing + { + get { return _editItemIndex >= 0; } + } + protected override void OnBeforeLabelEdit(LabelEditEventArgs e) { if(_originalText == null) { _originalText = this.Items[e.Item].Text; } - _editItemIndex = e.Item; + _editItemIndex = e.Item; base.OnBeforeLabelEdit(e); } protected override void OnAfterLabelEdit(LabelEditEventArgs e) { base.OnAfterLabelEdit(e); + string text = e.Label; + var item = this.Items[e.Item]; + if(_pressedEsc) { + text = _originalText; + item = new ListViewItem(_originalText); + this.Items.Insert(e.Item, item); + _pressedEsc = false; + } _originalText = null; _editItemIndex = -1; + AfterEdit?.Invoke(this, new LabelEditEventArgs(item.Index, text)); } - - protected override void OnKeyDown(KeyEventArgs e) - { - if(!this.IsEditing && e.KeyData == Keys.Delete) { - if(this.SelectedItems.Count >= 1) { - var itemsToRemove = new List(); - foreach(ListViewItem item in this.SelectedItems) { - itemsToRemove.Add(item); - } - foreach(ListViewItem item in itemsToRemove) { - this.Items.Remove(item); - } - } - } - this._preventCheck = false; - base.OnKeyDown(e); - } - + protected override bool ProcessCmdKey(ref Message msg, Keys keyData) { - if(this.SelectedItems.Count > _editItemIndex && _editItemIndex >= 0) { - if(keyData == Keys.Escape) { - this.SelectedItems[_editItemIndex].Text = _originalText; - } + if(_editItemIndex >= 0 && keyData == Keys.Escape) { + _pressedEsc = true; } return base.ProcessCmdKey(ref msg, keyData); } diff --git a/GUI.NET/Debugger/BreakpointManager.cs b/GUI.NET/Debugger/BreakpointManager.cs index b7593ac9..e74291a7 100644 --- a/GUI.NET/Debugger/BreakpointManager.cs +++ b/GUI.NET/Debugger/BreakpointManager.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using System.Windows.Forms; namespace Mesen.GUI.Debugger { @@ -24,8 +25,12 @@ namespace Mesen.GUI.Debugger public static void EditBreakpoint(Breakpoint bp) { - new frmBreakpoint(bp).ShowDialog(); - RefreshBreakpoints(bp); + if(new frmBreakpoint(bp).ShowDialog() == DialogResult.OK) { + if(!Breakpoints.Contains(bp)) { + Breakpoints.Add(bp); + } + RefreshBreakpoints(bp); + } } public static void RemoveBreakpoint(Breakpoint bp) @@ -42,7 +47,18 @@ namespace Mesen.GUI.Debugger public static Breakpoint GetMatchingBreakpoint(int address) { - return Breakpoints.FirstOrDefault((bp) => { return bp.Address == address; }); + return Breakpoints.FirstOrDefault((bp) => { return !bp.IsAbsoluteAddress && bp.Address == address; }); + } + + public static Breakpoint GetMatchingBreakpoint(UInt32 startAddress, UInt32 endAddress, bool ppuBreakpoint) + { + bool isAddressRange = startAddress != endAddress; + return BreakpointManager.Breakpoints.Where((bp) => + !bp.IsAbsoluteAddress && + ((!isAddressRange && bp.Address == startAddress) || (isAddressRange && bp.StartAddress == startAddress && bp.EndAddress == endAddress)) && + ((!ppuBreakpoint && (bp.BreakOnExec || bp.BreakOnRead || bp.BreakOnWrite)) || + (ppuBreakpoint && (bp.BreakOnReadVram || bp.BreakOnWriteVram))) + ).FirstOrDefault(); } public static void ToggleBreakpoint(int address, bool toggleEnabled) diff --git a/GUI.NET/Debugger/ByteColorProvider.cs b/GUI.NET/Debugger/ByteColorProvider.cs index 516e80f5..5ba396f4 100644 --- a/GUI.NET/Debugger/ByteColorProvider.cs +++ b/GUI.NET/Debugger/ByteColorProvider.cs @@ -10,6 +10,7 @@ namespace Mesen.GUI.Debugger Int32[] _readStamps; Int32[] _writeStamps; Int32[] _execStamps; + bool[] _freezeState; DebugState _state = new DebugState(); bool _showExec; bool _showWrite; @@ -30,6 +31,9 @@ namespace Mesen.GUI.Debugger _readStamps = InteropEmu.DebugGetMemoryAccessStamps((UInt32)firstByteIndex, (UInt32)(lastByteIndex - firstByteIndex + 1), _memoryType, MemoryOperationType.Read); _writeStamps = InteropEmu.DebugGetMemoryAccessStamps((UInt32)firstByteIndex, (UInt32)(lastByteIndex - firstByteIndex + 1), _memoryType, MemoryOperationType.Write); _execStamps = InteropEmu.DebugGetMemoryAccessStamps((UInt32)firstByteIndex, (UInt32)(lastByteIndex - firstByteIndex + 1), _memoryType, MemoryOperationType.Exec); + if(_memoryType == DebugMemoryType.CpuMemory) { + _freezeState = InteropEmu.DebugGetFreezeState((UInt16)firstByteIndex, (UInt16)(lastByteIndex - firstByteIndex + 1)); + } InteropEmu.DebugGetState(ref _state); } @@ -51,7 +55,9 @@ namespace Mesen.GUI.Debugger double framesSinceWrite = (double)(_state.CPU.CycleCount - _writeStamps[index]) / CyclesPerFrame; double framesSinceRead = (double)(_state.CPU.CycleCount - _readStamps[index]) / CyclesPerFrame; - if(_showExec && _execStamps[index] != 0 && framesSinceExec < _framesToFade) { + if(_freezeState != null && _freezeState[index]) { + return Color.Magenta; + } else if(_showExec && _execStamps[index] != 0 && framesSinceExec < _framesToFade) { return DarkerColor(Color.Green, (_framesToFade - framesSinceExec) / _framesToFade); } else if(_showWrite && _writeStamps[index] != 0 && framesSinceWrite < _framesToFade) { return DarkerColor(Color.Red, (_framesToFade - framesSinceWrite) / _framesToFade); diff --git a/GUI.NET/Debugger/Controls/ctrlDebuggerCode.cs b/GUI.NET/Debugger/Controls/ctrlDebuggerCode.cs index f9915d52..0b9eab50 100644 --- a/GUI.NET/Debugger/Controls/ctrlDebuggerCode.cs +++ b/GUI.NET/Debugger/Controls/ctrlDebuggerCode.cs @@ -17,7 +17,6 @@ namespace Mesen.GUI.Debugger { public delegate void AddressEventHandler(AddressEventArgs args); public delegate void WatchEventHandler(WatchEventArgs args); - public event WatchEventHandler OnWatchAdded; public event AddressEventHandler OnSetNextStatement; private DebugViewInfo _config; private HashSet _unexecutedAddresses = new HashSet(); @@ -598,9 +597,7 @@ namespace Mesen.GUI.Debugger private void AddWatch() { - if(this.OnWatchAdded != null) { - this.OnWatchAdded(new WatchEventArgs() { WatchValue = _newWatchValue }); - } + WatchManager.AddWatch(_newWatchValue); } private void mnuSetNextStatement_Click(object sender, EventArgs e) diff --git a/GUI.NET/Debugger/Controls/ctrlHexViewer.cs b/GUI.NET/Debugger/Controls/ctrlHexViewer.cs index 33375d97..05929f19 100644 --- a/GUI.NET/Debugger/Controls/ctrlHexViewer.cs +++ b/GUI.NET/Debugger/Controls/ctrlHexViewer.cs @@ -55,11 +55,17 @@ namespace Mesen.GUI.Debugger.Controls } if(changed) { + bool needInit = _byteProvider == null; _byteProvider = new StaticByteProvider(data); _byteProvider.ByteChanged += (int byteIndex, byte newValue, byte oldValue) => { ByteChanged?.Invoke(byteIndex, newValue, oldValue); }; + this.ctrlHexBox.ByteProvider = _byteProvider; + + if(needInit) { + InitializeContextMenu?.Invoke(this.ctrlHexBox, EventArgs.Empty); + } } } } @@ -280,6 +286,7 @@ namespace Mesen.GUI.Debugger.Controls remove { this.ctrlHexBox.RequiredWidthChanged -= value; } } + public event EventHandler InitializeContextMenu; public event ByteChangedHandler ByteChanged; [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] diff --git a/GUI.NET/Debugger/Controls/ctrlWatch.Designer.cs b/GUI.NET/Debugger/Controls/ctrlWatch.Designer.cs index 94f68a85..078713c9 100644 --- a/GUI.NET/Debugger/Controls/ctrlWatch.Designer.cs +++ b/GUI.NET/Debugger/Controls/ctrlWatch.Designer.cs @@ -16,6 +16,7 @@ if(disposing && (components != null)) { components.Dispose(); } + WatchManager.WatchChanged -= WatchManager_WatchChanged; base.Dispose(disposing); } @@ -29,13 +30,14 @@ { this.components = new System.ComponentModel.Container(); System.Windows.Forms.ListViewItem listViewItem1 = new System.Windows.Forms.ListViewItem(""); - this.lstWatch = new Mesen.GUI.Controls.MyListView(); + this.lstWatch = new Mesen.GUI.Controls.WatchList(); this.columnHeader1 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); this.columnHeader2 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); this.colLastColumn = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); this.contextMenuWatch = new System.Windows.Forms.ContextMenuStrip(this.components); this.mnuRemoveWatch = new System.Windows.Forms.ToolStripMenuItem(); this.mnuHexDisplay = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStripMenuItem1 = new System.Windows.Forms.ToolStripSeparator(); this.contextMenuWatch.SuspendLayout(); this.SuspendLayout(); // @@ -59,8 +61,7 @@ this.lstWatch.TabIndex = 6; this.lstWatch.UseCompatibleStateImageBehavior = false; this.lstWatch.View = System.Windows.Forms.View.Details; - this.lstWatch.BeforeLabelEdit += new System.Windows.Forms.LabelEditEventHandler(this.lstWatch_BeforeLabelEdit); - this.lstWatch.AfterLabelEdit += new System.Windows.Forms.LabelEditEventHandler(this.lstWatch_AfterLabelEdit); + this.lstWatch.AfterEdit += new System.Windows.Forms.LabelEditEventHandler(this.lstWatch_AfterEdit); this.lstWatch.SelectedIndexChanged += new System.EventHandler(this.lstWatch_SelectedIndexChanged); this.lstWatch.Click += new System.EventHandler(this.lstWatch_Click); this.lstWatch.DoubleClick += new System.EventHandler(this.lstWatch_DoubleClick); @@ -83,14 +84,16 @@ // this.contextMenuWatch.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { this.mnuRemoveWatch, + this.toolStripMenuItem1, this.mnuHexDisplay}); this.contextMenuWatch.Name = "contextMenuWatch"; - this.contextMenuWatch.Size = new System.Drawing.Size(184, 48); + this.contextMenuWatch.Size = new System.Drawing.Size(184, 76); // // mnuRemoveWatch // this.mnuRemoveWatch.Name = "mnuRemoveWatch"; - this.mnuRemoveWatch.ShortcutKeyDisplayString = "Del"; + this.mnuRemoveWatch.ShortcutKeyDisplayString = ""; + this.mnuRemoveWatch.ShortcutKeys = System.Windows.Forms.Keys.Delete; this.mnuRemoveWatch.Size = new System.Drawing.Size(183, 22); this.mnuRemoveWatch.Text = "Remove"; this.mnuRemoveWatch.Click += new System.EventHandler(this.mnuRemoveWatch_Click); @@ -105,6 +108,11 @@ this.mnuHexDisplay.Text = "Hexadecimal Display"; this.mnuHexDisplay.Click += new System.EventHandler(this.mnuHexDisplay_Click); // + // toolStripMenuItem1 + // + this.toolStripMenuItem1.Name = "toolStripMenuItem1"; + this.toolStripMenuItem1.Size = new System.Drawing.Size(180, 6); + // // ctrlWatch // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); @@ -119,12 +127,13 @@ #endregion - private Mesen.GUI.Controls.MyListView lstWatch; + private Mesen.GUI.Controls.WatchList lstWatch; private System.Windows.Forms.ColumnHeader columnHeader1; private System.Windows.Forms.ColumnHeader columnHeader2; private System.Windows.Forms.ContextMenuStrip contextMenuWatch; private System.Windows.Forms.ToolStripMenuItem mnuRemoveWatch; private System.Windows.Forms.ToolStripMenuItem mnuHexDisplay; private System.Windows.Forms.ColumnHeader colLastColumn; + private System.Windows.Forms.ToolStripSeparator toolStripMenuItem1; } } diff --git a/GUI.NET/Debugger/Controls/ctrlWatch.cs b/GUI.NET/Debugger/Controls/ctrlWatch.cs index f74c853d..861d27ff 100644 --- a/GUI.NET/Debugger/Controls/ctrlWatch.cs +++ b/GUI.NET/Debugger/Controls/ctrlWatch.cs @@ -14,6 +14,8 @@ namespace Mesen.GUI.Debugger { public partial class ctrlWatch : BaseControl { + private int _currentSelection = -1; + public ctrlWatch() { InitializeComponent(); @@ -23,9 +25,15 @@ namespace Mesen.GUI.Debugger bool designMode = (LicenseManager.UsageMode == LicenseUsageMode.Designtime); if(!designMode) { this.mnuHexDisplay.Checked = ConfigManager.Config.DebugInfo.HexDisplay; + WatchManager.WatchChanged += WatchManager_WatchChanged; } } + private void WatchManager_WatchChanged(object sender, EventArgs e) + { + this.UpdateWatch(); + } + protected override void OnLoad(EventArgs e) { base.OnLoad(e); @@ -58,96 +66,36 @@ namespace Mesen.GUI.Debugger lstWatch.ColumnWidthChanged += lstWatch_ColumnWidthChanged; } - public List GetWatchValues() - { - List watchValues = new List(); - foreach(ListViewItem listView in lstWatch.Items) { - watchValues.Add(listView.Text); - } - return watchValues; - } - - public void SetWatchValues(List watchValues) + public void UpdateWatch() { + lstWatch.BeginUpdate(); lstWatch.Items.Clear(); - foreach(string watchValue in watchValues) { - lstWatch.Items.Add(watchValue).SubItems.Add(""); - } - UpdateWatch(); - } - public void UpdateWatch(int currentSelection = -1) - { - lstWatch.SelectedIndices.Clear(); - - //Remove empty items - for(int i = lstWatch.Items.Count - 1; i >= 0; i--) { - if(string.IsNullOrWhiteSpace(lstWatch.Items[i].Text)) { - lstWatch.Items.RemoveAt(i); - } - } - lstWatch.Items.Add("").SubItems.Add(""); - - ListViewItem lastItem = lstWatch.Items[lstWatch.Items.Count - 1]; - foreach(ListViewItem item in lstWatch.Items) { + List itemsToAdd = new List(); + foreach(WatchValueInfo watch in WatchManager.GetWatchContent(mnuHexDisplay.Checked)) { + ListViewItem item = new ListViewItem(watch.Expression); item.UseItemStyleForSubItems = false; - if(item != lastItem) { - string previousValue = null; - if(item.SubItems.Count > 1) { - previousValue = item.SubItems[1].Text; - } - - string newValue = ""; - EvalResultType resultType; - Int32 result = InteropEmu.DebugEvaluateExpression(item.Text, out resultType); - - switch(resultType) { - case EvalResultType.Numeric: - if(mnuHexDisplay.Checked) { - newValue = "$" + result.ToString("X"); - } else { - newValue = result.ToString(); - } - break; - case EvalResultType.Boolean: - newValue = result == 0 ? "false" : "true"; - break; - - case EvalResultType.Invalid: - newValue = ""; - break; - } - - if(previousValue != newValue) { - item.SubItems[1].Text = newValue; - item.SubItems[1].ForeColor = Color.Red; - } else { - item.SubItems[1].ForeColor = Color.Black; - } - } + item.SubItems.Add(watch.Value).ForeColor = watch.HasChanged ? Color.Red : Color.Black; + itemsToAdd.Add(item); } + var lastItem = new ListViewItem(""); + lastItem.SubItems.Add(""); + itemsToAdd.Add(lastItem); + lstWatch.Items.AddRange(itemsToAdd.ToArray()); AdjustColumnWidth(); + lstWatch.EndUpdate(); - if(currentSelection >= 0 && lstWatch.Items.Count > currentSelection) { - lstWatch.FocusedItem = lstWatch.Items[currentSelection]; - lstWatch.Items[currentSelection].Selected = true; + if(_currentSelection >= 0 && lstWatch.Items.Count > _currentSelection) { + lstWatch.FocusedItem = lstWatch.Items[_currentSelection]; + lstWatch.Items[_currentSelection].Selected = true; + _currentSelection = -1; } } - - public void AddWatch(string watchValue) + + private void lstWatch_AfterEdit(object sender, LabelEditEventArgs e) { - ListViewItem item = lstWatch.Items.Insert(lstWatch.Items.Count - 1, watchValue); - item.SubItems.Add(""); - UpdateWatch(); - } - - private void lstWatch_BeforeLabelEdit(object sender, LabelEditEventArgs e) - { - } - - private void lstWatch_AfterLabelEdit(object sender, LabelEditEventArgs e) - { - this.BeginInvoke((MethodInvoker)(() => { this.UpdateWatch(e.Item); })); + _currentSelection = e.Item; + WatchManager.UpdateWatch(e.Item, e.Label); } private void mnuHexDisplay_Click(object sender, EventArgs e) @@ -179,14 +127,14 @@ namespace Mesen.GUI.Debugger private void mnuRemoveWatch_Click(object sender, EventArgs e) { if(lstWatch.SelectedItems.Count >= 1) { - var itemsToRemove = new List(); + var itemsToRemove = new List(); foreach(ListViewItem item in lstWatch.SelectedItems) { - itemsToRemove.Add(item); + if(_currentSelection == -1) { + _currentSelection = item.Index; + } + itemsToRemove.Add(item.Index); } - foreach(ListViewItem item in itemsToRemove) { - lstWatch.Items.Remove(item); - } - UpdateWatch(); + WatchManager.RemoveWatch(itemsToRemove.ToArray()); } } } diff --git a/GUI.NET/Debugger/HexBox/HexBox.cs b/GUI.NET/Debugger/HexBox/HexBox.cs index fda840f0..a5e209b2 100644 --- a/GUI.NET/Debugger/HexBox/HexBox.cs +++ b/GUI.NET/Debugger/HexBox/HexBox.cs @@ -1792,10 +1792,6 @@ namespace Be.Windows.Forms System.Diagnostics.Debug.WriteLine("CreateCaret()", "HexBox"); - // define the caret width depending on InsertActive mode - int caretWidth = (this.InsertActive) ? 1 : (int)_charSize.Width; - int caretHeight = (int)_charSize.Height; - UpdateCaret(); _caretVisible = true; @@ -1818,13 +1814,18 @@ namespace Be.Windows.Forms void DestroyCaret() { - if (!_caretVisible) - return; + //Never hide caret + return; + } - System.Diagnostics.Debug.WriteLine("DestroyCaret()", "HexBox"); - - _caretVisible = false; - this.Invalidate(); + BytePositionInfo? GetBytePositionInfo(Point p) + { + if(_recHex.Contains(p)) { + return GetHexBytePositionInfo(p); + } else if(_recStringView.Contains(p) || p.X > _recStringView.Right) { + return GetStringBytePositionInfo(p); + } + return null; } void SetCaretPosition(Point p) @@ -1837,6 +1838,8 @@ namespace Be.Windows.Forms long pos = _bytePos; int cp = _byteCharacterPos; + CreateCaret(); + if (_recHex.Contains(p)) { BytePositionInfo bpi = GetHexBytePositionInfo(p); @@ -2644,7 +2647,7 @@ namespace Be.Windows.Forms skipCount = keyLength - 1; } - float width = (float)Math.Ceiling(g.MeasureString(s, Font, 100, _stringFormat).Width); + float width = (float)Math.Ceiling(g.MeasureString(s, Font, 1000, _stringFormat).Width); float xPos = byteStringPointF.X+xOffset; _xPosCache[gridPoint] = xPos; _xPosList[gridPoint.Y].Add(xPos); @@ -3064,12 +3067,13 @@ namespace Be.Windows.Forms } set { - if (value == null) - return; - + if(value == null) + return; + base.Font = value; - this.UpdateRectanglePositioning(); - this.Invalidate(); + this.UpdateRectanglePositioning(); + this.UpdateCaret(); + this.Invalidate(); } } @@ -4065,8 +4069,21 @@ namespace Be.Windows.Forms if (!Focused) Focus(); - if (e.Button == MouseButtons.Left) + BytePositionInfo? bpi = GetBytePositionInfo(new Point(e.X, e.Y)); + bool insideSelection = false; + if(bpi.HasValue) { + if(_bytePos <= bpi.Value.Index && _bytePos + _selectionLength >= bpi.Value.Index) { + //Clicked inside selection + insideSelection = true; + } + } + + if(!insideSelection || e.Button == MouseButtons.Left) { + if(e.Button != MouseButtons.Left) { + _selectionLength = 0; + } SetCaretPosition(new Point(e.X, e.Y)); + } base.OnMouseDown(e); } diff --git a/GUI.NET/Debugger/WatchManager.cs b/GUI.NET/Debugger/WatchManager.cs new file mode 100644 index 00000000..d54bdf01 --- /dev/null +++ b/GUI.NET/Debugger/WatchManager.cs @@ -0,0 +1,84 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Mesen.GUI.Debugger +{ + class WatchManager + { + public static event EventHandler WatchChanged; + private static List _watchEntries = new List(); + private static List _previousValues = new List(); + + public static List WatchEntries + { + get { return _watchEntries; } + set + { + _watchEntries = value; + WatchChanged?.Invoke(null, EventArgs.Empty); + } + } + + public static List GetWatchContent(bool useHex) + { + var list = new List(); + for(int i = 0; i < _watchEntries.Count; i++) { + string expression = _watchEntries[i]; + string newValue = ""; + EvalResultType resultType; + Int32 result = InteropEmu.DebugEvaluateExpression(expression, out resultType); + bool forceHasChanged = false; + switch(resultType) { + case EvalResultType.Numeric: newValue = useHex ? ("$" + result.ToString("X2")) : result.ToString(); break; + case EvalResultType.Boolean: newValue = result == 0 ? "false" : "true"; break; + case EvalResultType.Invalid: newValue = ""; forceHasChanged = true; break; + } + + list.Add(new WatchValueInfo() { Expression = expression, Value = newValue, HasChanged = forceHasChanged || (i < _previousValues.Count ? (_previousValues[i].Value != newValue) : false) }); + } + + _previousValues = list; + return list; + } + + public static void AddWatch(params string[] expressions) + { + foreach(string expression in expressions) { + _watchEntries.Add(expression); + } + WatchChanged?.Invoke(null, EventArgs.Empty); + } + + public static void UpdateWatch(int index, string expression) + { + if(string.IsNullOrWhiteSpace(expression)) { + RemoveWatch(index); + } else { + if(index >= _watchEntries.Count) { + _watchEntries.Add(expression); + } else { + _watchEntries[index] = expression; + } + WatchChanged?.Invoke(null, EventArgs.Empty); + } + } + + public static void RemoveWatch(params int[] indexes) + { + HashSet set = new HashSet(indexes); + _watchEntries = _watchEntries.Where((el, index) => !set.Contains(index)).ToList(); + _previousValues = _previousValues.Where((el, index) => !set.Contains(index)).ToList(); + WatchChanged?.Invoke(null, EventArgs.Empty); + } + } + + public class WatchValueInfo + { + public string Expression { get; set; } + public string Value { get; set; } + public bool HasChanged { get; set; } + } +} diff --git a/GUI.NET/Debugger/frmDebugger.Designer.cs b/GUI.NET/Debugger/frmDebugger.Designer.cs index a65103b2..438a27f6 100644 --- a/GUI.NET/Debugger/frmDebugger.Designer.cs +++ b/GUI.NET/Debugger/frmDebugger.Designer.cs @@ -243,7 +243,6 @@ namespace Mesen.GUI.Debugger this.ctrlDebuggerCode.Name = "ctrlDebuggerCode"; this.ctrlDebuggerCode.Size = new System.Drawing.Size(510, 384); this.ctrlDebuggerCode.TabIndex = 2; - this.ctrlDebuggerCode.OnWatchAdded += new Mesen.GUI.Debugger.ctrlDebuggerCode.WatchEventHandler(this.ctrlDebuggerCode_OnWatchAdded); this.ctrlDebuggerCode.OnSetNextStatement += new Mesen.GUI.Debugger.ctrlDebuggerCode.AddressEventHandler(this.ctrlDebuggerCode_OnSetNextStatement); this.ctrlDebuggerCode.Enter += new System.EventHandler(this.ctrlDebuggerCode_Enter); // @@ -266,7 +265,6 @@ namespace Mesen.GUI.Debugger this.ctrlDebuggerCodeSplit.Size = new System.Drawing.Size(1, 384); this.ctrlDebuggerCodeSplit.TabIndex = 4; this.ctrlDebuggerCodeSplit.Visible = false; - this.ctrlDebuggerCodeSplit.OnWatchAdded += new Mesen.GUI.Debugger.ctrlDebuggerCode.WatchEventHandler(this.ctrlDebuggerCode_OnWatchAdded); this.ctrlDebuggerCodeSplit.OnSetNextStatement += new Mesen.GUI.Debugger.ctrlDebuggerCode.AddressEventHandler(this.ctrlDebuggerCode_OnSetNextStatement); this.ctrlDebuggerCodeSplit.Enter += new System.EventHandler(this.ctrlDebuggerCodeSplit_Enter); // diff --git a/GUI.NET/Debugger/frmDebugger.cs b/GUI.NET/Debugger/frmDebugger.cs index ae326500..20862e22 100644 --- a/GUI.NET/Debugger/frmDebugger.cs +++ b/GUI.NET/Debugger/frmDebugger.cs @@ -148,7 +148,7 @@ namespace Mesen.GUI.Debugger private void SaveWorkspace() { if(_workspace != null) { - _workspace.WatchValues = ctrlWatch.GetWatchValues(); + _workspace.WatchValues = WatchManager.WatchEntries; _workspace.Labels = LabelManager.GetLabels(); _workspace.Breakpoints = BreakpointManager.Breakpoints; _workspace.Save(); @@ -176,7 +176,7 @@ namespace Mesen.GUI.Debugger ctrlLabelList.UpdateLabelList(); ctrlFunctionList.UpdateFunctionList(true); - ctrlWatch.SetWatchValues(_workspace.WatchValues); + WatchManager.WatchEntries = _workspace.WatchValues; BreakpointManager.Breakpoints.Clear(); BreakpointManager.Breakpoints.AddRange(_workspace.Breakpoints); @@ -418,11 +418,6 @@ namespace Mesen.GUI.Debugger InteropEmu.DebugPpuStep(89341); } - private void ctrlDebuggerCode_OnWatchAdded(WatchEventArgs args) - { - this.ctrlWatch.AddWatch(args.WatchValue); - } - private void ctrlDebuggerCode_OnSetNextStatement(AddressEventArgs args) { UInt16 addr = (UInt16)args.Address; diff --git a/GUI.NET/Debugger/frmMemoryViewer.Designer.cs b/GUI.NET/Debugger/frmMemoryViewer.Designer.cs index 63c97018..d458f711 100644 --- a/GUI.NET/Debugger/frmMemoryViewer.Designer.cs +++ b/GUI.NET/Debugger/frmMemoryViewer.Designer.cs @@ -98,6 +98,7 @@ this.ctrlHexViewer.Size = new System.Drawing.Size(665, 346); this.ctrlHexViewer.TabIndex = 0; this.ctrlHexViewer.RequiredWidthChanged += new System.EventHandler(this.ctrlHexViewer_RequiredWidthChanged); + this.ctrlHexViewer.InitializeContextMenu += new System.EventHandler(this.ctrlHexViewer_InitializeContextMenu); this.ctrlHexViewer.ByteChanged += new Be.Windows.Forms.DynamicByteProvider.ByteChangedHandler(this.ctrlHexViewer_ByteChanged); // // flowLayoutPanel1 @@ -244,27 +245,27 @@ // this.mnuHightlightReads.CheckOnClick = true; this.mnuHightlightReads.Name = "mnuHightlightReads"; - this.mnuHightlightReads.Size = new System.Drawing.Size(152, 22); + this.mnuHightlightReads.Size = new System.Drawing.Size(133, 22); this.mnuHightlightReads.Text = "Reads"; // // mnuHighlightWrites // this.mnuHighlightWrites.CheckOnClick = true; this.mnuHighlightWrites.Name = "mnuHighlightWrites"; - this.mnuHighlightWrites.Size = new System.Drawing.Size(152, 22); + this.mnuHighlightWrites.Size = new System.Drawing.Size(133, 22); this.mnuHighlightWrites.Text = "Writes"; // // mnuHighlightExecution // this.mnuHighlightExecution.CheckOnClick = true; this.mnuHighlightExecution.Name = "mnuHighlightExecution"; - this.mnuHighlightExecution.Size = new System.Drawing.Size(152, 22); + this.mnuHighlightExecution.Size = new System.Drawing.Size(133, 22); this.mnuHighlightExecution.Text = "Execution"; // // toolStripMenuItem6 // this.toolStripMenuItem6.Name = "toolStripMenuItem6"; - this.toolStripMenuItem6.Size = new System.Drawing.Size(149, 6); + this.toolStripMenuItem6.Size = new System.Drawing.Size(130, 6); // // fadeSpeedToolStripMenuItem // @@ -275,13 +276,13 @@ this.toolStripMenuItem7, this.mnuCustomFadeSpeed}); this.fadeSpeedToolStripMenuItem.Name = "fadeSpeedToolStripMenuItem"; - this.fadeSpeedToolStripMenuItem.Size = new System.Drawing.Size(152, 22); + this.fadeSpeedToolStripMenuItem.Size = new System.Drawing.Size(133, 22); this.fadeSpeedToolStripMenuItem.Text = "Fade speed"; // // mnuFadeSlow // this.mnuFadeSlow.Name = "mnuFadeSlow"; - this.mnuFadeSlow.Size = new System.Drawing.Size(152, 22); + this.mnuFadeSlow.Size = new System.Drawing.Size(125, 22); this.mnuFadeSlow.Text = "Slow"; this.mnuFadeSlow.Click += new System.EventHandler(this.mnuFadeSpeed_Click); // @@ -290,26 +291,26 @@ this.mnuFadeNormal.Checked = true; this.mnuFadeNormal.CheckState = System.Windows.Forms.CheckState.Checked; this.mnuFadeNormal.Name = "mnuFadeNormal"; - this.mnuFadeNormal.Size = new System.Drawing.Size(152, 22); + this.mnuFadeNormal.Size = new System.Drawing.Size(125, 22); this.mnuFadeNormal.Text = "Normal"; this.mnuFadeNormal.Click += new System.EventHandler(this.mnuFadeSpeed_Click); // // mnuFadeFast // this.mnuFadeFast.Name = "mnuFadeFast"; - this.mnuFadeFast.Size = new System.Drawing.Size(152, 22); + this.mnuFadeFast.Size = new System.Drawing.Size(125, 22); this.mnuFadeFast.Text = "Fast"; this.mnuFadeFast.Click += new System.EventHandler(this.mnuFadeSpeed_Click); // // toolStripMenuItem7 // this.toolStripMenuItem7.Name = "toolStripMenuItem7"; - this.toolStripMenuItem7.Size = new System.Drawing.Size(149, 6); + this.toolStripMenuItem7.Size = new System.Drawing.Size(122, 6); // // mnuCustomFadeSpeed // this.mnuCustomFadeSpeed.Name = "mnuCustomFadeSpeed"; - this.mnuCustomFadeSpeed.Size = new System.Drawing.Size(152, 22); + this.mnuCustomFadeSpeed.Size = new System.Drawing.Size(125, 22); this.mnuCustomFadeSpeed.Text = "Custom..."; this.mnuCustomFadeSpeed.Click += new System.EventHandler(this.mnuCustomFadeSpeed_Click); // diff --git a/GUI.NET/Debugger/frmMemoryViewer.cs b/GUI.NET/Debugger/frmMemoryViewer.cs index b891990a..f24b8093 100644 --- a/GUI.NET/Debugger/frmMemoryViewer.cs +++ b/GUI.NET/Debugger/frmMemoryViewer.cs @@ -12,6 +12,7 @@ using Mesen.GUI.Config; using Mesen.GUI.Forms; using Mesen.GUI.Controls; using Be.Windows.Forms; +using Mesen.GUI.Debugger.Controls; namespace Mesen.GUI.Debugger { @@ -305,5 +306,119 @@ namespace Mesen.GUI.Debugger } } } + + private AddressType? GetAddressType() + { + switch(_memoryType) { + case DebugMemoryType.InternalRam: return AddressType.InternalRam; + case DebugMemoryType.WorkRam: return AddressType.WorkRam; + case DebugMemoryType.SaveRam: return AddressType.SaveRam; + case DebugMemoryType.PrgRom: return AddressType.PrgRom; + } + + return null; + } + + private void ctrlHexViewer_InitializeContextMenu(object sender, EventArgs evt) + { + HexBox hexBox = (HexBox)sender; + + var mnuEditLabel = new ToolStripMenuItem(); + mnuEditLabel.Click += (s, e) => { + UInt32 address = (UInt32)hexBox.SelectionStart; + if(this._memoryType == DebugMemoryType.CpuMemory) { + AddressTypeInfo info = new AddressTypeInfo(); + InteropEmu.DebugGetAbsoluteAddressAndType(address, ref info); + ctrlLabelList.EditLabel((UInt32)info.Address, info.Type); + } else { + ctrlLabelList.EditLabel(address, GetAddressType().Value); + } + }; + + var mnuEditBreakpoint = new ToolStripMenuItem(); + mnuEditBreakpoint.Click += (s, e) => { + UInt32 startAddress = (UInt32)hexBox.SelectionStart; + UInt32 endAddress = (UInt32)(hexBox.SelectionStart + (hexBox.SelectionLength == 0 ? 0 : (hexBox.SelectionLength - 1))); + BreakpointAddressType addressType = startAddress == endAddress ? BreakpointAddressType.SingleAddress : BreakpointAddressType.AddressRange; + + Breakpoint bp = BreakpointManager.GetMatchingBreakpoint(startAddress, endAddress, this._memoryType == DebugMemoryType.PpuMemory); + if(bp == null) { + bp = new Breakpoint() { Address = startAddress, StartAddress = startAddress, EndAddress = endAddress, AddressType = addressType, IsAbsoluteAddress = false }; + if(this._memoryType == DebugMemoryType.CpuMemory) { + bp.BreakOnWrite = bp.BreakOnRead = true; + } else { + bp.BreakOnWriteVram = bp.BreakOnReadVram = true; + } + } + BreakpointManager.EditBreakpoint(bp); + }; + + var mnuAddWatch = new ToolStripMenuItem(); + mnuAddWatch.Click += (s, e) => { + UInt32 startAddress = (UInt32)hexBox.SelectionStart; + UInt32 endAddress = (UInt32)(hexBox.SelectionStart + (hexBox.SelectionLength == 0 ? 0 : (hexBox.SelectionLength - 1))); + string[] toAdd = Enumerable.Range((int)startAddress, (int)(endAddress - startAddress + 1)).Select((num) => $"[${num.ToString("X4")}]").ToArray(); + WatchManager.AddWatch(toAdd); + }; + + var mnuFreeze = new ToolStripMenuItem(); + mnuFreeze.Click += (s, e) => { + UInt32 startAddress = (UInt32)hexBox.SelectionStart; + UInt32 endAddress = (UInt32)(hexBox.SelectionStart + (hexBox.SelectionLength == 0 ? 0 : (hexBox.SelectionLength - 1))); + + for(UInt32 i = startAddress; i <= endAddress; i++) { + InteropEmu.DebugSetFreezeState((UInt16)i, (bool)mnuFreeze.Tag); + } + }; + + hexBox.ContextMenuStrip.Opening += (s, e) => { + UInt32 startAddress = (UInt32)hexBox.SelectionStart; + UInt32 endAddress = (UInt32)(hexBox.SelectionStart + (hexBox.SelectionLength == 0 ? 0 : (hexBox.SelectionLength - 1))); + + string address = "$" + startAddress.ToString("X4"); + string addressRange; + if(startAddress != endAddress) { + addressRange = "$" + startAddress.ToString("X4") + "-$" + endAddress.ToString("X4"); + } else { + addressRange = address; + } + + mnuEditLabel.Text = $"Edit Label ({address})"; + mnuEditBreakpoint.Text = $"Edit Breakpoint ({addressRange})"; + mnuAddWatch.Text = $"Add to Watch ({addressRange})"; + + if(this._memoryType == DebugMemoryType.CpuMemory) { + bool[] freezeState = InteropEmu.DebugGetFreezeState((UInt16)startAddress, (UInt16)(endAddress - startAddress + 1)); + if(freezeState.All((frozen) => frozen)) { + mnuFreeze.Text = $"Unfreeze ({addressRange})"; + mnuFreeze.Tag = false; + } else { + mnuFreeze.Text = $"Freeze ({addressRange})"; + mnuFreeze.Tag = true; + } + } else { + mnuFreeze.Text = $"Freeze"; + mnuFreeze.Tag = false; + } + + bool disableEditLabel = false; + if(this._memoryType == DebugMemoryType.CpuMemory) { + AddressTypeInfo info = new AddressTypeInfo(); + InteropEmu.DebugGetAbsoluteAddressAndType(startAddress, ref info); + disableEditLabel = info.Address == -1; + } + + mnuEditLabel.Enabled = !disableEditLabel && (this._memoryType == DebugMemoryType.CpuMemory || this.GetAddressType().HasValue); + mnuEditBreakpoint.Enabled = this._memoryType == DebugMemoryType.CpuMemory || this._memoryType == DebugMemoryType.PpuMemory; + mnuAddWatch.Enabled = this._memoryType == DebugMemoryType.CpuMemory; + mnuFreeze.Enabled = this._memoryType == DebugMemoryType.CpuMemory; + }; + + hexBox.ContextMenuStrip.Items.Insert(0, new ToolStripSeparator()); + hexBox.ContextMenuStrip.Items.Insert(0, mnuFreeze); + hexBox.ContextMenuStrip.Items.Insert(0, mnuEditLabel); + hexBox.ContextMenuStrip.Items.Insert(0, mnuEditBreakpoint); + hexBox.ContextMenuStrip.Items.Insert(0, mnuAddWatch); + } } } diff --git a/GUI.NET/GUI.NET.csproj b/GUI.NET/GUI.NET.csproj index e017127a..c0fa4147 100644 --- a/GUI.NET/GUI.NET.csproj +++ b/GUI.NET/GUI.NET.csproj @@ -468,6 +468,7 @@ + BaseConfigForm.cs diff --git a/GUI.NET/InteropEmu.cs b/GUI.NET/InteropEmu.cs index 4bf96acd..af7064ba 100644 --- a/GUI.NET/InteropEmu.cs +++ b/GUI.NET/InteropEmu.cs @@ -191,6 +191,8 @@ namespace Mesen.GUI [DllImport(DLLPath)] public static extern void DebugGetAbsoluteAddressAndType(UInt32 relativeAddr, ref AddressTypeInfo addressTypeInfo); [DllImport(DLLPath)] public static extern void DebugSetPpuViewerScanlineCycle(Int32 scanline, Int32 cycle); + [DllImport(DLLPath)] public static extern void DebugSetFreezeState(UInt16 address, [MarshalAs(UnmanagedType.I1)]bool frozen); + [DllImport(DLLPath)] public static extern void DebugSetNextStatement(UInt16 addr); [DllImport(DLLPath)] public static extern Int32 DebugEvaluateExpression([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(UTF8Marshaler))]string expression, out EvalResultType resultType); @@ -364,6 +366,21 @@ namespace Mesen.GUI return stamps; } + [DllImport(DLLPath, EntryPoint= "DebugGetFreezeState")] private static extern void DebugGetFreezeStateWrapper(UInt16 startAddress, UInt16 length, IntPtr freezeState); + public static bool[] DebugGetFreezeState(UInt16 startAddress, UInt16 length) + { + bool[] freezeState = new bool[length]; + + GCHandle hFreezeState = GCHandle.Alloc(freezeState, GCHandleType.Pinned); + try { + InteropEmu.DebugGetFreezeStateWrapper(startAddress, length, hFreezeState.AddrOfPinnedObject()); + } finally { + hFreezeState.Free(); + } + + return freezeState; + } + [DllImport(DLLPath, EntryPoint="DebugGetCallstack")] private static extern void DebugGetCallstackWrapper(IntPtr callstackAbsolute, IntPtr callstackRelative); public static void DebugGetCallstack(out Int32[] callstackAbsolute, out Int32[] callstackRelative) { diff --git a/InteropDLL/DebugWrapper.cpp b/InteropDLL/DebugWrapper.cpp index 9dab672b..0ac928a7 100644 --- a/InteropDLL/DebugWrapper.cpp +++ b/InteropDLL/DebugWrapper.cpp @@ -85,7 +85,9 @@ extern "C" DllExport void __stdcall DebugGetProfilerData(int64_t* profilerData, ProfilerDataType dataType) { GetDebugger()->GetProfiler()->GetProfilerData(profilerData, dataType); } DllExport void __stdcall DebugResetProfiler() { GetDebugger()->GetProfiler()->Reset(); } - + + DllExport void __stdcall DebugSetFreezeState(uint16_t address, bool frozen) { GetDebugger()->SetFreezeState(address, frozen); } + DllExport void __stdcall DebugGetFreezeState(uint16_t startAddress, uint16_t length, bool* freezeState) { GetDebugger()->GetFreezeState(startAddress, length, freezeState); } DllExport uint32_t __stdcall DebugGetPpuScroll() { return GetDebugger()->GetPpuScroll(); } };