diff --git a/Core/BaseMapper.cpp b/Core/BaseMapper.cpp
index cd5f5c68..6fab5418 100644
--- a/Core/BaseMapper.cpp
+++ b/Core/BaseMapper.cpp
@@ -5,6 +5,7 @@
#include "../Utilities/FolderUtilities.h"
#include "CheatManager.h"
#include "Debugger.h"
+#include "MemoryDumper.h"
void BaseMapper::WriteRegister(uint16_t addr, uint8_t value) { }
uint8_t BaseMapper::ReadRegister(uint16_t addr) { return 0; }
@@ -570,7 +571,7 @@ void BaseMapper::ProcessNotification(ConsoleNotificationType type, void* paramet
void BaseMapper::ApplyCheats()
{
RestoreOriginalPrgRam();
- CheatManager::ApplyPrgCodes(_prgRom, GetPrgSize());
+ CheatManager::ApplyPrgCodes(_prgRom, _prgSize);
}
void BaseMapper::GetMemoryRanges(MemoryRanges &ranges)
@@ -764,14 +765,16 @@ void BaseMapper::WriteMemory(DebugMemoryType type, uint8_t* buffer)
}
}
-uint32_t BaseMapper::GetPrgSize(bool getWorkRamSize)
+uint32_t BaseMapper::GetMemorySize(DebugMemoryType type)
{
- return getWorkRamSize ? _workRamSize : _prgSize;
-}
-
-uint32_t BaseMapper::GetChrSize(bool getRamSize)
-{
- return getRamSize ? _chrRamSize : (_onlyChrRam ? 0 : _chrRomSize);
+ switch(type) {
+ default: return 0;
+ case DebugMemoryType::ChrRom: return _chrRomSize;
+ case DebugMemoryType::ChrRam: return _chrRamSize;
+ case DebugMemoryType::SaveRam: return _saveRamSize;
+ case DebugMemoryType::PrgRom: return _prgSize;
+ case DebugMemoryType::WorkRam: return _workRamSize;
+ }
}
int32_t BaseMapper::ToAbsoluteAddress(uint16_t addr)
diff --git a/Core/BaseMapper.h b/Core/BaseMapper.h
index 245296c8..def69bbf 100644
--- a/Core/BaseMapper.h
+++ b/Core/BaseMapper.h
@@ -228,8 +228,9 @@ public:
CartridgeState GetState();
uint8_t* GetPrgRom();
uint8_t* GetWorkRam();
- uint32_t GetPrgSize(bool getWorkRamSize = false);
- uint32_t GetChrSize(bool getRamSize = false);
+
+ uint32_t GetMemorySize(DebugMemoryType type);
+
uint32_t CopyMemory(DebugMemoryType type, uint8_t* buffer);
void WriteMemory(DebugMemoryType type, uint8_t* buffer);
int32_t ToAbsoluteAddress(uint16_t addr);
diff --git a/Core/CPU.h b/Core/CPU.h
index 9bf04db1..77931e75 100644
--- a/Core/CPU.h
+++ b/Core/CPU.h
@@ -102,7 +102,7 @@ private:
void DummyRead()
{
- MemoryRead(_state.PC, MemoryOperationType::Read);
+ MemoryRead(_state.PC, MemoryOperationType::DummyRead);
}
uint8_t ReadByte()
@@ -166,7 +166,6 @@ private:
IncCycleCount();
}
_cpuWrite = false;
-
}
uint8_t MemoryRead(uint16_t addr, MemoryOperationType operationType = MemoryOperationType::Read) {
@@ -252,12 +251,12 @@ private:
uint8_t GetZeroAddr() { return ReadByte(); }
uint8_t GetZeroXAddr() {
uint8_t value = ReadByte();
- MemoryRead(value); //Dummy read
+ MemoryRead(value, MemoryOperationType::DummyRead); //Dummy read
return value + X();
}
uint8_t GetZeroYAddr() {
uint8_t value = ReadByte();
- MemoryRead(value); //Dummy read
+ MemoryRead(value, MemoryOperationType::DummyRead); //Dummy read
return value + Y();
}
uint16_t GetAbsAddr() { return ReadWord(); }
@@ -268,7 +267,7 @@ private:
if(pageCrossed || dummyRead) {
//Dummy read done by the processor (only when page is crossed for READ instructions)
- MemoryRead(baseAddr + X() - (pageCrossed ? 0x100 : 0));
+ MemoryRead(baseAddr + X() - (pageCrossed ? 0x100 : 0), MemoryOperationType::DummyRead);
}
return baseAddr + X();
}
@@ -279,7 +278,7 @@ private:
if(pageCrossed || dummyRead) {
//Dummy read done by the processor (only when page is crossed for READ instructions)
- MemoryRead(baseAddr + Y() - (pageCrossed ? 0x100 : 0));
+ MemoryRead(baseAddr + Y() - (pageCrossed ? 0x100 : 0), MemoryOperationType::DummyRead);
}
return baseAddr + Y();
@@ -300,7 +299,7 @@ private:
uint8_t zero = ReadByte();
//Dummy read
- MemoryRead(zero);
+ MemoryRead(zero, MemoryOperationType::DummyRead);
zero += X();
@@ -326,7 +325,7 @@ private:
bool pageCrossed = CheckPageCrossed(addr, Y());
if(pageCrossed || dummyRead) {
//Dummy read done by the processor (only when page is crossed for READ instructions)
- MemoryRead(addr + Y() - (pageCrossed ? 0x100 : 0));
+ MemoryRead(addr + Y() - (pageCrossed ? 0x100 : 0), MemoryOperationType::DummyRead);
}
return addr + Y();
}
@@ -419,7 +418,7 @@ private:
uint8_t result = value >> 1;
SetZeroNegativeFlags(result);
- return value >> 1;
+ return result;
}
uint8_t ROL(uint8_t value) {
diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj
index c15d9828..ee47ee28 100644
--- a/Core/Core.vcxproj
+++ b/Core/Core.vcxproj
@@ -437,6 +437,7 @@
+
@@ -751,6 +752,7 @@
+
diff --git a/Core/Core.vcxproj.filters b/Core/Core.vcxproj.filters
index 9b560264..278970ce 100644
--- a/Core/Core.vcxproj.filters
+++ b/Core/Core.vcxproj.filters
@@ -1096,6 +1096,9 @@
Debugger
+
+ Debugger
+
@@ -1278,5 +1281,8 @@
Debugger
+
+ Debugger
+
\ No newline at end of file
diff --git a/Core/Debugger.cpp b/Core/Debugger.cpp
index 25748fb8..19e2709d 100644
--- a/Core/Debugger.cpp
+++ b/Core/Debugger.cpp
@@ -11,6 +11,8 @@
#include "CodeDataLogger.h"
#include "ExpressionEvaluator.h"
#include "LabelManager.h"
+#include "MemoryDumper.h"
+#include "MemoryAccessCounter.h"
Debugger* Debugger::Instance = nullptr;
const int Debugger::BreakpointTypeCount;
@@ -25,9 +27,10 @@ Debugger::Debugger(shared_ptr console, shared_ptr cpu, shared_ptr<
_mapper = mapper;
_labelManager.reset(new LabelManager(_mapper));
- _disassembler.reset(new Disassembler(memoryManager->GetInternalRAM(), mapper->GetPrgRom(), mapper->GetPrgSize(), mapper->GetWorkRam(), mapper->GetPrgSize(true), this));
- _codeDataLogger.reset(new CodeDataLogger(mapper->GetPrgSize(), mapper->GetChrSize()));
+ _disassembler.reset(new Disassembler(memoryManager->GetInternalRAM(), mapper->GetPrgRom(), mapper->GetMemorySize(DebugMemoryType::PrgRom), mapper->GetWorkRam(), mapper->GetMemorySize(DebugMemoryType::WorkRam), this));
+ _codeDataLogger.reset(new CodeDataLogger(mapper->GetMemorySize(DebugMemoryType::PrgRom), mapper->GetMemorySize(DebugMemoryType::ChrRom)));
_memoryDumper.reset(new MemoryDumper(_ppu, _memoryManager, _mapper, _codeDataLogger));
+ _memoryAccessCounter.reset(new MemoryAccessCounter());
_stepOut = false;
_stepCount = -1;
@@ -100,13 +103,13 @@ void Debugger::BreakIfDebugging()
bool Debugger::LoadCdlFile(string cdlFilepath)
{
if(_codeDataLogger->LoadCdlFile(cdlFilepath)) {
- for(int i = 0, len = _mapper->GetPrgSize(); i < len; i++) {
+ for(int i = 0, len = _mapper->GetMemorySize(DebugMemoryType::PrgRom); i < len; i++) {
if(_codeDataLogger->IsCode(i)) {
i = _disassembler->BuildCache(i, -1, 0xFFFF, _codeDataLogger->IsSubEntryPoint(i)) - 1;
}
}
- for(int i = 0, len = _mapper->GetPrgSize(); i < len; i++) {
+ for(int i = 0, len = _mapper->GetMemorySize(DebugMemoryType::PrgRom); i < len; i++) {
if(_codeDataLogger->IsSubEntryPoint(i)) {
_functionEntryPoints.emplace(i);
}
@@ -314,8 +317,14 @@ void Debugger::PrivateProcessRamOperation(MemoryOperationType type, uint16_t &ad
//Check if a breakpoint has been hit and freeze execution if one has
bool breakDone = false;
- int32_t absoluteAddr = _mapper->ToAbsoluteAddress(addr);
- int32_t absoluteRamAddr = _mapper->ToAbsoluteWorkRamAddress(addr);
+ AddressTypeInfo addressInfo;
+ GetAbsoluteAddressAndType(addr, &addressInfo);
+ int32_t absoluteAddr = addressInfo.Type == AddressType::PrgRom ? addressInfo.Address : -1;
+ int32_t absoluteRamAddr = addressInfo.Type == AddressType::WorkRam ? addressInfo.Address : -1;
+
+ if(addressInfo.Address >= 0 && type != MemoryOperationType::DummyRead) {
+ _memoryAccessCounter->ProcessMemoryAccess(addressInfo, type);
+ }
if(absoluteAddr >= 0) {
if(type == MemoryOperationType::ExecOperand) {
@@ -633,6 +642,11 @@ shared_ptr Debugger::GetMemoryDumper()
return _memoryDumper;
}
+shared_ptr Debugger::GetMemoryAccessCounter()
+{
+ return _memoryAccessCounter;
+}
+
bool Debugger::IsExecutionStopped()
{
return _executionStopped;
@@ -675,4 +689,9 @@ void Debugger::SetPpuViewerScanlineCycle(int32_t scanline, int32_t cycle)
{
_ppuViewerScanline = scanline;
_ppuViewerCycle = cycle;
+}
+
+int Debugger::GetMemorySize(DebugMemoryType memoryType)
+{
+ return _mapper->GetMemorySize(memoryType);
}
\ No newline at end of file
diff --git a/Core/Debugger.h b/Core/Debugger.h
index 293cb756..20cff247 100644
--- a/Core/Debugger.h
+++ b/Core/Debugger.h
@@ -13,7 +13,6 @@ using std::unordered_set;
#include "TraceLogger.h"
#include "../Utilities/SimpleLock.h"
#include "CodeDataLogger.h"
-#include "MemoryDumper.h"
#include "DebuggerTypes.h"
class CPU;
@@ -22,6 +21,8 @@ class MemoryManager;
class Console;
class Disassembler;
class LabelManager;
+class MemoryDumper;
+class MemoryAccessCounter;
class Debugger
{
@@ -33,6 +34,7 @@ private:
unique_ptr _disassembler;
shared_ptr _memoryDumper;
shared_ptr _codeDataLogger;
+ shared_ptr _memoryAccessCounter;
shared_ptr _console;
shared_ptr _cpu;
@@ -145,6 +147,7 @@ public:
void StopTraceLogger();
shared_ptr GetMemoryDumper();
+ shared_ptr GetMemoryAccessCounter();
int32_t EvaluateExpression(string expression, EvalResultType &resultType);
@@ -156,4 +159,6 @@ public:
static bool IsEnabled();
static void BreakIfDebugging();
+
+ int GetMemorySize(DebugMemoryType memoryType);
};
\ No newline at end of file
diff --git a/Core/IMemoryHandler.h b/Core/IMemoryHandler.h
index bf29f147..71a08538 100644
--- a/Core/IMemoryHandler.h
+++ b/Core/IMemoryHandler.h
@@ -16,6 +16,7 @@ enum class MemoryOperationType
ExecOpCode = 2,
ExecOperand = 3,
PpuRenderingRead = 4,
+ DummyRead = 5
};
class MemoryRanges
diff --git a/Core/MemoryAccessCounter.cpp b/Core/MemoryAccessCounter.cpp
new file mode 100644
index 00000000..c949085b
--- /dev/null
+++ b/Core/MemoryAccessCounter.cpp
@@ -0,0 +1,55 @@
+#include "stdafx.h"
+#include "MemoryAccessCounter.h"
+#include "Console.h"
+
+std::unordered_map& MemoryAccessCounter::GetCountMap(MemoryOperationType operationType, AddressType addressType)
+{
+ switch(operationType) {
+ case MemoryOperationType::Read: return _readCounts[(int)addressType];
+ case MemoryOperationType::Write: return _writeCounts[(int)addressType];
+
+ default:
+ case MemoryOperationType::ExecOpCode:
+ case MemoryOperationType::ExecOperand: return _execCounts[(int)addressType];
+ }
+}
+
+void MemoryAccessCounter::ProcessMemoryAccess(AddressTypeInfo &addressInfo, MemoryOperationType operation)
+{
+ int index = (int)addressInfo.Type;
+ std::unordered_map &countMap = GetCountMap(operation, addressInfo.Type);
+ if(operation != MemoryOperationType::Write &&
+ (addressInfo.Type == AddressType::InternalRam || addressInfo.Type == AddressType::WorkRam) &&
+ _initWrites[index].find(addressInfo.Address) == _initWrites[index].end()) {
+ //Mark address as read before being written to (if trying to read/execute)
+ _uninitReads[index].emplace(addressInfo.Address);
+ } else if(operation == MemoryOperationType::Write) {
+ _initWrites[index].emplace(addressInfo.Address);
+ }
+
+ countMap[addressInfo.Address]++;
+}
+
+void MemoryAccessCounter::ResetCounts()
+{
+ Console::Pause();
+ for(int i = 0; i < 4; i++) {
+ _readCounts[i].clear();
+ _writeCounts[i].clear();
+ _execCounts[i].clear();
+ }
+ Console::Resume();
+}
+
+void MemoryAccessCounter::GetAccessCounts(AddressType memoryType, MemoryOperationType operationType, uint32_t counts[], bool forUninitReads)
+{
+ if(forUninitReads) {
+ for(int address : _uninitReads[(int)memoryType]) {
+ counts[address] = 1;
+ }
+ } else {
+ for(auto kvp : GetCountMap(operationType, memoryType)) {
+ counts[kvp.first] = kvp.second;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Core/MemoryAccessCounter.h b/Core/MemoryAccessCounter.h
new file mode 100644
index 00000000..b283c245
--- /dev/null
+++ b/Core/MemoryAccessCounter.h
@@ -0,0 +1,25 @@
+#pragma once
+#include "stdafx.h"
+#include "DebuggerTypes.h"
+#include "IMemoryHandler.h"
+#include
+#include
+
+class MemoryAccessCounter
+{
+private:
+ std::unordered_map _readCounts[4];
+ std::unordered_map _writeCounts[4];
+ std::unordered_map _execCounts[4];
+
+ std::unordered_set _initWrites[4];
+ std::unordered_set _uninitReads[4];
+
+ std::unordered_map& GetCountMap(MemoryOperationType operationType, AddressType addressType);
+
+public:
+ void ProcessMemoryAccess(AddressTypeInfo &addressInfo, MemoryOperationType operation);
+ void ResetCounts();
+
+ void GetAccessCounts(AddressType memoryType, MemoryOperationType operationType, uint32_t counts[], bool forUninitReads);
+};
\ No newline at end of file
diff --git a/Core/MemoryDumper.cpp b/Core/MemoryDumper.cpp
index 6e1bb63e..ee3b538e 100644
--- a/Core/MemoryDumper.cpp
+++ b/Core/MemoryDumper.cpp
@@ -132,8 +132,8 @@ void MemoryDumper::GetChrBank(int bankIndex, uint32_t* frameBuffer, uint8_t pale
} else {
int bank = bankIndex - 2;
uint32_t baseAddr = bank * 0x1000;
- bool useChrRam = _mapper->GetChrSize(false) == 0;
- uint32_t chrSize = _mapper->GetChrSize(useChrRam);
+ bool useChrRam = _mapper->GetMemorySize(DebugMemoryType::ChrRam) > 0;
+ uint32_t chrSize = _mapper->GetMemorySize(useChrRam ? DebugMemoryType::ChrRam : DebugMemoryType::ChrRom);
vector chrData(chrSize, 0);
_mapper->CopyMemory(useChrRam ? DebugMemoryType::ChrRam : DebugMemoryType::ChrRom, chrData.data());
diff --git a/GUI.NET/Debugger/Controls/ctrlDebuggerCode.cs b/GUI.NET/Debugger/Controls/ctrlDebuggerCode.cs
index 1e74a5aa..d7c382a6 100644
--- a/GUI.NET/Debugger/Controls/ctrlDebuggerCode.cs
+++ b/GUI.NET/Debugger/Controls/ctrlDebuggerCode.cs
@@ -131,7 +131,7 @@ namespace Mesen.GUI.Debugger
}
lineNumbers.Add(relativeAddress);
- lineNumberNotes.Add(lineParts[2].Trim('0'));
+ lineNumberNotes.Add(lineParts[2].TrimStart('0'));
codeNotes.Add(lineParts[3]);
codeLines.Add(lineParts[4]);
}
diff --git a/GUI.NET/Debugger/Controls/ctrlHexViewer.cs b/GUI.NET/Debugger/Controls/ctrlHexViewer.cs
index 8f8aa44e..6ee3ef22 100644
--- a/GUI.NET/Debugger/Controls/ctrlHexViewer.cs
+++ b/GUI.NET/Debugger/Controls/ctrlHexViewer.cs
@@ -77,7 +77,7 @@ namespace Mesen.GUI.Debugger.Controls
{
get
{
- return 135 + this.ColumnCount * 30;
+ return 145 + this.ColumnCount * 30;
}
}
diff --git a/GUI.NET/Debugger/Controls/ctrlMemoryAccessCounters.Designer.cs b/GUI.NET/Debugger/Controls/ctrlMemoryAccessCounters.Designer.cs
new file mode 100644
index 00000000..09246e27
--- /dev/null
+++ b/GUI.NET/Debugger/Controls/ctrlMemoryAccessCounters.Designer.cs
@@ -0,0 +1,222 @@
+namespace Mesen.GUI.Debugger.Controls
+{
+ partial class ctrlMemoryAccessCounters
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if(disposing && (components != null)) {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Component Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ this.flowLayoutPanel1 = new System.Windows.Forms.FlowLayoutPanel();
+ this.lblViewMemoryType = new System.Windows.Forms.Label();
+ this.cboMemoryType = new System.Windows.Forms.ComboBox();
+ this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
+ this.flowLayoutPanel2 = new System.Windows.Forms.FlowLayoutPanel();
+ this.lblSort = new System.Windows.Forms.Label();
+ this.cboSort = new System.Windows.Forms.ComboBox();
+ this.chkHighlightUninitRead = new System.Windows.Forms.CheckBox();
+ this.btnReset = new System.Windows.Forms.Button();
+ this.ctrlScrollableTextbox = new Mesen.GUI.Debugger.ctrlScrollableTextbox();
+ this.tableLayoutPanel2 = new System.Windows.Forms.TableLayoutPanel();
+ this.flowLayoutPanel1.SuspendLayout();
+ this.tableLayoutPanel1.SuspendLayout();
+ this.flowLayoutPanel2.SuspendLayout();
+ this.tableLayoutPanel2.SuspendLayout();
+ this.SuspendLayout();
+ //
+ // flowLayoutPanel1
+ //
+ this.flowLayoutPanel1.Controls.Add(this.lblViewMemoryType);
+ this.flowLayoutPanel1.Controls.Add(this.cboMemoryType);
+ this.flowLayoutPanel1.Location = new System.Drawing.Point(3, 3);
+ this.flowLayoutPanel1.Name = "flowLayoutPanel1";
+ this.flowLayoutPanel1.Size = new System.Drawing.Size(167, 26);
+ this.flowLayoutPanel1.TabIndex = 2;
+ //
+ // lblViewMemoryType
+ //
+ this.lblViewMemoryType.Anchor = System.Windows.Forms.AnchorStyles.Left;
+ this.lblViewMemoryType.AutoSize = true;
+ this.lblViewMemoryType.Location = new System.Drawing.Point(3, 7);
+ this.lblViewMemoryType.Name = "lblViewMemoryType";
+ this.lblViewMemoryType.Size = new System.Drawing.Size(33, 13);
+ this.lblViewMemoryType.TabIndex = 0;
+ this.lblViewMemoryType.Text = "View:";
+ //
+ // cboMemoryType
+ //
+ this.cboMemoryType.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
+ this.cboMemoryType.FormattingEnabled = true;
+ this.cboMemoryType.Items.AddRange(new object[] {
+ "Console RAM",
+ "PRG ROM",
+ "Cartridge Save RAM",
+ "Cartridge Work RAM"});
+ this.cboMemoryType.Location = new System.Drawing.Point(42, 3);
+ this.cboMemoryType.Name = "cboMemoryType";
+ this.cboMemoryType.Size = new System.Drawing.Size(121, 21);
+ this.cboMemoryType.TabIndex = 1;
+ this.cboMemoryType.SelectedIndexChanged += new System.EventHandler(this.cboMemoryType_SelectedIndexChanged);
+ //
+ // tableLayoutPanel1
+ //
+ this.tableLayoutPanel1.ColumnCount = 2;
+ this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
+ this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
+ this.tableLayoutPanel1.Controls.Add(this.ctrlScrollableTextbox, 0, 1);
+ this.tableLayoutPanel1.Controls.Add(this.chkHighlightUninitRead, 0, 2);
+ this.tableLayoutPanel1.Controls.Add(this.btnReset, 1, 2);
+ this.tableLayoutPanel1.Controls.Add(this.tableLayoutPanel2, 0, 0);
+ this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill;
+ this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0);
+ this.tableLayoutPanel1.Name = "tableLayoutPanel1";
+ this.tableLayoutPanel1.RowCount = 3;
+ this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
+ this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
+ this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
+ this.tableLayoutPanel1.Size = new System.Drawing.Size(514, 307);
+ this.tableLayoutPanel1.TabIndex = 3;
+ //
+ // flowLayoutPanel2
+ //
+ this.flowLayoutPanel2.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
+ this.flowLayoutPanel2.Controls.Add(this.lblSort);
+ this.flowLayoutPanel2.Controls.Add(this.cboSort);
+ this.flowLayoutPanel2.Location = new System.Drawing.Point(335, 3);
+ this.flowLayoutPanel2.Name = "flowLayoutPanel2";
+ this.flowLayoutPanel2.Size = new System.Drawing.Size(176, 26);
+ this.flowLayoutPanel2.TabIndex = 3;
+ //
+ // lblSort
+ //
+ this.lblSort.Anchor = System.Windows.Forms.AnchorStyles.Left;
+ this.lblSort.AutoSize = true;
+ this.lblSort.Location = new System.Drawing.Point(3, 7);
+ this.lblSort.Name = "lblSort";
+ this.lblSort.Size = new System.Drawing.Size(43, 13);
+ this.lblSort.TabIndex = 0;
+ this.lblSort.Text = "Sort by:";
+ //
+ // cboSort
+ //
+ this.cboSort.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
+ this.cboSort.FormattingEnabled = true;
+ this.cboSort.Items.AddRange(new object[] {
+ "Address",
+ "Read Count",
+ "Write Count",
+ "Execute Count",
+ "Uninitialized Reads"});
+ this.cboSort.Location = new System.Drawing.Point(52, 3);
+ this.cboSort.Name = "cboSort";
+ this.cboSort.Size = new System.Drawing.Size(121, 21);
+ this.cboSort.TabIndex = 1;
+ this.cboSort.SelectedIndexChanged += new System.EventHandler(this.cboSort_SelectedIndexChanged);
+ //
+ // chkHighlightUninitRead
+ //
+ this.chkHighlightUninitRead.Anchor = System.Windows.Forms.AnchorStyles.Left;
+ this.chkHighlightUninitRead.AutoSize = true;
+ this.chkHighlightUninitRead.Location = new System.Drawing.Point(3, 284);
+ this.chkHighlightUninitRead.Name = "chkHighlightUninitRead";
+ this.chkHighlightUninitRead.Size = new System.Drawing.Size(422, 17);
+ this.chkHighlightUninitRead.TabIndex = 4;
+ this.chkHighlightUninitRead.Text = "Highlight uninitialized memory reads (only accurate if debugger is active at powe" +
+ "r on)";
+ this.chkHighlightUninitRead.UseVisualStyleBackColor = true;
+ this.chkHighlightUninitRead.CheckedChanged += new System.EventHandler(this.chkHighlightUninitRead_CheckedChanged);
+ //
+ // btnReset
+ //
+ this.btnReset.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
+ this.btnReset.Location = new System.Drawing.Point(436, 281);
+ this.btnReset.Name = "btnReset";
+ this.btnReset.Size = new System.Drawing.Size(75, 23);
+ this.btnReset.TabIndex = 5;
+ this.btnReset.Text = "Reset Counts";
+ this.btnReset.UseVisualStyleBackColor = true;
+ this.btnReset.Click += new System.EventHandler(this.btnReset_Click);
+ //
+ // ctrlScrollableTextbox
+ //
+ this.ctrlScrollableTextbox.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
+ this.tableLayoutPanel1.SetColumnSpan(this.ctrlScrollableTextbox, 2);
+ this.ctrlScrollableTextbox.Dock = System.Windows.Forms.DockStyle.Fill;
+ this.ctrlScrollableTextbox.FontSize = 13F;
+ this.ctrlScrollableTextbox.Location = new System.Drawing.Point(3, 35);
+ this.ctrlScrollableTextbox.Name = "ctrlScrollableTextbox";
+ this.ctrlScrollableTextbox.ShowContentNotes = false;
+ this.ctrlScrollableTextbox.ShowLineNumberNotes = false;
+ this.ctrlScrollableTextbox.Size = new System.Drawing.Size(508, 240);
+ this.ctrlScrollableTextbox.TabIndex = 0;
+ //
+ // tableLayoutPanel2
+ //
+ this.tableLayoutPanel2.ColumnCount = 2;
+ this.tableLayoutPanel1.SetColumnSpan(this.tableLayoutPanel2, 2);
+ this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));
+ this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));
+ this.tableLayoutPanel2.Controls.Add(this.flowLayoutPanel2, 1, 0);
+ this.tableLayoutPanel2.Controls.Add(this.flowLayoutPanel1, 0, 0);
+ this.tableLayoutPanel2.Dock = System.Windows.Forms.DockStyle.Fill;
+ this.tableLayoutPanel2.Location = new System.Drawing.Point(0, 0);
+ this.tableLayoutPanel2.Margin = new System.Windows.Forms.Padding(0, 0, 0, 0);
+ this.tableLayoutPanel2.Name = "tableLayoutPanel2";
+ this.tableLayoutPanel2.RowCount = 1;
+ this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F));
+ this.tableLayoutPanel2.Size = new System.Drawing.Size(514, 32);
+ this.tableLayoutPanel2.TabIndex = 6;
+ //
+ // ctrlMemoryAccessCounters
+ //
+ this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.Controls.Add(this.tableLayoutPanel1);
+ this.Name = "ctrlMemoryAccessCounters";
+ this.Size = new System.Drawing.Size(514, 307);
+ this.flowLayoutPanel1.ResumeLayout(false);
+ this.flowLayoutPanel1.PerformLayout();
+ this.tableLayoutPanel1.ResumeLayout(false);
+ this.tableLayoutPanel1.PerformLayout();
+ this.flowLayoutPanel2.ResumeLayout(false);
+ this.flowLayoutPanel2.PerformLayout();
+ this.tableLayoutPanel2.ResumeLayout(false);
+ this.ResumeLayout(false);
+
+ }
+
+ #endregion
+
+ private ctrlScrollableTextbox ctrlScrollableTextbox;
+ private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel1;
+ private System.Windows.Forms.Label lblViewMemoryType;
+ private System.Windows.Forms.ComboBox cboMemoryType;
+ private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1;
+ private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel2;
+ private System.Windows.Forms.Label lblSort;
+ private System.Windows.Forms.ComboBox cboSort;
+ private System.Windows.Forms.CheckBox chkHighlightUninitRead;
+ private System.Windows.Forms.Button btnReset;
+ private System.Windows.Forms.TableLayoutPanel tableLayoutPanel2;
+ }
+}
diff --git a/GUI.NET/Debugger/Controls/ctrlMemoryAccessCounters.cs b/GUI.NET/Debugger/Controls/ctrlMemoryAccessCounters.cs
new file mode 100644
index 00000000..114e8d2a
--- /dev/null
+++ b/GUI.NET/Debugger/Controls/ctrlMemoryAccessCounters.cs
@@ -0,0 +1,187 @@
+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;
+
+namespace Mesen.GUI.Debugger.Controls
+{
+ public partial class ctrlMemoryAccessCounters : UserControl
+ {
+ private MemoryCountData[] _data;
+ private AddressType _memoryType = AddressType.InternalRam;
+ private SortType _sortType = SortType.Address;
+
+ public ctrlMemoryAccessCounters()
+ {
+ InitializeComponent();
+
+ bool designMode = (LicenseManager.UsageMode == LicenseUsageMode.Designtime);
+ if(!designMode) {
+ cboMemoryType.SelectedIndex = 0;
+ cboSort.SelectedIndex = 0;
+ }
+ }
+
+ public void RefreshData()
+ {
+ ctrlScrollableTextbox.ClearLineStyles();
+
+ 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);
+
+ int[] addresses = new int[readCounts.Length];
+ string[] content = new 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(), data); break;
+ case SortType.Write: Array.Sort(data.Select((e) => -e.WriteCount).ToArray(), data); break;
+ case SortType.Exec: Array.Sort(data.Select((e) => -e.ExecCount).ToArray(), data); break;
+ case SortType.UninitRead: Array.Sort(data.Select((e) => e.UninitRead ? -e.ReadCount : (Int32.MaxValue - e.ReadCount)).ToArray(), data); break;
+ }
+
+ for(int i = 0; i < readCounts.Length; i++) {
+ addresses[i] = data[i].Address;
+ content[i] = data[i].Content;
+ }
+
+ ctrlScrollableTextbox.Header = "Read".PadRight(12) + "Write".PadRight(12) + "Execute".PadRight(12);
+ ctrlScrollableTextbox.LineNumbers = addresses;
+ ctrlScrollableTextbox.TextLines = content;
+
+ if(chkHighlightUninitRead.Checked) {
+ foreach(int address in data.Where((e) => e.UninitRead).Select((e) => e.Address)) {
+ ctrlScrollableTextbox.SetLineColor(address, null, Color.LightCoral);
+ }
+ }
+ }
+
+ private void cboMemoryType_SelectedIndexChanged(object sender, EventArgs e)
+ {
+ switch(this.cboMemoryType.SelectedIndex) {
+ default:
+ case 0: _memoryType = AddressType.InternalRam; break;
+ case 1: _memoryType = AddressType.PrgRom; break;
+ case 2: _memoryType = AddressType.SaveRam; break;
+ case 3: _memoryType = AddressType.WorkRam; break;
+ }
+
+ RefreshData();
+ }
+
+ private void cboSort_SelectedIndexChanged(object sender, EventArgs e)
+ {
+ _sortType = (SortType)cboSort.SelectedIndex;
+ RefreshData();
+ }
+
+ private void chkHighlightUninitRead_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 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; }
+ }
+ }
+}
diff --git a/GUI.NET/Debugger/Controls/ctrlMemoryAccessCounters.resx b/GUI.NET/Debugger/Controls/ctrlMemoryAccessCounters.resx
new file mode 100644
index 00000000..1af7de15
--- /dev/null
+++ b/GUI.NET/Debugger/Controls/ctrlMemoryAccessCounters.resx
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/GUI.NET/Debugger/Controls/ctrlTextbox.cs b/GUI.NET/Debugger/Controls/ctrlTextbox.cs
index 4d8c9749..0cc13d58 100644
--- a/GUI.NET/Debugger/Controls/ctrlTextbox.cs
+++ b/GUI.NET/Debugger/Controls/ctrlTextbox.cs
@@ -97,11 +97,13 @@ namespace Mesen.GUI.Debugger
UpdateHorizontalScrollWidth();
- _lineNumbers = new int[_contents.Length];
- _lineNumberIndex.Clear();
- for(int i = _contents.Length - 1; i >=0; i--) {
- _lineNumbers[i] = i;
- _lineNumberIndex[i] = i;
+ if(_lineNumbers.Length != _contents.Length) {
+ _lineNumbers = new int[_contents.Length];
+ _lineNumberIndex.Clear();
+ for(int i = _contents.Length - 1; i >=0; i--) {
+ _lineNumbers[i] = i;
+ _lineNumberIndex[i] = i;
+ }
}
this.Invalidate();
}
diff --git a/GUI.NET/Debugger/frmMemoryViewer.Designer.cs b/GUI.NET/Debugger/frmMemoryViewer.Designer.cs
index fb1dab4b..202444c9 100644
--- a/GUI.NET/Debugger/frmMemoryViewer.Designer.cs
+++ b/GUI.NET/Debugger/frmMemoryViewer.Designer.cs
@@ -31,6 +31,7 @@
///
private void InitializeComponent()
{
+ this.components = new System.ComponentModel.Container();
this.ctrlHexViewer = new Mesen.GUI.Debugger.Controls.ctrlHexViewer();
this.flowLayoutPanel1 = new System.Windows.Forms.FlowLayoutPanel();
this.lblViewMemoryType = new System.Windows.Forms.Label();
@@ -57,17 +58,25 @@
this.toolStrip1 = new System.Windows.Forms.ToolStrip();
this.btnImport = new System.Windows.Forms.ToolStripButton();
this.btnExport = new System.Windows.Forms.ToolStripButton();
+ this.tabMain = new System.Windows.Forms.TabControl();
+ this.tpgMemoryViewer = new System.Windows.Forms.TabPage();
+ this.tpgAccessCounters = new System.Windows.Forms.TabPage();
+ this.ctrlMemoryAccessCounters = new Mesen.GUI.Debugger.Controls.ctrlMemoryAccessCounters();
+ this.tmrRefresh = new System.Windows.Forms.Timer(this.components);
this.flowLayoutPanel1.SuspendLayout();
this.menuStrip1.SuspendLayout();
this.toolStrip1.SuspendLayout();
+ this.tabMain.SuspendLayout();
+ this.tpgMemoryViewer.SuspendLayout();
+ this.tpgAccessCounters.SuspendLayout();
this.SuspendLayout();
//
// ctrlHexViewer
//
this.ctrlHexViewer.Dock = System.Windows.Forms.DockStyle.Fill;
- this.ctrlHexViewer.Location = new System.Drawing.Point(0, 49);
+ this.ctrlHexViewer.Location = new System.Drawing.Point(3, 28);
this.ctrlHexViewer.Name = "ctrlHexViewer";
- this.ctrlHexViewer.Size = new System.Drawing.Size(461, 378);
+ this.ctrlHexViewer.Size = new System.Drawing.Size(513, 346);
this.ctrlHexViewer.TabIndex = 0;
this.ctrlHexViewer.ColumnCountChanged += new System.EventHandler(this.ctrlHexViewer_ColumnCountChanged);
//
@@ -75,7 +84,7 @@
//
this.flowLayoutPanel1.Controls.Add(this.lblViewMemoryType);
this.flowLayoutPanel1.Controls.Add(this.cboMemoryType);
- this.flowLayoutPanel1.Location = new System.Drawing.Point(0, 49);
+ this.flowLayoutPanel1.Location = new System.Drawing.Point(6, 31);
this.flowLayoutPanel1.Name = "flowLayoutPanel1";
this.flowLayoutPanel1.Size = new System.Drawing.Size(167, 27);
this.flowLayoutPanel1.TabIndex = 1;
@@ -120,7 +129,7 @@
this.toolStripMenuItem1});
this.menuStrip1.Location = new System.Drawing.Point(0, 0);
this.menuStrip1.Name = "menuStrip1";
- this.menuStrip1.Size = new System.Drawing.Size(461, 24);
+ this.menuStrip1.Size = new System.Drawing.Size(527, 24);
this.menuStrip1.TabIndex = 2;
this.menuStrip1.Text = "menuStrip1";
//
@@ -282,9 +291,9 @@
this.toolStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.btnImport,
this.btnExport});
- this.toolStrip1.Location = new System.Drawing.Point(0, 24);
+ this.toolStrip1.Location = new System.Drawing.Point(3, 3);
this.toolStrip1.Name = "toolStrip1";
- this.toolStrip1.Size = new System.Drawing.Size(461, 25);
+ this.toolStrip1.Size = new System.Drawing.Size(513, 25);
this.toolStrip1.TabIndex = 3;
this.toolStrip1.Text = "toolStrip1";
//
@@ -306,17 +315,64 @@
this.btnExport.Text = "Export";
this.btnExport.Click += new System.EventHandler(this.mnuExport_Click);
//
+ // tabMain
+ //
+ this.tabMain.Controls.Add(this.tpgMemoryViewer);
+ this.tabMain.Controls.Add(this.tpgAccessCounters);
+ this.tabMain.Dock = System.Windows.Forms.DockStyle.Fill;
+ this.tabMain.Location = new System.Drawing.Point(0, 24);
+ this.tabMain.Name = "tabMain";
+ this.tabMain.SelectedIndex = 0;
+ this.tabMain.Size = new System.Drawing.Size(527, 403);
+ this.tabMain.TabIndex = 4;
+ this.tabMain.SelectedIndexChanged += new System.EventHandler(this.tabMain_SelectedIndexChanged);
+ //
+ // tpgMemoryViewer
+ //
+ this.tpgMemoryViewer.Controls.Add(this.flowLayoutPanel1);
+ this.tpgMemoryViewer.Controls.Add(this.ctrlHexViewer);
+ this.tpgMemoryViewer.Controls.Add(this.toolStrip1);
+ this.tpgMemoryViewer.Location = new System.Drawing.Point(4, 22);
+ this.tpgMemoryViewer.Name = "tpgMemoryViewer";
+ this.tpgMemoryViewer.Padding = new System.Windows.Forms.Padding(3);
+ this.tpgMemoryViewer.Size = new System.Drawing.Size(519, 377);
+ this.tpgMemoryViewer.TabIndex = 0;
+ this.tpgMemoryViewer.Text = "Memory Viewer";
+ this.tpgMemoryViewer.UseVisualStyleBackColor = true;
+ //
+ // tpgAccessCounters
+ //
+ this.tpgAccessCounters.Controls.Add(this.ctrlMemoryAccessCounters);
+ this.tpgAccessCounters.Location = new System.Drawing.Point(4, 22);
+ this.tpgAccessCounters.Name = "tpgAccessCounters";
+ this.tpgAccessCounters.Padding = new System.Windows.Forms.Padding(3);
+ this.tpgAccessCounters.Size = new System.Drawing.Size(519, 377);
+ this.tpgAccessCounters.TabIndex = 1;
+ this.tpgAccessCounters.Text = "Access Counters";
+ this.tpgAccessCounters.UseVisualStyleBackColor = true;
+ //
+ // ctrlMemoryAccessCounters
+ //
+ this.ctrlMemoryAccessCounters.Dock = System.Windows.Forms.DockStyle.Fill;
+ this.ctrlMemoryAccessCounters.Location = new System.Drawing.Point(3, 3);
+ this.ctrlMemoryAccessCounters.Name = "ctrlMemoryAccessCounters";
+ this.ctrlMemoryAccessCounters.Size = new System.Drawing.Size(513, 371);
+ this.ctrlMemoryAccessCounters.TabIndex = 0;
+ //
+ // tmrRefresh
+ //
+ this.tmrRefresh.Enabled = true;
+ this.tmrRefresh.Tick += new System.EventHandler(this.tmrRefresh_Tick);
+ //
// frmMemoryViewer
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
- this.ClientSize = new System.Drawing.Size(461, 427);
- this.Controls.Add(this.flowLayoutPanel1);
- this.Controls.Add(this.ctrlHexViewer);
- this.Controls.Add(this.toolStrip1);
+ this.ClientSize = new System.Drawing.Size(527, 427);
+ this.Controls.Add(this.tabMain);
this.Controls.Add(this.menuStrip1);
this.MainMenuStrip = this.menuStrip1;
- this.MinimumSize = new System.Drawing.Size(477, 465);
+ this.MinimumSize = new System.Drawing.Size(543, 465);
this.Name = "frmMemoryViewer";
this.Text = "Memory Viewer";
this.flowLayoutPanel1.ResumeLayout(false);
@@ -325,6 +381,10 @@
this.menuStrip1.PerformLayout();
this.toolStrip1.ResumeLayout(false);
this.toolStrip1.PerformLayout();
+ this.tabMain.ResumeLayout(false);
+ this.tpgMemoryViewer.ResumeLayout(false);
+ this.tpgMemoryViewer.PerformLayout();
+ this.tpgAccessCounters.ResumeLayout(false);
this.ResumeLayout(false);
this.PerformLayout();
@@ -358,5 +418,10 @@
private System.Windows.Forms.ToolStrip toolStrip1;
private System.Windows.Forms.ToolStripButton btnImport;
private System.Windows.Forms.ToolStripButton btnExport;
+ private System.Windows.Forms.TabControl tabMain;
+ private System.Windows.Forms.TabPage tpgMemoryViewer;
+ private System.Windows.Forms.TabPage tpgAccessCounters;
+ private Controls.ctrlMemoryAccessCounters ctrlMemoryAccessCounters;
+ private System.Windows.Forms.Timer tmrRefresh;
}
}
\ No newline at end of file
diff --git a/GUI.NET/Debugger/frmMemoryViewer.cs b/GUI.NET/Debugger/frmMemoryViewer.cs
index a8c50730..9a45926e 100644
--- a/GUI.NET/Debugger/frmMemoryViewer.cs
+++ b/GUI.NET/Debugger/frmMemoryViewer.cs
@@ -16,7 +16,6 @@ namespace Mesen.GUI.Debugger
public partial class frmMemoryViewer : BaseForm
{
private InteropEmu.NotificationListener _notifListener;
- private int _autoRefreshCounter = 0;
private DebugMemoryType _memoryType = DebugMemoryType.CpuMemory;
public frmMemoryViewer()
@@ -44,13 +43,6 @@ namespace Mesen.GUI.Debugger
{
if(e.NotificationType == InteropEmu.ConsoleNotificationType.CodeBreak) {
this.BeginInvoke((MethodInvoker)(() => this.RefreshData()));
- } else if(e.NotificationType == InteropEmu.ConsoleNotificationType.PpuFrameDone) {
- this.BeginInvoke((MethodInvoker)(() => {
- if(_autoRefreshCounter % 4 == 0 && this.mnuAutoRefresh.Checked) {
- this.RefreshData();
- }
- _autoRefreshCounter++;
- }));
}
}
@@ -69,7 +61,11 @@ namespace Mesen.GUI.Debugger
private void RefreshData()
{
- this.ctrlHexViewer.Data = InteropEmu.DebugGetMemoryState((DebugMemoryType)this.cboMemoryType.SelectedIndex);
+ if(this.tabMain.SelectedTab == this.tpgAccessCounters) {
+ this.ctrlMemoryAccessCounters.RefreshData();
+ } else {
+ this.ctrlHexViewer.Data = InteropEmu.DebugGetMemoryState((DebugMemoryType)this.cboMemoryType.SelectedIndex);
+ }
}
private void ctrlHexViewer_ColumnCountChanged(object sender, EventArgs e)
@@ -172,5 +168,17 @@ namespace Mesen.GUI.Debugger
File.WriteAllBytes(sfd.FileName, this.ctrlHexViewer.Data);
}
}
+
+ private void tmrRefresh_Tick(object sender, EventArgs e)
+ {
+ if(this.mnuAutoRefresh.Checked) {
+ this.RefreshData();
+ }
+ }
+
+ private void tabMain_SelectedIndexChanged(object sender, EventArgs e)
+ {
+ this.tmrRefresh.Interval = this.tabMain.SelectedTab == this.tpgMemoryViewer ? 100 : 500;
+ }
}
}
diff --git a/GUI.NET/Debugger/frmMemoryViewer.resx b/GUI.NET/Debugger/frmMemoryViewer.resx
index 4e7f6e36..51a3bedd 100644
--- a/GUI.NET/Debugger/frmMemoryViewer.resx
+++ b/GUI.NET/Debugger/frmMemoryViewer.resx
@@ -126,4 +126,7 @@
222, 17
+
+ 327, 17
+
\ No newline at end of file
diff --git a/GUI.NET/GUI.NET.csproj b/GUI.NET/GUI.NET.csproj
index 76fbe3b6..23123afe 100644
--- a/GUI.NET/GUI.NET.csproj
+++ b/GUI.NET/GUI.NET.csproj
@@ -290,6 +290,12 @@
ctrlFunctionList.cs
+
+ UserControl
+
+
+ ctrlMemoryAccessCounters.cs
+
UserControl
@@ -616,6 +622,9 @@
ctrlFunctionList.cs
+
+ ctrlMemoryAccessCounters.cs
+
ctrlPaletteViewer.cs
diff --git a/GUI.NET/InteropEmu.cs b/GUI.NET/InteropEmu.cs
index e1215338..948d25d6 100644
--- a/GUI.NET/InteropEmu.cs
+++ b/GUI.NET/InteropEmu.cs
@@ -179,6 +179,7 @@ namespace Mesen.GUI
[DllImport(DLLPath)] public static extern Byte DebugGetMemoryValue(UInt32 addr);
[DllImport(DLLPath)] public static extern Int32 DebugGetRelativeAddress(UInt32 absoluteAddr, AddressType type);
[DllImport(DLLPath)] public static extern Int32 DebugGetAbsoluteAddress(UInt32 relativeAddr);
+ [DllImport(DLLPath)] public static extern Int32 DebugGetMemorySize(DebugMemoryType type);
[DllImport(DLLPath)] public static extern void DebugGetAbsoluteAddressAndType(UInt32 relativeAddr, ref AddressTypeInfo addressTypeInfo);
[DllImport(DLLPath)] public static extern void DebugSetPpuViewerScanlineCycle(Int32 scanline, Int32 cycle);
@@ -187,12 +188,13 @@ namespace Mesen.GUI
[DllImport(DLLPath)] public static extern void DebugStartTraceLogger(TraceLoggerOptions options);
[DllImport(DLLPath)] public static extern void DebugStopTraceLogger();
-
+
[DllImport(DLLPath)] [return: MarshalAs(UnmanagedType.I1)] public static extern bool DebugLoadCdlFile([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(UTF8Marshaler))]string cdlFilepath);
[DllImport(DLLPath)] [return: MarshalAs(UnmanagedType.I1)] public static extern bool DebugSaveCdlFile([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(UTF8Marshaler))]string cdlFilepath);
[DllImport(DLLPath)] public static extern void DebugGetCdlRatios(ref CdlRatios ratios);
[DllImport(DLLPath)] public static extern void DebugResetCdlLog();
-
+ [DllImport(DLLPath)] public static extern void DebugResetMemoryAccessCounts();
+
[DllImport(DLLPath, EntryPoint = "DebugGetCode")] private static extern IntPtr DebugGetCodeWrapper();
public static string DebugGetCode() { return PtrToStringUtf8(InteropEmu.DebugGetCodeWrapper()); }
@@ -298,6 +300,31 @@ namespace Mesen.GUI
return frameData;
}
+ [DllImport(DLLPath, EntryPoint= "DebugGetMemoryAccessCounts")] private static extern void DebugGetMemoryAccessCountsWrapper(AddressType type, MemoryOperationType operationType, IntPtr counts, [MarshalAs(UnmanagedType.I1)]bool forUninitReads);
+ public static Int32[] DebugGetMemoryAccessCounts(AddressType type, MemoryOperationType operationType, bool forUninitReads)
+ {
+ int size = 0;
+ switch(type) {
+ case AddressType.InternalRam: size = 0x2000; break;
+ case AddressType.PrgRom: size = InteropEmu.DebugGetMemorySize(DebugMemoryType.PrgRom); break;
+ case AddressType.WorkRam: size = InteropEmu.DebugGetMemorySize(DebugMemoryType.WorkRam); break;
+ case AddressType.SaveRam: size = InteropEmu.DebugGetMemorySize(DebugMemoryType.SaveRam); break;
+ }
+
+ Int32[] counts = new Int32[size];
+
+ if(size > 0) {
+ GCHandle hCounts = GCHandle.Alloc(counts, GCHandleType.Pinned);
+ try {
+ InteropEmu.DebugGetMemoryAccessCountsWrapper(type, operationType, hCounts.AddrOfPinnedObject(), forUninitReads);
+ } finally {
+ hCounts.Free();
+ }
+ }
+
+ return counts;
+ }
+
[DllImport(DLLPath, EntryPoint="DebugGetCallstack")] private static extern void DebugGetCallstackWrapper(IntPtr callstackAbsolute, IntPtr callstackRelative);
public static void DebugGetCallstack(out Int32[] callstackAbsolute, out Int32[] callstackRelative)
{
@@ -1078,6 +1105,14 @@ namespace Mesen.GUI
Register = 4
}
+ public enum MemoryOperationType
+ {
+ //Note: Not identical to the C++ enum
+ Read = 0,
+ Write = 1,
+ Exec = 2,
+ }
+
public struct AddressTypeInfo
{
public Int32 Address;
diff --git a/InteropDLL/DebugWrapper.cpp b/InteropDLL/DebugWrapper.cpp
index 46696ac9..735e7740 100644
--- a/InteropDLL/DebugWrapper.cpp
+++ b/InteropDLL/DebugWrapper.cpp
@@ -3,6 +3,8 @@
#include "../Core/Debugger.h"
#include "../Core/CodeDataLogger.h"
#include "../Core/LabelManager.h"
+#include "../Core/MemoryDumper.h"
+#include "../Core/MemoryAccessCounter.h"
shared_ptr GetDebugger()
{
@@ -73,4 +75,8 @@ extern "C"
DllExport void __stdcall DebugStartTraceLogger(TraceLoggerOptions options) { GetDebugger()->StartTraceLogger(options); }
DllExport void __stdcall DebugStopTraceLogger() { GetDebugger()->StopTraceLogger(); }
+
+ DllExport int32_t __stdcall DebugGetMemorySize(DebugMemoryType type) { return GetDebugger()->GetMemorySize(type); }
+ DllExport void __stdcall DebugGetMemoryAccessCounts(AddressType memoryType, MemoryOperationType operationType, uint32_t* counts, bool forUninitReads) { GetDebugger()->GetMemoryAccessCounter()->GetAccessCounts(memoryType, operationType, counts, forUninitReads); }
+ DllExport void __stdcall DebugResetMemoryAccessCounts() { GetDebugger()->GetMemoryAccessCounter()->ResetCounts(); }
};