From 72622a1b5a13083e1b4eda3d4584bfa2f04dc55c Mon Sep 17 00:00:00 2001 From: bunnei Date: Wed, 7 May 2014 21:04:55 -0400 Subject: - removed HLE mem "hack" and replaced with kernel mem region - added a helper function for getting command buffer for services - fixed bug where GSP DMA was incorrectly being done in DataSynchronizationBarrier (instead of gsp_TriggerCmdReqQueue) --- src/core/hle/service/gsp.cpp | 76 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 71 insertions(+), 5 deletions(-) (limited to 'src/core/hle/service/gsp.cpp') diff --git a/src/core/hle/service/gsp.cpp b/src/core/hle/service/gsp.cpp index 88c1f1a0f..58df970c4 100644 --- a/src/core/hle/service/gsp.cpp +++ b/src/core/hle/service/gsp.cpp @@ -4,6 +4,7 @@ #include "common/log.h" +#include "common/bit_field.h" #include "core/mem_map.h" #include "core/hle/hle.h" @@ -11,11 +12,57 @@ #include "core/hw/lcd.h" +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/// GSP shared memory GX command buffer header +union GX_CmdBufferHeader { + u32 hex; + + // Current command index. This index is updated by GSP module after loading the command data, + // right before the command is processed. When this index is updated by GSP module, the total + // commands field is decreased by one as well. + BitField<0,8,u32> index; + + // Total commands to process, must not be value 0 when GSP module handles commands. This must be + // <=15 when writing a command to shared memory. This is incremented by the application when + // writing a command to shared memory, after increasing this value TriggerCmdReqQueue is only + // used if this field is value 1. + BitField<8,8,u32> number_commands; + + // Must not be value 1. When the error-code u32 is set, this u8 is set to value 0x80. + BitField<16,8,u32> unk_0; + + // Bit 0 must not be set + BitField<24,8,u32> unk_1; +}; + +/// Gets the address of the start (header) of a command buffer in GSP shared memory +static inline u32 GX_GetCmdBufferAddress(u32 thread_id) { + return (0x10002000 + 0x800 + (thread_id * 0x200)); +} + +/// Gets a pointer to the start (header) of a command buffer in GSP shared memory +static inline u8* GX_GetCmdBufferPointer(u32 thread_id, u32 offset=0) { + return Memory::GetPointer(GX_GetCmdBufferAddress(thread_id) + offset); +} + +/// Finishes execution of a GSP command +void GX_FinishCommand(u32 thread_id) { + GX_CmdBufferHeader* header = (GX_CmdBufferHeader*)GX_GetCmdBufferPointer(thread_id); + header->number_commands = header->number_commands - 1; +} + //////////////////////////////////////////////////////////////////////////////////////////////////// // Namespace GSP_GPU namespace GSP_GPU { +u32 g_thread_id = 0; + +enum { + CMD_GX_REQUEST_DMA = 0x00000000, +}; + enum { REG_FRAMEBUFFER_1 = 0x00400468, REG_FRAMEBUFFER_2 = 0x00400494, @@ -26,7 +73,7 @@ void ReadHWRegs(Service::Interface* self) { static const u32 framebuffer_1[] = {LCD::PADDR_VRAM_TOP_LEFT_FRAME1, LCD::PADDR_VRAM_TOP_RIGHT_FRAME1}; static const u32 framebuffer_2[] = {LCD::PADDR_VRAM_TOP_LEFT_FRAME2, LCD::PADDR_VRAM_TOP_RIGHT_FRAME2}; - u32* cmd_buff = (u32*)HLE::GetPointer(HLE::CMD_BUFFER_ADDR + Service::kCommandHeaderOffset); + u32* cmd_buff = Service::GetCommandBuffer(); u32 reg_addr = cmd_buff[1]; u32 size = cmd_buff[2]; u32* dst = (u32*)Memory::GetPointer(cmd_buff[0x41]); @@ -50,18 +97,37 @@ void ReadHWRegs(Service::Interface* self) { break; default: - ERROR_LOG(OSHLE, "GSP_GPU::ReadHWRegs unknown register read at address %08X", reg_addr); + ERROR_LOG(GSP, "ReadHWRegs unknown register read at address %08X", reg_addr); } } void RegisterInterruptRelayQueue(Service::Interface* self) { - u32* cmd_buff = (u32*)HLE::GetPointer(HLE::CMD_BUFFER_ADDR + Service::kCommandHeaderOffset); + u32* cmd_buff = Service::GetCommandBuffer(); u32 flags = cmd_buff[1]; u32 event_handle = cmd_buff[3]; // TODO(bunnei): Implement event handling + + cmd_buff[2] = g_thread_id; // ThreadID cmd_buff[4] = self->NewHandle(); +} + +/// This triggers handling of the GX command written to the command buffer in shared memory. +void TriggerCmdReqQueue(Service::Interface* self) { + GX_CmdBufferHeader* header = (GX_CmdBufferHeader*)GX_GetCmdBufferPointer(g_thread_id); + u32* cmd_buff = (u32*)GX_GetCmdBufferPointer(g_thread_id, 0x20 + (header->index * 0x20)); - return; + switch (cmd_buff[0]) { + + // GX request DMA - typically used for copying memory from GSP heap to VRAM + case CMD_GX_REQUEST_DMA: + memcpy(Memory::GetPointer(cmd_buff[2]), Memory::GetPointer(cmd_buff[1]), cmd_buff[3]); + break; + + default: + ERROR_LOG(GSP, "TriggerCmdReqQueue unknown command 0x%08X", cmd_buff[0]); + } + + GX_FinishCommand(g_thread_id); } const Interface::FunctionInfo FunctionTable[] = { @@ -76,7 +142,7 @@ const Interface::FunctionInfo FunctionTable[] = { {0x00090082, NULL, "InvalidateDataCache"}, {0x000A0044, NULL, "RegisterInterruptEvents"}, {0x000B0040, NULL, "SetLcdForceBlack"}, - {0x000C0000, NULL, "TriggerCmdReqQueue"}, + {0x000C0000, TriggerCmdReqQueue, "TriggerCmdReqQueue"}, {0x000D0140, NULL, "SetDisplayTransfer"}, {0x000E0180, NULL, "SetTextureCopy"}, {0x000F0200, NULL, "SetMemoryFill"}, -- cgit v1.2.3