From f58354af06225bb6cb923513be2897f9318cbb8e Mon Sep 17 00:00:00 2001 From: wheremyfoodat <44909372+wheremyfoodat@users.noreply.github.com> Date: Sun, 18 Feb 2024 03:54:00 +0200 Subject: [PATCH] Update DSP semaphore on semaphore event signal Fixes Pokemon X and other DSP-needy games... --- include/audio/teakra_core.hpp | 2 +- include/kernel/kernel.hpp | 13 +++++++++---- include/kernel/kernel_types.hpp | 8 ++++++++ include/services/dsp.hpp | 4 ++++ src/core/audio/teakra_core.cpp | 16 ++++++++++------ src/core/kernel/events.cpp | 19 ++++++++++++++++--- src/core/services/dsp.cpp | 6 +++++- 7 files changed, 53 insertions(+), 15 deletions(-) diff --git a/include/audio/teakra_core.hpp b/include/audio/teakra_core.hpp index 99ae8800..400a9e71 100644 --- a/include/audio/teakra_core.hpp +++ b/include/audio/teakra_core.hpp @@ -79,7 +79,7 @@ namespace Audio { u16 recvData(u32 regId) override { return teakra.RecvData(regId); } bool recvDataIsReady(u32 regId) override { return teakra.RecvDataIsReady(regId); } - void setSemaphore(u16 value) override { return teakra.SetSemaphore(value); } + void setSemaphore(u16 value) override { teakra.SetSemaphore(value); } void setSemaphoreMask(u16 value) override { teakra.MaskSemaphore(value); } void writeProcessPipe(u32 channel, u32 size, u32 buffer) override; diff --git a/include/kernel/kernel.hpp b/include/kernel/kernel.hpp index e78a588a..27db30c6 100644 --- a/include/kernel/kernel.hpp +++ b/include/kernel/kernel.hpp @@ -66,15 +66,20 @@ class Kernel { Handle makeMemoryBlock(u32 addr, u32 size, u32 myPermission, u32 otherPermission); public: - Handle makeEvent(ResetType resetType); // Needs to be public to be accessible to the APT/HID services - Handle makeMutex(bool locked = false); // Needs to be public to be accessible to the APT/DSP services - Handle makeSemaphore(u32 initialCount, u32 maximumCount); // Needs to be public to be accessible to the service manager port + // Needs to be public to be accessible to the APT/HID services + Handle makeEvent(ResetType resetType, Event::CallbackType callback = Event::CallbackType::None); + // Needs to be public to be accessible to the APT/DSP services + Handle makeMutex(bool locked = false); + // Needs to be public to be accessible to the service manager port + Handle makeSemaphore(u32 initialCount, u32 maximumCount); Handle makeTimer(ResetType resetType); void pollTimers(); // Signals an event, returns true on success or false if the event does not exist bool signalEvent(Handle e); - + // Run the callback for "special" events that have callbacks + void runEventCallback(Event::CallbackType callback); + void clearEvent(Handle e) { KernelObject* object = getObject(e, KernelObjectType::Event); if (object != nullptr) { diff --git a/include/kernel/kernel_types.hpp b/include/kernel/kernel_types.hpp index 01af4bd9..a68ef8d5 100644 --- a/include/kernel/kernel_types.hpp +++ b/include/kernel/kernel_types.hpp @@ -62,11 +62,19 @@ struct Process { }; struct Event { + // Some events (for now, only the DSP semaphore events) need to execute a callback when signalled + // This enum stores what kind of callback they should execute + enum class CallbackType : u32 { + None, DSPSemaphore, + }; + u64 waitlist; // A bitfield where each bit symbolizes if the thread with thread with the corresponding index is waiting on the event ResetType resetType = ResetType::OneShot; + CallbackType callback = CallbackType::None; bool fired = false; Event(ResetType resetType) : resetType(resetType), waitlist(0) {} + Event(ResetType resetType, CallbackType cb) : resetType(resetType), waitlist(0), callback(cb) {} }; struct Port { diff --git a/include/services/dsp.hpp b/include/services/dsp.hpp index 5b8c0f4f..2c185923 100644 --- a/include/services/dsp.hpp +++ b/include/services/dsp.hpp @@ -27,6 +27,7 @@ class DSPService { DSPEvent interrupt0; DSPEvent interrupt1; std::array pipeEvents; + u16 semaphoreMask = 0; DSPEvent& getEventRef(u32 type, u32 pipe); static constexpr size_t maxEventCount = 6; @@ -55,6 +56,9 @@ public: void reset(); void handleSyncRequest(u32 messagePointer); void setDSPCore(Audio::DSPCore* pointer) { dsp = pointer; } + + // Special callback that's ran when the semaphore event is signalled + void onSemaphoreEventSignal() { dsp->setSemaphore(semaphoreMask); } enum class SoundOutputMode : u8 { Mono = 0, diff --git a/src/core/audio/teakra_core.cpp b/src/core/audio/teakra_core.cpp index 7541185a..7c263b1f 100644 --- a/src/core/audio/teakra_core.cpp +++ b/src/core/audio/teakra_core.cpp @@ -38,16 +38,20 @@ TeakraDSP::TeakraDSP(Memory& mem, DSPService& dspService) : DSPCore(mem, dspServ // Set up callbacks for Teakra Teakra::AHBMCallback ahbm; - ahbm.read8 = [&](u32 addr) -> u8 { return mem.read8(addr); }; - ahbm.read16 = [&](u32 addr) -> u16 { return mem.read16(addr); }; - ahbm.read32 = [&](u32 addr) -> u32 { return mem.read32(addr); }; + // The AHBM read handlers read from paddrs rather than vaddrs which mem.read8 and the like use + // TODO: When we implement more efficient paddr accesses with a page table or similar, these handlers + // Should be made to properly use it, since this method is hacky and will segfault if given an invalid addr + ahbm.read8 = [&](u32 addr) -> u8 { return mem.getFCRAM()[addr - PhysicalAddrs::FCRAM]; }; + ahbm.read16 = [&](u32 addr) -> u16 { return *(u16*)&mem.getFCRAM()[addr - PhysicalAddrs::FCRAM]; }; + ahbm.read32 = [&](u32 addr) -> u32 { return *(u32*)&mem.getFCRAM()[addr - PhysicalAddrs::FCRAM]; }; - ahbm.write8 = [&](u32 addr, u8 value) { mem.write8(addr, value); }; - ahbm.write16 = [&](u32 addr, u16 value) { mem.write16(addr, value); }; - ahbm.write32 = [&](u32 addr, u32 value) { mem.write32(addr, value); }; + ahbm.write8 = [&](u32 addr, u8 value) { mem.getFCRAM()[addr - PhysicalAddrs::FCRAM] = value; }; + ahbm.write16 = [&](u32 addr, u16 value) { *(u16*)&mem.getFCRAM()[addr - PhysicalAddrs::FCRAM] = value; }; + ahbm.write32 = [&](u32 addr, u32 value) { *(u32*)&mem.getFCRAM()[addr - PhysicalAddrs::FCRAM] = value; }; teakra.SetAHBMCallback(ahbm); teakra.SetAudioCallback([=](std::array sample) { + //printf("%d %d\n", sample[0], sample[1]); // NOP for now }); diff --git a/src/core/kernel/events.cpp b/src/core/kernel/events.cpp index b2f89fbf..7c0d3047 100644 --- a/src/core/kernel/events.cpp +++ b/src/core/kernel/events.cpp @@ -12,9 +12,9 @@ const char* Kernel::resetTypeToString(u32 type) { } } -Handle Kernel::makeEvent(ResetType resetType) { +Handle Kernel::makeEvent(ResetType resetType, Event::CallbackType callback) { Handle ret = makeObject(KernelObjectType::Event); - objects[ret].data = new Event(resetType); + objects[ret].data = new Event(resetType, callback); return ret; } @@ -42,8 +42,13 @@ bool Kernel::signalEvent(Handle handle) { event->fired = false; } } - + rescheduleThreads(); + // Run the callback for events that require a special callback + if (event->callback != Event::CallbackType::None) [[unlikely]] { + runEventCallback(event->callback); + } + return true; } @@ -230,4 +235,12 @@ void Kernel::waitSynchronizationN() { } else { Helpers::panic("WaitSynchronizationN with waitAll"); } +} + +void Kernel::runEventCallback(Event::CallbackType callback) { + switch (callback) { + case Event::CallbackType::None: break; + case Event::CallbackType::DSPSemaphore: serviceManager.getDSP().onSemaphoreEventSignal(); break; + default: Helpers::panic("Unimplemented special callback for kernel event!"); break; + } } \ No newline at end of file diff --git a/src/core/services/dsp.cpp b/src/core/services/dsp.cpp index c768248c..fafa0f16 100644 --- a/src/core/services/dsp.cpp +++ b/src/core/services/dsp.cpp @@ -32,6 +32,7 @@ namespace Result { void DSPService::reset() { totalEventCount = 0; + semaphoreMask = 0; semaphoreEvent = std::nullopt; interrupt0 = std::nullopt; @@ -83,6 +84,7 @@ void DSPService::loadComponent(u32 messagePointer) { for (u32 i = 0; i < size; i++) { data[i] = mem.read8(buffer + i); } + printf("Loado compartment: %08X %08X %08X %08X\n", data[0], data[1], data[2], data[3]); log("DSP::LoadComponent (size = %08X, program mask = %X, data mask = %X\n", size, programMask, dataMask); dsp->loadComponent(data, programMask, dataMask); @@ -200,7 +202,7 @@ void DSPService::getSemaphoreEventHandle(u32 messagePointer) { log("DSP::GetSemaphoreEventHandle\n"); if (!semaphoreEvent.has_value()) { - semaphoreEvent = kernel.makeEvent(ResetType::OneShot); + semaphoreEvent = kernel.makeEvent(ResetType::OneShot, Event::CallbackType::DSPSemaphore); } mem.write32(messagePointer, IPC::responseHeader(0x16, 1, 2)); @@ -224,6 +226,8 @@ void DSPService::setSemaphoreMask(u32 messagePointer) { log("DSP::SetSemaphoreMask(mask = %04X)\n", mask); dsp->setSemaphoreMask(mask); + semaphoreMask = mask; + mem.write32(messagePointer, IPC::responseHeader(0x17, 1, 0)); mem.write32(messagePointer + 4, Result::Success); }