From 004991d79e991cf7825ab95fceecb4324d9b3c8c Mon Sep 17 00:00:00 2001 From: MerryMage Date: Sun, 6 Mar 2016 21:13:12 +0000 Subject: DSP: Implement Pipe 2 Pipe 2 is a DSP pipe that is used to initialize both the DSP hardware (the application signals to the DSP to initialize) and the application (the DSP provides the memory location of structures in the shared memory region). --- src/core/hle/service/dsp_dsp.cpp | 194 ++++++++++++++++++++++++++++++--------- 1 file changed, 151 insertions(+), 43 deletions(-) (limited to 'src/core') diff --git a/src/core/hle/service/dsp_dsp.cpp b/src/core/hle/service/dsp_dsp.cpp index 22e85cfc6..3ba24d466 100644 --- a/src/core/hle/service/dsp_dsp.cpp +++ b/src/core/hle/service/dsp_dsp.cpp @@ -58,10 +58,10 @@ static void ConvertProcessAddressFromDspDram(Service::Interface* self) { u32 addr = cmd_buff[1]; - cmd_buff[1] = 0; // No error + cmd_buff[1] = RESULT_SUCCESS.raw; // No error cmd_buff[2] = (addr << 1) + (Memory::DSP_RAM_VADDR + 0x40000); - LOG_TRACE(Service_DSP, "addr=0x%08X", addr); + LOG_DEBUG(Service_DSP, "addr=0x%08X", addr); } /** @@ -142,8 +142,7 @@ static void FlushDataCache(Service::Interface* self) { cmd_buff[1] = RESULT_SUCCESS.raw; // No error - LOG_DEBUG(Service_DSP, "(STUBBED) called address=0x%08X, size=0x%X, process=0x%08X", - address, size, process); + LOG_TRACE(Service_DSP, "called address=0x%08X, size=0x%X, process=0x%08X", address, size, process); } /** @@ -167,14 +166,14 @@ static void RegisterInterruptEvents(Service::Interface* self) { if (evt) { interrupt_events[std::make_pair(interrupt, channel)] = evt; cmd_buff[1] = RESULT_SUCCESS.raw; - LOG_WARNING(Service_DSP, "Registered interrupt=%u, channel=%u, event_handle=0x%08X", interrupt, channel, event_handle); + LOG_INFO(Service_DSP, "Registered interrupt=%u, channel=%u, event_handle=0x%08X", interrupt, channel, event_handle); } else { - cmd_buff[1] = -1; - LOG_ERROR(Service_DSP, "Invalid event handle! interrupt=%u, channel=%u, event_handle=0x%08X", interrupt, channel, event_handle); + LOG_CRITICAL(Service_DSP, "Invalid event handle! interrupt=%u, channel=%u, event_handle=0x%08X", interrupt, channel, event_handle); + ASSERT(false); // This should really be handled at a IPC translation layer. } } else { interrupt_events.erase(std::make_pair(interrupt, channel)); - LOG_WARNING(Service_DSP, "Unregistered interrupt=%u, channel=%u, event_handle=0x%08X", interrupt, channel, event_handle); + LOG_INFO(Service_DSP, "Unregistered interrupt=%u, channel=%u, event_handle=0x%08X", interrupt, channel, event_handle); } } @@ -188,7 +187,7 @@ static void RegisterInterruptEvents(Service::Interface* self) { static void SetSemaphore(Service::Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); - cmd_buff[1] = 0; // No error + cmd_buff[1] = RESULT_SUCCESS.raw; // No error LOG_WARNING(Service_DSP, "(STUBBED) called"); } @@ -207,21 +206,12 @@ static void SetSemaphore(Service::Interface* self) { static void WriteProcessPipe(Service::Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); - u32 channel = cmd_buff[1]; - u32 size = cmd_buff[2]; - u32 buffer = cmd_buff[4]; + DSP::HLE::DspPipe pipe = static_cast(cmd_buff[1]); + u32 size = cmd_buff[2]; + u32 buffer = cmd_buff[4]; - if (IPC::StaticBufferDesc(size, 1) != cmd_buff[3]) { - LOG_ERROR(Service_DSP, "IPC static buffer descriptor failed validation (0x%X). channel=%u, size=0x%X, buffer=0x%08X", cmd_buff[3], channel, size, buffer); - cmd_buff[1] = -1; // TODO - return; - } - - if (!Memory::GetPointer(buffer)) { - LOG_ERROR(Service_DSP, "Invalid Buffer: channel=%u, size=0x%X, buffer=0x%08X", channel, size, buffer); - cmd_buff[1] = -1; // TODO - return; - } + ASSERT_MSG(IPC::StaticBufferDesc(size, 1) == cmd_buff[3], "IPC static buffer descriptor failed validation (0x%X). pipe=%u, size=0x%X, buffer=0x%08X", cmd_buff[3], pipe, size, buffer); + ASSERT_MSG(Memory::GetPointer(buffer) != nullptr, "Invalid Buffer: pipe=%u, size=0x%X, buffer=0x%08X", pipe, size, buffer); std::vector message(size); @@ -229,11 +219,11 @@ static void WriteProcessPipe(Service::Interface* self) { message[i] = Memory::Read8(buffer + i); } - DSP::HLE::PipeWrite(channel, message); + DSP::HLE::PipeWrite(pipe, message); cmd_buff[1] = RESULT_SUCCESS.raw; // No error - LOG_TRACE(Service_DSP, "channel=%u, size=0x%X, buffer=0x%08X", channel, size, buffer); + LOG_DEBUG(Service_DSP, "pipe=%u, size=0x%X, buffer=0x%08X", pipe, size, buffer); } /** @@ -245,7 +235,7 @@ static void WriteProcessPipe(Service::Interface* self) { * 1 : Pipe Number * 2 : Unknown * 3 : Size in bytes of read (observed only lower half word used) - * 0x41 : Virtual address to read from DSP pipe to in memory + * 0x41 : Virtual address of memory buffer to write pipe contents to * Outputs: * 1 : Result of function, 0 on success, otherwise error code * 2 : Number of bytes read from pipe @@ -253,25 +243,82 @@ static void WriteProcessPipe(Service::Interface* self) { static void ReadPipeIfPossible(Service::Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); - u32 pipe = cmd_buff[1]; - u32 unk2 = cmd_buff[2]; - u32 size = cmd_buff[3] & 0xFFFF;// Lower 16 bits are size + DSP::HLE::DspPipe pipe = static_cast(cmd_buff[1]); + u32 unknown = cmd_buff[2]; + u32 size = cmd_buff[3] & 0xFFFF; // Lower 16 bits are size VAddr addr = cmd_buff[0x41]; - if (!Memory::GetPointer(addr)) { - LOG_ERROR(Service_DSP, "Invalid addr: pipe=0x%08X, unk2=0x%08X, size=0x%X, buffer=0x%08X", pipe, unk2, size, addr); - cmd_buff[1] = -1; // TODO - return; + ASSERT_MSG(Memory::GetPointer(addr) != nullptr, "Invalid addr: pipe=0x%08X, unknown=0x%08X, size=0x%X, buffer=0x%08X", pipe, unknown, size, addr); + + cmd_buff[1] = RESULT_SUCCESS.raw; // No error + if (DSP::HLE::GetPipeReadableSize(pipe) >= size) { + std::vector response = DSP::HLE::PipeRead(pipe, size); + + Memory::WriteBlock(addr, response.data(), response.size()); + + cmd_buff[2] = static_cast(response.size()); + } else { + cmd_buff[2] = 0; // Return no data } - std::vector response = DSP::HLE::PipeRead(pipe, size); + LOG_DEBUG(Service_DSP, "pipe=0x%08X, unknown=0x%08X, size=0x%X, buffer=0x%08X, return cmd_buff[2]=0x%08X", pipe, unknown, size, addr, cmd_buff[2]); +} - Memory::WriteBlock(addr, response.data(), response.size()); +/** + * DSP_DSP::ReadPipe service function + * Inputs: + * 1 : Pipe Number + * 2 : Unknown + * 3 : Size in bytes of read (observed only lower half word used) + * 0x41 : Virtual address of memory buffer to write pipe contents to + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : Number of bytes read from pipe + */ +static void ReadPipe(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + + DSP::HLE::DspPipe pipe = static_cast(cmd_buff[1]); + u32 unknown = cmd_buff[2]; + u32 size = cmd_buff[3] & 0xFFFF; // Lower 16 bits are size + VAddr addr = cmd_buff[0x41]; - cmd_buff[1] = 0; // No error - cmd_buff[2] = (u32)response.size(); + ASSERT_MSG(Memory::GetPointer(addr) != nullptr, "Invalid addr: pipe=0x%08X, unknown=0x%08X, size=0x%X, buffer=0x%08X", pipe, unknown, size, addr); - LOG_TRACE(Service_DSP, "pipe=0x%08X, unk2=0x%08X, size=0x%X, buffer=0x%08X", pipe, unk2, size, addr); + if (DSP::HLE::GetPipeReadableSize(pipe) >= size) { + std::vector response = DSP::HLE::PipeRead(pipe, size); + + Memory::WriteBlock(addr, response.data(), response.size()); + + cmd_buff[1] = RESULT_SUCCESS.raw; // No error + cmd_buff[2] = static_cast(response.size()); + } else { + // No more data is in pipe. Hardware hangs in this case; this should never happen. + UNREACHABLE(); + } + + LOG_DEBUG(Service_DSP, "pipe=0x%08X, unknown=0x%08X, size=0x%X, buffer=0x%08X, return cmd_buff[2]=0x%08X", pipe, unknown, size, addr, cmd_buff[2]); +} + +/** + * DSP_DSP::GetPipeReadableSize service function + * Inputs: + * 1 : Pipe Number + * 2 : Unknown + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : Number of bytes readable from pipe + */ +static void GetPipeReadableSize(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + + DSP::HLE::DspPipe pipe = static_cast(cmd_buff[1]); + u32 unknown = cmd_buff[2]; + + cmd_buff[1] = RESULT_SUCCESS.raw; // No error + cmd_buff[2] = DSP::HLE::GetPipeReadableSize(pipe); + + LOG_DEBUG(Service_DSP, "pipe=0x%08X, unknown=0x%08X, return cmd_buff[2]=0x%08X", pipe, unknown, cmd_buff[2]); } /** @@ -306,12 +353,73 @@ static void GetHeadphoneStatus(Service::Interface* self) { cmd_buff[1] = RESULT_SUCCESS.raw; // No error cmd_buff[2] = 0; // Not using headphones? - LOG_DEBUG(Service_DSP, "(STUBBED) called"); + LOG_WARNING(Service_DSP, "(STUBBED) called"); +} + +/** + * DSP_DSP::RecvData service function + * This function reads a value out of a DSP register. + * Inputs: + * 1 : Register Number + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : Value in the register + * Notes: + * This function has only been observed being called with a register number of 0. + */ +static void RecvData(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + + u32 register_number = cmd_buff[1]; + + ASSERT_MSG(register_number == 0, "Unknown register_number %u", register_number); + + // Application reads this after requesting DSP shutdown, to verify the DSP has indeed shutdown or slept. + + cmd_buff[1] = RESULT_SUCCESS.raw; + switch (DSP::HLE::GetDspState()) { + case DSP::HLE::DspState::On: + cmd_buff[2] = 0; + break; + case DSP::HLE::DspState::Off: + case DSP::HLE::DspState::Sleeping: + cmd_buff[2] = 1; + break; + default: + UNREACHABLE(); + break; + } + + LOG_DEBUG(Service_DSP, "register_number=%u", register_number); +} + +/** + * DSP_DSP::RecvDataIsReady service function + * This function checks whether a DSP register is ready to be read. + * Inputs: + * 1 : Register Number + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : non-zero == ready + * Note: + * This function has only been observed being called with a register number of 0. + */ +static void RecvDataIsReady(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + + u32 register_number = cmd_buff[1]; + + ASSERT_MSG(register_number == 0, "Unknown register_number %u", register_number); + + cmd_buff[1] = RESULT_SUCCESS.raw; + cmd_buff[2] = 1; // Ready to read + + LOG_DEBUG(Service_DSP, "register_number=%u", register_number); } const Interface::FunctionInfo FunctionTable[] = { - {0x00010040, nullptr, "RecvData"}, - {0x00020040, nullptr, "RecvDataIsReady"}, + {0x00010040, RecvData, "RecvData"}, + {0x00020040, RecvDataIsReady, "RecvDataIsReady"}, {0x00030080, nullptr, "SendData"}, {0x00040040, nullptr, "SendDataIsEmpty"}, {0x000500C2, nullptr, "SendFifoEx"}, @@ -323,8 +431,8 @@ const Interface::FunctionInfo FunctionTable[] = { {0x000B0000, nullptr, "CheckSemaphoreRequest"}, {0x000C0040, ConvertProcessAddressFromDspDram, "ConvertProcessAddressFromDspDram"}, {0x000D0082, WriteProcessPipe, "WriteProcessPipe"}, - {0x000E00C0, nullptr, "ReadPipe"}, - {0x000F0080, nullptr, "GetPipeReadableSize"}, + {0x000E00C0, ReadPipe, "ReadPipe"}, + {0x000F0080, GetPipeReadableSize, "GetPipeReadableSize"}, {0x001000C0, ReadPipeIfPossible, "ReadPipeIfPossible"}, {0x001100C2, LoadComponent, "LoadComponent"}, {0x00120000, nullptr, "UnloadComponent"}, -- cgit v1.2.3