From 760c844d4db166eec62975886378959280926c8a Mon Sep 17 00:00:00 2001 From: Souryo Date: Mon, 5 Sep 2016 09:05:34 -0400 Subject: [PATCH] Debugger: Allow export/import of memory to/from files --- Core/BaseMapper.cpp | 35 ++++--- Core/BaseMapper.h | 7 +- Core/Debugger.cpp | 47 ++++++---- Core/Debugger.h | 5 +- Core/MemoryManager.cpp | 9 ++ Core/MemoryManager.h | 1 + Core/PPU.h | 3 +- GUI.NET/Debugger/Controls/ctrlHexViewer.cs | 4 +- GUI.NET/Debugger/frmMemoryViewer.Designer.cs | 96 +++++++++++++++++--- GUI.NET/Debugger/frmMemoryViewer.cs | 53 ++++++++++- GUI.NET/Debugger/frmMemoryViewer.resx | 3 + GUI.NET/InteropEmu.cs | 15 ++- InteropDLL/DebugWrapper.cpp | 1 + 13 files changed, 224 insertions(+), 55 deletions(-) diff --git a/Core/BaseMapper.cpp b/Core/BaseMapper.cpp index 9dec43b9..009b943c 100644 --- a/Core/BaseMapper.cpp +++ b/Core/BaseMapper.cpp @@ -4,6 +4,7 @@ #include #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); diff --git a/Core/BaseMapper.h b/Core/BaseMapper.h index 0e8ffa3b..f2190ce7 100644 --- a/Core/BaseMapper.h +++ b/Core/BaseMapper.h @@ -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); diff --git a/Core/Debugger.cpp b/Core/Debugger.cpp index 226fb71c..bde1eea8 100644 --- a/Core/Debugger.cpp +++ b/Core/Debugger.cpp @@ -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++) { diff --git a/Core/Debugger.h b/Core/Debugger.h index d0f8c56b..667d395a 100644 --- a/Core/Debugger.h +++ b/Core/Debugger.h @@ -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(); diff --git a/Core/MemoryManager.cpp b/Core/MemoryManager.cpp index 2f7ddb40..f3f11e05 100644 --- a/Core/MemoryManager.cpp +++ b/Core/MemoryManager.cpp @@ -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; diff --git a/Core/MemoryManager.h b/Core/MemoryManager.h index 4f649732..130cd987 100644 --- a/Core/MemoryManager.h +++ b/Core/MemoryManager.h @@ -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(); diff --git a/Core/PPU.h b/Core/PPU.h index 8a3ce3ec..81c6feef 100644 --- a/Core/PPU.h +++ b/Core/PPU.h @@ -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); diff --git a/GUI.NET/Debugger/Controls/ctrlHexViewer.cs b/GUI.NET/Debugger/Controls/ctrlHexViewer.cs index 4f7ba189..8f8aa44e 100644 --- a/GUI.NET/Debugger/Controls/ctrlHexViewer.cs +++ b/GUI.NET/Debugger/Controls/ctrlHexViewer.cs @@ -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 diff --git a/GUI.NET/Debugger/frmMemoryViewer.Designer.cs b/GUI.NET/Debugger/frmMemoryViewer.Designer.cs index e9613a1b..fb1dab4b 100644 --- a/GUI.NET/Debugger/frmMemoryViewer.Designer.cs +++ b/GUI.NET/Debugger/frmMemoryViewer.Designer.cs @@ -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; } } \ No newline at end of file diff --git a/GUI.NET/Debugger/frmMemoryViewer.cs b/GUI.NET/Debugger/frmMemoryViewer.cs index 498bc667..a8c50730 100644 --- a/GUI.NET/Debugger/frmMemoryViewer.cs +++ b/GUI.NET/Debugger/frmMemoryViewer.cs @@ -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); + } + } } } diff --git a/GUI.NET/Debugger/frmMemoryViewer.resx b/GUI.NET/Debugger/frmMemoryViewer.resx index e83821e0..4e7f6e36 100644 --- a/GUI.NET/Debugger/frmMemoryViewer.resx +++ b/GUI.NET/Debugger/frmMemoryViewer.resx @@ -123,4 +123,7 @@ 107, 17 + + 222, 17 + \ No newline at end of file diff --git a/GUI.NET/InteropEmu.cs b/GUI.NET/InteropEmu.cs index 3ea729f0..40f92a71 100644 --- a/GUI.NET/InteropEmu.cs +++ b/GUI.NET/InteropEmu.cs @@ -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 diff --git a/InteropDLL/DebugWrapper.cpp b/InteropDLL/DebugWrapper.cpp index e08e3d1e..500b4314 100644 --- a/InteropDLL/DebugWrapper.cpp +++ b/InteropDLL/DebugWrapper.cpp @@ -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); }