Debugger: Memory access counters (read/write/exec/uninitialized read)

This commit is contained in:
Souryo 2016-12-01 19:38:48 -05:00
parent 825db35191
commit c1a6453343
23 changed files with 830 additions and 57 deletions

View file

@ -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)

View file

@ -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);

View file

@ -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) {

View file

@ -437,6 +437,7 @@
<ClInclude Include="DaouInfosys.h" />
<ClInclude Include="DebuggerTypes.h" />
<ClInclude Include="LabelManager.h" />
<ClInclude Include="MemoryAccessCounter.h" />
<ClInclude Include="MemoryDumper.h" />
<ClInclude Include="DebugState.h" />
<ClInclude Include="DefaultVideoFilter.h" />
@ -751,6 +752,7 @@
<ClCompile Include="ControlManager.cpp" />
<ClCompile Include="Debugger.cpp" />
<ClCompile Include="LabelManager.cpp" />
<ClCompile Include="MemoryAccessCounter.cpp" />
<ClCompile Include="MemoryDumper.cpp" />
<ClCompile Include="DefaultVideoFilter.cpp" />
<ClCompile Include="DeltaModulationChannel.cpp" />

View file

@ -1096,6 +1096,9 @@
<ClInclude Include="DebuggerTypes.h">
<Filter>Debugger</Filter>
</ClInclude>
<ClInclude Include="MemoryAccessCounter.h">
<Filter>Debugger</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="stdafx.cpp">
@ -1278,5 +1281,8 @@
<ClCompile Include="LabelManager.cpp">
<Filter>Debugger</Filter>
</ClCompile>
<ClCompile Include="MemoryAccessCounter.cpp">
<Filter>Debugger</Filter>
</ClCompile>
</ItemGroup>
</Project>

View file

@ -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> console, shared_ptr<CPU> 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<MemoryDumper> Debugger::GetMemoryDumper()
return _memoryDumper;
}
shared_ptr<MemoryAccessCounter> 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);
}

View file

@ -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> _disassembler;
shared_ptr<MemoryDumper> _memoryDumper;
shared_ptr<CodeDataLogger> _codeDataLogger;
shared_ptr<MemoryAccessCounter> _memoryAccessCounter;
shared_ptr<Console> _console;
shared_ptr<CPU> _cpu;
@ -145,6 +147,7 @@ public:
void StopTraceLogger();
shared_ptr<MemoryDumper> GetMemoryDumper();
shared_ptr<MemoryAccessCounter> GetMemoryAccessCounter();
int32_t EvaluateExpression(string expression, EvalResultType &resultType);
@ -156,4 +159,6 @@ public:
static bool IsEnabled();
static void BreakIfDebugging();
int GetMemorySize(DebugMemoryType memoryType);
};

View file

@ -16,6 +16,7 @@ enum class MemoryOperationType
ExecOpCode = 2,
ExecOperand = 3,
PpuRenderingRead = 4,
DummyRead = 5
};
class MemoryRanges

View file

@ -0,0 +1,55 @@
#include "stdafx.h"
#include "MemoryAccessCounter.h"
#include "Console.h"
std::unordered_map<int, int>& 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<int, int> &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;
}
}
}

View file

@ -0,0 +1,25 @@
#pragma once
#include "stdafx.h"
#include "DebuggerTypes.h"
#include "IMemoryHandler.h"
#include <unordered_map>
#include <unordered_set>
class MemoryAccessCounter
{
private:
std::unordered_map<int, int> _readCounts[4];
std::unordered_map<int, int> _writeCounts[4];
std::unordered_map<int, int> _execCounts[4];
std::unordered_set<int> _initWrites[4];
std::unordered_set<int> _uninitReads[4];
std::unordered_map<int, int>& 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);
};

View file

@ -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<uint8_t> chrData(chrSize, 0);
_mapper->CopyMemory(useChrRam ? DebugMemoryType::ChrRam : DebugMemoryType::ChrRom, chrData.data());

View file

@ -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]);
}

View file

@ -77,7 +77,7 @@ namespace Mesen.GUI.Debugger.Controls
{
get
{
return 135 + this.ColumnCount * 30;
return 145 + this.ColumnCount * 30;
}
}

View file

@ -0,0 +1,222 @@
namespace Mesen.GUI.Debugger.Controls
{
partial class ctrlMemoryAccessCounters
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if(disposing && (components != null)) {
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
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;
}
}

View file

@ -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<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;
}
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; }
}
}
}

View file

@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View file

@ -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();
}

View file

@ -31,6 +31,7 @@
/// </summary>
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;
}
}

View file

@ -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;
}
}
}

View file

@ -126,4 +126,7 @@
<metadata name="toolStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>222, 17</value>
</metadata>
<metadata name="tmrRefresh.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>327, 17</value>
</metadata>
</root>

View file

@ -290,6 +290,12 @@
<Compile Include="Debugger\Controls\ctrlFunctionList.Designer.cs">
<DependentUpon>ctrlFunctionList.cs</DependentUpon>
</Compile>
<Compile Include="Debugger\Controls\ctrlMemoryAccessCounters.cs">
<SubType>UserControl</SubType>
</Compile>
<Compile Include="Debugger\Controls\ctrlMemoryAccessCounters.Designer.cs">
<DependentUpon>ctrlMemoryAccessCounters.cs</DependentUpon>
</Compile>
<Compile Include="Debugger\Controls\ctrlMemoryMapping.cs" />
<Compile Include="Debugger\Controls\ctrlPaletteViewer.cs">
<SubType>UserControl</SubType>
@ -616,6 +622,9 @@
<EmbeddedResource Include="Debugger\Controls\ctrlFunctionList.resx">
<DependentUpon>ctrlFunctionList.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Debugger\Controls\ctrlMemoryAccessCounters.resx">
<DependentUpon>ctrlMemoryAccessCounters.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Debugger\Controls\ctrlPaletteViewer.resx">
<DependentUpon>ctrlPaletteViewer.cs</DependentUpon>
</EmbeddedResource>

View file

@ -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;

View file

@ -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<Debugger> 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(); }
};