pipe.cpp 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. // Copyright 2016 Citra Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <array>
  5. #include <vector>
  6. #include "audio_core/hle/dsp.h"
  7. #include "audio_core/hle/pipe.h"
  8. #include "common/assert.h"
  9. #include "common/common_types.h"
  10. #include "common/logging/log.h"
  11. namespace DSP {
  12. namespace HLE {
  13. static DspState dsp_state = DspState::Off;
  14. static std::array<std::vector<u8>, NUM_DSP_PIPE> pipe_data;
  15. void ResetPipes() {
  16. for (auto& data : pipe_data) {
  17. data.clear();
  18. }
  19. dsp_state = DspState::Off;
  20. }
  21. std::vector<u8> PipeRead(DspPipe pipe_number, u32 length) {
  22. const size_t pipe_index = static_cast<size_t>(pipe_number);
  23. if (pipe_index >= NUM_DSP_PIPE) {
  24. LOG_ERROR(Audio_DSP, "pipe_number = %zu invalid", pipe_index);
  25. return {};
  26. }
  27. std::vector<u8>& data = pipe_data[pipe_index];
  28. if (length > data.size()) {
  29. LOG_WARNING(Audio_DSP, "pipe_number = %zu is out of data, application requested read of %u but %zu remain",
  30. pipe_index, length, data.size());
  31. length = data.size();
  32. }
  33. if (length == 0)
  34. return {};
  35. std::vector<u8> ret(data.begin(), data.begin() + length);
  36. data.erase(data.begin(), data.begin() + length);
  37. return ret;
  38. }
  39. size_t GetPipeReadableSize(DspPipe pipe_number) {
  40. const size_t pipe_index = static_cast<size_t>(pipe_number);
  41. if (pipe_index >= NUM_DSP_PIPE) {
  42. LOG_ERROR(Audio_DSP, "pipe_number = %zu invalid", pipe_index);
  43. return 0;
  44. }
  45. return pipe_data[pipe_index].size();
  46. }
  47. static void WriteU16(DspPipe pipe_number, u16 value) {
  48. const size_t pipe_index = static_cast<size_t>(pipe_number);
  49. std::vector<u8>& data = pipe_data.at(pipe_index);
  50. // Little endian
  51. data.emplace_back(value & 0xFF);
  52. data.emplace_back(value >> 8);
  53. }
  54. static void AudioPipeWriteStructAddresses() {
  55. // These struct addresses are DSP dram addresses.
  56. // See also: DSP_DSP::ConvertProcessAddressFromDspDram
  57. static const std::array<u16, 15> struct_addresses = {
  58. 0x8000 + offsetof(SharedMemory, frame_counter) / 2,
  59. 0x8000 + offsetof(SharedMemory, source_configurations) / 2,
  60. 0x8000 + offsetof(SharedMemory, source_statuses) / 2,
  61. 0x8000 + offsetof(SharedMemory, adpcm_coefficients) / 2,
  62. 0x8000 + offsetof(SharedMemory, dsp_configuration) / 2,
  63. 0x8000 + offsetof(SharedMemory, dsp_status) / 2,
  64. 0x8000 + offsetof(SharedMemory, final_samples) / 2,
  65. 0x8000 + offsetof(SharedMemory, intermediate_mix_samples) / 2,
  66. 0x8000 + offsetof(SharedMemory, compressor) / 2,
  67. 0x8000 + offsetof(SharedMemory, dsp_debug) / 2,
  68. 0x8000 + offsetof(SharedMemory, unknown10) / 2,
  69. 0x8000 + offsetof(SharedMemory, unknown11) / 2,
  70. 0x8000 + offsetof(SharedMemory, unknown12) / 2,
  71. 0x8000 + offsetof(SharedMemory, unknown13) / 2,
  72. 0x8000 + offsetof(SharedMemory, unknown14) / 2
  73. };
  74. // Begin with a u16 denoting the number of structs.
  75. WriteU16(DspPipe::Audio, struct_addresses.size());
  76. // Then write the struct addresses.
  77. for (u16 addr : struct_addresses) {
  78. WriteU16(DspPipe::Audio, addr);
  79. }
  80. }
  81. void PipeWrite(DspPipe pipe_number, const std::vector<u8>& buffer) {
  82. switch (pipe_number) {
  83. case DspPipe::Audio: {
  84. if (buffer.size() != 4) {
  85. LOG_ERROR(Audio_DSP, "DspPipe::Audio: Unexpected buffer length %zu was written", buffer.size());
  86. return;
  87. }
  88. enum class StateChange {
  89. Initalize = 0,
  90. Shutdown = 1,
  91. Wakeup = 2,
  92. Sleep = 3
  93. };
  94. // The difference between Initialize and Wakeup is that Input state is maintained
  95. // when sleeping but isn't when turning it off and on again. (TODO: Implement this.)
  96. // Waking up from sleep garbles some of the structs in the memory region. (TODO:
  97. // Implement this.) Applications store away the state of these structs before
  98. // sleeping and reset it back after wakeup on behalf of the DSP.
  99. switch (static_cast<StateChange>(buffer[0])) {
  100. case StateChange::Initalize:
  101. LOG_INFO(Audio_DSP, "Application has requested initialization of DSP hardware");
  102. ResetPipes();
  103. AudioPipeWriteStructAddresses();
  104. dsp_state = DspState::On;
  105. break;
  106. case StateChange::Shutdown:
  107. LOG_INFO(Audio_DSP, "Application has requested shutdown of DSP hardware");
  108. dsp_state = DspState::Off;
  109. break;
  110. case StateChange::Wakeup:
  111. LOG_INFO(Audio_DSP, "Application has requested wakeup of DSP hardware");
  112. ResetPipes();
  113. AudioPipeWriteStructAddresses();
  114. dsp_state = DspState::On;
  115. break;
  116. case StateChange::Sleep:
  117. LOG_INFO(Audio_DSP, "Application has requested sleep of DSP hardware");
  118. UNIMPLEMENTED();
  119. dsp_state = DspState::Sleeping;
  120. break;
  121. default:
  122. LOG_ERROR(Audio_DSP, "Application has requested unknown state transition of DSP hardware %hhu", buffer[0]);
  123. dsp_state = DspState::Off;
  124. break;
  125. }
  126. return;
  127. }
  128. default:
  129. LOG_CRITICAL(Audio_DSP, "pipe_number = %zu unimplemented", static_cast<size_t>(pipe_number));
  130. UNIMPLEMENTED();
  131. return;
  132. }
  133. }
  134. DspState GetDspState() {
  135. return dsp_state;
  136. }
  137. } // namespace HLE
  138. } // namespace DSP