Debugger: Allow export/import of memory to/from files

This commit is contained in:
Souryo 2016-09-05 09:05:34 -04:00
parent 3d453ba021
commit 760c844d4d
13 changed files with 224 additions and 55 deletions

View File

@ -4,6 +4,7 @@
#include <assert.h>
#include "../Utilities/FolderUtilities.h"
#include "CheatManager.h"
#include "Debugger.h"
void BaseMapper::WriteRegister(uint16_t addr, uint8_t value) { }
uint8_t BaseMapper::ReadRegister(uint16_t addr) { return 0; }
@ -732,10 +733,26 @@ uint8_t* BaseMapper::GetWorkRam()
return _workRam;
}
void BaseMapper::GetPrgCopy(uint8_t **buffer)
uint32_t BaseMapper::CopyMemory(DebugMemoryType type, uint8_t* buffer)
{
*buffer = new uint8_t[_prgSize];
memcpy(*buffer, _prgRom, _prgSize);
switch(type) {
case DebugMemoryType::ChrRam: memcpy(buffer, _chrRam, _chrRamSize); return _chrRamSize;
case DebugMemoryType::ChrRom: memcpy(buffer, _chrRom, _chrRomSize); return _chrRomSize;
case DebugMemoryType::PrgRom: memcpy(buffer, _prgRom, _prgSize); return _prgSize;
case DebugMemoryType::SaveRam: memcpy(buffer, _saveRam, _saveRamSize); return _saveRamSize;
case DebugMemoryType::WorkRam: memcpy(buffer, _workRam, _workRamSize); return _workRamSize;
}
return 0;
}
void BaseMapper::WriteMemory(DebugMemoryType type, uint8_t* buffer)
{
switch(type) {
case DebugMemoryType::ChrRam: memcpy(_chrRam, buffer, _chrRamSize); break;
case DebugMemoryType::SaveRam: memcpy(_saveRam, buffer, _saveRamSize); break;
case DebugMemoryType::WorkRam: memcpy(_workRam, buffer, _workRamSize); break;
}
}
uint32_t BaseMapper::GetPrgSize(bool getWorkRamSize)
@ -743,23 +760,11 @@ uint32_t BaseMapper::GetPrgSize(bool getWorkRamSize)
return getWorkRamSize ? _workRamSize : _prgSize;
}
void BaseMapper::GetChrRomCopy(uint8_t **buffer)
{
*buffer = new uint8_t[_chrRomSize];
memcpy(*buffer, _chrRom, _chrRomSize);
}
uint32_t BaseMapper::GetChrSize(bool getRamSize)
{
return getRamSize ? _chrRamSize : (_onlyChrRam ? 0 : _chrRomSize);
}
void BaseMapper::GetChrRamCopy(uint8_t **buffer)
{
*buffer = new uint8_t[_chrRamSize];
memcpy(*buffer, _chrRam, _chrRamSize);
}
int32_t BaseMapper::ToAbsoluteAddress(uint16_t addr)
{
uint8_t *prgAddr = _prgPages[addr >> 8] + (addr & 0xFF);

View File

@ -7,6 +7,8 @@
#include "RomLoader.h"
#include "EmulationSettings.h"
enum class DebugMemoryType;
enum class PrgMemoryType
{
PrgRom,
@ -219,11 +221,10 @@ public:
CartridgeState GetState();
uint8_t* GetPrgRom();
uint8_t* GetWorkRam();
void GetPrgCopy(uint8_t **buffer);
uint32_t GetPrgSize(bool getWorkRamSize = false);
void GetChrRomCopy(uint8_t **buffer);
uint32_t GetChrSize(bool getRamSize = false);
void GetChrRamCopy(uint8_t **buffer);
uint32_t CopyMemory(DebugMemoryType type, uint8_t* buffer);
void WriteMemory(DebugMemoryType type, uint8_t* buffer);
int32_t ToAbsoluteAddress(uint16_t addr);
int32_t ToAbsoluteRamAddress(uint16_t addr);
int32_t ToAbsoluteChrAddress(uint16_t addr);

View File

@ -549,6 +549,33 @@ void Debugger::ProcessVramOperation(MemoryOperationType type, uint16_t addr, uin
}
}
void Debugger::SetMemoryState(DebugMemoryType type, uint8_t *buffer)
{
switch(type) {
case DebugMemoryType::InternalRam:
for(int i = 0; i < 0x800; i++) {
_memoryManager->DebugWrite(i, buffer[i]);
}
break;
case DebugMemoryType::PaletteMemory:
for(int i = 0; i < 0x20; i++) {
_ppu->WritePaletteRAM(i, buffer[i]);
}
break;
case DebugMemoryType::SpriteMemory: memcpy(_ppu->GetSpriteRam(), buffer, 0x100); break;
case DebugMemoryType::SecondarySpriteMemory: memcpy(_ppu->GetSecondarySpriteRam(), buffer, 0x20); break;
case DebugMemoryType::ChrRam:
case DebugMemoryType::WorkRam:
case DebugMemoryType::SaveRam:
_mapper->WriteMemory(type, buffer);
break;
}
}
uint32_t Debugger::GetMemoryState(DebugMemoryType type, uint8_t *buffer)
{
switch(type) {
@ -579,25 +606,11 @@ uint32_t Debugger::GetMemoryState(DebugMemoryType type, uint8_t *buffer)
return 0x20;
case DebugMemoryType::PrgRom:
uint8_t *prgRom;
_mapper->GetPrgCopy(&prgRom);
memcpy(buffer, prgRom, _mapper->GetPrgSize());
delete[] prgRom;
return _mapper->GetPrgSize();
case DebugMemoryType::ChrRom:
uint8_t *chrRom;
_mapper->GetChrRomCopy(&chrRom);
memcpy(buffer, chrRom, _mapper->GetChrSize());
delete[] chrRom;
return _mapper->GetChrSize();
case DebugMemoryType::ChrRam:
uint8_t *chrRam;
_mapper->GetChrRamCopy(&chrRam);
memcpy(buffer, chrRam, _mapper->GetChrSize(true));
delete[] chrRam;
return _mapper->GetChrSize(true);
case DebugMemoryType::WorkRam:
case DebugMemoryType::SaveRam:
return _mapper->CopyMemory(type, buffer);
case DebugMemoryType::InternalRam:
for(int i = 0; i < 0x800; i++) {

View File

@ -28,7 +28,9 @@ enum class DebugMemoryType
PrgRom = 5,
ChrRom = 6,
ChrRam = 7,
InternalRam = 8,
WorkRam = 8,
SaveRam = 9,
InternalRam = 10
};
enum class DebuggerFlags
@ -132,6 +134,7 @@ public:
void ResetCdlLog();
void SetNextStatement(uint16_t addr);
void SetMemoryState(DebugMemoryType type, uint8_t *buffer);
bool IsCodeChanged();
string GenerateOutput();

View File

@ -135,6 +135,15 @@ void MemoryManager::Write(uint16_t addr, uint8_t value)
}
}
void MemoryManager::DebugWrite(uint16_t addr, uint8_t value)
{
if(addr <= 0x1FFF) {
_internalRAM[addr & 0x07FF] = value;
} else {
WriteRegister(addr, value);
}
}
void MemoryManager::ProcessVramAccess(uint16_t &addr)
{
addr &= 0x3FFF;

View File

@ -40,6 +40,7 @@ class MemoryManager: public Snapshotable
uint8_t DebugRead(uint16_t addr);
uint8_t DebugReadVRAM(uint16_t addr);
void DebugWrite(uint16_t addr, uint8_t value);
uint8_t* GetInternalRAM();

View File

@ -185,8 +185,6 @@ class PPU : public IMemoryHandler, public Snapshotable
void TriggerNmi();
void EndVBlank();
void WritePaletteRAM(uint16_t addr, uint8_t value);
void LoadTileInfo();
void LoadSprite(uint8_t spriteY, uint8_t tileIndex, uint8_t attributes, uint8_t spriteX, bool extraSprite);
void LoadSpriteTileInfo();
@ -237,6 +235,7 @@ class PPU : public IMemoryHandler, public Snapshotable
}
uint8_t ReadPaletteRAM(uint16_t addr);
void WritePaletteRAM(uint16_t addr, uint8_t value);
uint8_t ReadRAM(uint16_t addr);
void WriteRAM(uint16_t addr, uint8_t value);

View File

@ -22,7 +22,9 @@ namespace Mesen.GUI.Debugger.Controls
{
InitializeComponent();
this.cboNumberColumns.SelectedIndex = ConfigManager.Config.DebugInfo.RamColumnCount;
if(LicenseManager.UsageMode != LicenseUsageMode.Designtime) {
this.cboNumberColumns.SelectedIndex = ConfigManager.Config.DebugInfo.RamColumnCount;
}
}
protected override ctrlScrollableTextbox ScrollableTextbox

View File

@ -37,6 +37,9 @@
this.cboMemoryType = new System.Windows.Forms.ComboBox();
this.menuStrip1 = new System.Windows.Forms.MenuStrip();
this.fileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.mnuImport = new System.Windows.Forms.ToolStripMenuItem();
this.mnuExport = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripMenuItem3 = new System.Windows.Forms.ToolStripSeparator();
this.mnuClose = new System.Windows.Forms.ToolStripMenuItem();
this.mnuView = new System.Windows.Forms.ToolStripMenuItem();
this.mnuRefresh = new System.Windows.Forms.ToolStripMenuItem();
@ -51,16 +54,20 @@
this.mnuFindNext = new System.Windows.Forms.ToolStripMenuItem();
this.mnuFindPrev = new System.Windows.Forms.ToolStripMenuItem();
this.mnuGoTo = new System.Windows.Forms.ToolStripMenuItem();
this.toolStrip1 = new System.Windows.Forms.ToolStrip();
this.btnImport = new System.Windows.Forms.ToolStripButton();
this.btnExport = new System.Windows.Forms.ToolStripButton();
this.flowLayoutPanel1.SuspendLayout();
this.menuStrip1.SuspendLayout();
this.toolStrip1.SuspendLayout();
this.SuspendLayout();
//
// ctrlHexViewer
//
this.ctrlHexViewer.Dock = System.Windows.Forms.DockStyle.Fill;
this.ctrlHexViewer.Location = new System.Drawing.Point(0, 24);
this.ctrlHexViewer.Location = new System.Drawing.Point(0, 49);
this.ctrlHexViewer.Name = "ctrlHexViewer";
this.ctrlHexViewer.Size = new System.Drawing.Size(334, 238);
this.ctrlHexViewer.Size = new System.Drawing.Size(461, 378);
this.ctrlHexViewer.TabIndex = 0;
this.ctrlHexViewer.ColumnCountChanged += new System.EventHandler(this.ctrlHexViewer_ColumnCountChanged);
//
@ -68,7 +75,7 @@
//
this.flowLayoutPanel1.Controls.Add(this.lblViewMemoryType);
this.flowLayoutPanel1.Controls.Add(this.cboMemoryType);
this.flowLayoutPanel1.Location = new System.Drawing.Point(0, 25);
this.flowLayoutPanel1.Location = new System.Drawing.Point(0, 49);
this.flowLayoutPanel1.Name = "flowLayoutPanel1";
this.flowLayoutPanel1.Size = new System.Drawing.Size(167, 27);
this.flowLayoutPanel1.TabIndex = 1;
@ -95,7 +102,10 @@
"Secondary OAM Memory",
"PRG ROM",
"CHR ROM",
"CHR RAM"});
"CHR RAM",
"Work RAM",
"Save RAM",
"NES RAM"});
this.cboMemoryType.Location = new System.Drawing.Point(42, 3);
this.cboMemoryType.Name = "cboMemoryType";
this.cboMemoryType.Size = new System.Drawing.Size(121, 21);
@ -110,22 +120,46 @@
this.toolStripMenuItem1});
this.menuStrip1.Location = new System.Drawing.Point(0, 0);
this.menuStrip1.Name = "menuStrip1";
this.menuStrip1.Size = new System.Drawing.Size(334, 24);
this.menuStrip1.Size = new System.Drawing.Size(461, 24);
this.menuStrip1.TabIndex = 2;
this.menuStrip1.Text = "menuStrip1";
//
// fileToolStripMenuItem
//
this.fileToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.mnuImport,
this.mnuExport,
this.toolStripMenuItem3,
this.mnuClose});
this.fileToolStripMenuItem.Name = "fileToolStripMenuItem";
this.fileToolStripMenuItem.Size = new System.Drawing.Size(37, 20);
this.fileToolStripMenuItem.Text = "File";
//
// mnuImport
//
this.mnuImport.Name = "mnuImport";
this.mnuImport.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.O)));
this.mnuImport.Size = new System.Drawing.Size(153, 22);
this.mnuImport.Text = "Import";
this.mnuImport.Click += new System.EventHandler(this.mnuImport_Click);
//
// mnuExport
//
this.mnuExport.Name = "mnuExport";
this.mnuExport.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.S)));
this.mnuExport.Size = new System.Drawing.Size(153, 22);
this.mnuExport.Text = "Export";
this.mnuExport.Click += new System.EventHandler(this.mnuExport_Click);
//
// toolStripMenuItem3
//
this.toolStripMenuItem3.Name = "toolStripMenuItem3";
this.toolStripMenuItem3.Size = new System.Drawing.Size(150, 6);
//
// mnuClose
//
this.mnuClose.Name = "mnuClose";
this.mnuClose.Size = new System.Drawing.Size(103, 22);
this.mnuClose.Size = new System.Drawing.Size(153, 22);
this.mnuClose.Text = "Close";
this.mnuClose.Click += new System.EventHandler(this.mnuClose_Click);
//
@ -144,7 +178,7 @@
//
this.mnuRefresh.Name = "mnuRefresh";
this.mnuRefresh.ShortcutKeys = System.Windows.Forms.Keys.F5;
this.mnuRefresh.Size = new System.Drawing.Size(152, 22);
this.mnuRefresh.Size = new System.Drawing.Size(141, 22);
this.mnuRefresh.Text = "Refresh";
this.mnuRefresh.Click += new System.EventHandler(this.mnuRefresh_Click);
//
@ -155,7 +189,7 @@
this.mnuDecreaseFontSize,
this.mnuResetFontSize});
this.fontSizeToolStripMenuItem.Name = "fontSizeToolStripMenuItem";
this.fontSizeToolStripMenuItem.Size = new System.Drawing.Size(152, 22);
this.fontSizeToolStripMenuItem.Size = new System.Drawing.Size(141, 22);
this.fontSizeToolStripMenuItem.Text = "Text Size";
//
// mnuIncreaseFontSize
@ -188,7 +222,7 @@
// toolStripMenuItem2
//
this.toolStripMenuItem2.Name = "toolStripMenuItem2";
this.toolStripMenuItem2.Size = new System.Drawing.Size(149, 6);
this.toolStripMenuItem2.Size = new System.Drawing.Size(138, 6);
//
// mnuAutoRefresh
//
@ -196,7 +230,7 @@
this.mnuAutoRefresh.CheckOnClick = true;
this.mnuAutoRefresh.CheckState = System.Windows.Forms.CheckState.Checked;
this.mnuAutoRefresh.Name = "mnuAutoRefresh";
this.mnuAutoRefresh.Size = new System.Drawing.Size(152, 22);
this.mnuAutoRefresh.Size = new System.Drawing.Size(141, 22);
this.mnuAutoRefresh.Text = "Auto-refresh";
this.mnuAutoRefresh.Click += new System.EventHandler(this.mnuAutoRefresh_Click);
//
@ -243,22 +277,54 @@
this.mnuGoTo.Text = "Go To...";
this.mnuGoTo.Click += new System.EventHandler(this.mnuGoTo_Click);
//
// toolStrip1
//
this.toolStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.btnImport,
this.btnExport});
this.toolStrip1.Location = new System.Drawing.Point(0, 24);
this.toolStrip1.Name = "toolStrip1";
this.toolStrip1.Size = new System.Drawing.Size(461, 25);
this.toolStrip1.TabIndex = 3;
this.toolStrip1.Text = "toolStrip1";
//
// btnImport
//
this.btnImport.Image = global::Mesen.GUI.Properties.Resources.Import;
this.btnImport.ImageTransparentColor = System.Drawing.Color.Magenta;
this.btnImport.Name = "btnImport";
this.btnImport.Size = new System.Drawing.Size(63, 22);
this.btnImport.Text = "Import";
this.btnImport.Click += new System.EventHandler(this.mnuImport_Click);
//
// btnExport
//
this.btnExport.Image = global::Mesen.GUI.Properties.Resources.Export;
this.btnExport.ImageTransparentColor = System.Drawing.Color.Magenta;
this.btnExport.Name = "btnExport";
this.btnExport.Size = new System.Drawing.Size(60, 22);
this.btnExport.Text = "Export";
this.btnExport.Click += new System.EventHandler(this.mnuExport_Click);
//
// frmMemoryViewer
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(334, 262);
this.ClientSize = new System.Drawing.Size(461, 427);
this.Controls.Add(this.flowLayoutPanel1);
this.Controls.Add(this.ctrlHexViewer);
this.Controls.Add(this.toolStrip1);
this.Controls.Add(this.menuStrip1);
this.MainMenuStrip = this.menuStrip1;
this.MinimumSize = new System.Drawing.Size(350, 300);
this.MinimumSize = new System.Drawing.Size(477, 465);
this.Name = "frmMemoryViewer";
this.Text = "Memory Viewer";
this.flowLayoutPanel1.ResumeLayout(false);
this.flowLayoutPanel1.PerformLayout();
this.menuStrip1.ResumeLayout(false);
this.menuStrip1.PerformLayout();
this.toolStrip1.ResumeLayout(false);
this.toolStrip1.PerformLayout();
this.ResumeLayout(false);
this.PerformLayout();
@ -286,5 +352,11 @@
private System.Windows.Forms.ToolStripMenuItem mnuClose;
private System.Windows.Forms.ToolStripSeparator toolStripMenuItem2;
private System.Windows.Forms.ToolStripMenuItem mnuAutoRefresh;
private System.Windows.Forms.ToolStripMenuItem mnuImport;
private System.Windows.Forms.ToolStripMenuItem mnuExport;
private System.Windows.Forms.ToolStripSeparator toolStripMenuItem3;
private System.Windows.Forms.ToolStrip toolStrip1;
private System.Windows.Forms.ToolStripButton btnImport;
private System.Windows.Forms.ToolStripButton btnExport;
}
}

View File

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
@ -16,19 +17,22 @@ namespace Mesen.GUI.Debugger
{
private InteropEmu.NotificationListener _notifListener;
private int _autoRefreshCounter = 0;
private DebugMemoryType _memoryType = DebugMemoryType.CpuMemory;
public frmMemoryViewer()
{
InitializeComponent();
this.mnuAutoRefresh.Checked = ConfigManager.Config.DebugInfo.RamAutoRefresh;
this.ctrlHexViewer.FontSize = ConfigManager.Config.DebugInfo.RamFontSize;
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
this.mnuAutoRefresh.Checked = ConfigManager.Config.DebugInfo.RamAutoRefresh;
this.ctrlHexViewer.FontSize = ConfigManager.Config.DebugInfo.RamFontSize;
UpdateImportButton();
this.cboMemoryType.SelectedIndex = 0;
this.Size = new Size(this.ctrlHexViewer.IdealWidth, this.Height);
@ -52,6 +56,8 @@ namespace Mesen.GUI.Debugger
private void cboMemoryType_SelectedIndexChanged(object sender, EventArgs e)
{
this._memoryType = (DebugMemoryType)this.cboMemoryType.SelectedIndex;
this.UpdateImportButton();
this.RefreshData();
this.ctrlHexViewer.ScrollToTop();
}
@ -125,5 +131,46 @@ namespace Mesen.GUI.Debugger
{
this.UpdateConfig();
}
private void UpdateImportButton()
{
switch(_memoryType) {
case DebugMemoryType.ChrRam:
case DebugMemoryType.InternalRam:
case DebugMemoryType.PaletteMemory:
case DebugMemoryType.SecondarySpriteMemory:
case DebugMemoryType.SpriteMemory:
case DebugMemoryType.WorkRam:
case DebugMemoryType.SaveRam:
btnImport.Enabled = mnuImport.Enabled = true;
break;
default:
btnImport.Enabled = mnuImport.Enabled = false;
break;
}
}
private void mnuImport_Click(object sender, EventArgs e)
{
OpenFileDialog ofd = new OpenFileDialog();
ofd.Filter = "Memory dump files (*.dmp)|*.dmp|All files (*.*)|*.*";
ofd.InitialDirectory = ConfigManager.DebuggerFolder;
if(ofd.ShowDialog() == DialogResult.OK) {
InteropEmu.DebugSetMemoryState(_memoryType, File.ReadAllBytes(ofd.FileName));
RefreshData();
}
}
private void mnuExport_Click(object sender, EventArgs e)
{
SaveFileDialog sfd = new SaveFileDialog();
sfd.Filter = "Memory dump files (*.dmp)|*.dmp|All files (*.*)|*.*";
sfd.InitialDirectory = ConfigManager.DebuggerFolder;
sfd.FileName = InteropEmu.GetRomInfo().GetRomName() + " - " + cboMemoryType.SelectedItem.ToString() + ".dmp";
if(sfd.ShowDialog() == DialogResult.OK) {
File.WriteAllBytes(sfd.FileName, this.ctrlHexViewer.Data);
}
}
}
}

View File

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

View File

@ -198,6 +198,17 @@ namespace Mesen.GUI
return buffer;
}
[DllImport(DLLPath, EntryPoint="DebugSetMemoryState")] private static extern void DebugSetMemoryStateWrapper(DebugMemoryType type, IntPtr buffer);
public static void DebugSetMemoryState(DebugMemoryType type, byte[] data)
{
GCHandle handle = GCHandle.Alloc(data, GCHandleType.Pinned);
try {
InteropEmu.DebugSetMemoryStateWrapper(type, handle.AddrOfPinnedObject());
} finally {
handle.Free();
}
}
public static byte[] DebugGetInternalRam()
{
byte[] buffer = new byte[0x800];
@ -969,7 +980,9 @@ namespace Mesen.GUI
PrgRom = 5,
ChrRom = 6,
ChrRam = 7,
InternalRam = 8
WorkRam = 8,
SaveRam = 9,
InternalRam = 10
}
public class MD5Helper

View File

@ -42,6 +42,7 @@ extern "C"
DllExport const char* __stdcall DebugGetCode() { return GetDebugger()->GetCode()->c_str(); }
DllExport void __stdcall DebugSetNextStatement(uint16_t addr) { GetDebugger()->SetNextStatement(addr); }
DllExport void __stdcall DebugSetMemoryState(uint32_t type, uint8_t *buffer) { GetDebugger()->SetMemoryState((DebugMemoryType)type, buffer); }
DllExport uint32_t __stdcall DebugGetMemoryState(uint32_t type, uint8_t *buffer) { return GetDebugger()->GetMemoryState((DebugMemoryType)type, buffer); }
DllExport void __stdcall DebugGetNametable(uint32_t nametableIndex, uint32_t *frameBuffer, uint8_t *tileData, uint8_t *attributeData) { GetDebugger()->GetNametable(nametableIndex, frameBuffer, tileData, attributeData); }