From f7c6ec3b5778b737f3c865cc602cbad61ebb053d Mon Sep 17 00:00:00 2001 From: wheremyfoodat <44909372+wheremyfoodat@users.noreply.github.com> Date: Mon, 19 Feb 2024 18:50:41 +0200 Subject: [PATCH] Properly handle DSP interrupts in HLE --- include/audio/null_core.hpp | 8 +++--- include/kernel/kernel.hpp | 1 - include/services/dsp.hpp | 1 - include/services/service_manager.hpp | 2 -- src/core/audio/null_core.cpp | 39 +++++++++++++++++++++++++++- src/core/services/dsp.cpp | 10 ------- src/core/services/gsp_gpu.cpp | 4 --- 7 files changed, 43 insertions(+), 22 deletions(-) diff --git a/include/audio/null_core.hpp b/include/audio/null_core.hpp index 0c2ddbac..136a76ac 100644 --- a/include/audio/null_core.hpp +++ b/include/audio/null_core.hpp @@ -20,12 +20,14 @@ namespace Audio { std::array dspRam; void resetAudioPipe(); + bool loaded = false; // Have we loaded a component? public: NullDSP(Memory& mem, Scheduler& scheduler, DSPService& dspService) : DSPCore(mem, scheduler, dspService) {} void reset() override; - void runAudioFrame() override {} + void runAudioFrame() override; + u8* getDspMemory() override { return dspRam.data(); } u16 recvData(u32 regId) override; @@ -34,8 +36,8 @@ namespace Audio { std::vector readPipe(u32 channel, u32 peer, u32 size, u32 buffer) override; // NOPs for null DSP core - void loadComponent(std::vector& data, u32 programMask, u32 dataMask) override {} - void unloadComponent() override {} + void loadComponent(std::vector& data, u32 programMask, u32 dataMask) override; + void unloadComponent() override; void setSemaphore(u16 value) override {} void setSemaphoreMask(u16 value) override {} }; diff --git a/include/kernel/kernel.hpp b/include/kernel/kernel.hpp index 27db30c6..fc7fe3f3 100644 --- a/include/kernel/kernel.hpp +++ b/include/kernel/kernel.hpp @@ -245,6 +245,5 @@ public: ServiceManager& getServiceManager() { return serviceManager; } void sendGPUInterrupt(GPUInterrupt type) { serviceManager.sendGPUInterrupt(type); } - void signalDSPEvents() { serviceManager.signalDSPEvents(); } void clearInstructionCache(); }; \ No newline at end of file diff --git a/include/services/dsp.hpp b/include/services/dsp.hpp index 2c185923..bc27377d 100644 --- a/include/services/dsp.hpp +++ b/include/services/dsp.hpp @@ -66,7 +66,6 @@ public: Surround = 2 }; - void signalEvents(); void triggerPipeEvent(int index); void triggerSemaphoreEvent(); void triggerInterrupt0(); diff --git a/include/services/service_manager.hpp b/include/services/service_manager.hpp index b6c803b0..8d1cf381 100644 --- a/include/services/service_manager.hpp +++ b/include/services/service_manager.hpp @@ -105,8 +105,6 @@ class ServiceManager { void setHIDSharedMem(u8* ptr) { hid.setSharedMem(ptr); } void setCSNDSharedMem(u8* ptr) { csnd.setSharedMemory(ptr); } - void signalDSPEvents() { dsp.signalEvents(); } - // Input function wrappers HIDService& getHID() { return hid; } NFCService& getNFC() { return nfc; } diff --git a/src/core/audio/null_core.cpp b/src/core/audio/null_core.cpp index 4d355c1e..ec073ae7 100644 --- a/src/core/audio/null_core.cpp +++ b/src/core/audio/null_core.cpp @@ -1,5 +1,7 @@ #include "audio/null_core.hpp" +#include "services/dsp.hpp" + namespace Audio { namespace DSPPipeType { enum : u32 { @@ -45,11 +47,41 @@ namespace Audio { } void NullDSP::reset() { - for (auto& e : pipeData) e.clear(); + loaded = false; + for (auto& e : pipeData) { + e.clear(); + } // Note: Reset audio pipe AFTER resetting all pipes, otherwise the new data will be yeeted resetAudioPipe(); } + + void NullDSP::loadComponent(std::vector& data, u32 programMask, u32 dataMask) { + if (loaded) { + Helpers::warn("Loading DSP component when already loaded"); + } + + loaded = true; + scheduler.addEvent(Scheduler::EventType::RunDSP, scheduler.currentTimestamp + Audio::cyclesPerFrame); + } + + void NullDSP::unloadComponent() { + if (!loaded) { + Helpers::warn("Audio: unloadComponent called without a running program"); + } + + loaded = false; + scheduler.removeEvent(Scheduler::EventType::RunDSP); + } + + void NullDSP::runAudioFrame() { + // Signal audio pipe when an audio frame is done + if (dspState == DSPState::On) [[likely]] { + dspService.triggerPipeEvent(DSPPipeType::Audio); + } + + scheduler.addEvent(Scheduler::EventType::RunDSP, scheduler.currentTimestamp + Audio::cyclesPerFrame); + } u16 NullDSP::recvData(u32 regId) { if (regId != 0) { @@ -84,6 +116,8 @@ namespace Audio { // TODO: Other initialization stuff here dspState = DSPState::On; resetAudioPipe(); + + dspService.triggerPipeEvent(DSPPipeType::Audio); break; case StateChange::Shutdown: @@ -98,6 +132,9 @@ namespace Audio { case DSPPipeType::Binary: Helpers::warn("Unimplemented write to binary pipe! Size: %d\n", size); + + // This pipe and interrupt are normally used for requests like AAC decode + dspService.triggerPipeEvent(DSPPipeType::Binary); break; default: log("Audio::NullDSP: Wrote to unimplemented pipe %d\n", channel); break; diff --git a/src/core/services/dsp.cpp b/src/core/services/dsp.cpp index f5a6dcae..33c1703d 100644 --- a/src/core/services/dsp.cpp +++ b/src/core/services/dsp.cpp @@ -262,16 +262,6 @@ void DSPService::invalidateDCache(u32 messagePointer) { mem.write32(messagePointer + 4, Result::Success); } -void DSPService::signalEvents() { - for (const DSPEvent& e : pipeEvents) { - if (e.has_value()) { kernel.signalEvent(e.value()); } - } - - if (semaphoreEvent.has_value()) { kernel.signalEvent(semaphoreEvent.value()); } - if (interrupt0.has_value()) { kernel.signalEvent(interrupt0.value()); } - if (interrupt1.has_value()) { kernel.signalEvent(interrupt1.value()); } -} - void DSPService::triggerPipeEvent(int index) { if (index < pipeCount && pipeEvents[index].has_value()) { kernel.signalEvent(*pipeEvents[index]); diff --git a/src/core/services/gsp_gpu.cpp b/src/core/services/gsp_gpu.cpp index 98b091b8..7dcc1158 100644 --- a/src/core/services/gsp_gpu.cpp +++ b/src/core/services/gsp_gpu.cpp @@ -123,10 +123,6 @@ void GPUService::registerInterruptRelayQueue(u32 messagePointer) { } void GPUService::requestInterrupt(GPUInterrupt type) { - // HACK: Signal DSP events on GPU interrupt for now until we have the DSP since games need DSP events - // Maybe there's a better alternative? - //kernel.signalDSPEvents(); - if (sharedMem == nullptr) [[unlikely]] { // Shared memory hasn't been set up yet return; }