summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar MerryMage2016-04-24 10:21:10 +0100
committerGravatar MerryMage2016-04-27 06:35:06 +0100
commitff6db69c6052f674265c453932a3dc7637c46412 (patch)
tree74f174997c4ee9376a77bbe35ef59fbd3be77237 /src
parentDSP/Pipe: There are 8 pipes (diff)
downloadyuzu-ff6db69c6052f674265c453932a3dc7637c46412.tar.gz
yuzu-ff6db69c6052f674265c453932a3dc7637c46412.tar.xz
yuzu-ff6db69c6052f674265c453932a3dc7637c46412.zip
DSP_DSP: Updated interrupt implementation
Diffstat (limited to 'src')
-rw-r--r--src/audio_core/audio_core.cpp7
-rw-r--r--src/audio_core/hle/pipe.cpp4
-rw-r--r--src/core/hle/service/dsp_dsp.cpp129
-rw-r--r--src/core/hle/service/dsp_dsp.h19
4 files changed, 113 insertions, 46 deletions
diff --git a/src/audio_core/audio_core.cpp b/src/audio_core/audio_core.cpp
index 894f46990..0685eaf85 100644
--- a/src/audio_core/audio_core.cpp
+++ b/src/audio_core/audio_core.cpp
@@ -4,6 +4,7 @@
4 4
5#include "audio_core/audio_core.h" 5#include "audio_core/audio_core.h"
6#include "audio_core/hle/dsp.h" 6#include "audio_core/hle/dsp.h"
7#include "audio_core/hle/pipe.h"
7 8
8#include "core/core_timing.h" 9#include "core/core_timing.h"
9#include "core/hle/kernel/vm_manager.h" 10#include "core/hle/kernel/vm_manager.h"
@@ -17,10 +18,8 @@ static constexpr u64 audio_frame_ticks = 1310252ull; ///< Units: ARM11 cycles
17 18
18static void AudioTickCallback(u64 /*userdata*/, int cycles_late) { 19static void AudioTickCallback(u64 /*userdata*/, int cycles_late) {
19 if (DSP::HLE::Tick()) { 20 if (DSP::HLE::Tick()) {
20 // HACK: We're not signaling the interrups when they should be, but just firing them all off together. 21 // TODO(merry): Signal all the other interrupts as appropriate.
21 // It should be only (interrupt_id = 2, channel_id = 2) that's signalled here. 22 DSP_DSP::SignalPipeInterrupt(DSP::HLE::DspPipe::Audio);
22 // TODO(merry): Understand when the other interrupts are fired.
23 DSP_DSP::SignalAllInterrupts();
24 } 23 }
25 24
26 // Reschedule recurrent event 25 // Reschedule recurrent event
diff --git a/src/audio_core/hle/pipe.cpp b/src/audio_core/hle/pipe.cpp
index 7ec97dfda..03280780f 100644
--- a/src/audio_core/hle/pipe.cpp
+++ b/src/audio_core/hle/pipe.cpp
@@ -12,6 +12,8 @@
12#include "common/common_types.h" 12#include "common/common_types.h"
13#include "common/logging/log.h" 13#include "common/logging/log.h"
14 14
15#include "core/hle/service/dsp_dsp.h"
16
15namespace DSP { 17namespace DSP {
16namespace HLE { 18namespace HLE {
17 19
@@ -97,6 +99,8 @@ static void AudioPipeWriteStructAddresses() {
97 for (u16 addr : struct_addresses) { 99 for (u16 addr : struct_addresses) {
98 WriteU16(DspPipe::Audio, addr); 100 WriteU16(DspPipe::Audio, addr);
99 } 101 }
102 // Signal that we have data on this pipe.
103 DSP_DSP::SignalPipeInterrupt(DspPipe::Audio);
100} 104}
101 105
102void PipeWrite(DspPipe pipe_number, const std::vector<u8>& buffer) { 106void PipeWrite(DspPipe pipe_number, const std::vector<u8>& buffer) {
diff --git a/src/core/hle/service/dsp_dsp.cpp b/src/core/hle/service/dsp_dsp.cpp
index 751cb3d61..e9ef50f86 100644
--- a/src/core/hle/service/dsp_dsp.cpp
+++ b/src/core/hle/service/dsp_dsp.cpp
@@ -2,6 +2,7 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <algorithm>
5#include <cinttypes> 6#include <cinttypes>
6 7
7#include "audio_core/hle/pipe.h" 8#include "audio_core/hle/pipe.h"
@@ -12,6 +13,8 @@
12#include "core/hle/kernel/event.h" 13#include "core/hle/kernel/event.h"
13#include "core/hle/service/dsp_dsp.h" 14#include "core/hle/service/dsp_dsp.h"
14 15
16using DspPipe = DSP::HLE::DspPipe;
17
15//////////////////////////////////////////////////////////////////////////////////////////////////// 18////////////////////////////////////////////////////////////////////////////////////////////////////
16// Namespace DSP_DSP 19// Namespace DSP_DSP
17 20
@@ -19,29 +22,71 @@ namespace DSP_DSP {
19 22
20static Kernel::SharedPtr<Kernel::Event> semaphore_event; 23static Kernel::SharedPtr<Kernel::Event> semaphore_event;
21 24
22struct PairHash { 25/// There are three types of interrupts
23 template <typename T, typename U> 26enum class InterruptType {
24 std::size_t operator()(const std::pair<T, U> &x) const { 27 Zero, One, Pipe
25 // TODO(yuriks): Replace with better hash combining function. 28};
26 return std::hash<T>()(x.first) ^ std::hash<U>()(x.second); 29constexpr size_t NUM_INTERRUPT_TYPE = 3;
30
31class InterruptEvents final {
32public:
33 void Signal(InterruptType type, DspPipe pipe) {
34 Kernel::SharedPtr<Kernel::Event>& event = Get(type, pipe);
35 if (event) {
36 event->Signal();
37 }
38 }
39
40 Kernel::SharedPtr<Kernel::Event>& Get(InterruptType type, DspPipe dsp_pipe) {
41 switch (type) {
42 case InterruptType::Zero:
43 return zero;
44 case InterruptType::One:
45 return one;
46 case InterruptType::Pipe: {
47 const size_t pipe_index = static_cast<size_t>(dsp_pipe);
48 ASSERT(pipe_index < DSP::HLE::NUM_DSP_PIPE);
49 return pipe[pipe_index];
50 }
51 }
52
53 UNREACHABLE_MSG("Invalid interrupt type = %zu", static_cast<size_t>(type));
54 }
55
56 bool HasTooManyEventsRegistered() const {
57 // Actual service implementation only has 6 'slots' for interrupts.
58 constexpr size_t max_number_of_interrupt_events = 6;
59
60 size_t number = std::count_if(pipe.begin(), pipe.end(), [](const auto& evt) {
61 return evt != nullptr;
62 });
63
64 if (zero != nullptr)
65 number++;
66 if (one != nullptr)
67 number++;
68
69 return number >= max_number_of_interrupt_events;
27 } 70 }
71
72private:
73 /// Currently unknown purpose
74 Kernel::SharedPtr<Kernel::Event> zero = nullptr;
75 /// Currently unknown purpose
76 Kernel::SharedPtr<Kernel::Event> one = nullptr;
77 /// Each DSP pipe has an associated interrupt
78 std::array<Kernel::SharedPtr<Kernel::Event>, DSP::HLE::NUM_DSP_PIPE> pipe = {{}};
28}; 79};
29 80
30/// Map of (audio interrupt number, channel number) to Kernel::Events. See: RegisterInterruptEvents 81static InterruptEvents interrupt_events;
31static std::unordered_map<std::pair<u32, u32>, Kernel::SharedPtr<Kernel::Event>, PairHash> interrupt_events;
32 82
33// DSP Interrupts: 83// DSP Interrupts:
34// Interrupt #2 occurs every frame tick. Userland programs normally have a thread that's waiting 84// The audio-pipe interrupt occurs every frame tick. Userland programs normally have a thread
35// for an interrupt event. Immediately after this interrupt event, userland normally updates the 85// that's waiting for an interrupt event. Immediately after this interrupt event, userland
36// state in the next region and increments the relevant frame counter by two. 86// normally updates the state in the next region and increments the relevant frame counter by
37void SignalAllInterrupts() { 87// two.
38 // HACK: The other interrupts have currently unknown purpose, we trigger them each tick in any case. 88void SignalPipeInterrupt(DspPipe pipe) {
39 for (auto& interrupt_event : interrupt_events) 89 interrupt_events.Signal(InterruptType::Pipe, pipe);
40 interrupt_event.second->Signal();
41}
42
43void SignalInterrupt(u32 interrupt, u32 channel) {
44 interrupt_events[std::make_pair(interrupt, channel)]->Signal();
45} 90}
46 91
47/** 92/**
@@ -147,8 +192,8 @@ static void FlushDataCache(Service::Interface* self) {
147/** 192/**
148 * DSP_DSP::RegisterInterruptEvents service function 193 * DSP_DSP::RegisterInterruptEvents service function
149 * Inputs: 194 * Inputs:
150 * 1 : Interrupt Number 195 * 1 : Interrupt Type
151 * 2 : Channel Number 196 * 2 : Pipe Number
152 * 4 : Interrupt event handle 197 * 4 : Interrupt event handle
153 * Outputs: 198 * Outputs:
154 * 1 : Result of function, 0 on success, otherwise error code 199 * 1 : Result of function, 0 on success, otherwise error code
@@ -156,23 +201,40 @@ static void FlushDataCache(Service::Interface* self) {
156static void RegisterInterruptEvents(Service::Interface* self) { 201static void RegisterInterruptEvents(Service::Interface* self) {
157 u32* cmd_buff = Kernel::GetCommandBuffer(); 202 u32* cmd_buff = Kernel::GetCommandBuffer();
158 203
159 u32 interrupt = cmd_buff[1]; 204 u32 type_index = cmd_buff[1];
160 u32 channel = cmd_buff[2]; 205 u32 pipe_index = cmd_buff[2];
161 u32 event_handle = cmd_buff[4]; 206 u32 event_handle = cmd_buff[4];
162 207
208 ASSERT_MSG(type_index < NUM_INTERRUPT_TYPE && pipe_index < DSP::HLE::NUM_DSP_PIPE,
209 "Invalid type or pipe: type = %u, pipe = %u", type_index, pipe_index);
210
211 InterruptType type = static_cast<InterruptType>(cmd_buff[1]);
212 DspPipe pipe = static_cast<DspPipe>(cmd_buff[2]);
213
214 cmd_buff[0] = IPC::MakeHeader(0x15, 1, 0);
215
163 if (event_handle) { 216 if (event_handle) {
164 auto evt = Kernel::g_handle_table.Get<Kernel::Event>(cmd_buff[4]); 217 auto evt = Kernel::g_handle_table.Get<Kernel::Event>(cmd_buff[4]);
165 if (evt) { 218
166 interrupt_events[std::make_pair(interrupt, channel)] = evt; 219 if (!evt) {
167 cmd_buff[1] = RESULT_SUCCESS.raw; 220 LOG_INFO(Service_DSP, "Invalid event handle! type=%u, pipe=%u, event_handle=0x%08X", type_index, pipe_index, event_handle);
168 LOG_INFO(Service_DSP, "Registered interrupt=%u, channel=%u, event_handle=0x%08X", interrupt, channel, event_handle); 221 ASSERT(false); // TODO: This should really be handled at an IPC translation layer.
169 } else { 222 }
170 LOG_CRITICAL(Service_DSP, "Invalid event handle! interrupt=%u, channel=%u, event_handle=0x%08X", interrupt, channel, event_handle); 223
171 ASSERT(false); // This should really be handled at a IPC translation layer. 224 if (interrupt_events.HasTooManyEventsRegistered()) {
225 LOG_INFO(Service_DSP, "Ran out of space to register interrupts (Attempted to register type=%u, pipe=%u, event_handle=0x%08X)",
226 type_index, pipe_index, event_handle);
227 cmd_buff[1] = ResultCode(ErrorDescription::InvalidResultValue, ErrorModule::DSP, ErrorSummary::OutOfResource, ErrorLevel::Status).raw;
228 return;
172 } 229 }
230
231 interrupt_events.Get(type, pipe) = evt;
232 LOG_INFO(Service_DSP, "Registered type=%u, pipe=%u, event_handle=0x%08X", type_index, pipe_index, event_handle);
233 cmd_buff[1] = RESULT_SUCCESS.raw;
173 } else { 234 } else {
174 interrupt_events.erase(std::make_pair(interrupt, channel)); 235 interrupt_events.Get(type, pipe) = nullptr;
175 LOG_INFO(Service_DSP, "Unregistered interrupt=%u, channel=%u, event_handle=0x%08X", interrupt, channel, event_handle); 236 LOG_INFO(Service_DSP, "Unregistered interrupt=%u, channel=%u, event_handle=0x%08X", type_index, pipe_index, event_handle);
237 cmd_buff[1] = RESULT_SUCCESS.raw;
176 } 238 }
177} 239}
178 240
@@ -194,7 +256,7 @@ static void SetSemaphore(Service::Interface* self) {
194/** 256/**
195 * DSP_DSP::WriteProcessPipe service function 257 * DSP_DSP::WriteProcessPipe service function
196 * Inputs: 258 * Inputs:
197 * 1 : Channel 259 * 1 : Pipe Number
198 * 2 : Size 260 * 2 : Size
199 * 3 : (size << 14) | 0x402 261 * 3 : (size << 14) | 0x402
200 * 4 : Buffer 262 * 4 : Buffer
@@ -457,13 +519,14 @@ const Interface::FunctionInfo FunctionTable[] = {
457 519
458Interface::Interface() { 520Interface::Interface() {
459 semaphore_event = Kernel::Event::Create(Kernel::ResetType::OneShot, "DSP_DSP::semaphore_event"); 521 semaphore_event = Kernel::Event::Create(Kernel::ResetType::OneShot, "DSP_DSP::semaphore_event");
522 interrupt_events = {};
460 523
461 Register(FunctionTable); 524 Register(FunctionTable);
462} 525}
463 526
464Interface::~Interface() { 527Interface::~Interface() {
465 semaphore_event = nullptr; 528 semaphore_event = nullptr;
466 interrupt_events.clear(); 529 interrupt_events = {};
467} 530}
468 531
469} // namespace 532} // namespace
diff --git a/src/core/hle/service/dsp_dsp.h b/src/core/hle/service/dsp_dsp.h
index 32b89e9bb..22f6687cc 100644
--- a/src/core/hle/service/dsp_dsp.h
+++ b/src/core/hle/service/dsp_dsp.h
@@ -8,6 +8,12 @@
8 8
9#include "core/hle/service/service.h" 9#include "core/hle/service/service.h"
10 10
11namespace DSP {
12namespace HLE {
13enum class DspPipe;
14}
15}
16
11//////////////////////////////////////////////////////////////////////////////////////////////////// 17////////////////////////////////////////////////////////////////////////////////////////////////////
12// Namespace DSP_DSP 18// Namespace DSP_DSP
13 19
@@ -23,15 +29,10 @@ public:
23 } 29 }
24}; 30};
25 31
26/// Signal all audio related interrupts.
27void SignalAllInterrupts();
28
29/** 32/**
30 * Signal a specific audio related interrupt based on interrupt id and channel id. 33 * Signal a specific DSP related interrupt of type == InterruptType::Pipe, pipe == pipe.
31 * @param interrupt_id The interrupt id 34 * @param pipe The DSP pipe for which to signal an interrupt for.
32 * @param channel_id The channel id
33 * The significance of various values of interrupt_id and channel_id is not yet known.
34 */ 35 */
35void SignalInterrupt(u32 interrupt_id, u32 channel_id); 36void SignalPipeInterrupt(DSP::HLE::DspPipe pipe);
36 37
37} // namespace 38} // namespace DSP_DSP