diff options
Diffstat (limited to 'src/core/arm')
-rw-r--r-- | src/core/arm/dynarmic/arm_dynarmic_32.cpp | 23 | ||||
-rw-r--r-- | src/core/arm/dynarmic/arm_dynarmic_32.h | 5 | ||||
-rw-r--r-- | src/core/arm/dynarmic/arm_dynarmic_64.cpp | 4 | ||||
-rw-r--r-- | src/core/arm/dynarmic/arm_dynarmic_cp15.cpp | 81 | ||||
-rw-r--r-- | src/core/arm/dynarmic/arm_dynarmic_cp15.h | 126 |
5 files changed, 92 insertions, 147 deletions
diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp index 9bc86e3b9..4c8663d03 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp @@ -50,7 +50,8 @@ public: } void InterpreterFallback(u32 pc, std::size_t num_instructions) override { - UNIMPLEMENTED(); + UNIMPLEMENTED_MSG("This should never happen, pc = {:08X}, code = {:08X}", pc, + MemoryReadCode(pc)); } void ExceptionRaised(u32 pc, Dynarmic::A32::Exception exception) override { @@ -61,7 +62,7 @@ public: case Dynarmic::A32::Exception::Breakpoint: break; } - LOG_CRITICAL(HW_GPU, "ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X})", + LOG_CRITICAL(Core_ARM, "ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X})", static_cast<std::size_t>(exception), pc, MemoryReadCode(pc)); UNIMPLEMENTED(); } @@ -89,8 +90,6 @@ public: ARM_Dynarmic_32& parent; std::size_t num_interpreted_instructions{}; - u64 tpidrro_el0{}; - u64 tpidr_el0{}; }; std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable& page_table, @@ -99,7 +98,7 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable& config.callbacks = cb.get(); // TODO(bunnei): Implement page table for 32-bit // config.page_table = &page_table.pointers; - config.coprocessors[15] = std::make_shared<DynarmicCP15>((u32*)&CP15_regs[0]); + config.coprocessors[15] = cp15; config.define_unpredictable_behaviour = true; return std::make_unique<Dynarmic::A32::Jit>(config); } @@ -112,13 +111,13 @@ void ARM_Dynarmic_32::Run() { } void ARM_Dynarmic_32::Step() { - cb->InterpreterFallback(jit->Regs()[15], 1); + jit->Step(); } ARM_Dynarmic_32::ARM_Dynarmic_32(System& system, ExclusiveMonitor& exclusive_monitor, std::size_t core_index) - : ARM_Interface{system}, - cb(std::make_unique<DynarmicCallbacks32>(*this)), core_index{core_index}, + : ARM_Interface{system}, cb(std::make_unique<DynarmicCallbacks32>(*this)), + cp15(std::make_shared<DynarmicCP15>(*this)), core_index{core_index}, exclusive_monitor{dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor)} {} ARM_Dynarmic_32::~ARM_Dynarmic_32() = default; @@ -154,19 +153,19 @@ void ARM_Dynarmic_32::SetPSTATE(u32 cpsr) { } u64 ARM_Dynarmic_32::GetTlsAddress() const { - return CP15_regs[static_cast<std::size_t>(CP15Register::CP15_THREAD_URO)]; + return cp15->uro; } void ARM_Dynarmic_32::SetTlsAddress(VAddr address) { - CP15_regs[static_cast<std::size_t>(CP15Register::CP15_THREAD_URO)] = static_cast<u32>(address); + cp15->uro = static_cast<u32>(address); } u64 ARM_Dynarmic_32::GetTPIDR_EL0() const { - return cb->tpidr_el0; + return cp15->uprw; } void ARM_Dynarmic_32::SetTPIDR_EL0(u64 value) { - cb->tpidr_el0 = value; + cp15->uprw = static_cast<u32>(value); } void ARM_Dynarmic_32::SaveContext(ThreadContext32& ctx) { diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.h b/src/core/arm/dynarmic/arm_dynarmic_32.h index 8ba9cea8f..e5b92d7bb 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.h +++ b/src/core/arm/dynarmic/arm_dynarmic_32.h @@ -22,6 +22,7 @@ class Memory; namespace Core { class DynarmicCallbacks32; +class DynarmicCP15; class DynarmicExclusiveMonitor; class System; @@ -66,12 +67,14 @@ private: std::unordered_map<JitCacheKey, std::shared_ptr<Dynarmic::A32::Jit>, Common::PairHash>; friend class DynarmicCallbacks32; + friend class DynarmicCP15; + std::unique_ptr<DynarmicCallbacks32> cb; JitCacheType jit_cache; std::shared_ptr<Dynarmic::A32::Jit> jit; + std::shared_ptr<DynarmicCP15> cp15; std::size_t core_index; DynarmicExclusiveMonitor& exclusive_monitor; - std::array<u32, 84> CP15_regs{}; }; } // namespace Core diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp index 337b97be9..5f5e36d94 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp @@ -98,8 +98,8 @@ public: } [[fallthrough]]; default: - ASSERT_MSG(false, "ExceptionRaised(exception = {}, pc = {:X})", - static_cast<std::size_t>(exception), pc); + ASSERT_MSG(false, "ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X})", + static_cast<std::size_t>(exception), pc, MemoryReadCode(pc)); } } diff --git a/src/core/arm/dynarmic/arm_dynarmic_cp15.cpp b/src/core/arm/dynarmic/arm_dynarmic_cp15.cpp index 3fdcdebde..d43e4dd70 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_cp15.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_cp15.cpp @@ -2,79 +2,132 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include <fmt/format.h> +#include "common/logging/log.h" +#include "core/arm/dynarmic/arm_dynarmic_32.h" #include "core/arm/dynarmic/arm_dynarmic_cp15.h" +#include "core/core.h" +#include "core/core_timing.h" +#include "core/core_timing_util.h" using Callback = Dynarmic::A32::Coprocessor::Callback; using CallbackOrAccessOneWord = Dynarmic::A32::Coprocessor::CallbackOrAccessOneWord; using CallbackOrAccessTwoWords = Dynarmic::A32::Coprocessor::CallbackOrAccessTwoWords; +template <> +struct fmt::formatter<Dynarmic::A32::CoprocReg> { + constexpr auto parse(format_parse_context& ctx) { + return ctx.begin(); + } + template <typename FormatContext> + auto format(const Dynarmic::A32::CoprocReg& reg, FormatContext& ctx) { + return format_to(ctx.out(), "cp{}", static_cast<size_t>(reg)); + } +}; + +namespace Core { + +static u32 dummy_value; + std::optional<Callback> DynarmicCP15::CompileInternalOperation(bool two, unsigned opc1, CoprocReg CRd, CoprocReg CRn, CoprocReg CRm, unsigned opc2) { + LOG_CRITICAL(Core_ARM, "CP15: cdp{} p15, {}, {}, {}, {}, {}", two ? "2" : "", opc1, CRd, CRn, + CRm, opc2); return {}; } CallbackOrAccessOneWord DynarmicCP15::CompileSendOneWord(bool two, unsigned opc1, CoprocReg CRn, CoprocReg CRm, unsigned opc2) { - // TODO(merry): Privileged CP15 registers - if (!two && CRn == CoprocReg::C7 && opc1 == 0 && CRm == CoprocReg::C5 && opc2 == 4) { + // CP15_FLUSH_PREFETCH_BUFFER // This is a dummy write, we ignore the value written here. - return &CP15[static_cast<std::size_t>(CP15Register::CP15_FLUSH_PREFETCH_BUFFER)]; + return &dummy_value; } if (!two && CRn == CoprocReg::C7 && opc1 == 0 && CRm == CoprocReg::C10) { switch (opc2) { case 4: + // CP15_DATA_SYNC_BARRIER // This is a dummy write, we ignore the value written here. - return &CP15[static_cast<std::size_t>(CP15Register::CP15_DATA_SYNC_BARRIER)]; + return &dummy_value; case 5: + // CP15_DATA_MEMORY_BARRIER // This is a dummy write, we ignore the value written here. - return &CP15[static_cast<std::size_t>(CP15Register::CP15_DATA_MEMORY_BARRIER)]; - default: - return {}; + return &dummy_value; } } if (!two && CRn == CoprocReg::C13 && opc1 == 0 && CRm == CoprocReg::C0 && opc2 == 2) { - return &CP15[static_cast<std::size_t>(CP15Register::CP15_THREAD_UPRW)]; + // CP15_THREAD_UPRW + return &uprw; } + LOG_CRITICAL(Core_ARM, "CP15: mcr{} p15, {}, <Rt>, {}, {}, {}", two ? "2" : "", opc1, CRn, CRm, + opc2); return {}; } CallbackOrAccessTwoWords DynarmicCP15::CompileSendTwoWords(bool two, unsigned opc, CoprocReg CRm) { + LOG_CRITICAL(Core_ARM, "CP15: mcrr{} p15, {}, <Rt>, <Rt2>, {}", two ? "2" : "", opc, CRm); return {}; } CallbackOrAccessOneWord DynarmicCP15::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 &CP15[static_cast<std::size_t>(CP15Register::CP15_THREAD_UPRW)]; + // CP15_THREAD_UPRW + return &uprw; case 3: - return &CP15[static_cast<std::size_t>(CP15Register::CP15_THREAD_URO)]; - default: - return {}; + // CP15_THREAD_URO + return &uro; } } + LOG_CRITICAL(Core_ARM, "CP15: mrc{} p15, {}, <Rt>, {}, {}, {}", two ? "2" : "", opc1, CRn, CRm, + opc2); return {}; } CallbackOrAccessTwoWords DynarmicCP15::CompileGetTwoWords(bool two, unsigned opc, CoprocReg CRm) { + if (!two && opc == 0 && CRm == CoprocReg::C14) { + // CNTPCT + const auto callback = static_cast<u64 (*)(Dynarmic::A32::Jit*, void*, u32, u32)>( + [](Dynarmic::A32::Jit*, void* arg, u32, u32) -> u64 { + ARM_Dynarmic_32& parent = *(ARM_Dynarmic_32*)arg; + return Timing::CpuCyclesToClockCycles(parent.system.CoreTiming().GetTicks()); + }); + return Dynarmic::A32::Coprocessor::Callback{callback, (void*)&parent}; + } + + LOG_CRITICAL(Core_ARM, "CP15: mrrc{} p15, {}, <Rt>, <Rt2>, {}", two ? "2" : "", opc, CRm); return {}; } std::optional<Callback> DynarmicCP15::CompileLoadWords(bool two, bool long_transfer, CoprocReg CRd, std::optional<u8> option) { + if (option) { + LOG_CRITICAL(Core_ARM, "CP15: mrrc{}{} p15, {}, [...], {}", two ? "2" : "", + long_transfer ? "l" : "", CRd, *option); + } else { + LOG_CRITICAL(Core_ARM, "CP15: mrrc{}{} p15, {}, [...]", two ? "2" : "", + long_transfer ? "l" : "", CRd); + } return {}; } std::optional<Callback> DynarmicCP15::CompileStoreWords(bool two, bool long_transfer, CoprocReg CRd, std::optional<u8> option) { + if (option) { + LOG_CRITICAL(Core_ARM, "CP15: mrrc{}{} p15, {}, [...], {}", two ? "2" : "", + long_transfer ? "l" : "", CRd, *option); + } else { + LOG_CRITICAL(Core_ARM, "CP15: mrrc{}{} p15, {}, [...]", two ? "2" : "", + long_transfer ? "l" : "", CRd); + } return {}; } + +} // namespace Core diff --git a/src/core/arm/dynarmic/arm_dynarmic_cp15.h b/src/core/arm/dynarmic/arm_dynarmic_cp15.h index 07bcde5f9..7356d252e 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_cp15.h +++ b/src/core/arm/dynarmic/arm_dynarmic_cp15.h @@ -10,128 +10,15 @@ #include <dynarmic/A32/coprocessor.h> #include "common/common_types.h" -enum class CP15Register { - // c0 - Information registers - CP15_MAIN_ID, - CP15_CACHE_TYPE, - CP15_TCM_STATUS, - CP15_TLB_TYPE, - CP15_CPU_ID, - CP15_PROCESSOR_FEATURE_0, - CP15_PROCESSOR_FEATURE_1, - CP15_DEBUG_FEATURE_0, - CP15_AUXILIARY_FEATURE_0, - CP15_MEMORY_MODEL_FEATURE_0, - CP15_MEMORY_MODEL_FEATURE_1, - CP15_MEMORY_MODEL_FEATURE_2, - CP15_MEMORY_MODEL_FEATURE_3, - CP15_ISA_FEATURE_0, - CP15_ISA_FEATURE_1, - CP15_ISA_FEATURE_2, - CP15_ISA_FEATURE_3, - CP15_ISA_FEATURE_4, +namespace Core { - // c1 - Control registers - CP15_CONTROL, - CP15_AUXILIARY_CONTROL, - CP15_COPROCESSOR_ACCESS_CONTROL, - - // c2 - Translation table registers - CP15_TRANSLATION_BASE_TABLE_0, - CP15_TRANSLATION_BASE_TABLE_1, - CP15_TRANSLATION_BASE_CONTROL, - CP15_DOMAIN_ACCESS_CONTROL, - CP15_RESERVED, - - // c5 - Fault status registers - CP15_FAULT_STATUS, - CP15_INSTR_FAULT_STATUS, - CP15_COMBINED_DATA_FSR = CP15_FAULT_STATUS, - CP15_INST_FSR, - - // c6 - Fault Address registers - CP15_FAULT_ADDRESS, - CP15_COMBINED_DATA_FAR = CP15_FAULT_ADDRESS, - CP15_WFAR, - CP15_IFAR, - - // c7 - Cache operation registers - CP15_WAIT_FOR_INTERRUPT, - CP15_PHYS_ADDRESS, - CP15_INVALIDATE_INSTR_CACHE, - CP15_INVALIDATE_INSTR_CACHE_USING_MVA, - CP15_INVALIDATE_INSTR_CACHE_USING_INDEX, - CP15_FLUSH_PREFETCH_BUFFER, - CP15_FLUSH_BRANCH_TARGET_CACHE, - CP15_FLUSH_BRANCH_TARGET_CACHE_ENTRY, - CP15_INVALIDATE_DATA_CACHE, - CP15_INVALIDATE_DATA_CACHE_LINE_USING_MVA, - CP15_INVALIDATE_DATA_CACHE_LINE_USING_INDEX, - CP15_INVALIDATE_DATA_AND_INSTR_CACHE, - CP15_CLEAN_DATA_CACHE, - CP15_CLEAN_DATA_CACHE_LINE_USING_MVA, - CP15_CLEAN_DATA_CACHE_LINE_USING_INDEX, - CP15_DATA_SYNC_BARRIER, - CP15_DATA_MEMORY_BARRIER, - CP15_CLEAN_AND_INVALIDATE_DATA_CACHE, - CP15_CLEAN_AND_INVALIDATE_DATA_CACHE_LINE_USING_MVA, - CP15_CLEAN_AND_INVALIDATE_DATA_CACHE_LINE_USING_INDEX, - - // c8 - TLB operations - CP15_INVALIDATE_ITLB, - CP15_INVALIDATE_ITLB_SINGLE_ENTRY, - CP15_INVALIDATE_ITLB_ENTRY_ON_ASID_MATCH, - CP15_INVALIDATE_ITLB_ENTRY_ON_MVA, - CP15_INVALIDATE_DTLB, - CP15_INVALIDATE_DTLB_SINGLE_ENTRY, - CP15_INVALIDATE_DTLB_ENTRY_ON_ASID_MATCH, - CP15_INVALIDATE_DTLB_ENTRY_ON_MVA, - CP15_INVALIDATE_UTLB, - CP15_INVALIDATE_UTLB_SINGLE_ENTRY, - CP15_INVALIDATE_UTLB_ENTRY_ON_ASID_MATCH, - CP15_INVALIDATE_UTLB_ENTRY_ON_MVA, - - // c9 - Data cache lockdown register - CP15_DATA_CACHE_LOCKDOWN, - - // c10 - TLB/Memory map registers - CP15_TLB_LOCKDOWN, - CP15_PRIMARY_REGION_REMAP, - CP15_NORMAL_REGION_REMAP, - - // c13 - Thread related registers - CP15_PID, - CP15_CONTEXT_ID, - CP15_THREAD_UPRW, // Thread ID register - User/Privileged Read/Write - CP15_THREAD_URO, // Thread ID register - User Read Only (Privileged R/W) - CP15_THREAD_PRW, // Thread ID register - Privileged R/W only. - - // c15 - Performance and TLB lockdown registers - CP15_PERFORMANCE_MONITOR_CONTROL, - CP15_CYCLE_COUNTER, - CP15_COUNT_0, - CP15_COUNT_1, - CP15_READ_MAIN_TLB_LOCKDOWN_ENTRY, - CP15_WRITE_MAIN_TLB_LOCKDOWN_ENTRY, - CP15_MAIN_TLB_LOCKDOWN_VIRT_ADDRESS, - CP15_MAIN_TLB_LOCKDOWN_PHYS_ADDRESS, - CP15_MAIN_TLB_LOCKDOWN_ATTRIBUTE, - CP15_TLB_DEBUG_CONTROL, - - // Skyeye defined - CP15_TLB_FAULT_ADDR, - CP15_TLB_FAULT_STATUS, - - // Not an actual register. - // All registers should be defined above this. - CP15_REGISTER_COUNT, -}; +class ARM_Dynarmic_32; class DynarmicCP15 final : public Dynarmic::A32::Coprocessor { public: using CoprocReg = Dynarmic::A32::CoprocReg; - explicit DynarmicCP15(u32* cp15) : CP15(cp15){}; + explicit DynarmicCP15(ARM_Dynarmic_32& parent) : parent(parent) {} std::optional<Callback> CompileInternalOperation(bool two, unsigned opc1, CoprocReg CRd, CoprocReg CRn, CoprocReg CRm, @@ -147,6 +34,9 @@ public: std::optional<Callback> CompileStoreWords(bool two, bool long_transfer, CoprocReg CRd, std::optional<u8> option) override; -private: - u32* CP15{}; + ARM_Dynarmic_32& parent; + u32 uprw; + u32 uro; }; + +} // namespace Core |