123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229 |
- /* This file is part of the dynarmic project.
- * Copyright (c) 2022 MerryMage
- * SPDX-License-Identifier: 0BSD
- */
- #include <memory>
- #include <catch2/catch_test_macros.hpp>
- #include "./testenv.h"
- #include "dynarmic/frontend/A32/a32_location_descriptor.h"
- #include "dynarmic/interface/A32/a32.h"
- #include "dynarmic/interface/A32/coprocessor.h"
- using namespace Dynarmic;
- struct CP15State {
- u32 cp15_thread_uprw = 0;
- u32 cp15_thread_uro = 0;
- u32 cp15_flush_prefetch_buffer = 0; ///< dummy value
- u32 cp15_data_sync_barrier = 0; ///< dummy value
- u32 cp15_data_memory_barrier = 0; ///< dummy value
- };
- class TestCP15 final : public Dynarmic::A32::Coprocessor {
- public:
- using CoprocReg = Dynarmic::A32::CoprocReg;
- explicit TestCP15(CP15State&);
- ~TestCP15() override;
- std::optional<Callback> CompileInternalOperation(bool two, unsigned opc1, CoprocReg CRd, CoprocReg CRn, CoprocReg CRm, unsigned opc2) override;
- CallbackOrAccessOneWord CompileSendOneWord(bool two, unsigned opc1, CoprocReg CRn, CoprocReg CRm, unsigned opc2) override;
- CallbackOrAccessTwoWords CompileSendTwoWords(bool two, unsigned opc, CoprocReg CRm) override;
- CallbackOrAccessOneWord CompileGetOneWord(bool two, unsigned opc1, CoprocReg CRn, CoprocReg CRm, unsigned opc2) override;
- CallbackOrAccessTwoWords CompileGetTwoWords(bool two, unsigned opc, CoprocReg CRm) override;
- std::optional<Callback> CompileLoadWords(bool two, bool long_transfer, CoprocReg CRd, std::optional<u8> option) override;
- std::optional<Callback> CompileStoreWords(bool two, bool long_transfer, CoprocReg CRd, std::optional<u8> option) override;
- private:
- CP15State& state;
- };
- using Callback = Dynarmic::A32::Coprocessor::Callback;
- using CallbackOrAccessOneWord = Dynarmic::A32::Coprocessor::CallbackOrAccessOneWord;
- using CallbackOrAccessTwoWords = Dynarmic::A32::Coprocessor::CallbackOrAccessTwoWords;
- TestCP15::TestCP15(CP15State& state)
- : state(state) {}
- TestCP15::~TestCP15() = default;
- 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) {
- return std::nullopt;
- }
- CallbackOrAccessOneWord TestCP15::CompileSendOneWord(bool two, unsigned opc1, CoprocReg CRn, CoprocReg CRm, unsigned opc2) {
- if (!two && CRn == CoprocReg::C7 && opc1 == 0 && CRm == CoprocReg::C5 && opc2 == 4) {
- return Callback{
- [](void* user_arg, std::uint32_t, std::uint32_t) -> std::uint64_t {
- CP15State& state = *reinterpret_cast<CP15State*>(user_arg);
- state.cp15_flush_prefetch_buffer = 1;
- return 0;
- },
- reinterpret_cast<void*>(&state),
- };
- }
- if (!two && CRn == CoprocReg::C7 && opc1 == 0 && CRm == CoprocReg::C10) {
- switch (opc2) {
- case 4:
- return Callback{
- [](void* user_arg, std::uint32_t, std::uint32_t) -> std::uint64_t {
- CP15State& state = *reinterpret_cast<CP15State*>(user_arg);
- state.cp15_data_sync_barrier = 1;
- return 0;
- },
- reinterpret_cast<void*>(&state),
- };
- case 5:
- return Callback{
- [](void* user_arg, std::uint32_t, std::uint32_t) -> std::uint64_t {
- CP15State& state = *reinterpret_cast<CP15State*>(user_arg);
- state.cp15_data_memory_barrier = 1;
- return 0;
- },
- reinterpret_cast<void*>(&state),
- };
- default:
- return std::monostate{};
- }
- }
- if (!two && CRn == CoprocReg::C13 && opc1 == 0 && CRm == CoprocReg::C0 && opc2 == 2) {
- return &state.cp15_thread_uprw;
- }
- return std::monostate{};
- }
- CallbackOrAccessTwoWords TestCP15::CompileSendTwoWords([[maybe_unused]] bool two, [[maybe_unused]] unsigned opc, [[maybe_unused]] CoprocReg CRm) {
- return std::monostate{};
- }
- CallbackOrAccessOneWord TestCP15::CompileGetOneWord(bool two, unsigned opc1, CoprocReg CRn, CoprocReg CRm, unsigned opc2) {
- // TODO(merry): Privileged CP15 registers
- if (!two && CRn == CoprocReg::C13 && opc1 == 0 && CRm == CoprocReg::C0) {
- switch (opc2) {
- case 2:
- return &state.cp15_thread_uprw;
- case 3:
- return &state.cp15_thread_uro;
- default:
- return std::monostate{};
- }
- }
- return std::monostate{};
- }
- CallbackOrAccessTwoWords TestCP15::CompileGetTwoWords([[maybe_unused]] bool two, [[maybe_unused]] unsigned opc, [[maybe_unused]] CoprocReg CRm) {
- return std::monostate{};
- }
- std::optional<Callback> TestCP15::CompileLoadWords([[maybe_unused]] bool two, [[maybe_unused]] bool long_transfer, [[maybe_unused]] CoprocReg CRd, [[maybe_unused]] std::optional<u8> option) {
- return std::nullopt;
- }
- std::optional<Callback> TestCP15::CompileStoreWords([[maybe_unused]] bool two, [[maybe_unused]] bool long_transfer, [[maybe_unused]] CoprocReg CRd, [[maybe_unused]] std::optional<u8> option) {
- return std::nullopt;
- }
- static A32::UserConfig GetUserConfig(ArmTestEnv* testenv, CP15State& cp15_state) {
- A32::UserConfig user_config;
- user_config.optimizations &= ~OptimizationFlag::FastDispatch;
- user_config.callbacks = testenv;
- user_config.coprocessors[15] = std::make_unique<TestCP15>(cp15_state);
- return user_config;
- }
- TEST_CASE("arm: Test coprocessor (Read TPIDRURO)", "[arm][A32]") {
- ArmTestEnv test_env;
- CP15State cp15_state;
- A32::Jit jit{GetUserConfig(&test_env, cp15_state)};
- cp15_state.cp15_thread_uro = 0xf00d;
- cp15_state.cp15_thread_uprw = 0xcafe;
- jit.Regs()[0] = 0xaaaa;
- test_env.code_mem = {
- 0xee1d1f70, // mrc p15, 0, r1, c13, c0, 3 (Read TPIDRURO into R1)
- 0xeafffffe, // b +#0
- };
- jit.SetCpsr(0x000001d0); // User-mode
- test_env.ticks_left = 2;
- jit.Run();
- REQUIRE(jit.Regs()[1] == 0xf00d);
- }
- TEST_CASE("arm: Test coprocessor (Read TPIDRURW)", "[arm][A32]") {
- ArmTestEnv test_env;
- CP15State cp15_state;
- A32::Jit jit{GetUserConfig(&test_env, cp15_state)};
- cp15_state.cp15_thread_uro = 0xf00d;
- cp15_state.cp15_thread_uprw = 0xcafe;
- jit.Regs()[0] = 0xaaaa;
- test_env.code_mem = {
- 0xee1d1f50, // mrc p15, 0, r1, c13, c0, 2 (Read TPIDRURW into R1)
- 0xeafffffe, // b +#0
- };
- jit.SetCpsr(0x000001d0); // User-mode
- test_env.ticks_left = 2;
- jit.Run();
- REQUIRE(jit.Regs()[1] == 0xcafe);
- }
- TEST_CASE("arm: Test coprocessor (Write TPIDRURW)", "[arm][A32]") {
- ArmTestEnv test_env;
- CP15State cp15_state;
- A32::Jit jit{GetUserConfig(&test_env, cp15_state)};
- cp15_state.cp15_thread_uro = 0xf00d;
- cp15_state.cp15_thread_uprw = 0xcafe;
- jit.Regs()[0] = 0xaaaa;
- test_env.code_mem = {
- 0xee0d0f50, // mcr p15, 0, r0, c13, c0, 2 (Write R0 into TPIDRURW)
- 0xeafffffe, // b +#0
- };
- jit.SetCpsr(0x000001d0); // User-mode
- test_env.ticks_left = 2;
- jit.Run();
- REQUIRE(cp15_state.cp15_thread_uprw == 0xaaaa);
- }
- TEST_CASE("arm: Test coprocessor (DMB)", "[arm][A32]") {
- ArmTestEnv test_env;
- CP15State cp15_state;
- A32::Jit jit{GetUserConfig(&test_env, cp15_state)};
- cp15_state.cp15_thread_uro = 0xf00d;
- cp15_state.cp15_thread_uprw = 0xcafe;
- jit.Regs()[0] = 0xaaaa;
- test_env.code_mem = {
- 0xee070fba, // mcr p15, 0, r0, c7, c10, 5 (Data Memory Barrier)
- 0xeafffffe, // b +#0
- };
- jit.SetCpsr(0x000001d0); // User-mode
- test_env.ticks_left = 2;
- jit.Run();
- REQUIRE(cp15_state.cp15_data_memory_barrier == 1);
- }
|