Merge pull request #498 from wheremyfoodat/hle-dsp

Qt: Add support for dumping DSP firmware
This commit is contained in:
wheremyfoodat 2024-04-25 22:40:44 +00:00 committed by GitHub
commit 2fc66fd3ba
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 87 additions and 10 deletions

View file

@ -40,7 +40,7 @@ jobs:
MacOS: MacOS:
runs-on: macos-latest runs-on: macos-13
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2

View file

@ -16,7 +16,7 @@ jobs:
# well on Windows or Mac. You can convert this to a matrix build if you need # well on Windows or Mac. You can convert this to a matrix build if you need
# cross-platform coverage. # cross-platform coverage.
# See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix # See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix
runs-on: macos-latest runs-on: macos-13
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2

View file

@ -51,7 +51,7 @@ jobs:
path: upload path: upload
MacOS: MacOS:
runs-on: macos-latest runs-on: macos-13
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2

View file

@ -106,6 +106,7 @@ class MainWindow : public QMainWindow {
void emuThreadMainLoop(); void emuThreadMainLoop();
void selectLuaFile(); void selectLuaFile();
void selectROM(); void selectROM();
void dumpDspFirmware();
void dumpRomFS(); void dumpRomFS();
void openLuaEditor(); void openLuaEditor();
void openCheatsEditor(); void openCheatsEditor();

View file

@ -1,6 +1,9 @@
#pragma once #pragma once
#include <array> #include <array>
#include <filesystem>
#include <optional> #include <optional>
#include <vector>
#include "audio/dsp_core.hpp" #include "audio/dsp_core.hpp"
#include "helpers.hpp" #include "helpers.hpp"
#include "logger.hpp" #include "logger.hpp"
@ -34,9 +37,10 @@ class DSPService {
// Total number of DSP service events registered with registerInterruptEvents // Total number of DSP service events registered with registerInterruptEvents
size_t totalEventCount; size_t totalEventCount;
std::vector<u8> loadedComponent;
// Service functions // Service functions
void convertProcessAddressFromDspDram(u32 messagePointer); // Nice function name void convertProcessAddressFromDspDram(u32 messagePointer); // Nice function name
void flushDataCache(u32 messagePointer); void flushDataCache(u32 messagePointer);
void getHeadphoneStatus(u32 messagePointer); void getHeadphoneStatus(u32 messagePointer);
void getSemaphoreEventHandle(u32 messagePointer); void getSemaphoreEventHandle(u32 messagePointer);
@ -51,23 +55,31 @@ class DSPService {
void unloadComponent(u32 messagePointer); void unloadComponent(u32 messagePointer);
void writeProcessPipe(u32 messagePointer); void writeProcessPipe(u32 messagePointer);
public: public:
DSPService(Memory& mem, Kernel& kernel) : mem(mem), kernel(kernel) {} DSPService(Memory& mem, Kernel& kernel) : mem(mem), kernel(kernel) {}
void reset(); void reset();
void handleSyncRequest(u32 messagePointer); void handleSyncRequest(u32 messagePointer);
void setDSPCore(Audio::DSPCore* pointer) { dsp = pointer; } void setDSPCore(Audio::DSPCore* pointer) { dsp = pointer; }
// Special callback that's ran when the semaphore event is signalled // Special callback that's ran when the semaphore event is signalled
void onSemaphoreEventSignal() { dsp->setSemaphore(semaphoreMask); } void onSemaphoreEventSignal() { dsp->setSemaphore(semaphoreMask); }
enum class SoundOutputMode : u8 { enum class SoundOutputMode : u8 {
Mono = 0, Mono = 0,
Stereo = 1, Stereo = 1,
Surround = 2 Surround = 2,
};
enum class ComponentDumpResult : u8 {
Success = 0,
NotLoaded,
FileFailure,
}; };
void triggerPipeEvent(int index); void triggerPipeEvent(int index);
void triggerSemaphoreEvent(); void triggerSemaphoreEvent();
void triggerInterrupt0(); void triggerInterrupt0();
void triggerInterrupt1(); void triggerInterrupt1();
ComponentDumpResult dumpComponent(const std::filesystem::path& path);
}; };

View file

@ -3,6 +3,7 @@
#include "kernel.hpp" #include "kernel.hpp"
#include <algorithm> #include <algorithm>
#include <fstream>
namespace DSPCommands { namespace DSPCommands {
enum : u32 { enum : u32 {
@ -41,6 +42,8 @@ void DSPService::reset() {
for (DSPEvent& e : pipeEvents) { for (DSPEvent& e : pipeEvents) {
e = std::nullopt; e = std::nullopt;
} }
loadedComponent.clear();
} }
void DSPService::handleSyncRequest(u32 messagePointer) { void DSPService::handleSyncRequest(u32 messagePointer) {
@ -80,13 +83,14 @@ void DSPService::loadComponent(u32 messagePointer) {
u32 dataMask = mem.read32(messagePointer + 12); u32 dataMask = mem.read32(messagePointer + 12);
u32 buffer = mem.read32(messagePointer + 20); u32 buffer = mem.read32(messagePointer + 20);
std::vector<u8> data(size); loadedComponent.resize(size);
for (u32 i = 0; i < size; i++) { for (u32 i = 0; i < size; i++) {
data[i] = mem.read8(buffer + i); loadedComponent[i] = mem.read8(buffer + i);
} }
log("DSP::LoadComponent (size = %08X, program mask = %X, data mask = %X\n", size, programMask, dataMask); log("DSP::LoadComponent (size = %08X, program mask = %X, data mask = %X\n", size, programMask, dataMask);
dsp->loadComponent(data, programMask, dataMask); dsp->loadComponent(loadedComponent, programMask, dataMask);
mem.write32(messagePointer, IPC::responseHeader(0x11, 2, 2)); mem.write32(messagePointer, IPC::responseHeader(0x11, 2, 2));
mem.write32(messagePointer + 4, Result::Success); mem.write32(messagePointer + 4, Result::Success);
@ -262,6 +266,21 @@ void DSPService::invalidateDCache(u32 messagePointer) {
mem.write32(messagePointer + 4, Result::Success); mem.write32(messagePointer + 4, Result::Success);
} }
DSPService::ComponentDumpResult DSPService::dumpComponent(const std::filesystem::path& path) {
if (loadedComponent.empty()) {
return ComponentDumpResult::NotLoaded;
}
std::ofstream file(path, std::ios::out | std::ios::binary);
if (file.bad()) {
return ComponentDumpResult::FileFailure;
}
file.write((char*)&loadedComponent[0], loadedComponent.size() * sizeof(u8));
file.close();
return ComponentDumpResult::Success;
}
void DSPService::triggerPipeEvent(int index) { void DSPService::triggerPipeEvent(int index) {
if (index < pipeCount && pipeEvents[index].has_value()) { if (index < pipeCount && pipeEvents[index].has_value()) {
kernel.signalEvent(*pipeEvents[index]); kernel.signalEvent(*pipeEvents[index]);

View file

@ -9,6 +9,7 @@
#include "cheats.hpp" #include "cheats.hpp"
#include "input_mappings.hpp" #include "input_mappings.hpp"
#include "services/dsp.hpp"
MainWindow::MainWindow(QApplication* app, QWidget* parent) : QMainWindow(parent), keyboardMappings(InputMappings::defaultKeyboardMappings()), screen(this) { MainWindow::MainWindow(QApplication* app, QWidget* parent) : QMainWindow(parent), keyboardMappings(InputMappings::defaultKeyboardMappings()), screen(this) {
setWindowTitle("Alber"); setWindowTitle("Alber");
@ -53,9 +54,12 @@ MainWindow::MainWindow(QApplication* app, QWidget* parent) : QMainWindow(parent)
auto dumpRomFSAction = toolsMenu->addAction(tr("Dump RomFS")); auto dumpRomFSAction = toolsMenu->addAction(tr("Dump RomFS"));
auto luaEditorAction = toolsMenu->addAction(tr("Open Lua Editor")); auto luaEditorAction = toolsMenu->addAction(tr("Open Lua Editor"));
auto cheatsEditorAction = toolsMenu->addAction(tr("Open Cheats Editor")); auto cheatsEditorAction = toolsMenu->addAction(tr("Open Cheats Editor"));
auto dumpDspFirmware = toolsMenu->addAction(tr("Dump loaded DSP firmware"));
connect(dumpRomFSAction, &QAction::triggered, this, &MainWindow::dumpRomFS); connect(dumpRomFSAction, &QAction::triggered, this, &MainWindow::dumpRomFS);
connect(luaEditorAction, &QAction::triggered, this, &MainWindow::openLuaEditor); connect(luaEditorAction, &QAction::triggered, this, &MainWindow::openLuaEditor);
connect(cheatsEditorAction, &QAction::triggered, this, &MainWindow::openCheatsEditor); connect(cheatsEditorAction, &QAction::triggered, this, &MainWindow::openCheatsEditor);
connect(dumpDspFirmware, &QAction::triggered, this, &MainWindow::dumpDspFirmware);
auto aboutAction = aboutMenu->addAction(tr("About Panda3DS")); auto aboutAction = aboutMenu->addAction(tr("About Panda3DS"));
connect(aboutAction, &QAction::triggered, this, &MainWindow::showAboutMenu); connect(aboutAction, &QAction::triggered, this, &MainWindow::showAboutMenu);
@ -241,6 +245,47 @@ void MainWindow::dumpRomFS() {
} }
} }
void MainWindow::dumpDspFirmware() {
auto file = QFileDialog::getSaveFileName(this, tr("Select file"), "", tr("DSP firmware file (*.cdc)"));
if (file.isEmpty()) {
return;
}
std::filesystem::path path(file.toStdU16String());
messageQueueMutex.lock();
auto res = emu->getServiceManager().getDSP().dumpComponent(path);
messageQueueMutex.unlock();
switch (res) {
case DSPService::ComponentDumpResult::Success: break;
case DSPService::ComponentDumpResult::NotLoaded: {
QMessageBox messageBox(
QMessageBox::Icon::Warning, tr("No DSP firmware loaded"),
tr("The currently loaded app has not uploaded a firmware to the DSP")
);
QAbstractButton* button = messageBox.addButton(tr("OK"), QMessageBox::ButtonRole::YesRole);
button->setIcon(QIcon(":/docs/img/rsob_icon.png"));
messageBox.exec();
break;
}
case DSPService::ComponentDumpResult::FileFailure: {
QMessageBox messageBox(
QMessageBox::Icon::Warning, tr("Failed to open output file"),
tr("The currently loaded DSP firmware could not be written to the selected file. Please make sure you have permission to access this "
"file")
);
QAbstractButton* button = messageBox.addButton(tr("OK"), QMessageBox::ButtonRole::YesRole);
button->setIcon(QIcon(":/docs/img/rstarstruck_icon.png"));
messageBox.exec();
break;
}
}
}
void MainWindow::showAboutMenu() { void MainWindow::showAboutMenu() {
AboutWindow about(this); AboutWindow about(this);
about.exec(); about.exec();