test_coprocessor.cpp 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. /* This file is part of the dynarmic project.
  2. * Copyright (c) 2022 MerryMage
  3. * SPDX-License-Identifier: 0BSD
  4. */
  5. #include <memory>
  6. #include <catch2/catch_test_macros.hpp>
  7. #include "./testenv.h"
  8. #include "dynarmic/frontend/A32/a32_location_descriptor.h"
  9. #include "dynarmic/interface/A32/a32.h"
  10. #include "dynarmic/interface/A32/coprocessor.h"
  11. using namespace Dynarmic;
  12. struct CP15State {
  13. u32 cp15_thread_uprw = 0;
  14. u32 cp15_thread_uro = 0;
  15. u32 cp15_flush_prefetch_buffer = 0; ///< dummy value
  16. u32 cp15_data_sync_barrier = 0; ///< dummy value
  17. u32 cp15_data_memory_barrier = 0; ///< dummy value
  18. };
  19. class TestCP15 final : public Dynarmic::A32::Coprocessor {
  20. public:
  21. using CoprocReg = Dynarmic::A32::CoprocReg;
  22. explicit TestCP15(CP15State&);
  23. ~TestCP15() override;
  24. std::optional<Callback> CompileInternalOperation(bool two, unsigned opc1, CoprocReg CRd, CoprocReg CRn, CoprocReg CRm, unsigned opc2) override;
  25. CallbackOrAccessOneWord CompileSendOneWord(bool two, unsigned opc1, CoprocReg CRn, CoprocReg CRm, unsigned opc2) override;
  26. CallbackOrAccessTwoWords CompileSendTwoWords(bool two, unsigned opc, CoprocReg CRm) override;
  27. CallbackOrAccessOneWord CompileGetOneWord(bool two, unsigned opc1, CoprocReg CRn, CoprocReg CRm, unsigned opc2) override;
  28. CallbackOrAccessTwoWords CompileGetTwoWords(bool two, unsigned opc, CoprocReg CRm) override;
  29. std::optional<Callback> CompileLoadWords(bool two, bool long_transfer, CoprocReg CRd, std::optional<u8> option) override;
  30. std::optional<Callback> CompileStoreWords(bool two, bool long_transfer, CoprocReg CRd, std::optional<u8> option) override;
  31. private:
  32. CP15State& state;
  33. };
  34. using Callback = Dynarmic::A32::Coprocessor::Callback;
  35. using CallbackOrAccessOneWord = Dynarmic::A32::Coprocessor::CallbackOrAccessOneWord;
  36. using CallbackOrAccessTwoWords = Dynarmic::A32::Coprocessor::CallbackOrAccessTwoWords;
  37. TestCP15::TestCP15(CP15State& state)
  38. : state(state) {}
  39. TestCP15::~TestCP15() = default;
  40. std::optional<Callback> TestCP15::CompileInternalOperation([[maybe_unused]] bool two, [[maybe_unused]] unsigned opc1, [[maybe_unused]] CoprocReg CRd, [[maybe_unused]] CoprocReg CRn, [[maybe_unused]] CoprocReg CRm, [[maybe_unused]] unsigned opc2) {
  41. return std::nullopt;
  42. }
  43. CallbackOrAccessOneWord TestCP15::CompileSendOneWord(bool two, unsigned opc1, CoprocReg CRn, CoprocReg CRm, unsigned opc2) {
  44. if (!two && CRn == CoprocReg::C7 && opc1 == 0 && CRm == CoprocReg::C5 && opc2 == 4) {
  45. return Callback{
  46. [](void* user_arg, std::uint32_t, std::uint32_t) -> std::uint64_t {
  47. CP15State& state = *reinterpret_cast<CP15State*>(user_arg);
  48. state.cp15_flush_prefetch_buffer = 1;
  49. return 0;
  50. },
  51. reinterpret_cast<void*>(&state),
  52. };
  53. }
  54. if (!two && CRn == CoprocReg::C7 && opc1 == 0 && CRm == CoprocReg::C10) {
  55. switch (opc2) {
  56. case 4:
  57. return Callback{
  58. [](void* user_arg, std::uint32_t, std::uint32_t) -> std::uint64_t {
  59. CP15State& state = *reinterpret_cast<CP15State*>(user_arg);
  60. state.cp15_data_sync_barrier = 1;
  61. return 0;
  62. },
  63. reinterpret_cast<void*>(&state),
  64. };
  65. case 5:
  66. return Callback{
  67. [](void* user_arg, std::uint32_t, std::uint32_t) -> std::uint64_t {
  68. CP15State& state = *reinterpret_cast<CP15State*>(user_arg);
  69. state.cp15_data_memory_barrier = 1;
  70. return 0;
  71. },
  72. reinterpret_cast<void*>(&state),
  73. };
  74. default:
  75. return std::monostate{};
  76. }
  77. }
  78. if (!two && CRn == CoprocReg::C13 && opc1 == 0 && CRm == CoprocReg::C0 && opc2 == 2) {
  79. return &state.cp15_thread_uprw;
  80. }
  81. return std::monostate{};
  82. }
  83. CallbackOrAccessTwoWords TestCP15::CompileSendTwoWords([[maybe_unused]] bool two, [[maybe_unused]] unsigned opc, [[maybe_unused]] CoprocReg CRm) {
  84. return std::monostate{};
  85. }
  86. CallbackOrAccessOneWord TestCP15::CompileGetOneWord(bool two, unsigned opc1, CoprocReg CRn, CoprocReg CRm, unsigned opc2) {
  87. // TODO(merry): Privileged CP15 registers
  88. if (!two && CRn == CoprocReg::C13 && opc1 == 0 && CRm == CoprocReg::C0) {
  89. switch (opc2) {
  90. case 2:
  91. return &state.cp15_thread_uprw;
  92. case 3:
  93. return &state.cp15_thread_uro;
  94. default:
  95. return std::monostate{};
  96. }
  97. }
  98. return std::monostate{};
  99. }
  100. CallbackOrAccessTwoWords TestCP15::CompileGetTwoWords([[maybe_unused]] bool two, [[maybe_unused]] unsigned opc, [[maybe_unused]] CoprocReg CRm) {
  101. return std::monostate{};
  102. }
  103. std::optional<Callback> TestCP15::CompileLoadWords([[maybe_unused]] bool two, [[maybe_unused]] bool long_transfer, [[maybe_unused]] CoprocReg CRd, [[maybe_unused]] std::optional<u8> option) {
  104. return std::nullopt;
  105. }
  106. std::optional<Callback> TestCP15::CompileStoreWords([[maybe_unused]] bool two, [[maybe_unused]] bool long_transfer, [[maybe_unused]] CoprocReg CRd, [[maybe_unused]] std::optional<u8> option) {
  107. return std::nullopt;
  108. }
  109. static A32::UserConfig GetUserConfig(ArmTestEnv* testenv, CP15State& cp15_state) {
  110. A32::UserConfig user_config;
  111. user_config.optimizations &= ~OptimizationFlag::FastDispatch;
  112. user_config.callbacks = testenv;
  113. user_config.coprocessors[15] = std::make_unique<TestCP15>(cp15_state);
  114. return user_config;
  115. }
  116. TEST_CASE("arm: Test coprocessor (Read TPIDRURO)", "[arm][A32]") {
  117. ArmTestEnv test_env;
  118. CP15State cp15_state;
  119. A32::Jit jit{GetUserConfig(&test_env, cp15_state)};
  120. cp15_state.cp15_thread_uro = 0xf00d;
  121. cp15_state.cp15_thread_uprw = 0xcafe;
  122. jit.Regs()[0] = 0xaaaa;
  123. test_env.code_mem = {
  124. 0xee1d1f70, // mrc p15, 0, r1, c13, c0, 3 (Read TPIDRURO into R1)
  125. 0xeafffffe, // b +#0
  126. };
  127. jit.SetCpsr(0x000001d0); // User-mode
  128. test_env.ticks_left = 2;
  129. jit.Run();
  130. REQUIRE(jit.Regs()[1] == 0xf00d);
  131. }
  132. TEST_CASE("arm: Test coprocessor (Read TPIDRURW)", "[arm][A32]") {
  133. ArmTestEnv test_env;
  134. CP15State cp15_state;
  135. A32::Jit jit{GetUserConfig(&test_env, cp15_state)};
  136. cp15_state.cp15_thread_uro = 0xf00d;
  137. cp15_state.cp15_thread_uprw = 0xcafe;
  138. jit.Regs()[0] = 0xaaaa;
  139. test_env.code_mem = {
  140. 0xee1d1f50, // mrc p15, 0, r1, c13, c0, 2 (Read TPIDRURW into R1)
  141. 0xeafffffe, // b +#0
  142. };
  143. jit.SetCpsr(0x000001d0); // User-mode
  144. test_env.ticks_left = 2;
  145. jit.Run();
  146. REQUIRE(jit.Regs()[1] == 0xcafe);
  147. }
  148. TEST_CASE("arm: Test coprocessor (Write TPIDRURW)", "[arm][A32]") {
  149. ArmTestEnv test_env;
  150. CP15State cp15_state;
  151. A32::Jit jit{GetUserConfig(&test_env, cp15_state)};
  152. cp15_state.cp15_thread_uro = 0xf00d;
  153. cp15_state.cp15_thread_uprw = 0xcafe;
  154. jit.Regs()[0] = 0xaaaa;
  155. test_env.code_mem = {
  156. 0xee0d0f50, // mcr p15, 0, r0, c13, c0, 2 (Write R0 into TPIDRURW)
  157. 0xeafffffe, // b +#0
  158. };
  159. jit.SetCpsr(0x000001d0); // User-mode
  160. test_env.ticks_left = 2;
  161. jit.Run();
  162. REQUIRE(cp15_state.cp15_thread_uprw == 0xaaaa);
  163. }
  164. TEST_CASE("arm: Test coprocessor (DMB)", "[arm][A32]") {
  165. ArmTestEnv test_env;
  166. CP15State cp15_state;
  167. A32::Jit jit{GetUserConfig(&test_env, cp15_state)};
  168. cp15_state.cp15_thread_uro = 0xf00d;
  169. cp15_state.cp15_thread_uprw = 0xcafe;
  170. jit.Regs()[0] = 0xaaaa;
  171. test_env.code_mem = {
  172. 0xee070fba, // mcr p15, 0, r0, c7, c10, 5 (Data Memory Barrier)
  173. 0xeafffffe, // b +#0
  174. };
  175. jit.SetCpsr(0x000001d0); // User-mode
  176. test_env.ticks_left = 2;
  177. jit.Run();
  178. REQUIRE(cp15_state.cp15_data_memory_barrier == 1);
  179. }