summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar bunnei2016-03-07 20:29:30 -0500
committerGravatar bunnei2016-03-07 20:29:30 -0500
commit58c336b67109e89b3d47e2873e8271e7291a59d0 (patch)
tree9b0707e1162d9b828e7baa206dcda8b69fd774e0 /src
parentMerge pull request #1467 from LittleWhite-tb/bug-shader-object (diff)
parentDSP: Implement Pipe 2 (diff)
downloadyuzu-58c336b67109e89b3d47e2873e8271e7291a59d0.tar.gz
yuzu-58c336b67109e89b3d47e2873e8271e7291a59d0.tar.xz
yuzu-58c336b67109e89b3d47e2873e8271e7291a59d0.zip
Merge pull request #1441 from MerryMage/dsp-pipes
AudioCore: Implement Pipe 2
Diffstat (limited to 'src')
-rw-r--r--src/audio_core/hle/dsp.h45
-rw-r--r--src/audio_core/hle/pipe.cpp150
-rw-r--r--src/audio_core/hle/pipe.h33
-rw-r--r--src/core/hle/service/dsp_dsp.cpp194
4 files changed, 345 insertions, 77 deletions
diff --git a/src/audio_core/hle/dsp.h b/src/audio_core/hle/dsp.h
index 14c4000c6..376436c29 100644
--- a/src/audio_core/hle/dsp.h
+++ b/src/audio_core/hle/dsp.h
@@ -66,9 +66,9 @@ static_assert(std::is_trivially_copyable<u32_dsp>::value, "u32_dsp isn't trivial
66#endif 66#endif
67 67
68// There are 15 structures in each memory region. A table of them in the order they appear in memory 68// There are 15 structures in each memory region. A table of them in the order they appear in memory
69// is presented below 69// is presented below:
70// 70//
71// Pipe 2 # First Region DSP Address Purpose Control 71// # First Region DSP Address Purpose Control
72// 5 0x8400 DSP Status DSP 72// 5 0x8400 DSP Status DSP
73// 9 0x8410 DSP Debug Info DSP 73// 9 0x8410 DSP Debug Info DSP
74// 6 0x8540 Final Mix Samples DSP 74// 6 0x8540 Final Mix Samples DSP
@@ -85,6 +85,9 @@ static_assert(std::is_trivially_copyable<u32_dsp>::value, "u32_dsp isn't trivial
85// 14 0xAC5C Surround Sound Related 85// 14 0xAC5C Surround Sound Related
86// 0 0xBFFF Frame Counter Application 86// 0 0xBFFF Frame Counter Application
87// 87//
88// #: This refers to the order in which they appear in the DspPipe::Audio DSP pipe.
89// See also: DSP::HLE::PipeRead.
90//
88// Note that the above addresses do vary slightly between audio firmwares observed; the addresses are 91// Note that the above addresses do vary slightly between audio firmwares observed; the addresses are
89// not fixed in stone. The addresses above are only an examplar; they're what this implementation 92// not fixed in stone. The addresses above are only an examplar; they're what this implementation
90// does and provides to applications. 93// does and provides to applications.
@@ -472,13 +475,47 @@ struct SharedMemory {
472 475
473 AdpcmCoefficients adpcm_coefficients; 476 AdpcmCoefficients adpcm_coefficients;
474 477
475 /// Unknown 10-14 (Surround sound related) 478 struct {
476 INSERT_PADDING_DSPWORDS(0x16ED); 479 INSERT_PADDING_DSPWORDS(0x100);
480 } unknown10;
481
482 struct {
483 INSERT_PADDING_DSPWORDS(0xC0);
484 } unknown11;
485
486 struct {
487 INSERT_PADDING_DSPWORDS(0x180);
488 } unknown12;
489
490 struct {
491 INSERT_PADDING_DSPWORDS(0xA);
492 } unknown13;
493
494 struct {
495 INSERT_PADDING_DSPWORDS(0x13A3);
496 } unknown14;
477 497
478 u16_le frame_counter; 498 u16_le frame_counter;
479}; 499};
480ASSERT_DSP_STRUCT(SharedMemory, 0x8000); 500ASSERT_DSP_STRUCT(SharedMemory, 0x8000);
481 501
502// Structures must have an offset that is a multiple of two.
503static_assert(offsetof(SharedMemory, frame_counter) % 2 == 0, "Structures in DSP::HLE::SharedMemory must be 2-byte aligned");
504static_assert(offsetof(SharedMemory, source_configurations) % 2 == 0, "Structures in DSP::HLE::SharedMemory must be 2-byte aligned");
505static_assert(offsetof(SharedMemory, source_statuses) % 2 == 0, "Structures in DSP::HLE::SharedMemory must be 2-byte aligned");
506static_assert(offsetof(SharedMemory, adpcm_coefficients) % 2 == 0, "Structures in DSP::HLE::SharedMemory must be 2-byte aligned");
507static_assert(offsetof(SharedMemory, dsp_configuration) % 2 == 0, "Structures in DSP::HLE::SharedMemory must be 2-byte aligned");
508static_assert(offsetof(SharedMemory, dsp_status) % 2 == 0, "Structures in DSP::HLE::SharedMemory must be 2-byte aligned");
509static_assert(offsetof(SharedMemory, final_samples) % 2 == 0, "Structures in DSP::HLE::SharedMemory must be 2-byte aligned");
510static_assert(offsetof(SharedMemory, intermediate_mix_samples) % 2 == 0, "Structures in DSP::HLE::SharedMemory must be 2-byte aligned");
511static_assert(offsetof(SharedMemory, compressor) % 2 == 0, "Structures in DSP::HLE::SharedMemory must be 2-byte aligned");
512static_assert(offsetof(SharedMemory, dsp_debug) % 2 == 0, "Structures in DSP::HLE::SharedMemory must be 2-byte aligned");
513static_assert(offsetof(SharedMemory, unknown10) % 2 == 0, "Structures in DSP::HLE::SharedMemory must be 2-byte aligned");
514static_assert(offsetof(SharedMemory, unknown11) % 2 == 0, "Structures in DSP::HLE::SharedMemory must be 2-byte aligned");
515static_assert(offsetof(SharedMemory, unknown12) % 2 == 0, "Structures in DSP::HLE::SharedMemory must be 2-byte aligned");
516static_assert(offsetof(SharedMemory, unknown13) % 2 == 0, "Structures in DSP::HLE::SharedMemory must be 2-byte aligned");
517static_assert(offsetof(SharedMemory, unknown14) % 2 == 0, "Structures in DSP::HLE::SharedMemory must be 2-byte aligned");
518
482#undef INSERT_PADDING_DSPWORDS 519#undef INSERT_PADDING_DSPWORDS
483#undef ASSERT_DSP_STRUCT 520#undef ASSERT_DSP_STRUCT
484 521
diff --git a/src/audio_core/hle/pipe.cpp b/src/audio_core/hle/pipe.cpp
index 6542c760c..9381883b4 100644
--- a/src/audio_core/hle/pipe.cpp
+++ b/src/audio_core/hle/pipe.cpp
@@ -5,50 +5,154 @@
5#include <array> 5#include <array>
6#include <vector> 6#include <vector>
7 7
8#include "audio_core/hle/dsp.h"
8#include "audio_core/hle/pipe.h" 9#include "audio_core/hle/pipe.h"
9 10
11#include "common/assert.h"
10#include "common/common_types.h" 12#include "common/common_types.h"
11#include "common/logging/log.h" 13#include "common/logging/log.h"
12 14
13namespace DSP { 15namespace DSP {
14namespace HLE { 16namespace HLE {
15 17
16static size_t pipe2position = 0; 18static DspState dsp_state = DspState::Off;
19
20static std::array<std::vector<u8>, static_cast<size_t>(DspPipe::DspPipe_MAX)> pipe_data;
17 21
18void ResetPipes() { 22void ResetPipes() {
19 pipe2position = 0; 23 for (auto& data : pipe_data) {
24 data.clear();
25 }
26 dsp_state = DspState::Off;
20} 27}
21 28
22std::vector<u8> PipeRead(u32 pipe_number, u32 length) { 29std::vector<u8> PipeRead(DspPipe pipe_number, u32 length) {
23 if (pipe_number != 2) { 30 if (pipe_number >= DspPipe::DspPipe_MAX) {
24 LOG_WARNING(Audio_DSP, "pipe_number = %u (!= 2), unimplemented", pipe_number); 31 LOG_ERROR(Audio_DSP, "pipe_number = %u invalid", pipe_number);
25 return {}; // We currently don't handle anything other than the audio pipe. 32 return {};
33 }
34
35 std::vector<u8>& data = pipe_data[static_cast<size_t>(pipe_number)];
36
37 if (length > data.size()) {
38 LOG_WARNING(Audio_DSP, "pipe_number = %u is out of data, application requested read of %u but %zu remain",
39 pipe_number, length, data.size());
40 length = data.size();
26 } 41 }
27 42
28 // Canned DSP responses that games expect. These were taken from HW by 3dmoo team. 43 if (length == 0)
29 // TODO: Our implementation will actually use a slightly different response than this one.
30 // TODO: Use offsetof on DSP structures instead for a proper response.
31 static const std::array<u8, 32> canned_response {{
32 0x0F, 0x00, 0xFF, 0xBF, 0x8E, 0x9E, 0x80, 0x86, 0x8E, 0xA7, 0x30, 0x94, 0x00, 0x84, 0x40, 0x85,
33 0x8E, 0x94, 0x10, 0x87, 0x10, 0x84, 0x0E, 0xA9, 0x0E, 0xAA, 0xCE, 0xAA, 0x4E, 0xAC, 0x58, 0xAC
34 }};
35
36 // TODO: Move this into dsp::DSP service since it happens on the service side.
37 // Hardware observation: No data is returned if requested length reads beyond the end of the data in-pipe.
38 if (pipe2position + length > canned_response.size()) {
39 return {}; 44 return {};
45
46 std::vector<u8> ret(data.begin(), data.begin() + length);
47 data.erase(data.begin(), data.begin() + length);
48 return ret;
49}
50
51size_t GetPipeReadableSize(DspPipe pipe_number) {
52 if (pipe_number >= DspPipe::DspPipe_MAX) {
53 LOG_ERROR(Audio_DSP, "pipe_number = %u invalid", pipe_number);
54 return 0;
40 } 55 }
41 56
42 std::vector<u8> ret; 57 return pipe_data[static_cast<size_t>(pipe_number)].size();
43 for (size_t i = 0; i < length; i++, pipe2position++) { 58}
44 ret.emplace_back(canned_response[pipe2position]); 59
60static void WriteU16(DspPipe pipe_number, u16 value) {
61 std::vector<u8>& data = pipe_data[static_cast<size_t>(pipe_number)];
62 // Little endian
63 data.emplace_back(value & 0xFF);
64 data.emplace_back(value >> 8);
65}
66
67static void AudioPipeWriteStructAddresses() {
68 // These struct addresses are DSP dram addresses.
69 // See also: DSP_DSP::ConvertProcessAddressFromDspDram
70 static const std::array<u16, 15> struct_addresses = {
71 0x8000 + offsetof(SharedMemory, frame_counter) / 2,
72 0x8000 + offsetof(SharedMemory, source_configurations) / 2,
73 0x8000 + offsetof(SharedMemory, source_statuses) / 2,
74 0x8000 + offsetof(SharedMemory, adpcm_coefficients) / 2,
75 0x8000 + offsetof(SharedMemory, dsp_configuration) / 2,
76 0x8000 + offsetof(SharedMemory, dsp_status) / 2,
77 0x8000 + offsetof(SharedMemory, final_samples) / 2,
78 0x8000 + offsetof(SharedMemory, intermediate_mix_samples) / 2,
79 0x8000 + offsetof(SharedMemory, compressor) / 2,
80 0x8000 + offsetof(SharedMemory, dsp_debug) / 2,
81 0x8000 + offsetof(SharedMemory, unknown10) / 2,
82 0x8000 + offsetof(SharedMemory, unknown11) / 2,
83 0x8000 + offsetof(SharedMemory, unknown12) / 2,
84 0x8000 + offsetof(SharedMemory, unknown13) / 2,
85 0x8000 + offsetof(SharedMemory, unknown14) / 2
86 };
87
88 // Begin with a u16 denoting the number of structs.
89 WriteU16(DspPipe::Audio, struct_addresses.size());
90 // Then write the struct addresses.
91 for (u16 addr : struct_addresses) {
92 WriteU16(DspPipe::Audio, addr);
45 } 93 }
94}
46 95
47 return ret; 96void PipeWrite(DspPipe pipe_number, const std::vector<u8>& buffer) {
97 switch (pipe_number) {
98 case DspPipe::Audio: {
99 if (buffer.size() != 4) {
100 LOG_ERROR(Audio_DSP, "DspPipe::Audio: Unexpected buffer length %zu was written", buffer.size());
101 return;
102 }
103
104 enum class StateChange {
105 Initalize = 0,
106 Shutdown = 1,
107 Wakeup = 2,
108 Sleep = 3
109 };
110
111 // The difference between Initialize and Wakeup is that Input state is maintained
112 // when sleeping but isn't when turning it off and on again. (TODO: Implement this.)
113 // Waking up from sleep garbles some of the structs in the memory region. (TODO:
114 // Implement this.) Applications store away the state of these structs before
115 // sleeping and reset it back after wakeup on behalf of the DSP.
116
117 switch (static_cast<StateChange>(buffer[0])) {
118 case StateChange::Initalize:
119 LOG_INFO(Audio_DSP, "Application has requested initialization of DSP hardware");
120 ResetPipes();
121 AudioPipeWriteStructAddresses();
122 dsp_state = DspState::On;
123 break;
124 case StateChange::Shutdown:
125 LOG_INFO(Audio_DSP, "Application has requested shutdown of DSP hardware");
126 dsp_state = DspState::Off;
127 break;
128 case StateChange::Wakeup:
129 LOG_INFO(Audio_DSP, "Application has requested wakeup of DSP hardware");
130 ResetPipes();
131 AudioPipeWriteStructAddresses();
132 dsp_state = DspState::On;
133 break;
134 case StateChange::Sleep:
135 LOG_INFO(Audio_DSP, "Application has requested sleep of DSP hardware");
136 UNIMPLEMENTED();
137 dsp_state = DspState::Sleeping;
138 break;
139 default:
140 LOG_ERROR(Audio_DSP, "Application has requested unknown state transition of DSP hardware %hhu", buffer[0]);
141 dsp_state = DspState::Off;
142 break;
143 }
144
145 return;
146 }
147 default:
148 LOG_CRITICAL(Audio_DSP, "pipe_number = %u unimplemented", pipe_number);
149 UNIMPLEMENTED();
150 return;
151 }
48} 152}
49 153
50void PipeWrite(u32 pipe_number, const std::vector<u8>& buffer) { 154DspState GetDspState() {
51 // TODO: proper pipe behaviour 155 return dsp_state;
52} 156}
53 157
54} // namespace HLE 158} // namespace HLE
diff --git a/src/audio_core/hle/pipe.h b/src/audio_core/hle/pipe.h
index ff6536950..382d35e87 100644
--- a/src/audio_core/hle/pipe.h
+++ b/src/audio_core/hle/pipe.h
@@ -4,6 +4,7 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <cstddef>
7#include <vector> 8#include <vector>
8 9
9#include "common/common_types.h" 10#include "common/common_types.h"
@@ -14,25 +15,43 @@ namespace HLE {
14/// Reset the pipes by setting pipe positions back to the beginning. 15/// Reset the pipes by setting pipe positions back to the beginning.
15void ResetPipes(); 16void ResetPipes();
16 17
18enum class DspPipe {
19 Debug = 0,
20 Dma = 1,
21 Audio = 2,
22 Binary = 3,
23 DspPipe_MAX
24};
25
17/** 26/**
18 * Read a DSP pipe. 27 * Read a DSP pipe.
19 * Pipe IDs:
20 * pipe_number = 0: Debug
21 * pipe_number = 1: P-DMA
22 * pipe_number = 2: Audio
23 * pipe_number = 3: Binary
24 * @param pipe_number The Pipe ID 28 * @param pipe_number The Pipe ID
25 * @param length How much data to request. 29 * @param length How much data to request.
26 * @return The data read from the pipe. The size of this vector can be less than the length requested. 30 * @return The data read from the pipe. The size of this vector can be less than the length requested.
27 */ 31 */
28std::vector<u8> PipeRead(u32 pipe_number, u32 length); 32std::vector<u8> PipeRead(DspPipe pipe_number, u32 length);
33
34/**
35 * How much data is left in pipe
36 * @param pipe_number The Pipe ID
37 * @return The amount of data remaning in the pipe. This is the maximum length PipeRead will return.
38 */
39size_t GetPipeReadableSize(DspPipe pipe_number);
29 40
30/** 41/**
31 * Write to a DSP pipe. 42 * Write to a DSP pipe.
32 * @param pipe_number The Pipe ID 43 * @param pipe_number The Pipe ID
33 * @param buffer The data to write to the pipe. 44 * @param buffer The data to write to the pipe.
34 */ 45 */
35void PipeWrite(u32 pipe_number, const std::vector<u8>& buffer); 46void PipeWrite(DspPipe pipe_number, const std::vector<u8>& buffer);
47
48enum class DspState {
49 Off,
50 On,
51 Sleeping
52};
53/// Get the state of the DSP
54DspState GetDspState();
36 55
37} // namespace HLE 56} // namespace HLE
38} // namespace DSP 57} // namespace DSP
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) {
58 58
59 u32 addr = cmd_buff[1]; 59 u32 addr = cmd_buff[1];
60 60
61 cmd_buff[1] = 0; // No error 61 cmd_buff[1] = RESULT_SUCCESS.raw; // No error
62 cmd_buff[2] = (addr << 1) + (Memory::DSP_RAM_VADDR + 0x40000); 62 cmd_buff[2] = (addr << 1) + (Memory::DSP_RAM_VADDR + 0x40000);
63 63
64 LOG_TRACE(Service_DSP, "addr=0x%08X", addr); 64 LOG_DEBUG(Service_DSP, "addr=0x%08X", addr);
65} 65}
66 66
67/** 67/**
@@ -142,8 +142,7 @@ static void FlushDataCache(Service::Interface* self) {
142 142
143 cmd_buff[1] = RESULT_SUCCESS.raw; // No error 143 cmd_buff[1] = RESULT_SUCCESS.raw; // No error
144 144
145 LOG_DEBUG(Service_DSP, "(STUBBED) called address=0x%08X, size=0x%X, process=0x%08X", 145 LOG_TRACE(Service_DSP, "called address=0x%08X, size=0x%X, process=0x%08X", address, size, process);
146 address, size, process);
147} 146}
148 147
149/** 148/**
@@ -167,14 +166,14 @@ static void RegisterInterruptEvents(Service::Interface* self) {
167 if (evt) { 166 if (evt) {
168 interrupt_events[std::make_pair(interrupt, channel)] = evt; 167 interrupt_events[std::make_pair(interrupt, channel)] = evt;
169 cmd_buff[1] = RESULT_SUCCESS.raw; 168 cmd_buff[1] = RESULT_SUCCESS.raw;
170 LOG_WARNING(Service_DSP, "Registered interrupt=%u, channel=%u, event_handle=0x%08X", interrupt, channel, event_handle); 169 LOG_INFO(Service_DSP, "Registered interrupt=%u, channel=%u, event_handle=0x%08X", interrupt, channel, event_handle);
171 } else { 170 } else {
172 cmd_buff[1] = -1; 171 LOG_CRITICAL(Service_DSP, "Invalid event handle! interrupt=%u, channel=%u, event_handle=0x%08X", interrupt, channel, event_handle);
173 LOG_ERROR(Service_DSP, "Invalid event handle! interrupt=%u, channel=%u, event_handle=0x%08X", interrupt, channel, event_handle); 172 ASSERT(false); // This should really be handled at a IPC translation layer.
174 } 173 }
175 } else { 174 } else {
176 interrupt_events.erase(std::make_pair(interrupt, channel)); 175 interrupt_events.erase(std::make_pair(interrupt, channel));
177 LOG_WARNING(Service_DSP, "Unregistered interrupt=%u, channel=%u, event_handle=0x%08X", interrupt, channel, event_handle); 176 LOG_INFO(Service_DSP, "Unregistered interrupt=%u, channel=%u, event_handle=0x%08X", interrupt, channel, event_handle);
178 } 177 }
179} 178}
180 179
@@ -188,7 +187,7 @@ static void RegisterInterruptEvents(Service::Interface* self) {
188static void SetSemaphore(Service::Interface* self) { 187static void SetSemaphore(Service::Interface* self) {
189 u32* cmd_buff = Kernel::GetCommandBuffer(); 188 u32* cmd_buff = Kernel::GetCommandBuffer();
190 189
191 cmd_buff[1] = 0; // No error 190 cmd_buff[1] = RESULT_SUCCESS.raw; // No error
192 191
193 LOG_WARNING(Service_DSP, "(STUBBED) called"); 192 LOG_WARNING(Service_DSP, "(STUBBED) called");
194} 193}
@@ -207,21 +206,12 @@ static void SetSemaphore(Service::Interface* self) {
207static void WriteProcessPipe(Service::Interface* self) { 206static void WriteProcessPipe(Service::Interface* self) {
208 u32* cmd_buff = Kernel::GetCommandBuffer(); 207 u32* cmd_buff = Kernel::GetCommandBuffer();
209 208
210 u32 channel = cmd_buff[1]; 209 DSP::HLE::DspPipe pipe = static_cast<DSP::HLE::DspPipe>(cmd_buff[1]);
211 u32 size = cmd_buff[2]; 210 u32 size = cmd_buff[2];
212 u32 buffer = cmd_buff[4]; 211 u32 buffer = cmd_buff[4];
213 212
214 if (IPC::StaticBufferDesc(size, 1) != cmd_buff[3]) { 213 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);
215 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); 214 ASSERT_MSG(Memory::GetPointer(buffer) != nullptr, "Invalid Buffer: pipe=%u, size=0x%X, buffer=0x%08X", pipe, size, buffer);
216 cmd_buff[1] = -1; // TODO
217 return;
218 }
219
220 if (!Memory::GetPointer(buffer)) {
221 LOG_ERROR(Service_DSP, "Invalid Buffer: channel=%u, size=0x%X, buffer=0x%08X", channel, size, buffer);
222 cmd_buff[1] = -1; // TODO
223 return;
224 }
225 215
226 std::vector<u8> message(size); 216 std::vector<u8> message(size);
227 217
@@ -229,11 +219,11 @@ static void WriteProcessPipe(Service::Interface* self) {
229 message[i] = Memory::Read8(buffer + i); 219 message[i] = Memory::Read8(buffer + i);
230 } 220 }
231 221
232 DSP::HLE::PipeWrite(channel, message); 222 DSP::HLE::PipeWrite(pipe, message);
233 223
234 cmd_buff[1] = RESULT_SUCCESS.raw; // No error 224 cmd_buff[1] = RESULT_SUCCESS.raw; // No error
235 225
236 LOG_TRACE(Service_DSP, "channel=%u, size=0x%X, buffer=0x%08X", channel, size, buffer); 226 LOG_DEBUG(Service_DSP, "pipe=%u, size=0x%X, buffer=0x%08X", pipe, size, buffer);
237} 227}
238 228
239/** 229/**
@@ -245,7 +235,7 @@ static void WriteProcessPipe(Service::Interface* self) {
245 * 1 : Pipe Number 235 * 1 : Pipe Number
246 * 2 : Unknown 236 * 2 : Unknown
247 * 3 : Size in bytes of read (observed only lower half word used) 237 * 3 : Size in bytes of read (observed only lower half word used)
248 * 0x41 : Virtual address to read from DSP pipe to in memory 238 * 0x41 : Virtual address of memory buffer to write pipe contents to
249 * Outputs: 239 * Outputs:
250 * 1 : Result of function, 0 on success, otherwise error code 240 * 1 : Result of function, 0 on success, otherwise error code
251 * 2 : Number of bytes read from pipe 241 * 2 : Number of bytes read from pipe
@@ -253,25 +243,82 @@ static void WriteProcessPipe(Service::Interface* self) {
253static void ReadPipeIfPossible(Service::Interface* self) { 243static void ReadPipeIfPossible(Service::Interface* self) {
254 u32* cmd_buff = Kernel::GetCommandBuffer(); 244 u32* cmd_buff = Kernel::GetCommandBuffer();
255 245
256 u32 pipe = cmd_buff[1]; 246 DSP::HLE::DspPipe pipe = static_cast<DSP::HLE::DspPipe>(cmd_buff[1]);
257 u32 unk2 = cmd_buff[2]; 247 u32 unknown = cmd_buff[2];
258 u32 size = cmd_buff[3] & 0xFFFF;// Lower 16 bits are size 248 u32 size = cmd_buff[3] & 0xFFFF; // Lower 16 bits are size
259 VAddr addr = cmd_buff[0x41]; 249 VAddr addr = cmd_buff[0x41];
260 250
261 if (!Memory::GetPointer(addr)) { 251 ASSERT_MSG(Memory::GetPointer(addr) != nullptr, "Invalid addr: pipe=0x%08X, unknown=0x%08X, size=0x%X, buffer=0x%08X", pipe, unknown, size, addr);
262 LOG_ERROR(Service_DSP, "Invalid addr: pipe=0x%08X, unk2=0x%08X, size=0x%X, buffer=0x%08X", pipe, unk2, size, addr); 252
263 cmd_buff[1] = -1; // TODO 253 cmd_buff[1] = RESULT_SUCCESS.raw; // No error
264 return; 254 if (DSP::HLE::GetPipeReadableSize(pipe) >= size) {
255 std::vector<u8> response = DSP::HLE::PipeRead(pipe, size);
256
257 Memory::WriteBlock(addr, response.data(), response.size());
258
259 cmd_buff[2] = static_cast<u32>(response.size());
260 } else {
261 cmd_buff[2] = 0; // Return no data
265 } 262 }
266 263
267 std::vector<u8> response = DSP::HLE::PipeRead(pipe, size); 264 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]);
265}
268 266
269 Memory::WriteBlock(addr, response.data(), response.size()); 267/**
268 * DSP_DSP::ReadPipe service function
269 * Inputs:
270 * 1 : Pipe Number
271 * 2 : Unknown
272 * 3 : Size in bytes of read (observed only lower half word used)
273 * 0x41 : Virtual address of memory buffer to write pipe contents to
274 * Outputs:
275 * 1 : Result of function, 0 on success, otherwise error code
276 * 2 : Number of bytes read from pipe
277 */
278static void ReadPipe(Service::Interface* self) {
279 u32* cmd_buff = Kernel::GetCommandBuffer();
280
281 DSP::HLE::DspPipe pipe = static_cast<DSP::HLE::DspPipe>(cmd_buff[1]);
282 u32 unknown = cmd_buff[2];
283 u32 size = cmd_buff[3] & 0xFFFF; // Lower 16 bits are size
284 VAddr addr = cmd_buff[0x41];
270 285
271 cmd_buff[1] = 0; // No error 286 ASSERT_MSG(Memory::GetPointer(addr) != nullptr, "Invalid addr: pipe=0x%08X, unknown=0x%08X, size=0x%X, buffer=0x%08X", pipe, unknown, size, addr);
272 cmd_buff[2] = (u32)response.size();
273 287
274 LOG_TRACE(Service_DSP, "pipe=0x%08X, unk2=0x%08X, size=0x%X, buffer=0x%08X", pipe, unk2, size, addr); 288 if (DSP::HLE::GetPipeReadableSize(pipe) >= size) {
289 std::vector<u8> response = DSP::HLE::PipeRead(pipe, size);
290
291 Memory::WriteBlock(addr, response.data(), response.size());
292
293 cmd_buff[1] = RESULT_SUCCESS.raw; // No error
294 cmd_buff[2] = static_cast<u32>(response.size());
295 } else {
296 // No more data is in pipe. Hardware hangs in this case; this should never happen.
297 UNREACHABLE();
298 }
299
300 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]);
301}
302
303/**
304 * DSP_DSP::GetPipeReadableSize service function
305 * Inputs:
306 * 1 : Pipe Number
307 * 2 : Unknown
308 * Outputs:
309 * 1 : Result of function, 0 on success, otherwise error code
310 * 2 : Number of bytes readable from pipe
311 */
312static void GetPipeReadableSize(Service::Interface* self) {
313 u32* cmd_buff = Kernel::GetCommandBuffer();
314
315 DSP::HLE::DspPipe pipe = static_cast<DSP::HLE::DspPipe>(cmd_buff[1]);
316 u32 unknown = cmd_buff[2];
317
318 cmd_buff[1] = RESULT_SUCCESS.raw; // No error
319 cmd_buff[2] = DSP::HLE::GetPipeReadableSize(pipe);
320
321 LOG_DEBUG(Service_DSP, "pipe=0x%08X, unknown=0x%08X, return cmd_buff[2]=0x%08X", pipe, unknown, cmd_buff[2]);
275} 322}
276 323
277/** 324/**
@@ -306,12 +353,73 @@ static void GetHeadphoneStatus(Service::Interface* self) {
306 cmd_buff[1] = RESULT_SUCCESS.raw; // No error 353 cmd_buff[1] = RESULT_SUCCESS.raw; // No error
307 cmd_buff[2] = 0; // Not using headphones? 354 cmd_buff[2] = 0; // Not using headphones?
308 355
309 LOG_DEBUG(Service_DSP, "(STUBBED) called"); 356 LOG_WARNING(Service_DSP, "(STUBBED) called");
357}
358
359/**
360 * DSP_DSP::RecvData service function
361 * This function reads a value out of a DSP register.
362 * Inputs:
363 * 1 : Register Number
364 * Outputs:
365 * 1 : Result of function, 0 on success, otherwise error code
366 * 2 : Value in the register
367 * Notes:
368 * This function has only been observed being called with a register number of 0.
369 */
370static void RecvData(Service::Interface* self) {
371 u32* cmd_buff = Kernel::GetCommandBuffer();
372
373 u32 register_number = cmd_buff[1];
374
375 ASSERT_MSG(register_number == 0, "Unknown register_number %u", register_number);
376
377 // Application reads this after requesting DSP shutdown, to verify the DSP has indeed shutdown or slept.
378
379 cmd_buff[1] = RESULT_SUCCESS.raw;
380 switch (DSP::HLE::GetDspState()) {
381 case DSP::HLE::DspState::On:
382 cmd_buff[2] = 0;
383 break;
384 case DSP::HLE::DspState::Off:
385 case DSP::HLE::DspState::Sleeping:
386 cmd_buff[2] = 1;
387 break;
388 default:
389 UNREACHABLE();
390 break;
391 }
392
393 LOG_DEBUG(Service_DSP, "register_number=%u", register_number);
394}
395
396/**
397 * DSP_DSP::RecvDataIsReady service function
398 * This function checks whether a DSP register is ready to be read.
399 * Inputs:
400 * 1 : Register Number
401 * Outputs:
402 * 1 : Result of function, 0 on success, otherwise error code
403 * 2 : non-zero == ready
404 * Note:
405 * This function has only been observed being called with a register number of 0.
406 */
407static void RecvDataIsReady(Service::Interface* self) {
408 u32* cmd_buff = Kernel::GetCommandBuffer();
409
410 u32 register_number = cmd_buff[1];
411
412 ASSERT_MSG(register_number == 0, "Unknown register_number %u", register_number);
413
414 cmd_buff[1] = RESULT_SUCCESS.raw;
415 cmd_buff[2] = 1; // Ready to read
416
417 LOG_DEBUG(Service_DSP, "register_number=%u", register_number);
310} 418}
311 419
312const Interface::FunctionInfo FunctionTable[] = { 420const Interface::FunctionInfo FunctionTable[] = {
313 {0x00010040, nullptr, "RecvData"}, 421 {0x00010040, RecvData, "RecvData"},
314 {0x00020040, nullptr, "RecvDataIsReady"}, 422 {0x00020040, RecvDataIsReady, "RecvDataIsReady"},
315 {0x00030080, nullptr, "SendData"}, 423 {0x00030080, nullptr, "SendData"},
316 {0x00040040, nullptr, "SendDataIsEmpty"}, 424 {0x00040040, nullptr, "SendDataIsEmpty"},
317 {0x000500C2, nullptr, "SendFifoEx"}, 425 {0x000500C2, nullptr, "SendFifoEx"},
@@ -323,8 +431,8 @@ const Interface::FunctionInfo FunctionTable[] = {
323 {0x000B0000, nullptr, "CheckSemaphoreRequest"}, 431 {0x000B0000, nullptr, "CheckSemaphoreRequest"},
324 {0x000C0040, ConvertProcessAddressFromDspDram, "ConvertProcessAddressFromDspDram"}, 432 {0x000C0040, ConvertProcessAddressFromDspDram, "ConvertProcessAddressFromDspDram"},
325 {0x000D0082, WriteProcessPipe, "WriteProcessPipe"}, 433 {0x000D0082, WriteProcessPipe, "WriteProcessPipe"},
326 {0x000E00C0, nullptr, "ReadPipe"}, 434 {0x000E00C0, ReadPipe, "ReadPipe"},
327 {0x000F0080, nullptr, "GetPipeReadableSize"}, 435 {0x000F0080, GetPipeReadableSize, "GetPipeReadableSize"},
328 {0x001000C0, ReadPipeIfPossible, "ReadPipeIfPossible"}, 436 {0x001000C0, ReadPipeIfPossible, "ReadPipeIfPossible"},
329 {0x001100C2, LoadComponent, "LoadComponent"}, 437 {0x001100C2, LoadComponent, "LoadComponent"},
330 {0x00120000, nullptr, "UnloadComponent"}, 438 {0x00120000, nullptr, "UnloadComponent"},