Mesen-X/GUI.NET/Debugger/Controls/ctrlMemoryAccessCounters.cs

267 lines
7.4 KiB
C#
Raw Normal View History

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
2016-12-11 14:25:29 -05:00
using Mesen.GUI.Controls;
using Mesen.GUI.Forms;
using Mesen.GUI.Config;
namespace Mesen.GUI.Debugger.Controls
{
2016-12-11 14:25:29 -05:00
public partial class ctrlMemoryAccessCounters : BaseControl
{
private MemoryCountData[] _data;
private AddressType _memoryType = AddressType.InternalRam;
private SortType _sortType = SortType.Address;
public ctrlMemoryAccessCounters()
{
InitializeComponent();
this.toolTip.SetToolTip(chkHighlightUninitRead, "The uninitialized memory reads highlight will only be accurate if the debugger was active when the game was loaded (or if the game has been power cycled since)");
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
if(!IsDesignMode) {
InitMemoryTypeDropdown();
cboSort.SelectedIndex = 0;
InitShortcuts();
}
}
private void InitShortcuts()
{
mnuCopy.InitShortcut(this, nameof(DebuggerShortcutsConfig.Copy));
mnuSelectAll.InitShortcut(this, nameof(DebuggerShortcutsConfig.SelectAll));
}
public void InitMemoryTypeDropdown()
{
cboMemoryType.SelectedIndexChanged -= cboMemoryType_SelectedIndexChanged;
AddressType originalValue = cboMemoryType.GetEnumValue<AddressType>();
cboMemoryType.BeginUpdate();
cboMemoryType.Items.Clear();
cboMemoryType.Items.Add(ResourceHelper.GetEnumText(AddressType.InternalRam));
if(InteropEmu.DebugGetMemorySize(DebugMemoryType.PrgRom) > 0) {
cboMemoryType.Items.Add(ResourceHelper.GetEnumText(AddressType.PrgRom));
}
if(InteropEmu.DebugGetMemorySize(DebugMemoryType.WorkRam) > 0) {
cboMemoryType.Items.Add(ResourceHelper.GetEnumText(AddressType.WorkRam));
}
if(InteropEmu.DebugGetMemorySize(DebugMemoryType.SaveRam) > 0) {
cboMemoryType.Items.Add(ResourceHelper.GetEnumText(AddressType.SaveRam));
}
cboMemoryType.SelectedIndex = 0;
cboMemoryType.SetEnumValue(originalValue);
cboMemoryType.SelectedIndexChanged += cboMemoryType_SelectedIndexChanged;
cboMemoryType.EndUpdate();
UpdateMemoryType();
}
public Font BaseFont { get { return ctrlScrollableTextbox.BaseFont; } set { ctrlScrollableTextbox.BaseFont = value; } }
public int TextZoom { get { return ctrlScrollableTextbox.TextZoom; } set { ctrlScrollableTextbox.TextZoom = value; } }
public void RefreshData()
{
int[] readCounts = InteropEmu.DebugGetMemoryAccessCounts(_memoryType, MemoryOperationType.Read, false);
int[] writeCounts = InteropEmu.DebugGetMemoryAccessCounts(_memoryType, MemoryOperationType.Write, false);
int[] execCounts = InteropEmu.DebugGetMemoryAccessCounts(_memoryType, MemoryOperationType.Exec, false);
int[] uninitReads = InteropEmu.DebugGetMemoryAccessCounts(_memoryType, MemoryOperationType.Read, true);
List<int> addresses = new List<int>(readCounts.Length);
List<string> content = new List<string>(readCounts.Length);
if(_data == null || _data.Length != readCounts.Length) {
_data = new MemoryCountData[readCounts.Length];
for(int i = 0; i < readCounts.Length; i++) {
_data[i] = new MemoryCountData();
}
}
for(int i = 0; i < readCounts.Length; i++) {
_data[i].Address = i;
_data[i].ReadCount = readCounts[i];
_data[i].WriteCount = writeCounts[i];
_data[i].ExecCount = execCounts[i];
_data[i].UninitRead = uninitReads[i] > 0;
}
MemoryCountData[] data = new MemoryCountData[readCounts.Length];
Array.Copy(_data, data, readCounts.Length);
switch(_sortType) {
case SortType.Address: break;
case SortType.Read: Array.Sort(data.Select((e) => -e.ReadCount).ToArray<int>(), data); break;
case SortType.Write: Array.Sort(data.Select((e) => -e.WriteCount).ToArray<int>(), data); break;
case SortType.Exec: Array.Sort(data.Select((e) => -e.ExecCount).ToArray<int>(), data); break;
case SortType.UninitRead: Array.Sort(data.Select((e) => e.UninitRead ? -e.ReadCount : (Int32.MaxValue - e.ReadCount)).ToArray<int>(), data); break;
}
bool hideUnusedAddresses = chkHideUnusedAddresses.Checked;
for(int i = 0; i < readCounts.Length; i++) {
if(!hideUnusedAddresses || !data[i].Empty) {
addresses.Add(data[i].Address);
content.Add(data[i].Content);
}
}
if(chkHighlightUninitRead.Checked) {
ctrlScrollableTextbox.StyleProvider = new LineStyleProvider(new HashSet<int>(data.Where((e) => e.UninitRead).Select((e) => e.Address)));
} else {
ctrlScrollableTextbox.StyleProvider = null;
}
ctrlScrollableTextbox.Header = " " + "Read".PadRight(12) + "Write".PadRight(12) + "Execute";
ctrlScrollableTextbox.LineNumbers = addresses.ToArray();
ctrlScrollableTextbox.TextLines = content.ToArray();
}
private class LineStyleProvider : ctrlTextbox.ILineStyleProvider
{
HashSet<int> _addresses = new HashSet<int>();
public LineStyleProvider(HashSet<int> addresses)
{
_addresses = addresses;
}
public string GetLineComment(int lineIndex)
{
return null;
}
public LineProperties GetLineStyle(int cpuAddress, int lineIndex)
{
if(_addresses.Contains(cpuAddress)) {
return new LineProperties() { TextBgColor = Color.LightCoral };
}
return null;
}
}
private void cboMemoryType_SelectedIndexChanged(object sender, EventArgs e)
{
UpdateMemoryType();
}
private void UpdateMemoryType()
{
_memoryType = cboMemoryType.GetEnumValue<AddressType>();
RefreshData();
}
private void cboSort_SelectedIndexChanged(object sender, EventArgs e)
{
_sortType = (SortType)cboSort.SelectedIndex;
RefreshData();
}
private void chkOption_CheckedChanged(object sender, EventArgs e)
{
RefreshData();
}
private void btnReset_Click(object sender, EventArgs e)
{
InteropEmu.DebugResetMemoryAccessCounts();
RefreshData();
}
private enum SortType
{
Address = 0,
Read = 1,
Write = 2,
Exec = 3,
UninitRead = 4,
}
private class MemoryCountData
{
private bool _needRecalc = true;
private int _readCount = 0;
private int _writeCount = 0;
private int _execCount = 0;
private string _content = string.Empty;
public int Address { get; set; }
public int ReadCount
{
get { return _readCount; }
set
{
if(this._readCount!=value) {
this._readCount = value;
this._needRecalc = true;
};
}
}
public int WriteCount
{
get { return _writeCount; }
set
{
if(this._writeCount!=value) {
this._writeCount = value;
this._needRecalc = true;
};
}
}
public int ExecCount
{
get { return _execCount; }
set
{
if(this._execCount!=value) {
this._execCount = value;
this._needRecalc = true;
};
}
}
public bool Empty { get { return ReadCount == 0 && WriteCount == 0 && ExecCount == 0; } }
public string Content
{
get
{
if(this._needRecalc) {
_content = " " + (_readCount == 0 ? "0" : _readCount.ToString()).PadRight(12) +
(_writeCount == 0 ? "0" : _writeCount.ToString()).PadRight(12) +
(_execCount == 0 ? "0" : _execCount.ToString());
_needRecalc = false;
}
return _content;
}
}
public bool UninitRead { get; set; }
}
private void mnuCopy_Click(object sender, EventArgs e)
{
ctrlScrollableTextbox.CopySelection(true, false, false);
}
private void mnuSelectAll_Click(object sender, EventArgs e)
{
ctrlScrollableTextbox.SelectAll();
}
}
}