diff --git a/Core/BaseMapper.cpp b/Core/BaseMapper.cpp index 217c62a8..ae30e3b4 100644 --- a/Core/BaseMapper.cpp +++ b/Core/BaseMapper.cpp @@ -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(); + } } \ No newline at end of file diff --git a/Core/BaseMapper.h b/Core/BaseMapper.h index 03463462..dde0673b 100644 --- a/Core/BaseMapper.h +++ b/Core/BaseMapper.h @@ -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); }; \ No newline at end of file diff --git a/Core/Console.cpp b/Core/Console.cpp index e782b92a..87b243ce 100644 --- a/Core/Console.cpp +++ b/Core/Console.cpp @@ -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) { diff --git a/Core/Console.h b/Core/Console.h index f4bf413e..f42717ea 100644 --- a/Core/Console.h +++ b/Core/Console.h @@ -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(); diff --git a/Core/Debugger.cpp b/Core/Debugger.cpp index b5cfdf74..cc8b695e 100644 --- a/Core/Debugger.cpp +++ b/Core/Debugger.cpp @@ -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); +} diff --git a/Core/Debugger.h b/Core/Debugger.h index 75681a23..22f39952 100644 --- a/Core/Debugger.h +++ b/Core/Debugger.h @@ -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); }; \ No newline at end of file diff --git a/Core/DisassemblyInfo.cpp b/Core/DisassemblyInfo.cpp index 1431e853..edc60640 100644 --- a/Core/DisassemblyInfo.cpp +++ b/Core/DisassemblyInfo.cpp @@ -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; diff --git a/Core/FdsLoader.h b/Core/FdsLoader.h index 2604c3a3..8759f0a3 100644 --- a/Core/FdsLoader.h +++ b/Core/FdsLoader.h @@ -154,6 +154,7 @@ public: RomData romData; + romData.Format = RomFormat::Fds; romData.MapperID = MapperFactory::FdsMapperID; romData.Mirroring = MirroringType::Vertical; romData.PrgRom = LoadBios(); diff --git a/Core/RomData.h b/Core/RomData.h index d1c93e99..4b984d17 100644 --- a/Core/RomData.h +++ b/Core/RomData.h @@ -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; diff --git a/Core/UnifLoader.h b/Core/UnifLoader.h index 9938457b..0e3fbac9 100644 --- a/Core/UnifLoader.h +++ b/Core/UnifLoader.h @@ -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()); diff --git a/Core/iNesLoader.cpp b/Core/iNesLoader.cpp index abab5363..bd2e77d1 100644 --- a/Core/iNesLoader.cpp +++ b/Core/iNesLoader.cpp @@ -15,6 +15,8 @@ RomData iNesLoader::LoadRom(vector& romFile) header.SanitizeHeader(romFile.size()); + romData.Format = RomFormat::iNes; + romData.IsNes20Header = (header.GetRomHeaderVersion() == RomHeaderVersion::Nes2_0); romData.MapperID = header.GetMapperID(); romData.SubMapperID = header.GetSubMapper(); diff --git a/GUI.NET/Debugger/frmDebugger.Designer.cs b/GUI.NET/Debugger/frmDebugger.Designer.cs index e52baffc..1bdd9986 100644 --- a/GUI.NET/Debugger/frmDebugger.Designer.cs +++ b/GUI.NET/Debugger/frmDebugger.Designer.cs @@ -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; } } \ No newline at end of file diff --git a/GUI.NET/Debugger/frmDebugger.cs b/GUI.NET/Debugger/frmDebugger.cs index 047b50ba..f5f46417 100644 --- a/GUI.NET/Debugger/frmDebugger.cs +++ b/GUI.NET/Debugger/frmDebugger.cs @@ -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); + } + } + } } } diff --git a/GUI.NET/InteropEmu.cs b/GUI.NET/InteropEmu.cs index 210a698d..ecbb2d84 100644 --- a/GUI.NET/InteropEmu.cs +++ b/GUI.NET/InteropEmu.cs @@ -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() diff --git a/InteropDLL/ConsoleWrapper.cpp b/InteropDLL/ConsoleWrapper.cpp index c1f48be4..6e1f509c 100644 --- a/InteropDLL/ConsoleWrapper.cpp +++ b/InteropDLL/ConsoleWrapper.cpp @@ -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; } } } diff --git a/InteropDLL/DebugWrapper.cpp b/InteropDLL/DebugWrapper.cpp index a76a9cc3..f11bc692 100644 --- a/InteropDLL/DebugWrapper.cpp +++ b/InteropDLL/DebugWrapper.cpp @@ -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); } };