Debugger: Added several commands to right-click menu in hex editor (including freeze/unfreeze feature)
This commit is contained in:
parent
66753c843c
commit
51afb5ae3f
20 changed files with 429 additions and 180 deletions
|
@ -60,6 +60,8 @@ Debugger::Debugger(shared_ptr<Console> console, shared_ptr<CPU> 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;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -56,6 +56,8 @@ private:
|
|||
vector<Breakpoint> _breakpoints[BreakpointTypeCount];
|
||||
bool _hasBreakpoint[BreakpointTypeCount] = {};
|
||||
|
||||
vector<uint8_t> _frozenAddresses;
|
||||
|
||||
deque<uint32_t> _callstackAbsolute;
|
||||
deque<uint32_t> _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);
|
||||
};
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#include "stdafx.h"
|
||||
#include "stdafx.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include "MessageManager.h"
|
||||
|
|
|
@ -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<ListViewItem>();
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -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<Breakpoint>((bp) => { return bp.Address == address; });
|
||||
return Breakpoints.FirstOrDefault<Breakpoint>((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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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<int> _unexecutedAddresses = new HashSet<int>();
|
||||
|
@ -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)
|
||||
|
|
|
@ -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)]
|
||||
|
|
21
GUI.NET/Debugger/Controls/ctrlWatch.Designer.cs
generated
21
GUI.NET/Debugger/Controls/ctrlWatch.Designer.cs
generated
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<string> GetWatchValues()
|
||||
{
|
||||
List<string> watchValues = new List<string>();
|
||||
foreach(ListViewItem listView in lstWatch.Items) {
|
||||
watchValues.Add(listView.Text);
|
||||
}
|
||||
return watchValues;
|
||||
}
|
||||
|
||||
public void SetWatchValues(List<string> 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<ListViewItem> itemsToAdd = new List<ListViewItem>();
|
||||
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 = "<invalid expression>";
|
||||
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<ListViewItem>();
|
||||
var itemsToRemove = new List<int>();
|
||||
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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
84
GUI.NET/Debugger/WatchManager.cs
Normal file
84
GUI.NET/Debugger/WatchManager.cs
Normal file
|
@ -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<string> _watchEntries = new List<string>();
|
||||
private static List<WatchValueInfo> _previousValues = new List<WatchValueInfo>();
|
||||
|
||||
public static List<string> WatchEntries
|
||||
{
|
||||
get { return _watchEntries; }
|
||||
set
|
||||
{
|
||||
_watchEntries = value;
|
||||
WatchChanged?.Invoke(null, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
public static List<WatchValueInfo> GetWatchContent(bool useHex)
|
||||
{
|
||||
var list = new List<WatchValueInfo>();
|
||||
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 = "<invalid expression>"; 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<int> set = new HashSet<int>(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; }
|
||||
}
|
||||
}
|
2
GUI.NET/Debugger/frmDebugger.Designer.cs
generated
2
GUI.NET/Debugger/frmDebugger.Designer.cs
generated
|
@ -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);
|
||||
//
|
||||
|
|
|
@ -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;
|
||||
|
|
21
GUI.NET/Debugger/frmMemoryViewer.Designer.cs
generated
21
GUI.NET/Debugger/frmMemoryViewer.Designer.cs
generated
|
@ -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);
|
||||
//
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -468,6 +468,7 @@
|
|||
<Compile Include="Debugger\LabelManager.cs" />
|
||||
<Compile Include="Debugger\TblLoader.cs" />
|
||||
<Compile Include="Debugger\TextboxHistory.cs" />
|
||||
<Compile Include="Debugger\WatchManager.cs" />
|
||||
<Compile Include="Forms\BaseConfigForm.Designer.cs">
|
||||
<DependentUpon>BaseConfigForm.cs</DependentUpon>
|
||||
</Compile>
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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(); }
|
||||
};
|
||||
|
|
Loading…
Add table
Reference in a new issue