From 42d9fb0ea175645a4fc74f2636fe9a28404299ff Mon Sep 17 00:00:00 2001 From: Souryo Date: Sat, 26 Nov 2016 14:15:50 -0500 Subject: [PATCH] Debugger: Fixed flickering lists, performance improvements, etc. --- Core/Disassembler.cpp | 21 ++--- GUI.NET/Controls/MyListView.cs | 13 +++ GUI.NET/Debugger/Controls/ctrlBreakpoints.cs | 1 - .../Controls/ctrlCallstack.Designer.cs | 4 +- GUI.NET/Debugger/Controls/ctrlCallstack.cs | 86 ++++++++++++++----- .../Controls/ctrlConsoleStatus.Designer.cs | 4 +- .../Debugger/Controls/ctrlConsoleStatus.cs | 22 ++--- GUI.NET/Debugger/Controls/ctrlDebuggerCode.cs | 14 +-- .../Controls/ctrlFunctionList.Designer.cs | 4 +- GUI.NET/Debugger/Controls/ctrlFunctionList.cs | 84 ++++++++++++------ .../Controls/ctrlLabelList.Designer.cs | 4 +- GUI.NET/Debugger/Controls/ctrlLabelList.cs | 39 ++++++++- GUI.NET/Debugger/Controls/ctrlTextbox.cs | 49 +++++------ GUI.NET/Debugger/Controls/ctrlWatch.cs | 14 ++- GUI.NET/Debugger/frmDebugger.cs | 23 +++-- 15 files changed, 258 insertions(+), 124 deletions(-) diff --git a/Core/Disassembler.cpp b/Core/Disassembler.cpp index b70da252..1c8f21f3 100644 --- a/Core/Disassembler.cpp +++ b/Core/Disassembler.cpp @@ -191,7 +191,7 @@ vector Disassembler::SplitComment(string input) string Disassembler::GetLine(string code, string comment, int32_t cpuAddress, int32_t absoluteAddress, string byteCode, string addressing) { string out; - out.reserve(50); + out.reserve(100); if(cpuAddress >= 0) { out += HexUtilities::ToHex((uint16_t)cpuAddress); } @@ -226,8 +226,8 @@ string Disassembler::GetCode(uint32_t startAddr, uint32_t endAddr, uint16_t memo string output; output.reserve(10000000); - int32_t dbRelativeAddr; - int32_t dbAbsoluteAddr; + int32_t dbRelativeAddr = 0; + int32_t dbAbsoluteAddr = 0; string dbBuffer; uint16_t resetVector = memoryManager->DebugReadWord(CPU::ResetVector); @@ -314,7 +314,7 @@ string Disassembler::GetCode(uint32_t startAddr, uint32_t endAddr, uint16_t memo } if(!showOnlyDiassembledCode) { - if(byteCount >= 8 || !label.empty() || !commentString.empty()) { + if(byteCount >= 8 || ((!label.empty() || !commentString.empty()) && byteCount > 0)) { output += GetLine(dbBuffer, "", dbRelativeAddr, dbAbsoluteAddr); byteCount = 0; } @@ -332,20 +332,21 @@ string Disassembler::GetCode(uint32_t startAddr, uint32_t endAddr, uint16_t memo if(!label.empty() || !commentString.empty()) { output += GetLine(dbBuffer, commentString, dbRelativeAddr, dbAbsoluteAddr); + byteCount = 0; + } else { + byteCount++; } - - byteCount++; } addr++; memoryAddr++; } } + if(byteCount > 0) { + output += GetLine(dbBuffer, "", dbRelativeAddr, dbAbsoluteAddr); + } + if(skippingCode) { - if(showOnlyDiassembledCode && byteCount > 0) { - output += GetLine(dbBuffer, "", dbRelativeAddr, dbAbsoluteAddr); - } - output += GetLine("----", "", (uint16_t)(memoryAddr - 1), addr - 1); } diff --git a/GUI.NET/Controls/MyListView.cs b/GUI.NET/Controls/MyListView.cs index 48f6a163..ab4ac6db 100644 --- a/GUI.NET/Controls/MyListView.cs +++ b/GUI.NET/Controls/MyListView.cs @@ -15,6 +15,11 @@ namespace Mesen.GUI.Controls private int _editItemIndex = -1; private string _originalText = null; + public MyListView() + { + this.DoubleBuffered = true; + } + public bool IsEditing { get { return _editItemIndex >= 0; } @@ -96,4 +101,12 @@ namespace Mesen.GUI.Controls base.OnKeyPress(e); } } + + public class DoubleBufferedListView : ListView + { + public DoubleBufferedListView() + { + this.DoubleBuffered = true; + } + } } diff --git a/GUI.NET/Debugger/Controls/ctrlBreakpoints.cs b/GUI.NET/Debugger/Controls/ctrlBreakpoints.cs index e2c5e1cd..08a4e130 100644 --- a/GUI.NET/Debugger/Controls/ctrlBreakpoints.cs +++ b/GUI.NET/Debugger/Controls/ctrlBreakpoints.cs @@ -17,7 +17,6 @@ namespace Mesen.GUI.Debugger.Controls public ctrlBreakpoints() { InitializeComponent(); - BreakpointManager.BreakpointsChanged += BreakpointManager_OnBreakpointChanged; } diff --git a/GUI.NET/Debugger/Controls/ctrlCallstack.Designer.cs b/GUI.NET/Debugger/Controls/ctrlCallstack.Designer.cs index 16468705..15194d30 100644 --- a/GUI.NET/Debugger/Controls/ctrlCallstack.Designer.cs +++ b/GUI.NET/Debugger/Controls/ctrlCallstack.Designer.cs @@ -27,7 +27,7 @@ /// private void InitializeComponent() { - this.lstCallstack = new System.Windows.Forms.ListView(); + this.lstCallstack = new Mesen.GUI.Controls.DoubleBufferedListView(); this.colFunctionAddress = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); this.colStackAddr = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); this.colRomOffset = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); @@ -82,7 +82,7 @@ #endregion - private System.Windows.Forms.ListView lstCallstack; + private Mesen.GUI.Controls.DoubleBufferedListView lstCallstack; private System.Windows.Forms.ColumnHeader colFunctionAddress; private System.Windows.Forms.ColumnHeader colStackAddr; private System.Windows.Forms.ColumnHeader colRomOffset; diff --git a/GUI.NET/Debugger/Controls/ctrlCallstack.cs b/GUI.NET/Debugger/Controls/ctrlCallstack.cs index 4551d766..e7dfe0f6 100644 --- a/GUI.NET/Debugger/Controls/ctrlCallstack.cs +++ b/GUI.NET/Debugger/Controls/ctrlCallstack.cs @@ -12,6 +12,14 @@ namespace Mesen.GUI.Debugger.Controls { public partial class ctrlCallstack : UserControl { + private class StackInfo + { + public string SubName; + public bool IsMapped; + public int CurrentRelativeAddr; + public int CurrentAbsoluteAddr; + } + public event EventHandler FunctionSelected; private Int32[] _absoluteCallstack; @@ -24,6 +32,12 @@ namespace Mesen.GUI.Debugger.Controls } public void UpdateCallstack() + { + List stack = GetStackInfo(); + this.UpdateList(stack); + } + + private List GetStackInfo() { int nmiHandler = InteropEmu.DebugGetMemoryValue(0xFFFA) | (InteropEmu.DebugGetMemoryValue(0xFFFB) << 8); int irqHandler = InteropEmu.DebugGetMemoryValue(0xFFFE) | (InteropEmu.DebugGetMemoryValue(0xFFFF) << 8); @@ -33,43 +47,69 @@ namespace Mesen.GUI.Debugger.Controls InteropEmu.DebugGetState(ref state); _programCounter = state.CPU.DebugPC; - this.lstCallstack.BeginUpdate(); - this.lstCallstack.Items.Clear(); - int relSubEntryAddr = -1, absSubEntryAddr = -1, relCurrentAddr = -1, relDestinationAddr = -1, absCurrentAddr = -1, absDestinationAddr = -1; - ListViewItem item; + int relDestinationAddr = -1, absDestinationAddr = -1; + + List stack = new List(); for(int i = 0, len = _relativeCallstack.Length; i < len; i+=2) { if(_relativeCallstack[i] == -2) { break; } - relSubEntryAddr = i == 0 ? -1 : _relativeCallstack[i-1] & 0xFFFF; - absSubEntryAddr = i == 0 ? -1 : _absoluteCallstack[i-1]; + int relSubEntryAddr = i == 0 ? -1 : _relativeCallstack[i-1] & 0xFFFF; + int absSubEntryAddr = i == 0 ? -1 : _absoluteCallstack[i-1]; + + stack.Add(new StackInfo() { + SubName = this.GetFunctionName(relSubEntryAddr, absSubEntryAddr, nmiHandler, irqHandler), + IsMapped = (_relativeCallstack[i] & 0x10000) != 0x10000, + CurrentRelativeAddr = _relativeCallstack[i] & 0xFFFF, + CurrentAbsoluteAddr = _absoluteCallstack[i] + }); - bool currentAddrUnmapped = (_relativeCallstack[i] & 0x10000) == 0x10000; - relCurrentAddr = _relativeCallstack[i] & 0xFFFF; relDestinationAddr = _relativeCallstack[i+1] & 0xFFFF; - absCurrentAddr = _absoluteCallstack[i]; absDestinationAddr = _absoluteCallstack[i+1]; + } - item = this.lstCallstack.Items.Insert(0, this.GetFunctionName(relSubEntryAddr, absSubEntryAddr, nmiHandler, irqHandler)); - item.SubItems.Add("@ $" + relCurrentAddr.ToString("X4")); - item.SubItems.Add("[$" + absCurrentAddr.ToString("X4") + "]"); + //Add current location + stack.Add(new StackInfo() { + SubName = this.GetFunctionName(relDestinationAddr, absDestinationAddr, nmiHandler, irqHandler), + IsMapped = true, + CurrentRelativeAddr = _programCounter, + CurrentAbsoluteAddr = InteropEmu.DebugGetAbsoluteAddress((UInt32)_programCounter) + }); - if(currentAddrUnmapped) { - item.ForeColor = Color.Gray; - item.Font = new Font(item.Font, FontStyle.Italic); + return stack; + } + + private void UpdateList(List stack) + { + if(this.lstCallstack.Items.Count != stack.Count) { + this.lstCallstack.Items.Clear(); + for(int i = 0, len = stack.Count; i < len; i++) { + this.lstCallstack.Items.Add("").SubItems.AddRange(new string[] { "", "" }); } } - item = this.lstCallstack.Items.Insert(0, this.GetFunctionName(relDestinationAddr, absDestinationAddr, nmiHandler, irqHandler)); - item.SubItems.Add("@ $" + _programCounter.ToString("X4")); - item.SubItems.Add("[$" + InteropEmu.DebugGetAbsoluteAddress((UInt32)_programCounter).ToString("X4") + "]"); - if((relDestinationAddr & 0x10000) == 0x10000) { - item.ForeColor = Color.Gray; - item.Font = new Font(item.Font, FontStyle.Italic); - } + for(int i = 0, len = stack.Count; i < len; i++) { + StackInfo stackInfo = stack[i]; + ListViewItem item = this.lstCallstack.Items[len - i - 1]; + + item.Text = stackInfo.SubName; + item.SubItems[1].Text = "@ $" + stackInfo.CurrentRelativeAddr.ToString("X4"); + item.SubItems[2].Text = "[$" + stackInfo.CurrentAbsoluteAddr.ToString("X4") + "]"; + + if(!stackInfo.IsMapped && item.ForeColor != Color.Gray) { + item.ForeColor = Color.Gray; + item.Font = new Font(item.Font, FontStyle.Italic); + } else if(stackInfo.IsMapped && item.ForeColor != Color.Black) { + item.ForeColor = Color.Black; + item.Font = new Font(item.Font, FontStyle.Regular); + } + } + } + + private void UpdateList() + { - this.lstCallstack.EndUpdate(); } private string GetFunctionName(int relSubEntryAddr, int absSubEntryAddr, int nmiHandler, int irqHandler) diff --git a/GUI.NET/Debugger/Controls/ctrlConsoleStatus.Designer.cs b/GUI.NET/Debugger/Controls/ctrlConsoleStatus.Designer.cs index c6511562..e7a1d04d 100644 --- a/GUI.NET/Debugger/Controls/ctrlConsoleStatus.Designer.cs +++ b/GUI.NET/Debugger/Controls/ctrlConsoleStatus.Designer.cs @@ -89,7 +89,7 @@ this.flowLayoutPanel4 = new System.Windows.Forms.FlowLayoutPanel(); this.lblSP = new System.Windows.Forms.Label(); this.txtSP = new System.Windows.Forms.TextBox(); - this.lstStack = new System.Windows.Forms.ListView(); + this.lstStack = new Mesen.GUI.Controls.DoubleBufferedListView(); this.columnHeader1 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); this.flowLayoutPanel1 = new System.Windows.Forms.FlowLayoutPanel(); this.lblA = new System.Windows.Forms.Label(); @@ -1128,7 +1128,7 @@ private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel4; private System.Windows.Forms.Label lblSP; private System.Windows.Forms.TextBox txtSP; - private System.Windows.Forms.ListView lstStack; + private Mesen.GUI.Controls.DoubleBufferedListView lstStack; private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel1; private System.Windows.Forms.Label lblA; private System.Windows.Forms.TextBox txtA; diff --git a/GUI.NET/Debugger/Controls/ctrlConsoleStatus.cs b/GUI.NET/Debugger/Controls/ctrlConsoleStatus.cs index 9c3a0b44..0c2ccfff 100644 --- a/GUI.NET/Debugger/Controls/ctrlConsoleStatus.cs +++ b/GUI.NET/Debugger/Controls/ctrlConsoleStatus.cs @@ -20,12 +20,12 @@ namespace Mesen.GUI.Debugger private void UpdateCPUStatus(ref DebugState state) { - txtA.Text = state.CPU.A.ToString("X"); - txtX.Text = state.CPU.X.ToString("X"); - txtY.Text = state.CPU.Y.ToString("X"); - txtPC.Text = state.CPU.PC.ToString("X"); - txtSP.Text = state.CPU.SP.ToString("X"); - txtStatus.Text = state.CPU.PS.ToString("X"); + txtA.Text = state.CPU.A.ToString("X2"); + txtX.Text = state.CPU.X.ToString("X2"); + txtY.Text = state.CPU.Y.ToString("X2"); + txtPC.Text = state.CPU.PC.ToString("X4"); + txtSP.Text = state.CPU.SP.ToString("X2"); + txtStatus.Text = state.CPU.PS.ToString("X2"); txtCycleCount.Text = state.CPU.CycleCount.ToString(); PSFlags flags = (PSFlags)state.CPU.PS; @@ -63,20 +63,20 @@ namespace Mesen.GUI.Debugger chkIntensifyGreen.Checked = Convert.ToBoolean(state.PPU.ControlFlags.IntensifyGreen); chkIntensifyBlue.Checked = Convert.ToBoolean(state.PPU.ControlFlags.IntensifyBlue); - txtBGAddr.Text = state.PPU.ControlFlags.BackgroundPatternAddr.ToString("X"); - txtSprAddr.Text = state.PPU.ControlFlags.SpritePatternAddr.ToString("X"); + txtBGAddr.Text = state.PPU.ControlFlags.BackgroundPatternAddr.ToString("X4"); + txtSprAddr.Text = state.PPU.ControlFlags.SpritePatternAddr.ToString("X4"); - txtVRAMAddr.Text = state.PPU.State.VideoRamAddr.ToString("X"); + txtVRAMAddr.Text = state.PPU.State.VideoRamAddr.ToString("X4"); txtCycle.Text = state.PPU.Cycle.ToString(); txtScanline.Text = state.PPU.Scanline.ToString(); - txtNTAddr.Text = (0x2000 | (state.PPU.State.VideoRamAddr & 0x0FFF)).ToString("X"); + txtNTAddr.Text = (0x2000 | (state.PPU.State.VideoRamAddr & 0x0FFF)).ToString("X4"); } private void UpdateStack(UInt16 stackPointer) { lstStack.Items.Clear(); for(UInt32 i = (UInt32)0x100 + stackPointer; i < 0x200; i++) { - lstStack.Items.Add("$" + InteropEmu.DebugGetMemoryValue(i).ToString("X")); + lstStack.Items.Add("$" + InteropEmu.DebugGetMemoryValue(i).ToString("X2")); } } diff --git a/GUI.NET/Debugger/Controls/ctrlDebuggerCode.cs b/GUI.NET/Debugger/Controls/ctrlDebuggerCode.cs index 871f6083..0e08c3eb 100644 --- a/GUI.NET/Debugger/Controls/ctrlDebuggerCode.cs +++ b/GUI.NET/Debugger/Controls/ctrlDebuggerCode.cs @@ -95,8 +95,6 @@ namespace Mesen.GUI.Debugger public bool UpdateCode(bool forceUpdate = false) { if(_codeChanged || forceUpdate) { - System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch(); - sw.Start(); this.ctrlCodeViewer.ClearLineStyles(); List lineNumbers = new List(); @@ -104,24 +102,26 @@ namespace Mesen.GUI.Debugger List codeNotes = new List(); List codeLines = new List(); - string[] lines = _code.Split('\n'); - for(int i = 0, len = lines.Length - 1; i < len; i++) { - string line = lines[i]; + int index = -1; + int previousIndex = -1; + while((index = _code.IndexOf('\n', index + 1)) >= 0) { + string line = _code.Substring(previousIndex + 1, index - previousIndex - 1); string[] lineParts = line.Split('\x1'); - + if(lineParts.Length >= 4) { lineNumbers.Add(ParseHexAddress(lineParts[0])); lineNumberNotes.Add(lineParts[1]); codeNotes.Add(lineParts[2]); codeLines.Add(lineParts[3]); } + + previousIndex = index; } ctrlCodeViewer.TextLines = codeLines.ToArray(); ctrlCodeViewer.LineNumbers = lineNumbers.ToArray(); ctrlCodeViewer.TextLineNotes = codeNotes.ToArray(); ctrlCodeViewer.LineNumberNotes = lineNumberNotes.ToArray(); - sw.Stop(); _codeChanged = false; return true; } diff --git a/GUI.NET/Debugger/Controls/ctrlFunctionList.Designer.cs b/GUI.NET/Debugger/Controls/ctrlFunctionList.Designer.cs index ac679eb6..bc00e129 100644 --- a/GUI.NET/Debugger/Controls/ctrlFunctionList.Designer.cs +++ b/GUI.NET/Debugger/Controls/ctrlFunctionList.Designer.cs @@ -27,7 +27,7 @@ /// private void InitializeComponent() { - this.lstFunctions = new System.Windows.Forms.ListView(); + this.lstFunctions = new Mesen.GUI.Controls.DoubleBufferedListView(); this.colFunctionLabel = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); this.colFunctionAddress = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); this.colMemoryAddress = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); @@ -82,7 +82,7 @@ #endregion - private System.Windows.Forms.ListView lstFunctions; + private Mesen.GUI.Controls.DoubleBufferedListView lstFunctions; private System.Windows.Forms.ColumnHeader colFunctionLabel; private System.Windows.Forms.ColumnHeader colFunctionAddress; private System.Windows.Forms.ColumnHeader colMemoryAddress; diff --git a/GUI.NET/Debugger/Controls/ctrlFunctionList.cs b/GUI.NET/Debugger/Controls/ctrlFunctionList.cs index 6849f15a..137ee5a0 100644 --- a/GUI.NET/Debugger/Controls/ctrlFunctionList.cs +++ b/GUI.NET/Debugger/Controls/ctrlFunctionList.cs @@ -30,8 +30,8 @@ namespace Mesen.GUI.Debugger.Controls string bText = string.IsNullOrWhiteSpace(b.Text) ? "ZZZZZZZZZZZZZZZZZZZZZZZ" : b.Text; Int32 aRelative = (Int32)a.Tag == -1 ? Int32.MaxValue : (Int32)a.Tag; Int32 bRelative = (Int32)b.Tag == -1 ? Int32.MaxValue : (Int32)b.Tag; - Int32 aAbsolute = (Int32)a.SubItems[1].Tag; - Int32 bAbsolute = (Int32)b.SubItems[1].Tag; + Int32 aAbsolute = (Int32)a.SubItems[2].Tag; + Int32 bAbsolute = (Int32)b.SubItems[2].Tag; if(a.Text == b.Text) { if(a.Tag == b.Tag) { @@ -45,33 +45,63 @@ namespace Mesen.GUI.Debugger.Controls } } - public void UpdateFunctionList() + private Dictionary _functions = new Dictionary(); + public void UpdateFunctionList(bool reset) { - Int32[] entryPoints = InteropEmu.DebugGetFunctionEntryPoints(); - - lstFunctions.BeginUpdate(); - lstFunctions.ListViewItemSorter = null; - lstFunctions.Items.Clear(); - for(int i = 0; entryPoints[i] >= 0; i++) { - CodeLabel label = LabelManager.GetLabel((UInt32)entryPoints[i], AddressType.PrgRom); - ListViewItem item = lstFunctions.Items.Add(label?.Label); - - Int32 relativeAddress = InteropEmu.DebugGetRelativeAddress((UInt32)entryPoints[i], AddressType.PrgRom); - if(relativeAddress >= 0) { - item.SubItems.Add("$" + relativeAddress.ToString("X4")); - } else { - item.SubItems.Add("[n/a]"); - item.ForeColor = Color.Gray; - item.Font = new Font(item.Font, FontStyle.Italic); - } - item.SubItems.Add("$" + entryPoints[i].ToString("X4")); - item.SubItems[1].Tag = entryPoints[i]; - - item.Tag = relativeAddress; + if(reset) { + lstFunctions.Items.Clear(); + _functions.Clear(); + } + + Int32[] entryPoints = InteropEmu.DebugGetFunctionEntryPoints(); + bool updating = false; + + for(int i = 0; entryPoints[i] >= 0; i++) { + Int32 entryPoint = entryPoints[i]; + ListViewItem item; + if(!_functions.TryGetValue(entryPoint, out item)) { + if(!updating) { + updating = true; + lstFunctions.BeginUpdate(); + lstFunctions.ListViewItemSorter = null; + } + + CodeLabel label = LabelManager.GetLabel((UInt32)entryPoint, AddressType.PrgRom); + item = lstFunctions.Items.Add(label?.Label); + item.Tag = -1; + item.SubItems.Add(""); + item.SubItems.Add("$" + entryPoint.ToString("X4")); + item.SubItems[2].Tag = entryPoint; + + _functions[entryPoint] = item; + } + + Int32 relativeAddress = InteropEmu.DebugGetRelativeAddress((UInt32)entryPoint, AddressType.PrgRom); + if(relativeAddress != (Int32)item.Tag) { + if(!updating) { + updating = true; + lstFunctions.BeginUpdate(); + lstFunctions.ListViewItemSorter = null; + } + + if(relativeAddress >= 0) { + item.SubItems[1].Text = "$" + relativeAddress.ToString("X4"); + item.ForeColor = Color.Black; + item.Font = new Font(item.Font, FontStyle.Regular); + } else { + item.SubItems[1].Text = "[n/a]"; + item.ForeColor = Color.Gray; + item.Font = new Font(item.Font, FontStyle.Italic); + } + item.Tag = relativeAddress; + } + } + + if(updating) { + lstFunctions.ListViewItemSorter = new FunctionComparer(); + lstFunctions.Sort(); + lstFunctions.EndUpdate(); } - lstFunctions.ListViewItemSorter = new FunctionComparer(); - lstFunctions.Sort(); - lstFunctions.EndUpdate(); } private void lstFunctions_DoubleClick(object sender, EventArgs e) diff --git a/GUI.NET/Debugger/Controls/ctrlLabelList.Designer.cs b/GUI.NET/Debugger/Controls/ctrlLabelList.Designer.cs index 138e66e0..9d2fddb6 100644 --- a/GUI.NET/Debugger/Controls/ctrlLabelList.Designer.cs +++ b/GUI.NET/Debugger/Controls/ctrlLabelList.Designer.cs @@ -28,7 +28,7 @@ private void InitializeComponent() { this.components = new System.ComponentModel.Container(); - this.lstLabels = new System.Windows.Forms.ListView(); + this.lstLabels = new Mesen.GUI.Controls.DoubleBufferedListView(); this.colFunctionLabel = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); this.colFunctionAddress = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); this.colMemoryAddress = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); @@ -122,7 +122,7 @@ #endregion - private System.Windows.Forms.ListView lstLabels; + private Mesen.GUI.Controls.DoubleBufferedListView lstLabels; private System.Windows.Forms.ColumnHeader colFunctionLabel; private System.Windows.Forms.ColumnHeader colFunctionAddress; private System.Windows.Forms.ColumnHeader colMemoryAddress; diff --git a/GUI.NET/Debugger/Controls/ctrlLabelList.cs b/GUI.NET/Debugger/Controls/ctrlLabelList.cs index 54148f4a..fa15b058 100644 --- a/GUI.NET/Debugger/Controls/ctrlLabelList.cs +++ b/GUI.NET/Debugger/Controls/ctrlLabelList.cs @@ -14,6 +14,8 @@ namespace Mesen.GUI.Debugger.Controls public partial class ctrlLabelList : UserControl { public event EventHandler OnLabelSelected; + private List _listItems = new List(); + public ctrlLabelList() { InitializeComponent(); @@ -36,10 +38,38 @@ namespace Mesen.GUI.Debugger.Controls } } + public void UpdateLabelListAddresses() + { + bool updating = false; + foreach(ListViewItem item in _listItems) { + CodeLabel label = (CodeLabel)item.SubItems[1].Tag; + + Int32 relativeAddress = InteropEmu.DebugGetRelativeAddress(label.Address, label.AddressType); + if(relativeAddress != (Int32)item.Tag) { + if(!updating) { + lstLabels.BeginUpdate(); + updating = true; + } + if(relativeAddress >= 0) { + item.SubItems[0].Text = "$" + relativeAddress.ToString("X4"); + item.ForeColor = Color.Black; + item.Font = new Font(item.Font, FontStyle.Regular); + } else { + item.SubItems[0].Text = "[n/a]"; + item.ForeColor = Color.Gray; + item.Font = new Font(item.Font, FontStyle.Italic); + } + item.Tag = relativeAddress; + } + } + if(updating) { + lstLabels.Sort(); + lstLabels.EndUpdate(); + } + } + public void UpdateLabelList() { - Int32[] entryPoints = InteropEmu.DebugGetFunctionEntryPoints(); - lstLabels.BeginUpdate(); lstLabels.Items.Clear(); foreach(CodeLabel label in LabelManager.GetLabels()) { @@ -62,6 +92,11 @@ namespace Mesen.GUI.Debugger.Controls } lstLabels.Sort(); lstLabels.EndUpdate(); + + _listItems = new List(); + foreach(ListViewItem item in lstLabels.Items) { + _listItems.Add(item); + } } private void lstLabels_DoubleClick(object sender, EventArgs e) diff --git a/GUI.NET/Debugger/Controls/ctrlTextbox.cs b/GUI.NET/Debugger/Controls/ctrlTextbox.cs index 9acbaf02..7c51051a 100644 --- a/GUI.NET/Debugger/Controls/ctrlTextbox.cs +++ b/GUI.NET/Debugger/Controls/ctrlTextbox.cs @@ -502,7 +502,7 @@ namespace Mesen.GUI.Debugger this.CursorPosition = this.ScrollPosition + clickedLine; } - private void DrawLine(Graphics g, int currentLine, int marginLeft, int positionY) + private void DrawLine(Graphics g, int currentLine, int marginLeft, int positionY, int lineHeight) { string[] lineContent = _contents[currentLine].Split('\x2'); string codeString = lineContent[0].TrimStart(); @@ -514,7 +514,7 @@ namespace Mesen.GUI.Debugger if(currentLine == this.CursorPosition) { //Highlight current line - g.FillRectangle(Brushes.AliceBlue, marginLeft, positionY, Math.Max(_maxLineWidth, this.ClientRectangle.Width), this.LineHeight); + g.FillRectangle(Brushes.AliceBlue, marginLeft, positionY, Math.Max(_maxLineWidth, this.ClientRectangle.Width), lineHeight); } //Adjust background color highlights based on number of spaces in front of content @@ -528,17 +528,17 @@ namespace Mesen.GUI.Debugger if(lineProperties.BgColor.HasValue) { using(Brush bgBrush = new SolidBrush(lineProperties.BgColor.Value)) { - g.FillRectangle(bgBrush, marginLeft, positionY + 1, codeStringLength, this.LineHeight-1); + g.FillRectangle(bgBrush, marginLeft, positionY + 1, codeStringLength, lineHeight-1); } } if(lineProperties.OutlineColor.HasValue) { using(Pen outlinePen = new Pen(lineProperties.OutlineColor.Value, 1)) { - g.DrawRectangle(outlinePen, marginLeft, positionY + 1, codeStringLength, this.LineHeight-1); + g.DrawRectangle(outlinePen, marginLeft, positionY + 1, codeStringLength, lineHeight-1); } } } - this.DrawLineText(g, currentLine, marginLeft, positionY, codeString, addressString, commentString, codeStringLength, addressStringLength, textColor); + this.DrawLineText(g, currentLine, marginLeft, positionY, codeString, addressString, commentString, codeStringLength, addressStringLength, textColor, lineHeight); } private void DrawLineNumber(Graphics g, int currentLine, int marginLeft, int positionY) @@ -552,7 +552,7 @@ namespace Mesen.GUI.Debugger } } - private void DrawLineText(Graphics g, int currentLine, int marginLeft, int positionY, string codeString, string addressString, string commentString, float codeStringLength, float addressStringLength, Color textColor) + private void DrawLineText(Graphics g, int currentLine, int marginLeft, int positionY, string codeString, string addressString, string commentString, float codeStringLength, float addressStringLength, Color textColor, int lineHeight) { using(Brush fgBrush = new SolidBrush(textColor)) { if(codeString.StartsWith("--") && codeString.EndsWith("--")) { @@ -561,7 +561,7 @@ namespace Mesen.GUI.Debugger string text = codeString.Substring(2, codeString.Length - 4); float textLength = g.MeasureString(text, this._noteFont).Width; g.DrawString(text, this._noteFont, fgBrush, (marginLeft + this.Width - textLength) / 2, positionY); - g.DrawLine(Pens.Black, marginLeft, positionY+this.LineHeight-2, marginLeft+this.Width, positionY+this.LineHeight-2); + g.DrawLine(Pens.Black, marginLeft, positionY+lineHeight-2, marginLeft+this.Width, positionY+lineHeight-2); g.TranslateTransform(-HorizontalScrollPosition * HorizontalScrollFactor, 0); } else if(codeString.StartsWith("__") && codeString.EndsWith("__")) { //Draw block end @@ -598,33 +598,33 @@ namespace Mesen.GUI.Debugger } } - private void DrawLineSymbols(Graphics g, int positionY, LineProperties lineProperties) + private void DrawLineSymbols(Graphics g, int positionY, LineProperties lineProperties, int lineHeight) { if(lineProperties.Symbol.HasFlag(LineSymbol.Circle)) { using(Brush brush = new SolidBrush(lineProperties.OutlineColor.Value)) { - g.FillEllipse(brush, 1, positionY + 2, this.LineHeight - 3, this.LineHeight - 3); + g.FillEllipse(brush, 1, positionY + 2, lineHeight - 3, lineHeight - 3); } } if(lineProperties.Symbol.HasFlag(LineSymbol.CircleOutline) && lineProperties.OutlineColor.HasValue) { using(Pen pen = new Pen(lineProperties.OutlineColor.Value, 1)) { - g.DrawEllipse(pen, 1, positionY + 2, this.LineHeight - 3, this.LineHeight - 3); + g.DrawEllipse(pen, 1, positionY + 2, lineHeight - 3, lineHeight - 3); } } if(lineProperties.Symbol.HasFlag(LineSymbol.Arrow)) { - int arrowY = positionY + this.LineHeight / 2 + 1; - using(Pen pen = new Pen(Color.Black, this.LineHeight * 0.33f)) { + int arrowY = positionY + lineHeight / 2 + 1; + using(Pen pen = new Pen(Color.Black, lineHeight * 0.33f)) { //Outline - g.DrawLine(pen, 3, arrowY, 3 + this.LineHeight * 0.25f, arrowY); + g.DrawLine(pen, 3, arrowY, 3 + lineHeight * 0.25f, arrowY); pen.EndCap = System.Drawing.Drawing2D.LineCap.ArrowAnchor; - g.DrawLine(pen, 3 + this.LineHeight * 0.25f, arrowY, 3 + this.LineHeight * 0.75f, arrowY); + g.DrawLine(pen, 3 + lineHeight * 0.25f, arrowY, 3 + lineHeight * 0.75f, arrowY); //Fill pen.Width-=2f; pen.Color = lineProperties.BgColor.Value; pen.EndCap = System.Drawing.Drawing2D.LineCap.Square; - g.DrawLine(pen, 4, arrowY, 3 + this.LineHeight * 0.25f - 1, arrowY); + g.DrawLine(pen, 4, arrowY, 3 + lineHeight * 0.25f - 1, arrowY); pen.EndCap = System.Drawing.Drawing2D.LineCap.ArrowAnchor; - g.DrawLine(pen, 3 + this.LineHeight * 0.25f, arrowY, this.LineHeight * 0.75f + 1, arrowY); + g.DrawLine(pen, 3 + lineHeight * 0.25f, arrowY, lineHeight * 0.75f + 1, arrowY); } } } @@ -680,7 +680,7 @@ namespace Mesen.GUI.Debugger } } - private void DrawMargin(Graphics g, int currentLine, int marginLeft, int positionY) + private void DrawMargin(Graphics g, int currentLine, int marginLeft, int positionY, int lineHeight) { if(this.ShowLineNumbers) { //Show line number @@ -691,12 +691,13 @@ namespace Mesen.GUI.Debugger marginLeft += _lineMargins[currentLine]; if(_lineProperties.ContainsKey(currentLine)) { - this.DrawLineSymbols(g, positionY, _lineProperties[currentLine]); + this.DrawLineSymbols(g, positionY, _lineProperties[currentLine], lineHeight); } } protected override void OnPaint(PaintEventArgs pe) { + int lineHeight = this.LineHeight; pe.Graphics.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality; using(Brush lightGrayBrush = new SolidBrush(Color.FromArgb(240,240,240))) { using(Pen grayPen = new Pen(Color.LightGray)) { @@ -710,14 +711,14 @@ namespace Mesen.GUI.Debugger int positionY = 0; if(!string.IsNullOrWhiteSpace(this._header)) { - pe.Graphics.FillRectangle(lightGrayBrush, marginLeft, 0, Math.Max(_maxLineWidth, rect.Right), this.LineHeight); + pe.Graphics.FillRectangle(lightGrayBrush, marginLeft, 0, Math.Max(_maxLineWidth, rect.Right), lineHeight); pe.Graphics.DrawString(_header, this.Font, Brushes.Gray, marginLeft, positionY); - positionY += this.LineHeight; + positionY += lineHeight; } while(positionY < rect.Bottom && currentLine < _contents.Length) { - this.DrawLine(pe.Graphics, currentLine, marginLeft, positionY); - positionY += this.LineHeight; + this.DrawLine(pe.Graphics, currentLine, marginLeft, positionY, lineHeight); + positionY += lineHeight; currentLine++; } @@ -731,8 +732,8 @@ namespace Mesen.GUI.Debugger currentLine = this.ScrollPosition; positionY = 0; while(positionY < rect.Bottom && currentLine < _contents.Length) { - this.DrawMargin(pe.Graphics, currentLine, marginLeft, positionY); - positionY += this.LineHeight; + this.DrawMargin(pe.Graphics, currentLine, marginLeft, positionY, lineHeight); + positionY += lineHeight; currentLine++; } } diff --git a/GUI.NET/Debugger/Controls/ctrlWatch.cs b/GUI.NET/Debugger/Controls/ctrlWatch.cs index 4e929d0e..94b3545d 100644 --- a/GUI.NET/Debugger/Controls/ctrlWatch.cs +++ b/GUI.NET/Debugger/Controls/ctrlWatch.cs @@ -17,6 +17,8 @@ namespace Mesen.GUI.Debugger { InitializeComponent(); + this.DoubleBuffered = true; + bool designMode = (LicenseManager.UsageMode == LicenseUsageMode.Designtime); if(!designMode) { this.mnuHexDisplay.Checked = ConfigManager.Config.DebugInfo.HexDisplay; @@ -68,7 +70,7 @@ namespace Mesen.GUI.Debugger { lstWatch.Items.Clear(); foreach(string watchValue in watchValues) { - lstWatch.Items.Add(watchValue); + lstWatch.Items.Add(watchValue).SubItems.Add(""); } UpdateWatch(); } @@ -92,7 +94,6 @@ namespace Mesen.GUI.Debugger string previousValue = null; if(item.SubItems.Count > 1) { previousValue = item.SubItems[1].Text; - item.SubItems.RemoveAt(1); } string newValue = ""; @@ -116,8 +117,12 @@ namespace Mesen.GUI.Debugger break; } - item.SubItems.Add(newValue); - item.SubItems[1].ForeColor = newValue != previousValue ? Color.Red : Color.Black; + if(previousValue != newValue) { + item.SubItems[1].Text = newValue; + item.SubItems[1].ForeColor = Color.Red; + } else { + item.SubItems[1].ForeColor = Color.Black; + } } } AdjustColumnWidth(); @@ -131,6 +136,7 @@ namespace Mesen.GUI.Debugger public void AddWatch(string watchValue) { ListViewItem item = lstWatch.Items.Insert(lstWatch.Items.Count - 1, watchValue); + item.SubItems.Add(""); UpdateWatch(); } diff --git a/GUI.NET/Debugger/frmDebugger.cs b/GUI.NET/Debugger/frmDebugger.cs index 6fb320f8..52ad3f8a 100644 --- a/GUI.NET/Debugger/frmDebugger.cs +++ b/GUI.NET/Debugger/frmDebugger.cs @@ -107,6 +107,9 @@ namespace Mesen.GUI.Debugger } LabelManager.OnLabelUpdated += LabelManager_OnLabelUpdated; + ctrlLabelList.UpdateLabelList(); + ctrlFunctionList.UpdateFunctionList(true); + ctrlWatch.SetWatchValues(_workspace.WatchValues); BreakpointManager.Breakpoints.Clear(); @@ -186,32 +189,36 @@ namespace Mesen.GUI.Debugger mnuGoToIrqHandler.Text = "IRQ Handler ($" + irqHandler.ToString("X4") + ")"; } + string _previousCode = string.Empty; private void UpdateDebugger(bool updateActiveAddress = true) { - ctrlLabelList.UpdateLabelList(); - ctrlFunctionList.UpdateFunctionList(); + ctrlLabelList.UpdateLabelListAddresses(); + ctrlFunctionList.UpdateFunctionList(false); UpdateDebuggerFlags(); UpdateVectorAddresses(); if(InteropEmu.DebugIsCodeChanged()) { - string code = InteropEmu.DebugGetCode(); - ctrlDebuggerCode.Code = code; - ctrlDebuggerCodeSplit.Code = code; + _previousCode = InteropEmu.DebugGetCode(); + ctrlDebuggerCode.Code = _previousCode; } DebugState state = new DebugState(); InteropEmu.DebugGetState(ref state); if(UpdateSplitView()) { + ctrlDebuggerCodeSplit.Code = _previousCode; ctrlDebuggerCodeSplit.UpdateCode(true); } else { _lastCodeWindow = ctrlDebuggerCode; } + ctrlDebuggerCode.SetActiveAddress(state.CPU.DebugPC); + ctrlDebuggerCodeSplit.SetActiveAddress(state.CPU.DebugPC); + if(updateActiveAddress) { - ctrlDebuggerCode.SelectActiveAddress(state.CPU.DebugPC); - ctrlDebuggerCodeSplit.SetActiveAddress(state.CPU.DebugPC); + _lastCodeWindow.SelectActiveAddress(state.CPU.DebugPC); } + RefreshBreakpoints(); ctrlConsoleStatus.UpdateStatus(ref state); @@ -536,6 +543,8 @@ namespace Mesen.GUI.Debugger private void LabelManager_OnLabelUpdated(object sender, EventArgs e) { + ctrlLabelList.UpdateLabelList(); + ctrlFunctionList.UpdateFunctionList(true); UpdateDebugger(false); }