mirror of
https://github.com/wheremyfoodat/Panda3DS.git
synced 2025-04-11 00:25:41 +12:00
Merge pull request #22 from wheremyfoodat/dont_explode_on_vram
Implement more DSP pipe stuff, stub APT::PreloadLibraryApplet for Picross 3D
This commit is contained in:
commit
64ee82d892
5 changed files with 91 additions and 61 deletions
|
@ -38,6 +38,7 @@ class APTService {
|
||||||
void initialize(u32 messagePointer);
|
void initialize(u32 messagePointer);
|
||||||
void inquireNotification(u32 messagePointer);
|
void inquireNotification(u32 messagePointer);
|
||||||
void notifyToWait(u32 messagePointer);
|
void notifyToWait(u32 messagePointer);
|
||||||
|
void preloadLibraryApplet(u32 messagePointer);
|
||||||
void receiveParameter(u32 messagePointer);
|
void receiveParameter(u32 messagePointer);
|
||||||
void replySleepQuery(u32 messagePointer);
|
void replySleepQuery(u32 messagePointer);
|
||||||
void setApplicationCpuTimeLimit(u32 messagePointer);
|
void setApplicationCpuTimeLimit(u32 messagePointer);
|
||||||
|
|
|
@ -5,46 +5,6 @@
|
||||||
#include "logger.hpp"
|
#include "logger.hpp"
|
||||||
#include "memory.hpp"
|
#include "memory.hpp"
|
||||||
|
|
||||||
// Stub for DSP audio pipe
|
|
||||||
class DSPPipe {
|
|
||||||
// Hardcoded responses for now
|
|
||||||
// These are DSP DRAM offsets for various variables
|
|
||||||
// https://www.3dbrew.org/wiki/DSP_Memory_Region
|
|
||||||
static constexpr std::array<u16, 16> pipeData = {
|
|
||||||
0x000F, // Number of responses
|
|
||||||
0xBFFF, // Frame counter
|
|
||||||
0x9E92, // Source configs
|
|
||||||
0x8680, // Source statuses
|
|
||||||
0xA792, // ADPCM coefficients
|
|
||||||
0x9430, // DSP configs
|
|
||||||
0x8400, // DSP status
|
|
||||||
0x8540, // Final samples
|
|
||||||
0x9492, // Intermediate mix samples
|
|
||||||
0x8710, // Compressor
|
|
||||||
0x8410, // Debug
|
|
||||||
0xA912, // ??
|
|
||||||
0xAA12, // ??
|
|
||||||
0xAAD2, // ??
|
|
||||||
0xAC52, // Surround sound biquad filter 1
|
|
||||||
0xAC5C // Surround sound biquad filter 2
|
|
||||||
};
|
|
||||||
uint index = 0;
|
|
||||||
|
|
||||||
public:
|
|
||||||
void reset() {
|
|
||||||
index = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read without checking if the pipe has overflowed
|
|
||||||
u16 readUnchecked() {
|
|
||||||
return pipeData[index++];
|
|
||||||
}
|
|
||||||
|
|
||||||
bool empty() {
|
|
||||||
return index >= pipeData.size();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace DSPPipeType {
|
namespace DSPPipeType {
|
||||||
enum : u32 {
|
enum : u32 {
|
||||||
Debug = 0, DMA = 1, Audio = 2, Binary = 3
|
Debug = 0, DMA = 1, Audio = 2, Binary = 3
|
||||||
|
@ -66,7 +26,6 @@ class DSPService {
|
||||||
|
|
||||||
// Number of DSP pipes
|
// Number of DSP pipes
|
||||||
static constexpr size_t pipeCount = 8;
|
static constexpr size_t pipeCount = 8;
|
||||||
DSPPipe audioPipe;
|
|
||||||
DSPState dspState;
|
DSPState dspState;
|
||||||
|
|
||||||
// DSP service event handles
|
// DSP service event handles
|
||||||
|
@ -76,6 +35,10 @@ class DSPService {
|
||||||
DSPEvent interrupt0;
|
DSPEvent interrupt0;
|
||||||
DSPEvent interrupt1;
|
DSPEvent interrupt1;
|
||||||
std::array<DSPEvent, pipeCount> pipeEvents;
|
std::array<DSPEvent, pipeCount> pipeEvents;
|
||||||
|
std::array<std::vector<u8>, pipeCount> pipeData; // The data of each pipe
|
||||||
|
|
||||||
|
void resetAudioPipe();
|
||||||
|
std::vector<u8> readPipe(u32 pipe, u32 size);
|
||||||
|
|
||||||
DSPEvent& getEventRef(u32 type, u32 pipe);
|
DSPEvent& getEventRef(u32 type, u32 pipe);
|
||||||
static constexpr size_t maxEventCount = 6;
|
static constexpr size_t maxEventCount = 6;
|
||||||
|
|
|
@ -256,7 +256,7 @@ void GPU::fireDMA(u32 dest, u32 source, u32 size) {
|
||||||
u8* fcram = mem.getFCRAM();
|
u8* fcram = mem.getFCRAM();
|
||||||
std::memcpy(&vram[dest - vramStart], &fcram[source - fcramStart], size);
|
std::memcpy(&vram[dest - vramStart], &fcram[source - fcramStart], size);
|
||||||
} else {
|
} else {
|
||||||
printf("Non-trivially optimizable GPU DMA. Falling back to byte-by-byte transfer");
|
printf("Non-trivially optimizable GPU DMA. Falling back to byte-by-byte transfer\n");
|
||||||
|
|
||||||
for (u32 i = 0; i < size; i++) {
|
for (u32 i = 0; i < size; i++) {
|
||||||
mem.write8(dest + i, mem.read8(source + i));
|
mem.write8(dest + i, mem.read8(source + i));
|
||||||
|
|
|
@ -10,6 +10,7 @@ namespace APTCommands {
|
||||||
InquireNotification = 0x000B0040,
|
InquireNotification = 0x000B0040,
|
||||||
ReceiveParameter = 0x000D0080,
|
ReceiveParameter = 0x000D0080,
|
||||||
GlanceParameter = 0x000E0080,
|
GlanceParameter = 0x000E0080,
|
||||||
|
PreloadLibraryApplet = 0x00160040,
|
||||||
ReplySleepQuery = 0x003E0080,
|
ReplySleepQuery = 0x003E0080,
|
||||||
NotifyToWait = 0x00430040,
|
NotifyToWait = 0x00430040,
|
||||||
GetSharedFont = 0x00440000,
|
GetSharedFont = 0x00440000,
|
||||||
|
@ -80,6 +81,7 @@ void APTService::handleSyncRequest(u32 messagePointer) {
|
||||||
case APTCommands::GetWirelessRebootInfo: getWirelessRebootInfo(messagePointer); break;
|
case APTCommands::GetWirelessRebootInfo: getWirelessRebootInfo(messagePointer); break;
|
||||||
case APTCommands::GlanceParameter: glanceParameter(messagePointer); break;
|
case APTCommands::GlanceParameter: glanceParameter(messagePointer); break;
|
||||||
case APTCommands::NotifyToWait: notifyToWait(messagePointer); break;
|
case APTCommands::NotifyToWait: notifyToWait(messagePointer); break;
|
||||||
|
case APTCommands::PreloadLibraryApplet: preloadLibraryApplet(messagePointer); break;
|
||||||
case APTCommands::ReceiveParameter: [[likely]] receiveParameter(messagePointer); break;
|
case APTCommands::ReceiveParameter: [[likely]] receiveParameter(messagePointer); break;
|
||||||
case APTCommands::ReplySleepQuery: replySleepQuery(messagePointer); break;
|
case APTCommands::ReplySleepQuery: replySleepQuery(messagePointer); break;
|
||||||
case APTCommands::SetApplicationCpuTimeLimit: setApplicationCpuTimeLimit(messagePointer); break;
|
case APTCommands::SetApplicationCpuTimeLimit: setApplicationCpuTimeLimit(messagePointer); break;
|
||||||
|
@ -95,12 +97,20 @@ void APTService::appletUtility(u32 messagePointer) {
|
||||||
u32 outputSize = mem.read32(messagePointer + 12);
|
u32 outputSize = mem.read32(messagePointer + 12);
|
||||||
u32 inputPointer = mem.read32(messagePointer + 20);
|
u32 inputPointer = mem.read32(messagePointer + 20);
|
||||||
|
|
||||||
log("APT::AppletUtility(utility = %d, input size = %x, output size = %x, inputPointer = %08X)\n", utility, inputSize,
|
log("APT::AppletUtility(utility = %d, input size = %x, output size = %x, inputPointer = %08X) (Stubbed)\n", utility, inputSize,
|
||||||
outputSize, inputPointer);
|
outputSize, inputPointer);
|
||||||
mem.write32(messagePointer, IPC::responseHeader(0x4B, 2, 2));
|
mem.write32(messagePointer, IPC::responseHeader(0x4B, 2, 2));
|
||||||
mem.write32(messagePointer + 4, Result::Success);
|
mem.write32(messagePointer + 4, Result::Success);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void APTService::preloadLibraryApplet(u32 messagePointer) {
|
||||||
|
const u32 appID = mem.read32(messagePointer + 4);
|
||||||
|
log("APT::PreloadLibraryApplet (app ID = %d) (stubbed)\n", appID);
|
||||||
|
|
||||||
|
mem.write32(messagePointer, IPC::responseHeader(0x16, 1, 0));
|
||||||
|
mem.write32(messagePointer + 4, Result::Success);
|
||||||
|
}
|
||||||
|
|
||||||
void APTService::checkNew3DS(u32 messagePointer) {
|
void APTService::checkNew3DS(u32 messagePointer) {
|
||||||
log("APT::CheckNew3DS\n");
|
log("APT::CheckNew3DS\n");
|
||||||
mem.write32(messagePointer, IPC::responseHeader(0x102, 2, 0));
|
mem.write32(messagePointer, IPC::responseHeader(0x102, 2, 0));
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
#include "ipc.hpp"
|
#include "ipc.hpp"
|
||||||
#include "kernel.hpp"
|
#include "kernel.hpp"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
namespace DSPCommands {
|
namespace DSPCommands {
|
||||||
enum : u32 {
|
enum : u32 {
|
||||||
RecvData = 0x00010040,
|
RecvData = 0x00010040,
|
||||||
|
@ -30,7 +32,11 @@ namespace Result {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DSPService::reset() {
|
void DSPService::reset() {
|
||||||
audioPipe.reset();
|
for (auto& e : pipeData)
|
||||||
|
e.clear();
|
||||||
|
|
||||||
|
// Note: Reset audio pipe AFTER resetting all pipes, otherwise the new data will be yeeted
|
||||||
|
resetAudioPipe();
|
||||||
totalEventCount = 0;
|
totalEventCount = 0;
|
||||||
dspState = DSPState::Off;
|
dspState = DSPState::Off;
|
||||||
|
|
||||||
|
@ -43,6 +49,40 @@ void DSPService::reset() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DSPService::resetAudioPipe() {
|
||||||
|
// Hardcoded responses for now
|
||||||
|
// These are DSP DRAM offsets for various variables
|
||||||
|
// https://www.3dbrew.org/wiki/DSP_Memory_Region
|
||||||
|
static constexpr std::array<u16, 16> responses = {
|
||||||
|
0x000F, // Number of responses
|
||||||
|
0xBFFF, // Frame counter
|
||||||
|
0x9E92, // Source configs
|
||||||
|
0x8680, // Source statuses
|
||||||
|
0xA792, // ADPCM coefficients
|
||||||
|
0x9430, // DSP configs
|
||||||
|
0x8400, // DSP status
|
||||||
|
0x8540, // Final samples
|
||||||
|
0x9492, // Intermediate mix samples
|
||||||
|
0x8710, // Compressor
|
||||||
|
0x8410, // Debug
|
||||||
|
0xA912, // ??
|
||||||
|
0xAA12, // ??
|
||||||
|
0xAAD2, // ??
|
||||||
|
0xAC52, // Surround sound biquad filter 1
|
||||||
|
0xAC5C // Surround sound biquad filter 2
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<u8>& audioPipe = pipeData[DSPPipeType::Audio];
|
||||||
|
audioPipe.resize(responses.size() * sizeof(u16));
|
||||||
|
|
||||||
|
// Push back every response to the audio pipe
|
||||||
|
size_t index = 0;
|
||||||
|
for (auto e : responses) {
|
||||||
|
audioPipe[index++] = e & 0xff;
|
||||||
|
audioPipe[index++] = e >> 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void DSPService::handleSyncRequest(u32 messagePointer) {
|
void DSPService::handleSyncRequest(u32 messagePointer) {
|
||||||
const u32 command = mem.read32(messagePointer);
|
const u32 command = mem.read32(messagePointer);
|
||||||
switch (command) {
|
switch (command) {
|
||||||
|
@ -93,31 +133,43 @@ void DSPService::unloadComponent(u32 messagePointer) {
|
||||||
mem.write32(messagePointer + 4, Result::Success);
|
mem.write32(messagePointer + 4, Result::Success);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<u8> DSPService::readPipe(u32 pipe, u32 size) {
|
||||||
|
if (size & 1) Helpers::panic("Tried to read odd amount of bytes from DSP pipe");
|
||||||
|
if (pipe >= pipeCount || size > 0xffff) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pipe != DSPPipeType::Audio) {
|
||||||
|
log("Reading from non-audio pipe! This might be broken, might need to check what pipe is being read from and implement writing to it\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<u8>& data = pipeData[pipe];
|
||||||
|
size = std::min<u32>(size, data.size()); // Clamp size to the maximum available data size
|
||||||
|
|
||||||
|
if (size == 0)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
// Return "size" bytes from the audio pipe and erase them
|
||||||
|
std::vector<u8> out(data.begin(), data.begin() + size);
|
||||||
|
data.erase(data.begin(), data.begin() + size);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
void DSPService::readPipeIfPossible(u32 messagePointer) {
|
void DSPService::readPipeIfPossible(u32 messagePointer) {
|
||||||
u32 channel = mem.read32(messagePointer + 4);
|
u32 channel = mem.read32(messagePointer + 4);
|
||||||
u32 peer = mem.read32(messagePointer + 8);
|
u32 peer = mem.read32(messagePointer + 8);
|
||||||
u16 size = mem.read16(messagePointer + 12);
|
u16 size = mem.read16(messagePointer + 12);
|
||||||
u32 buffer = mem.read32(messagePointer + 0x100 + 4);
|
u32 buffer = mem.read32(messagePointer + 0x100 + 4);
|
||||||
log("DSP::ReadPipeIfPossible (channel = %d, peer = %d, size = %04X, buffer = %08X)\n", channel, peer, size, buffer);
|
log("DSP::ReadPipeIfPossible (channel = %d, peer = %d, size = %04X, buffer = %08X)\n", channel, peer, size, buffer);
|
||||||
|
mem.write32(messagePointer, IPC::responseHeader(0x10, 2, 2));
|
||||||
|
|
||||||
if (size & 1) Helpers::panic("Tried to read odd amount of bytes from DSP pipe");
|
std::vector<u8> data = readPipe(channel, size);
|
||||||
if (channel != 2) Helpers::panic("Read from non-audio pipe");
|
for (uint i = 0; i < data.size(); i++) {
|
||||||
|
mem.write8(buffer + i, data[i]);
|
||||||
DSPPipe& pipe = audioPipe;
|
|
||||||
|
|
||||||
uint i; // Number of bytes transferred
|
|
||||||
for (i = 0; i < size; i += 2) {
|
|
||||||
if (pipe.empty()) {
|
|
||||||
printf("Tried to read from empty pipe\n");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
mem.write16(buffer + i, pipe.readUnchecked());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mem.write32(messagePointer, IPC::responseHeader(0x10, 2, 2));
|
|
||||||
mem.write32(messagePointer + 4, Result::Success);
|
mem.write32(messagePointer + 4, Result::Success);
|
||||||
mem.write16(messagePointer + 8, i); // Number of bytes read
|
mem.write16(messagePointer + 8, data.size()); // Number of bytes read
|
||||||
}
|
}
|
||||||
|
|
||||||
void DSPService::recvData(u32 messagePointer) {
|
void DSPService::recvData(u32 messagePointer) {
|
||||||
|
@ -130,7 +182,7 @@ void DSPService::recvData(u32 messagePointer) {
|
||||||
|
|
||||||
mem.write32(messagePointer, IPC::responseHeader(0x01, 2, 0));
|
mem.write32(messagePointer, IPC::responseHeader(0x01, 2, 0));
|
||||||
mem.write32(messagePointer + 4, Result::Success);
|
mem.write32(messagePointer + 4, Result::Success);
|
||||||
mem.write16(messagePointer + 8, ret); // Always return that the DSP is on
|
mem.write16(messagePointer + 8, ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DSPService::recvDataIsReady(u32 messagePointer) {
|
void DSPService::recvDataIsReady(u32 messagePointer) {
|
||||||
|
@ -257,7 +309,7 @@ void DSPService::writeProcessPipe(u32 messagePointer) {
|
||||||
case StateChange::Initialize:
|
case StateChange::Initialize:
|
||||||
// TODO: Other initialization stuff here
|
// TODO: Other initialization stuff here
|
||||||
dspState = DSPState::On;
|
dspState = DSPState::On;
|
||||||
audioPipe.reset();
|
resetAudioPipe();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case StateChange::Shutdown:
|
case StateChange::Shutdown:
|
||||||
|
@ -270,6 +322,10 @@ void DSPService::writeProcessPipe(u32 messagePointer) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case DSPPipeType::Binary:
|
||||||
|
Helpers::warn("Unimplemented write to binary pipe! Size: %d\n", size);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
log("DSP: Wrote to unimplemented pipe %d\n", channel);
|
log("DSP: Wrote to unimplemented pipe %d\n", channel);
|
||||||
break;
|
break;
|
||||||
|
|
Loading…
Add table
Reference in a new issue