mirror of
https://github.com/SourMesen/Mesen.git
synced 2025-04-02 10:52:48 -04:00
Debugger: Fixed flickering lists, performance improvements, etc.
This commit is contained in:
parent
80bd7d0b3e
commit
42d9fb0ea1
15 changed files with 258 additions and 124 deletions
|
@ -191,7 +191,7 @@ vector<string> 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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,6 @@ namespace Mesen.GUI.Debugger.Controls
|
|||
public ctrlBreakpoints()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
BreakpointManager.BreakpointsChanged += BreakpointManager_OnBreakpointChanged;
|
||||
}
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
/// </summary>
|
||||
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;
|
||||
|
|
|
@ -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<StackInfo> stack = GetStackInfo();
|
||||
this.UpdateList(stack);
|
||||
}
|
||||
|
||||
private List<StackInfo> 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<StackInfo> stack = new List<StackInfo>();
|
||||
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<StackInfo> 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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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"));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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<int> lineNumbers = new List<int>();
|
||||
|
@ -104,24 +102,26 @@ namespace Mesen.GUI.Debugger
|
|||
List<string> codeNotes = new List<string>();
|
||||
List<string> codeLines = new List<string>();
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
/// </summary>
|
||||
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;
|
||||
|
|
|
@ -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<Int32, ListViewItem> _functions = new Dictionary<int, ListViewItem>();
|
||||
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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -14,6 +14,8 @@ namespace Mesen.GUI.Debugger.Controls
|
|||
public partial class ctrlLabelList : UserControl
|
||||
{
|
||||
public event EventHandler OnLabelSelected;
|
||||
private List<ListViewItem> _listItems = new List<ListViewItem>();
|
||||
|
||||
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<ListViewItem>();
|
||||
foreach(ListViewItem item in lstLabels.Items) {
|
||||
_listItems.Add(item);
|
||||
}
|
||||
}
|
||||
|
||||
private void lstLabels_DoubleClick(object sender, EventArgs e)
|
||||
|
|
|
@ -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++;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue