summaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
authorMerryMage <MerryMage@users.noreply.github.com>2016-03-06 21:13:12 +0000
committerMerryMage <MerryMage@users.noreply.github.com>2016-03-06 21:25:44 +0000
commit004991d79e991cf7825ab95fceecb4324d9b3c8c (patch)
tree066e17358e9debf470bd10f3bbc667631bfbbbd8 /src/core
parent2d40891b4526b4559f20efaaea320f004fccc063 (diff)
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).
Diffstat (limited to 'src/core')
-rw-r--r--src/core/hle/service/dsp_dsp.cpp194
1 files changed, 151 insertions, 43 deletions
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<DSP::HLE::DspPipe>(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<u8> 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<DSP::HLE::DspPipe>(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<u8> response = DSP::HLE::PipeRead(pipe, size);
+
+ Memory::WriteBlock(addr, response.data(), response.size());
+
+ cmd_buff[2] = static_cast<u32>(response.size());
+ } else {
+ cmd_buff[2] = 0; // Return no data
}
- std::vector<u8> 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<DSP::HLE::DspPipe>(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<u8> 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<u32>(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<DSP::HLE::DspPipe>(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"},