mirror of
https://github.com/wheremyfoodat/Panda3DS.git
synced 2025-04-12 09:09:47 +12:00
[DSP] Add event stubs to fix games locking up
This commit is contained in:
parent
2ebbb08766
commit
908e1fc4fd
7 changed files with 94 additions and 27 deletions
|
@ -182,10 +182,10 @@ struct Mutex {
|
||||||
|
|
||||||
struct Semaphore {
|
struct Semaphore {
|
||||||
u64 waitlist; // Refer to the getWaitlist function below for documentation
|
u64 waitlist; // Refer to the getWaitlist function below for documentation
|
||||||
u32 initialCount;
|
s32 availableCount;
|
||||||
u32 maximumCount;
|
s32 maximumCount;
|
||||||
|
|
||||||
Semaphore(u32 initialCount, u32 maximumCount) : initialCount(initialCount), maximumCount(maximumCount), waitlist(0) {}
|
Semaphore(s32 initialCount, s32 maximumCount) : availableCount(initialCount), maximumCount(maximumCount), waitlist(0) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct MemoryBlock {
|
struct MemoryBlock {
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
#include <array>
|
||||||
|
#include <optional>
|
||||||
#include "helpers.hpp"
|
#include "helpers.hpp"
|
||||||
#include "logger.hpp"
|
#include "logger.hpp"
|
||||||
#include "memory.hpp"
|
#include "memory.hpp"
|
||||||
|
@ -41,18 +43,38 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Circular dependencies!
|
||||||
|
class Kernel;
|
||||||
|
|
||||||
class DSPService {
|
class DSPService {
|
||||||
Handle handle = KernelHandles::DSP;
|
Handle handle = KernelHandles::DSP;
|
||||||
Memory& mem;
|
Memory& mem;
|
||||||
|
Kernel& kernel;
|
||||||
MAKE_LOG_FUNCTION(log, dspServiceLogger)
|
MAKE_LOG_FUNCTION(log, dspServiceLogger)
|
||||||
|
|
||||||
|
// Number of DSP pipes
|
||||||
|
static constexpr size_t pipeCount = 8;
|
||||||
DSPPipe audioPipe;
|
DSPPipe audioPipe;
|
||||||
|
|
||||||
|
// DSP service event handles
|
||||||
|
using DSPEvent = std::optional<Handle>;
|
||||||
|
|
||||||
|
DSPEvent semaphoreEvent;
|
||||||
|
DSPEvent interrupt0;
|
||||||
|
DSPEvent interrupt1;
|
||||||
|
std::array<DSPEvent, pipeCount> pipeEvents;
|
||||||
|
|
||||||
|
DSPEvent& getEventRef(u32 type, u32 pipe);
|
||||||
|
static constexpr size_t maxEventCount = 6;
|
||||||
|
|
||||||
|
// Total number of DSP service events registered with registerInterruptEvents
|
||||||
|
size_t totalEventCount;
|
||||||
|
|
||||||
// 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 getSemaphoreHandle(u32 messagePointer);
|
void getSemaphoreEventHandle(u32 messagePointer);
|
||||||
void invalidateDCache(u32 messagePointer);
|
void invalidateDCache(u32 messagePointer);
|
||||||
void loadComponent(u32 messagePointer);
|
void loadComponent(u32 messagePointer);
|
||||||
void readPipeIfPossible(u32 messagePointer);
|
void readPipeIfPossible(u32 messagePointer);
|
||||||
|
@ -62,7 +84,7 @@ class DSPService {
|
||||||
void writeProcessPipe(u32 messagePointer);
|
void writeProcessPipe(u32 messagePointer);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DSPService(Memory& mem) : mem(mem) {}
|
DSPService(Memory& mem, Kernel& kernel) : mem(mem), kernel(kernel) {}
|
||||||
void reset();
|
void reset();
|
||||||
void handleSyncRequest(u32 messagePointer);
|
void handleSyncRequest(u32 messagePointer);
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@ Handle Kernel::makeArbiter() {
|
||||||
|
|
||||||
// Result CreateAddressArbiter(Handle* arbiter)
|
// Result CreateAddressArbiter(Handle* arbiter)
|
||||||
void Kernel::createAddressArbiter() {
|
void Kernel::createAddressArbiter() {
|
||||||
|
logSVC("CreateAddressArbiter\n");
|
||||||
regs[0] = SVCResult::Success;
|
regs[0] = SVCResult::Success;
|
||||||
regs[1] = makeArbiter();
|
regs[1] = makeArbiter();
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,8 +28,8 @@ bool Kernel::signalEvent(Handle handle) {
|
||||||
Event* event = object->getData<Event>();
|
Event* event = object->getData<Event>();
|
||||||
event->fired = true;
|
event->fired = true;
|
||||||
|
|
||||||
// One shot events go back to being not fired once they wake up one or more thread
|
// One shot events go back to being not fired once they are signaled
|
||||||
if (event->waitlist != 0 && event->resetType == ResetType::OneShot) {
|
if (event->resetType == ResetType::Pulse) {
|
||||||
event->fired = false;
|
event->fired = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,9 +165,6 @@ void Kernel::waitSynchronizationN() {
|
||||||
|
|
||||||
logSVC("WaitSynchronizationN (handle pointer: %08X, count: %d, timeout = %lld)\n", handles, handleCount, ns);
|
logSVC("WaitSynchronizationN (handle pointer: %08X, count: %d, timeout = %lld)\n", handles, handleCount, ns);
|
||||||
|
|
||||||
if (waitAll && handleCount > 1)
|
|
||||||
Helpers::panic("Trying to wait on more than 1 object");
|
|
||||||
|
|
||||||
if (handleCount < 0)
|
if (handleCount < 0)
|
||||||
Helpers::panic("WaitSyncN: Invalid handle count");
|
Helpers::panic("WaitSyncN: Invalid handle count");
|
||||||
|
|
||||||
|
|
|
@ -272,7 +272,7 @@ void Kernel::createThread() {
|
||||||
// void SleepThread(s64 nanoseconds)
|
// void SleepThread(s64 nanoseconds)
|
||||||
void Kernel::svcSleepThread() {
|
void Kernel::svcSleepThread() {
|
||||||
const s64 ns = s64(u64(regs[0]) | (u64(regs[1]) << 32));
|
const s64 ns = s64(u64(regs[0]) | (u64(regs[1]) << 32));
|
||||||
logSVC("SleepThread(ns = %lld)\n", ns);
|
//logSVC("SleepThread(ns = %lld)\n", ns);
|
||||||
|
|
||||||
regs[0] = SVCResult::Success;
|
regs[0] = SVCResult::Success;
|
||||||
sleepThread(ns);
|
sleepThread(ns);
|
||||||
|
@ -417,8 +417,8 @@ bool Kernel::shouldWaitOnObject(KernelObject* object) {
|
||||||
case KernelObjectType::Thread: // Waiting on a thread waits until it's dead. If it's dead then no need to wait
|
case KernelObjectType::Thread: // Waiting on a thread waits until it's dead. If it's dead then no need to wait
|
||||||
return object->getData<Thread>()->status != ThreadStatus::Dead;
|
return object->getData<Thread>()->status != ThreadStatus::Dead;
|
||||||
|
|
||||||
case KernelObjectType::Semaphore:
|
case KernelObjectType::Semaphore: // Wait if the semaphore count <= 0
|
||||||
Helpers::panic("No semaphore :(");
|
return object->getData<Semaphore>()->availableCount <= 0;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
Helpers::panic("Not sure whether to wait on object (type: %s)", object->getTypeName());
|
Helpers::panic("Not sure whether to wait on object (type: %s)", object->getTypeName());
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include "services/dsp.hpp"
|
#include "services/dsp.hpp"
|
||||||
#include "ipc.hpp"
|
#include "ipc.hpp"
|
||||||
|
#include "kernel.hpp"
|
||||||
|
|
||||||
namespace DSPCommands {
|
namespace DSPCommands {
|
||||||
enum : u32 {
|
enum : u32 {
|
||||||
|
@ -11,7 +12,7 @@ namespace DSPCommands {
|
||||||
FlushDataCache = 0x00130082,
|
FlushDataCache = 0x00130082,
|
||||||
InvalidateDataCache = 0x00140082,
|
InvalidateDataCache = 0x00140082,
|
||||||
RegisterInterruptEvents = 0x00150082,
|
RegisterInterruptEvents = 0x00150082,
|
||||||
GetSemaphoreHandle = 0x00160000,
|
GetSemaphoreEventHandle = 0x00160000,
|
||||||
SetSemaphoreMask = 0x00170040,
|
SetSemaphoreMask = 0x00170040,
|
||||||
GetHeadphoneStatus = 0x001F0000
|
GetHeadphoneStatus = 0x001F0000
|
||||||
};
|
};
|
||||||
|
@ -27,6 +28,15 @@ namespace Result {
|
||||||
|
|
||||||
void DSPService::reset() {
|
void DSPService::reset() {
|
||||||
audioPipe.reset();
|
audioPipe.reset();
|
||||||
|
totalEventCount = 0;
|
||||||
|
|
||||||
|
semaphoreEvent = std::nullopt;
|
||||||
|
interrupt0 = std::nullopt;
|
||||||
|
interrupt1 = std::nullopt;
|
||||||
|
|
||||||
|
for (DSPEvent& e : pipeEvents) {
|
||||||
|
e = std::nullopt;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DSPService::handleSyncRequest(u32 messagePointer) {
|
void DSPService::handleSyncRequest(u32 messagePointer) {
|
||||||
|
@ -36,7 +46,7 @@ void DSPService::handleSyncRequest(u32 messagePointer) {
|
||||||
case DSPCommands::FlushDataCache: flushDataCache(messagePointer); break;
|
case DSPCommands::FlushDataCache: flushDataCache(messagePointer); break;
|
||||||
case DSPCommands::InvalidateDataCache: invalidateDCache(messagePointer); break;
|
case DSPCommands::InvalidateDataCache: invalidateDCache(messagePointer); break;
|
||||||
case DSPCommands::GetHeadphoneStatus: getHeadphoneStatus(messagePointer); break;
|
case DSPCommands::GetHeadphoneStatus: getHeadphoneStatus(messagePointer); break;
|
||||||
case DSPCommands::GetSemaphoreHandle: getSemaphoreHandle(messagePointer); break;
|
case DSPCommands::GetSemaphoreEventHandle: getSemaphoreEventHandle(messagePointer); break;
|
||||||
case DSPCommands::LoadComponent: loadComponent(messagePointer); break;
|
case DSPCommands::LoadComponent: loadComponent(messagePointer); break;
|
||||||
case DSPCommands::ReadPipeIfPossible: readPipeIfPossible(messagePointer); break;
|
case DSPCommands::ReadPipeIfPossible: readPipeIfPossible(messagePointer); break;
|
||||||
case DSPCommands::RegisterInterruptEvents: registerInterruptEvents(messagePointer); break;
|
case DSPCommands::RegisterInterruptEvents: registerInterruptEvents(messagePointer); break;
|
||||||
|
@ -97,14 +107,47 @@ void DSPService::readPipeIfPossible(u32 messagePointer) {
|
||||||
mem.write16(messagePointer + 8, i); // Number of bytes read
|
mem.write16(messagePointer + 8, i); // Number of bytes read
|
||||||
}
|
}
|
||||||
|
|
||||||
void DSPService::registerInterruptEvents(u32 messagePointer) {
|
DSPService::DSPEvent& DSPService::getEventRef(u32 type, u32 pipe) {
|
||||||
u32 interrupt = mem.read32(messagePointer + 4);
|
switch (type) {
|
||||||
u32 channel = mem.read32(messagePointer + 8);
|
case 0: return interrupt0;
|
||||||
u32 event = mem.read32(messagePointer + 16);
|
case 1: return interrupt1;
|
||||||
|
|
||||||
log("DSP::RegisterInterruptEvents (interrupt = %d, channel = %d, event = %d)\n", interrupt, channel, event);
|
case 2:
|
||||||
mem.write32(messagePointer, IPC::responseHeader(0x15, 1, 0));
|
if (pipe >= pipeCount)
|
||||||
mem.write32(messagePointer + 4, Result::Success);
|
Helpers::panic("Tried to access the event of an invalid pipe");
|
||||||
|
return pipeEvents[pipe];
|
||||||
|
|
||||||
|
default:
|
||||||
|
Helpers::panic("Unknown type for DSP::getEventRef");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DSPService::registerInterruptEvents(u32 messagePointer) {
|
||||||
|
const u32 interrupt = mem.read32(messagePointer + 4);
|
||||||
|
const u32 channel = mem.read32(messagePointer + 8);
|
||||||
|
const u32 eventHandle = mem.read32(messagePointer + 16);
|
||||||
|
log("DSP::RegisterInterruptEvents (interrupt = %d, channel = %d, event = %d)\n", interrupt, channel, eventHandle);
|
||||||
|
|
||||||
|
// The event handle being 0 means we're removing an event
|
||||||
|
if (eventHandle == 0) {
|
||||||
|
Helpers::panic("DSP::DSP::RegisterinterruptEvents Trying to remove a registered interrupt");
|
||||||
|
} else {
|
||||||
|
const KernelObject* object = kernel.getObject(eventHandle, KernelObjectType::Event);
|
||||||
|
if (!object) {
|
||||||
|
Helpers::panic("DSP::DSP::RegisterInterruptEvents with invalid event handle");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (totalEventCount >= maxEventCount)
|
||||||
|
Helpers::panic("DSP::RegisterInterruptEvents overflowed total number of allowed events");
|
||||||
|
else {
|
||||||
|
getEventRef(interrupt, channel) = eventHandle;
|
||||||
|
mem.write32(messagePointer, IPC::responseHeader(0x15, 1, 0));
|
||||||
|
mem.write32(messagePointer + 4, Result::Success);
|
||||||
|
|
||||||
|
totalEventCount++;
|
||||||
|
kernel.signalEvent(eventHandle);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DSPService::getHeadphoneStatus(u32 messagePointer) {
|
void DSPService::getHeadphoneStatus(u32 messagePointer) {
|
||||||
|
@ -115,13 +158,17 @@ void DSPService::getHeadphoneStatus(u32 messagePointer) {
|
||||||
mem.write32(messagePointer + 8, Result::HeadphonesInserted); // This should be toggleable for shits and giggles
|
mem.write32(messagePointer + 8, Result::HeadphonesInserted); // This should be toggleable for shits and giggles
|
||||||
}
|
}
|
||||||
|
|
||||||
void DSPService::getSemaphoreHandle(u32 messagePointer) {
|
void DSPService::getSemaphoreEventHandle(u32 messagePointer) {
|
||||||
log("DSP::GetSemaphoreHandle\n");
|
log("DSP::GetSemaphoreEventHandle\n");
|
||||||
|
|
||||||
|
if (!semaphoreEvent.has_value()) {
|
||||||
|
semaphoreEvent = kernel.makeEvent(ResetType::OneShot);
|
||||||
|
}
|
||||||
|
|
||||||
mem.write32(messagePointer, IPC::responseHeader(0x16, 1, 2));
|
mem.write32(messagePointer, IPC::responseHeader(0x16, 1, 2));
|
||||||
mem.write32(messagePointer + 4, Result::Success);
|
mem.write32(messagePointer + 4, Result::Success);
|
||||||
// TODO: Translation descriptor here?
|
// TODO: Translation descriptor here?
|
||||||
mem.write32(messagePointer + 12, 0xF9991234); // Semaphore handle (stubbed with random, obvious number)
|
mem.write32(messagePointer + 12, semaphoreEvent.value()); // Semaphore event handle
|
||||||
}
|
}
|
||||||
|
|
||||||
void DSPService::setSemaphore(u32 messagePointer) {
|
void DSPService::setSemaphore(u32 messagePointer) {
|
||||||
|
|
|
@ -5,8 +5,8 @@
|
||||||
|
|
||||||
ServiceManager::ServiceManager(std::array<u32, 16>& regs, Memory& mem, GPU& gpu, u32& currentPID, Kernel& kernel)
|
ServiceManager::ServiceManager(std::array<u32, 16>& regs, Memory& mem, GPU& gpu, u32& currentPID, Kernel& kernel)
|
||||||
: regs(regs), mem(mem), kernel(kernel), ac(mem), am(mem), boss(mem), apt(mem, kernel), cam(mem), cecd(mem), cfg(mem),
|
: regs(regs), mem(mem), kernel(kernel), ac(mem), am(mem), boss(mem), apt(mem, kernel), cam(mem), cecd(mem), cfg(mem),
|
||||||
dsp(mem), hid(mem), frd(mem), fs(mem, kernel), gsp_gpu(mem, gpu, kernel, currentPID), gsp_lcd(mem), ldr(mem), mic(mem),
|
dsp(mem, kernel), hid(mem), frd(mem), fs(mem, kernel), gsp_gpu(mem, gpu, kernel, currentPID), gsp_lcd(mem), ldr(mem),
|
||||||
nim(mem), ndm(mem), ptm(mem), y2r(mem, kernel) {}
|
mic(mem), nim(mem), ndm(mem), ptm(mem), y2r(mem, kernel) {}
|
||||||
|
|
||||||
static constexpr int MAX_NOTIFICATION_COUNT = 16;
|
static constexpr int MAX_NOTIFICATION_COUNT = 16;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue