Debugger: Memory access counters (read/write/exec/uninitialized read)
This commit is contained in:
parent
825db35191
commit
c1a6453343
23 changed files with 830 additions and 57 deletions
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
17
Core/CPU.h
17
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) {
|
||||
|
|
|
@ -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" />
|
||||
|
|
|
@ -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>
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
};
|
|
@ -16,6 +16,7 @@ enum class MemoryOperationType
|
|||
ExecOpCode = 2,
|
||||
ExecOperand = 3,
|
||||
PpuRenderingRead = 4,
|
||||
DummyRead = 5
|
||||
};
|
||||
|
||||
class MemoryRanges
|
||||
|
|
55
Core/MemoryAccessCounter.cpp
Normal file
55
Core/MemoryAccessCounter.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
25
Core/MemoryAccessCounter.h
Normal file
25
Core/MemoryAccessCounter.h
Normal 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);
|
||||
};
|
|
@ -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());
|
||||
|
||||
|
|
|
@ -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]);
|
||||
}
|
||||
|
|
|
@ -77,7 +77,7 @@ namespace Mesen.GUI.Debugger.Controls
|
|||
{
|
||||
get
|
||||
{
|
||||
return 135 + this.ColumnCount * 30;
|
||||
return 145 + this.ColumnCount * 30;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
222
GUI.NET/Debugger/Controls/ctrlMemoryAccessCounters.Designer.cs
generated
Normal file
222
GUI.NET/Debugger/Controls/ctrlMemoryAccessCounters.Designer.cs
generated
Normal 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;
|
||||
}
|
||||
}
|
187
GUI.NET/Debugger/Controls/ctrlMemoryAccessCounters.cs
Normal file
187
GUI.NET/Debugger/Controls/ctrlMemoryAccessCounters.cs
Normal 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; }
|
||||
}
|
||||
}
|
||||
}
|
120
GUI.NET/Debugger/Controls/ctrlMemoryAccessCounters.resx
Normal file
120
GUI.NET/Debugger/Controls/ctrlMemoryAccessCounters.resx
Normal 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>
|
|
@ -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();
|
||||
}
|
||||
|
|
87
GUI.NET/Debugger/frmMemoryViewer.Designer.cs
generated
87
GUI.NET/Debugger/frmMemoryViewer.Designer.cs
generated
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>
|
|
@ -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>
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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(); }
|
||||
};
|
||||
|
|
Loading…
Add table
Reference in a new issue