diff --git a/src/core/system.cpp b/src/core/system.cpp
index 27f2b0161..0420a482a 100644
--- a/src/core/system.cpp
+++ b/src/core/system.cpp
@@ -1228,6 +1228,15 @@ void UpdateMemoryCards()
}
}
+bool DumpRAM(const char* filename)
+{
+ auto fp = FileSystem::OpenManagedCFile(filename, "wb");
+ if (!fp)
+ return false;
+
+ return std::fwrite(Bus::g_ram, Bus::RAM_SIZE, 1, fp.get()) == 1;
+}
+
bool HasMedia()
{
return g_cdrom.HasMedia();
@@ -1333,7 +1342,8 @@ bool RemoveMediaPathFromPlaylist(u32 index)
if (GetMediaPlaylistIndex() == index)
{
- g_host_interface->AddFormattedOSDMessage(10.0f, "Removing current media from playlist, removing media from CD-ROM.");
+ g_host_interface->AddFormattedOSDMessage(10.0f,
+ "Removing current media from playlist, removing media from CD-ROM.");
g_cdrom.RemoveMedia();
}
diff --git a/src/core/system.h b/src/core/system.h
index 551247f6f..eee1f6973 100644
--- a/src/core/system.h
+++ b/src/core/system.h
@@ -104,6 +104,9 @@ void UpdateControllerSettings();
void ResetControllers();
void UpdateMemoryCards();
+/// Dumps RAM to a file.
+bool DumpRAM(const char* filename);
+
bool HasMedia();
bool InsertMedia(const char* path);
void RemoveMedia();
diff --git a/src/duckstation-qt/mainwindow.cpp b/src/duckstation-qt/mainwindow.cpp
index bc28a4fb3..f32f55cc8 100644
--- a/src/duckstation-qt/mainwindow.cpp
+++ b/src/duckstation-qt/mainwindow.cpp
@@ -662,6 +662,13 @@ void MainWindow::connectSignals()
else
m_host_interface->stopDumpingAudio();
});
+ connect(m_ui.actionDumpRAM, &QAction::triggered, [this]() {
+ const QString filename = QFileDialog::getSaveFileName(this, tr("Destination File"));
+ if (filename.isEmpty())
+ return;
+
+ m_host_interface->dumpRAM(filename);
+ });
SettingWidgetBinder::BindWidgetToBoolSetting(m_host_interface, m_ui.actionDebugShowVRAM, "Debug", "ShowVRAM");
SettingWidgetBinder::BindWidgetToBoolSetting(m_host_interface, m_ui.actionDebugShowGPUState, "Debug", "ShowGPUState");
SettingWidgetBinder::BindWidgetToBoolSetting(m_host_interface, m_ui.actionDebugShowCDROMState, "Debug",
diff --git a/src/duckstation-qt/mainwindow.ui b/src/duckstation-qt/mainwindow.ui
index 458d04621..03dafc216 100644
--- a/src/duckstation-qt/mainwindow.ui
+++ b/src/duckstation-qt/mainwindow.ui
@@ -149,9 +149,10 @@
-
+
+
@@ -484,6 +485,11 @@
Dump Audio
+
+
+ Dump RAM...
+
+
true
diff --git a/src/duckstation-qt/qthostinterface.cpp b/src/duckstation-qt/qthostinterface.cpp
index 716ed9fca..39b6f6fa1 100644
--- a/src/duckstation-qt/qthostinterface.cpp
+++ b/src/duckstation-qt/qthostinterface.cpp
@@ -1026,6 +1026,24 @@ void QtHostInterface::stopDumpingAudio()
StopDumpingAudio();
}
+void QtHostInterface::dumpRAM(const QString& filename)
+{
+ if (!isOnWorkerThread())
+ {
+ QMetaObject::invokeMethod(this, "dumpRAM", Q_ARG(const QString&, filename));
+ return;
+ }
+
+ if (System::IsShutdown())
+ return;
+
+ const std::string filename_str = filename.toStdString();
+ if (System::DumpRAM(filename_str.c_str()))
+ ReportFormattedMessage("RAM dumped to '%s'", filename_str.c_str());
+ else
+ ReportFormattedMessage("Failed to dump RAM to '%s'", filename_str.c_str());
+}
+
void QtHostInterface::saveScreenshot()
{
if (!isOnWorkerThread())
diff --git a/src/duckstation-qt/qthostinterface.h b/src/duckstation-qt/qthostinterface.h
index f6476aa4a..5f843364c 100644
--- a/src/duckstation-qt/qthostinterface.h
+++ b/src/duckstation-qt/qthostinterface.h
@@ -151,6 +151,7 @@ public Q_SLOTS:
void setAudioOutputMuted(bool muted);
void startDumpingAudio();
void stopDumpingAudio();
+ void dumpRAM(const QString& filename);
void saveScreenshot();
void redrawDisplayWindow();
void toggleFullscreen();
diff --git a/src/duckstation-sdl/sdl_host_interface.cpp b/src/duckstation-sdl/sdl_host_interface.cpp
index 7a874465d..06dcb5bd2 100644
--- a/src/duckstation-sdl/sdl_host_interface.cpp
+++ b/src/duckstation-sdl/sdl_host_interface.cpp
@@ -904,6 +904,7 @@ void SDLHostInterface::DrawQuickSettingsMenu()
void SDLHostInterface::DrawDebugMenu()
{
+ const bool system_valid = System::IsValid();
Settings::DebugSettings& debug_settings = g_settings.debugging;
bool settings_changed = false;
@@ -931,6 +932,9 @@ void SDLHostInterface::DrawDebugMenu()
settings_changed |= ImGui::MenuItem("Dump CPU to VRAM Copies", nullptr, &debug_settings.dump_cpu_to_vram_copies);
settings_changed |= ImGui::MenuItem("Dump VRAM to CPU Copies", nullptr, &debug_settings.dump_vram_to_cpu_copies);
+ if (ImGui::MenuItem("Dump RAM...", nullptr, nullptr, system_valid))
+ DoDumpRAM();
+
ImGui::Separator();
settings_changed |= ImGui::MenuItem("Show VRAM", nullptr, &debug_settings.show_vram);
@@ -1511,6 +1515,22 @@ void SDLHostInterface::DoChangeDisc()
System::ResetPerformanceCounters();
}
+void SDLHostInterface::DoDumpRAM()
+{
+ Assert(!System::IsShutdown());
+
+ nfdchar_t* path = nullptr;
+ if (!NFD_SaveDialog("bin", nullptr, &path) || !path || std::strlen(path) == 0)
+ return;
+
+ if (System::DumpRAM(path))
+ AddFormattedOSDMessage(5.0f, "Dumped RAM to '%s'", path);
+ else
+ AddFormattedOSDMessage(10.0f, "Failed to dump RAM to '%s'", path);
+
+ System::ResetPerformanceCounters();
+}
+
void SDLHostInterface::Run()
{
while (!m_quit_request)
diff --git a/src/duckstation-sdl/sdl_host_interface.h b/src/duckstation-sdl/sdl_host_interface.h
index de98db5bd..ac0eae485 100644
--- a/src/duckstation-sdl/sdl_host_interface.h
+++ b/src/duckstation-sdl/sdl_host_interface.h
@@ -79,6 +79,7 @@ private:
void DrawImGuiWindows() override;
void DoStartDisc();
void DoChangeDisc();
+ void DoDumpRAM();
void HandleSDLEvent(const SDL_Event* event);
void ProcessEvents();