Debugger: Ability to save modified PRG/CHR back to a rom

This commit is contained in:
Souryo 2017-03-04 22:24:41 -05:00
parent 485e8cc2ce
commit 910e27f0af
16 changed files with 121 additions and 15 deletions

View file

@ -507,6 +507,7 @@ void BaseMapper::Initialize(RomData &romData)
AddRegisterRange(RegisterStartAddress(), RegisterEndAddress(), MemoryOperation::Any);
_nesHeader = romData.NesHeader;
_romFormat = romData.Format;
_mirroringType = romData.Mirroring;
@ -702,6 +703,11 @@ string BaseMapper::GetRomName()
return _romName;
}
RomFormat BaseMapper::GetRomFormat()
{
return _romFormat;
}
uint32_t BaseMapper::GetCrc32()
{
return _crc32;
@ -952,4 +958,15 @@ CartridgeState BaseMapper::GetState()
}
return state;
}
void BaseMapper::SaveRomToDisk(string filename)
{
ofstream file(filename, ios::out | ios::binary);
if(file.good()) {
file.write((char*)&_nesHeader, sizeof(NESHeader));
file.write((char*)_prgRom, _prgSize);
file.write((char*)_chrRom, _onlyChrRam ? 0 : _chrRomSize);
file.close();
}
}

View file

@ -75,6 +75,7 @@ private:
string _romFilename;
string _romName;
RomFormat _romFormat;
bool _allowRegisterRead = false;
uint8_t _isReadRegisterAddr[0x10000];
@ -210,6 +211,7 @@ public:
uint32_t GetCrc32();
uint32_t GetPrgCrc32();
string GetRomName();
RomFormat GetRomFormat();
uint8_t ReadRAM(uint16_t addr) override;
virtual void WriteRAM(uint16_t addr, uint8_t value) override;
@ -238,4 +240,6 @@ public:
int32_t ToAbsoluteWorkRamAddress(uint16_t addr);
int32_t ToAbsoluteChrAddress(uint16_t addr);
int32_t FromAbsoluteAddress(uint32_t addr, AddressType type = AddressType::PrgRom);
void SaveRomToDisk(string filename);
};

View file

@ -162,6 +162,15 @@ string Console::GetRomName()
}
}
RomFormat Console::GetRomFormat()
{
if(Instance->_mapper) {
return Instance->_mapper->GetRomFormat();
} else {
return RomFormat::Unknown;
}
}
uint32_t Console::GetCrc32()
{
if(Instance->_mapper) {

View file

@ -9,6 +9,7 @@
#include "ControlManager.h"
#include "../Utilities/SimpleLock.h"
#include "AutoSaveManager.h"
#include "RomData.h"
class Debugger;
class BaseMapper;
@ -76,6 +77,7 @@ class Console
static bool LoadROM(string romName, uint32_t crc32Hash);
static string GetROMPath();
static string GetRomName();
static RomFormat GetRomFormat();
static uint32_t GetCrc32();
static uint32_t GetPrgCrc32();
static NesModel GetModel();

View file

@ -758,3 +758,8 @@ void Debugger::GetFreezeState(uint16_t startAddress, uint16_t length, bool* free
freezeState[i] = _frozenAddresses[startAddress + i] ? true : false;
}
}
void Debugger::SaveRomToDisk(string filename)
{
_mapper->SaveRomToDisk(filename);
}

View file

@ -176,4 +176,6 @@ public:
void SetFreezeState(uint16_t address, bool frozen);
void GetFreezeState(uint16_t startAddress, uint16_t length, bool* freezeState);
void SaveRomToDisk(string filename);
};

View file

@ -37,7 +37,7 @@ char* DisassemblyInfo::ToString(uint32_t memoryAddr, MemoryManager* memoryManage
char* DisassemblyInfo::ToString(uint32_t memoryAddr, MemoryManager* memoryManager, LabelManager* labelManager, uint16_t &length)
{
uint8_t opCode = *_opPointer;
length = DisassemblyInfo::OPName[opCode].size();
length = (uint16_t)DisassemblyInfo::OPName[opCode].size();
memcpy(_toStringBuffer, DisassemblyInfo::OPName[opCode].c_str(), length);
uint16_t* ptrPos = &length;

View file

@ -154,6 +154,7 @@ public:
RomData romData;
romData.Format = RomFormat::Fds;
romData.MapperID = MapperFactory::FdsMapperID;
romData.Mirroring = MirroringType::Vertical;
romData.PrgRom = LoadBios();

View file

@ -263,10 +263,19 @@ struct GameInfo
string InputType;
};
enum class RomFormat
{
Unknown = 0,
iNes = 1,
Unif = 2,
Fds = 3,
};
struct RomData
{
string RomName;
string Filename;
RomFormat Format;
uint16_t MapperID = 0;
uint8_t SubMapperID = 0;

View file

@ -324,6 +324,7 @@ public:
fullRom.insert(fullRom.end(), romData.PrgRom.begin(), romData.PrgRom.end());
fullRom.insert(fullRom.end(), romData.ChrRom.begin(), romData.ChrRom.end());
romData.Format = RomFormat::Unif;
romData.Crc32 = CRC32::GetCRC(fullRom.data(), fullRom.size());;
romData.PrgCrc32 = CRC32::GetCRC(romData.PrgRom.data(), romData.PrgRom.size());

View file

@ -15,6 +15,8 @@ RomData iNesLoader::LoadRom(vector<uint8_t>& romFile)
header.SanitizeHeader(romFile.size());
romData.Format = RomFormat::iNes;
romData.IsNes20Header = (header.GetRomHeaderVersion() == RomHeaderVersion::Nes2_0);
romData.MapperID = header.GetMapperID();
romData.SubMapperID = header.GetSubMapper();

View file

@ -61,6 +61,8 @@ namespace Mesen.GUI.Debugger
this.ctrlCallstack = new Mesen.GUI.Debugger.Controls.ctrlCallstack();
this.menuStrip = new System.Windows.Forms.MenuStrip();
this.fileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.mnuSaveRom = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripMenuItem14 = new System.Windows.Forms.ToolStripSeparator();
this.mnuWorkspace = new System.Windows.Forms.ToolStripMenuItem();
this.mnuImportLabels = new System.Windows.Forms.ToolStripMenuItem();
this.mnuResetWorkspace = new System.Windows.Forms.ToolStripMenuItem();
@ -213,7 +215,7 @@ namespace Mesen.GUI.Debugger
this.ctrlSplitContainerTop.Panel2.Controls.Add(this.tlpFunctionLabelLists);
this.ctrlSplitContainerTop.Panel2MinSize = 150;
this.ctrlSplitContainerTop.Size = new System.Drawing.Size(1260, 390);
this.ctrlSplitContainerTop.SplitterDistance = 933;
this.ctrlSplitContainerTop.SplitterDistance = 927;
this.ctrlSplitContainerTop.SplitterWidth = 7;
this.ctrlSplitContainerTop.TabIndex = 3;
this.ctrlSplitContainerTop.PanelCollapsed += new System.EventHandler(this.ctrlSplitContainerTop_PanelCollapsed);
@ -234,7 +236,7 @@ namespace Mesen.GUI.Debugger
this.tlpTop.Name = "tlpTop";
this.tlpTop.RowCount = 1;
this.tlpTop.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tlpTop.Size = new System.Drawing.Size(933, 390);
this.tlpTop.Size = new System.Drawing.Size(927, 390);
this.tlpTop.TabIndex = 2;
//
// ctrlDebuggerCode
@ -243,7 +245,7 @@ namespace Mesen.GUI.Debugger
this.ctrlDebuggerCode.Dock = System.Windows.Forms.DockStyle.Fill;
this.ctrlDebuggerCode.Location = new System.Drawing.Point(3, 3);
this.ctrlDebuggerCode.Name = "ctrlDebuggerCode";
this.ctrlDebuggerCode.Size = new System.Drawing.Size(495, 384);
this.ctrlDebuggerCode.Size = new System.Drawing.Size(489, 384);
this.ctrlDebuggerCode.TabIndex = 2;
this.ctrlDebuggerCode.OnSetNextStatement += new Mesen.GUI.Debugger.ctrlDebuggerCode.AddressEventHandler(this.ctrlDebuggerCode_OnSetNextStatement);
this.ctrlDebuggerCode.Enter += new System.EventHandler(this.ctrlDebuggerCode_Enter);
@ -251,7 +253,7 @@ namespace Mesen.GUI.Debugger
// ctrlConsoleStatus
//
this.ctrlConsoleStatus.Dock = System.Windows.Forms.DockStyle.Fill;
this.ctrlConsoleStatus.Location = new System.Drawing.Point(501, 0);
this.ctrlConsoleStatus.Location = new System.Drawing.Point(495, 0);
this.ctrlConsoleStatus.Margin = new System.Windows.Forms.Padding(0);
this.ctrlConsoleStatus.Name = "ctrlConsoleStatus";
this.ctrlConsoleStatus.Size = new System.Drawing.Size(432, 390);
@ -262,7 +264,7 @@ namespace Mesen.GUI.Debugger
//
this.ctrlDebuggerCodeSplit.Code = null;
this.ctrlDebuggerCodeSplit.Dock = System.Windows.Forms.DockStyle.Fill;
this.ctrlDebuggerCodeSplit.Location = new System.Drawing.Point(504, 3);
this.ctrlDebuggerCodeSplit.Location = new System.Drawing.Point(498, 3);
this.ctrlDebuggerCodeSplit.Name = "ctrlDebuggerCodeSplit";
this.ctrlDebuggerCodeSplit.Size = new System.Drawing.Size(1, 384);
this.ctrlDebuggerCodeSplit.TabIndex = 4;
@ -283,7 +285,7 @@ namespace Mesen.GUI.Debugger
this.tlpFunctionLabelLists.RowCount = 2;
this.tlpFunctionLabelLists.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F));
this.tlpFunctionLabelLists.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F));
this.tlpFunctionLabelLists.Size = new System.Drawing.Size(320, 390);
this.tlpFunctionLabelLists.Size = new System.Drawing.Size(326, 390);
this.tlpFunctionLabelLists.TabIndex = 5;
//
// grpLabels
@ -292,7 +294,7 @@ namespace Mesen.GUI.Debugger
this.grpLabels.Dock = System.Windows.Forms.DockStyle.Fill;
this.grpLabels.Location = new System.Drawing.Point(3, 198);
this.grpLabels.Name = "grpLabels";
this.grpLabels.Size = new System.Drawing.Size(314, 189);
this.grpLabels.Size = new System.Drawing.Size(320, 189);
this.grpLabels.TabIndex = 6;
this.grpLabels.TabStop = false;
this.grpLabels.Text = "Labels";
@ -302,7 +304,7 @@ namespace Mesen.GUI.Debugger
this.ctrlLabelList.Dock = System.Windows.Forms.DockStyle.Fill;
this.ctrlLabelList.Location = new System.Drawing.Point(3, 16);
this.ctrlLabelList.Name = "ctrlLabelList";
this.ctrlLabelList.Size = new System.Drawing.Size(308, 170);
this.ctrlLabelList.Size = new System.Drawing.Size(314, 170);
this.ctrlLabelList.TabIndex = 0;
this.ctrlLabelList.OnFindOccurrence += new System.EventHandler(this.ctrlLabelList_OnFindOccurrence);
this.ctrlLabelList.OnLabelSelected += new System.EventHandler(this.ctrlLabelList_OnLabelSelected);
@ -313,7 +315,7 @@ namespace Mesen.GUI.Debugger
this.grpFunctions.Dock = System.Windows.Forms.DockStyle.Fill;
this.grpFunctions.Location = new System.Drawing.Point(3, 3);
this.grpFunctions.Name = "grpFunctions";
this.grpFunctions.Size = new System.Drawing.Size(314, 189);
this.grpFunctions.Size = new System.Drawing.Size(320, 189);
this.grpFunctions.TabIndex = 5;
this.grpFunctions.TabStop = false;
this.grpFunctions.Text = "Functions";
@ -323,7 +325,7 @@ namespace Mesen.GUI.Debugger
this.ctrlFunctionList.Dock = System.Windows.Forms.DockStyle.Fill;
this.ctrlFunctionList.Location = new System.Drawing.Point(3, 16);
this.ctrlFunctionList.Name = "ctrlFunctionList";
this.ctrlFunctionList.Size = new System.Drawing.Size(308, 170);
this.ctrlFunctionList.Size = new System.Drawing.Size(314, 170);
this.ctrlFunctionList.TabIndex = 0;
this.ctrlFunctionList.OnFindOccurrence += new System.EventHandler(this.ctrlFunctionList_OnFindOccurrence);
this.ctrlFunctionList.OnFunctionSelected += new System.EventHandler(this.ctrlFunctionList_OnFunctionSelected);
@ -434,6 +436,8 @@ namespace Mesen.GUI.Debugger
// fileToolStripMenuItem
//
this.fileToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.mnuSaveRom,
this.toolStripMenuItem14,
this.mnuWorkspace,
this.toolStripMenuItem3,
this.mnuClose});
@ -441,6 +445,19 @@ namespace Mesen.GUI.Debugger
this.fileToolStripMenuItem.Size = new System.Drawing.Size(37, 20);
this.fileToolStripMenuItem.Text = "File";
//
// mnuSaveRom
//
this.mnuSaveRom.Image = global::Mesen.GUI.Properties.Resources.Floppy;
this.mnuSaveRom.Name = "mnuSaveRom";
this.mnuSaveRom.Size = new System.Drawing.Size(151, 22);
this.mnuSaveRom.Text = "Save ROM as...";
this.mnuSaveRom.Click += new System.EventHandler(this.mnuSaveRom_Click);
//
// toolStripMenuItem14
//
this.toolStripMenuItem14.Name = "toolStripMenuItem14";
this.toolStripMenuItem14.Size = new System.Drawing.Size(148, 6);
//
// mnuWorkspace
//
this.mnuWorkspace.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
@ -450,7 +467,7 @@ namespace Mesen.GUI.Debugger
this.mnuAutoLoadDbgFiles,
this.mnuDisableDefaultLabels});
this.mnuWorkspace.Name = "mnuWorkspace";
this.mnuWorkspace.Size = new System.Drawing.Size(132, 22);
this.mnuWorkspace.Size = new System.Drawing.Size(151, 22);
this.mnuWorkspace.Text = "Workspace";
//
// mnuImportLabels
@ -493,13 +510,13 @@ namespace Mesen.GUI.Debugger
// toolStripMenuItem3
//
this.toolStripMenuItem3.Name = "toolStripMenuItem3";
this.toolStripMenuItem3.Size = new System.Drawing.Size(129, 6);
this.toolStripMenuItem3.Size = new System.Drawing.Size(148, 6);
//
// mnuClose
//
this.mnuClose.Image = global::Mesen.GUI.Properties.Resources.Exit;
this.mnuClose.Name = "mnuClose";
this.mnuClose.Size = new System.Drawing.Size(132, 22);
this.mnuClose.Size = new System.Drawing.Size(151, 22);
this.mnuClose.Text = "Close";
this.mnuClose.Click += new System.EventHandler(this.mnuClose_Click);
//
@ -997,7 +1014,7 @@ namespace Mesen.GUI.Debugger
//
this.mnuTraceLogger.Image = global::Mesen.GUI.Properties.Resources.LogWindow;
this.mnuTraceLogger.Name = "mnuTraceLogger";
this.mnuTraceLogger.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.T)));
this.mnuTraceLogger.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.L)));
this.mnuTraceLogger.Size = new System.Drawing.Size(196, 22);
this.mnuTraceLogger.Text = "Trace Logger";
this.mnuTraceLogger.Click += new System.EventHandler(this.mnuTraceLogger_Click);
@ -1286,5 +1303,7 @@ namespace Mesen.GUI.Debugger
private System.Windows.Forms.ToolStripSeparator toolStripMenuItem13;
private System.Windows.Forms.ToolStripMenuItem mnuBreakOnUnofficialOpcodes;
private System.Windows.Forms.ToolStripMenuItem mnuBreakOnBrk;
private System.Windows.Forms.ToolStripMenuItem mnuSaveRom;
private System.Windows.Forms.ToolStripSeparator toolStripMenuItem14;
}
}

View file

@ -125,6 +125,8 @@ namespace Mesen.GUI.Debugger
UpdateCdlRatios();
tmrCdlRatios.Start();
mnuSaveRom.Enabled = InteropEmu.GetRomInfo().Format == RomFormat.iNes;
}
private void ctrlProfiler_OnFunctionSelected(object sender, EventArgs e)
@ -235,6 +237,8 @@ namespace Mesen.GUI.Debugger
case InteropEmu.ConsoleNotificationType.GameReset:
case InteropEmu.ConsoleNotificationType.GameLoaded:
this.BeginInvoke((MethodInvoker)(() => {
mnuSaveRom.Enabled = InteropEmu.GetRomInfo().Format == RomFormat.iNes;
this.UpdateWorkspace();
this.AutoLoadDbgFile(true);
UpdateDebugger();
@ -837,5 +841,17 @@ namespace Mesen.GUI.Debugger
splitContainer.CollapsePanel();
}
}
private void mnuSaveRom_Click(object sender, EventArgs e)
{
using(SaveFileDialog sfd = new SaveFileDialog()) {
sfd.Filter = "NES roms (*.nes)|*.nes";
sfd.FileName = InteropEmu.GetRomInfo().GetRomName() + "_Modified.nes";
sfd.InitialDirectory = ConfigManager.DebuggerFolder;
if(sfd.ShowDialog() == DialogResult.OK) {
InteropEmu.DebugSaveRomToDisk(sfd.FileName);
}
}
}
}
}

View file

@ -209,6 +209,8 @@ namespace Mesen.GUI
[DllImport(DLLPath)] public static extern void DebugResetMemoryAccessCounts();
[DllImport(DLLPath)] public static extern void DebugResetProfiler();
[DllImport(DLLPath)] public static extern void DebugSaveRomToDisk([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8Marshaler))]string filename);
[DllImport(DLLPath, EntryPoint = "DebugGetCode")] private static extern IntPtr DebugGetCodeWrapper();
public static string DebugGetCode() { return PtrToStringUtf8(InteropEmu.DebugGetCodeWrapper()); }
@ -906,6 +908,15 @@ namespace Mesen.GUI
public IntPtr RomNamePointer;
public UInt32 Crc32;
public UInt32 PrgCrc32;
public RomFormat Format;
}
public enum RomFormat
{
Unknown = 0,
iNes = 1,
Unif = 2,
Fds = 3,
}
public class RomInfo
@ -913,12 +924,14 @@ namespace Mesen.GUI
public string RomName;
public UInt32 Crc32;
public UInt32 PrgCrc32;
public RomFormat Format;
public RomInfo(InteropRomInfo romInfo)
{
this.RomName = UTF8Marshaler.GetStringFromIntPtr(romInfo.RomNamePointer);
this.Crc32 = romInfo.Crc32;
this.PrgCrc32 = romInfo.PrgCrc32;
this.Format = romInfo.Format;
}
public string GetRomName()

View file

@ -61,6 +61,7 @@ namespace InteropEmu {
const char* RomName;
uint32_t Crc32;
uint32_t PrgCrc32;
RomFormat Format;
};
extern "C" {
@ -178,6 +179,7 @@ namespace InteropEmu {
romInfo.RomName = _returnString.c_str();
romInfo.Crc32 = Console::GetCrc32();
romInfo.PrgCrc32 = Console::GetPrgCrc32();
romInfo.Format = Console::GetRomFormat();
} else {
RomLoader romLoader;
if(romLoader.LoadFile(filename, nullptr, "", archiveFileIndex)) {
@ -187,11 +189,13 @@ namespace InteropEmu {
romInfo.RomName = _returnString.c_str();
romInfo.Crc32 = romData.Crc32;
romInfo.PrgCrc32 = romData.PrgCrc32;
romInfo.Format = RomFormat::Unknown;
} else {
_returnString = "";
romInfo.RomName = _returnString.c_str();
romInfo.Crc32 = 0;
romInfo.PrgCrc32 = 0;
romInfo.Format = RomFormat::Unknown;
}
}
}

View file

@ -92,4 +92,6 @@ extern "C"
DllExport void __stdcall DebugGetFreezeState(uint16_t startAddress, uint16_t length, bool* freezeState) { GetDebugger()->GetFreezeState(startAddress, length, freezeState); }
DllExport uint32_t __stdcall DebugGetPpuScroll() { return GetDebugger()->GetPpuScroll(); }
DllExport void __stdcall DebugSaveRomToDisk(char* filename) { GetDebugger()->SaveRomToDisk(filename); }
};