Files
P3DS-test/src/core/services/gsp_gpu.cpp
2022-09-20 23:22:35 +03:00

147 lines
4.9 KiB
C++

#include "services/gsp_gpu.hpp"
namespace GPUCommands {
enum : u32 {
AcquireRight = 0x00160042,
RegisterInterruptRelayQueue = 0x00130042,
WriteHwRegs = 0x00010082,
WriteHwRegsWithMask = 0x00020084
};
}
namespace Result {
enum : u32 {
Success = 0,
SuccessRegisterIRQ = 0x2A07 // TODO: Is this a reference to the Ricoh 2A07 used in PAL NES systems?
};
}
void GPUService::reset() {
privilegedProcess = 0xFFFFFFFF; // Set the privileged process to an invalid handle
sharedMem = nullptr;
}
void GPUService::handleSyncRequest(u32 messagePointer) {
const u32 command = mem.read32(messagePointer);
switch (command) {
case GPUCommands::AcquireRight: acquireRight(messagePointer); break;
case GPUCommands::RegisterInterruptRelayQueue: registerInterruptRelayQueue(messagePointer); break;
case GPUCommands::WriteHwRegs: writeHwRegs(messagePointer); break;
case GPUCommands::WriteHwRegsWithMask: writeHwRegsWithMask(messagePointer); break;
; default: Helpers::panic("GPU service requested. Command: %08X\n", command);
}
}
void GPUService::acquireRight(u32 messagePointer) {
const u32 flag = mem.read32(messagePointer + 4);
const u32 pid = mem.read32(messagePointer + 12);
printf("GSP::GPU::AcquireRight (flag = %X, pid = %X)\n", flag, pid);
if (flag != 0) {
Helpers::panic("GSP::GPU::acquireRight with flag != 0 needs to perform additional initialization");
}
if (pid == KernelHandles::CurrentProcess) {
privilegedProcess = currentPID;
} else {
privilegedProcess = pid;
}
mem.write32(messagePointer + 4, Result::Success);
}
// TODO: What is the flags field meant to be?
// What is the "GSP module thread index" meant to be?
// How does the shared memory handle thing work?
void GPUService::registerInterruptRelayQueue(u32 messagePointer) {
const u32 flags = mem.read32(messagePointer + 4);
const u32 eventHandle = mem.read32(messagePointer + 12);
printf("GSP::GPU::RegisterInterruptRelayQueue (flags = %X, event handle = %X)\n", flags, eventHandle);
mem.write32(messagePointer + 4, Result::SuccessRegisterIRQ);
mem.write32(messagePointer + 8, 0); // TODO: GSP module thread index
mem.write32(messagePointer + 12, 0); // Translation descriptor
mem.write32(messagePointer + 16, KernelHandles::GSPSharedMemHandle);
}
void GPUService::requestInterrupt(GPUInterrupt type) {
if (sharedMem == nullptr) [[unlikely]] { // Shared memory hasn't been set up yet
return;
}
u8 index = sharedMem[0];
u8& interruptCount = sharedMem[1];
u8 flagIndex = (index + interruptCount) % 0x34;
interruptCount++;
sharedMem[0xC + flagIndex] = static_cast<u8>(type);
}
void GPUService::writeHwRegs(u32 messagePointer) {
u32 ioAddr = mem.read32(messagePointer + 4); // GPU address based at 0x1EB00000, word aligned
const u32 size = mem.read32(messagePointer + 8); // Size in bytes
u32 dataPointer = mem.read32(messagePointer + 16);
printf("GSP::GPU::writeHwRegs (GPU address = %08X, size = %X, data address = %08X)\n", ioAddr, size, dataPointer);
// Check for alignment
if ((size & 3) || (ioAddr & 3) || (dataPointer & 3)) {
Helpers::panic("GSP::GPU::writeHwRegs misalignment");
}
if (size > 0x80) {
Helpers::panic("GSP::GPU::writeHwRegs size too big");
}
if (ioAddr >= 0x420000) {
Helpers::panic("GSP::GPU::writeHwRegs offset too big");
}
for (u32 i = 0; i < size; i += 4) {
const u32 value = mem.read32(dataPointer);
printf("GSP::GPU: Wrote %08X to GPU register %X\n", value, ioAddr);
dataPointer += 4;
ioAddr += 4;
// TODO: Write the value to the register
}
mem.write32(messagePointer + 4, Result::Success);
}
// Update sequential GPU registers using an array of data and mask values using this formula
// GPU register = (register & ~mask) | (data & mask).
void GPUService::writeHwRegsWithMask(u32 messagePointer) {
u32 ioAddr = mem.read32(messagePointer + 4); // GPU address based at 0x1EB00000, word aligned
const u32 size = mem.read32(messagePointer + 8); // Size in bytes
u32 dataPointer = mem.read32(messagePointer + 16); // Data pointer
u32 maskPointer = mem.read32(messagePointer + 24); // Mask pointer
printf("GSP::GPU::writeHwRegsWithMask (GPU address = %08X, size = %X, data address = %08X, mask address = %08X)\n",
ioAddr, size, dataPointer, maskPointer);
// Check for alignment
if ((size & 3) || (ioAddr & 3) || (dataPointer & 3) || (maskPointer & 3)) {
Helpers::panic("GSP::GPU::writeHwRegs misalignment");
}
if (size > 0x80) {
Helpers::panic("GSP::GPU::writeHwRegs size too big");
}
if (ioAddr >= 0x420000) {
Helpers::panic("GSP::GPU::writeHwRegs offset too big");
}
for (u32 i = 0; i < size; i += 4) {
const u32 currentValue = 0; // TODO: Read the actual register value
const u32 data = mem.read32(dataPointer);
const u32 mask = mem.read32(maskPointer);
u32 newValue = (currentValue & ~mask) | (data & mask);
// TODO: write new value
maskPointer += 4;
dataPointer += 4;
ioAddr += 4;
}
mem.write32(messagePointer + 4, Result::Success);
}