From 8b7b6e9f74de6b8df1028caf367ded873fdde626 Mon Sep 17 00:00:00 2001 From: MerryMage Date: Mon, 6 Apr 2020 17:31:12 +0100 Subject: [PATCH] arm_dynarmic: Remove dependence on interpreter --- src/citra_qt/debugger/registers.cpp | 11 --- src/core/arm/dynarmic/arm_dynarmic.cpp | 91 +++++++++++---------- src/core/arm/dynarmic/arm_dynarmic.h | 12 ++- src/core/arm/dynarmic/arm_dynarmic_cp15.cpp | 14 ++-- src/core/arm/dynarmic/arm_dynarmic_cp15.h | 12 ++- src/core/core.cpp | 2 +- 6 files changed, 73 insertions(+), 69 deletions(-) diff --git a/src/citra_qt/debugger/registers.cpp b/src/citra_qt/debugger/registers.cpp index eb4d3d6dc4..9c67073f3b 100644 --- a/src/citra_qt/debugger/registers.cpp +++ b/src/citra_qt/debugger/registers.cpp @@ -103,8 +103,6 @@ void RegistersWidget::OnEmulationStopping() { vfp_system_registers->child(0)->setText(1, QString{}); vfp_system_registers->child(1)->setText(1, QString{}); - vfp_system_registers->child(2)->setText(1, QString{}); - vfp_system_registers->child(3)->setText(1, QString{}); setEnabled(false); } @@ -188,16 +186,12 @@ void RegistersWidget::CreateVFPSystemRegisterChildren() { vfp_system_registers->addChild(fpscr); vfp_system_registers->addChild(fpexc); - vfp_system_registers->addChild(new QTreeWidgetItem(QStringList(QStringLiteral("FPINST")))); - vfp_system_registers->addChild(new QTreeWidgetItem(QStringList(QStringLiteral("FPINST2")))); } void RegistersWidget::UpdateVFPSystemRegisterValues() { // Todo: handle all cores const u32 fpscr_val = Core::GetCore(0).GetVFPSystemReg(VFP_FPSCR); const u32 fpexc_val = Core::GetCore(0).GetVFPSystemReg(VFP_FPEXC); - const u32 fpinst_val = Core::GetCore(0).GetVFPSystemReg(VFP_FPINST); - const u32 fpinst2_val = Core::GetCore(0).GetVFPSystemReg(VFP_FPINST2); QTreeWidgetItem* const fpscr = vfp_system_registers->child(0); fpscr->setText(1, QStringLiteral("0x%1").arg(fpscr_val, 8, 16, QLatin1Char('0'))); @@ -237,9 +231,4 @@ void RegistersWidget::UpdateVFPSystemRegisterValues() { fpexc->child(5)->setText(1, QString::number((fpexc_val >> 28) & 1)); fpexc->child(6)->setText(1, QString::number((fpexc_val >> 30) & 1)); fpexc->child(7)->setText(1, QString::number((fpexc_val >> 31) & 1)); - - vfp_system_registers->child(2)->setText( - 1, QStringLiteral("0x%1").arg(fpinst_val, 8, 16, QLatin1Char('0'))); - vfp_system_registers->child(3)->setText( - 1, QStringLiteral("0x%1").arg(fpinst2_val, 8, 16, QLatin1Char('0'))); } diff --git a/src/core/arm/dynarmic/arm_dynarmic.cpp b/src/core/arm/dynarmic/arm_dynarmic.cpp index bb32f470cc..55da53b142 100644 --- a/src/core/arm/dynarmic/arm_dynarmic.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic.cpp @@ -9,7 +9,6 @@ #include "common/microprofile.h" #include "core/arm/dynarmic/arm_dynarmic.h" #include "core/arm/dynarmic/arm_dynarmic_cp15.h" -#include "core/arm/dyncom/arm_dyncom_interpreter.h" #include "core/core.h" #include "core/core_timing.h" #include "core/gdbstub/gdbstub.h" @@ -102,24 +101,9 @@ public: } void InterpreterFallback(VAddr pc, std::size_t num_instructions) override { - parent.interpreter_state->Reg = parent.jit->Regs(); - parent.interpreter_state->Cpsr = parent.jit->Cpsr(); - parent.interpreter_state->Reg[15] = pc; - parent.interpreter_state->ExtReg = parent.jit->ExtRegs(); - parent.interpreter_state->VFP[VFP_FPSCR] = parent.jit->Fpscr(); - parent.interpreter_state->NumInstrsToExecute = num_instructions; - - InterpreterMainLoop(parent.interpreter_state.get()); - - bool is_thumb = (parent.interpreter_state->Cpsr & (1 << 5)) != 0; - parent.interpreter_state->Reg[15] &= (is_thumb ? 0xFFFFFFFE : 0xFFFFFFFC); - - parent.jit->Regs() = parent.interpreter_state->Reg; - parent.jit->SetCpsr(parent.interpreter_state->Cpsr); - parent.jit->ExtRegs() = parent.interpreter_state->ExtReg; - parent.jit->SetFpscr(parent.interpreter_state->VFP[VFP_FPSCR]); - - parent.interpreter_state->ServeBreak(); + // Should never happen. + UNREACHABLE_MSG("InterpeterFallback reached with pc = 0x{:08x}, code = 0x{:08x}, num = {}", + pc, MemoryReadCode(pc), num_instructions); } void CallSVC(std::uint32_t swi) override { @@ -135,11 +119,7 @@ public: if (GDBStub::IsConnected()) { parent.jit->HaltExecution(); parent.SetPC(pc); - Kernel::Thread* thread = - parent.system.Kernel().GetCurrentThreadManager().GetCurrentThread(); - parent.SaveContext(thread->context); - GDBStub::Break(); - GDBStub::SendTrap(thread, 5); + parent.ServeBreak(); return; } break; @@ -169,12 +149,10 @@ public: Memory::MemorySystem& memory; }; -ARM_Dynarmic::ARM_Dynarmic(Core::System* system, Memory::MemorySystem& memory, - PrivilegeMode initial_mode, u32 id, +ARM_Dynarmic::ARM_Dynarmic(Core::System* system, Memory::MemorySystem& memory, u32 id, std::shared_ptr timer) : ARM_Interface(id, timer), system(*system), memory(memory), cb(std::make_unique(*this)) { - interpreter_state = std::make_shared(system, memory, initial_mode); PageTableChanged(); } @@ -190,7 +168,11 @@ void ARM_Dynarmic::Run() { } void ARM_Dynarmic::Step() { - cb->InterpreterFallback(jit->Regs()[15], 1); + jit->Step(); + + if (GDBStub::IsConnected()) { + ServeBreak(); + } } void ARM_Dynarmic::SetPC(u32 pc) { @@ -218,21 +200,25 @@ void ARM_Dynarmic::SetVFPReg(int index, u32 value) { } u32 ARM_Dynarmic::GetVFPSystemReg(VFPSystemRegister reg) const { - if (reg == VFP_FPSCR) { + switch (reg) { + case VFP_FPSCR: return jit->Fpscr(); + case VFP_FPEXC: + return fpexc; } - - // Dynarmic does not implement and/or expose other VFP registers, fallback to interpreter state - return interpreter_state->VFP[reg]; + UNREACHABLE_MSG("Unknown VFP system register: {}", static_cast(reg)); } void ARM_Dynarmic::SetVFPSystemReg(VFPSystemRegister reg, u32 value) { - if (reg == VFP_FPSCR) { + switch (reg) { + case VFP_FPSCR: jit->SetFpscr(value); + return; + case VFP_FPEXC: + fpexc = value; + return; } - - // Dynarmic does not implement and/or expose other VFP registers, fallback to interpreter state - interpreter_state->VFP[reg] = value; + UNREACHABLE_MSG("Unknown VFP system register: {}", static_cast(reg)); } u32 ARM_Dynarmic::GetCPSR() const { @@ -244,11 +230,25 @@ void ARM_Dynarmic::SetCPSR(u32 cpsr) { } u32 ARM_Dynarmic::GetCP15Register(CP15Register reg) { - return interpreter_state->CP15[reg]; + switch (reg) { + case CP15_THREAD_UPRW: + return cp15_state.cp15_thread_uprw; + case CP15_THREAD_URO: + return cp15_state.cp15_thread_uro; + } + UNREACHABLE_MSG("Unknown CP15 register: {}", static_cast(reg)); } void ARM_Dynarmic::SetCP15Register(CP15Register reg, u32 value) { - interpreter_state->CP15[reg] = value; + switch (reg) { + case CP15_THREAD_UPRW: + cp15_state.cp15_thread_uprw = value; + return; + case CP15_THREAD_URO: + cp15_state.cp15_thread_uro = value; + return; + } + UNREACHABLE_MSG("Unknown CP15 register: {}", static_cast(reg)); } std::unique_ptr ARM_Dynarmic::NewContext() const { @@ -260,7 +260,7 @@ void ARM_Dynarmic::SaveContext(const std::unique_ptr& arg) { ASSERT(ctx); jit->SaveContext(ctx->ctx); - ctx->fpexc = interpreter_state->VFP[VFP_FPEXC]; + ctx->fpexc = fpexc; } void ARM_Dynarmic::LoadContext(const std::unique_ptr& arg) { @@ -268,7 +268,7 @@ void ARM_Dynarmic::LoadContext(const std::unique_ptr& arg) { ASSERT(ctx); jit->LoadContext(ctx->ctx); - interpreter_state->VFP[VFP_FPEXC] = ctx->fpexc; + fpexc = ctx->fpexc; } void ARM_Dynarmic::PrepareReschedule() { @@ -278,11 +278,9 @@ void ARM_Dynarmic::PrepareReschedule() { } void ARM_Dynarmic::ClearInstructionCache() { - // TODO: Clear interpreter cache when appropriate. for (const auto& j : jits) { j.second->ClearCache(); } - interpreter_state->instruction_cache.clear(); } void ARM_Dynarmic::InvalidateCacheRange(u32 start_address, std::size_t length) { @@ -303,11 +301,18 @@ void ARM_Dynarmic::PageTableChanged() { jits.emplace(current_page_table, std::move(new_jit)); } +void ARM_Dynarmic::ServeBreak() { + Kernel::Thread* thread = system.Kernel().GetCurrentThreadManager().GetCurrentThread(); + SaveContext(thread->context); + GDBStub::Break(); + GDBStub::SendTrap(thread, 5); +} + std::unique_ptr ARM_Dynarmic::MakeJit() { Dynarmic::A32::UserConfig config; config.callbacks = cb.get(); config.page_table = ¤t_page_table->pointers; - config.coprocessors[15] = std::make_shared(interpreter_state); + config.coprocessors[15] = std::make_shared(cp15_state); config.define_unpredictable_behaviour = true; return std::make_unique(config); } diff --git a/src/core/arm/dynarmic/arm_dynarmic.h b/src/core/arm/dynarmic/arm_dynarmic.h index 4aaec1bf11..c403f438e4 100644 --- a/src/core/arm/dynarmic/arm_dynarmic.h +++ b/src/core/arm/dynarmic/arm_dynarmic.h @@ -9,7 +9,7 @@ #include #include "common/common_types.h" #include "core/arm/arm_interface.h" -#include "core/arm/skyeye_common/armstate.h" +#include "core/arm/dynarmic/arm_dynarmic_cp15.h" namespace Memory { struct PageTable; @@ -24,8 +24,8 @@ class DynarmicUserCallbacks; class ARM_Dynarmic final : public ARM_Interface { public: - ARM_Dynarmic(Core::System* system, Memory::MemorySystem& memory, PrivilegeMode initial_mode, - u32 id, std::shared_ptr timer); + ARM_Dynarmic(Core::System* system, Memory::MemorySystem& memory, u32 id, + std::shared_ptr timer); ~ARM_Dynarmic() override; void Run() override; @@ -55,14 +55,18 @@ public: void PageTableChanged() override; private: + void ServeBreak(); + friend class DynarmicUserCallbacks; Core::System& system; Memory::MemorySystem& memory; std::unique_ptr cb; std::unique_ptr MakeJit(); + u32 fpexc = 0; + CP15State cp15_state; + Dynarmic::A32::Jit* jit = nullptr; Memory::PageTable* current_page_table = nullptr; std::map> jits; - std::shared_ptr interpreter_state; }; diff --git a/src/core/arm/dynarmic/arm_dynarmic_cp15.cpp b/src/core/arm/dynarmic/arm_dynarmic_cp15.cpp index 167f58e47b..8f55fb54e1 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_cp15.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_cp15.cpp @@ -10,7 +10,7 @@ using Callback = Dynarmic::A32::Coprocessor::Callback; using CallbackOrAccessOneWord = Dynarmic::A32::Coprocessor::CallbackOrAccessOneWord; using CallbackOrAccessTwoWords = Dynarmic::A32::Coprocessor::CallbackOrAccessTwoWords; -DynarmicCP15::DynarmicCP15(const std::shared_ptr& state) : interpreter_state(state) {} +DynarmicCP15::DynarmicCP15(CP15State& state) : state(state) {} DynarmicCP15::~DynarmicCP15() = default; @@ -26,24 +26,24 @@ CallbackOrAccessOneWord DynarmicCP15::CompileSendOneWord(bool two, unsigned opc1 if (!two && CRn == CoprocReg::C7 && opc1 == 0 && CRm == CoprocReg::C5 && opc2 == 4) { // This is a dummy write, we ignore the value written here. - return &interpreter_state->CP15[CP15_FLUSH_PREFETCH_BUFFER]; + return &state.cp15_flush_prefetch_buffer; } if (!two && CRn == CoprocReg::C7 && opc1 == 0 && CRm == CoprocReg::C10) { switch (opc2) { case 4: // This is a dummy write, we ignore the value written here. - return &interpreter_state->CP15[CP15_DATA_SYNC_BARRIER]; + return &state.cp15_data_sync_barrier; case 5: // This is a dummy write, we ignore the value written here. - return &interpreter_state->CP15[CP15_DATA_MEMORY_BARRIER]; + return &state.cp15_data_memory_barrier; default: return std::monostate{}; } } if (!two && CRn == CoprocReg::C13 && opc1 == 0 && CRm == CoprocReg::C0 && opc2 == 2) { - return &interpreter_state->CP15[CP15_THREAD_UPRW]; + return &state.cp15_thread_uprw; } return std::monostate{}; @@ -60,9 +60,9 @@ CallbackOrAccessOneWord DynarmicCP15::CompileGetOneWord(bool two, unsigned opc1, if (!two && CRn == CoprocReg::C13 && opc1 == 0 && CRm == CoprocReg::C0) { switch (opc2) { case 2: - return &interpreter_state->CP15[CP15_THREAD_UPRW]; + return &state.cp15_thread_uprw; case 3: - return &interpreter_state->CP15[CP15_THREAD_URO]; + return &state.cp15_thread_uro; default: return std::monostate{}; } diff --git a/src/core/arm/dynarmic/arm_dynarmic_cp15.h b/src/core/arm/dynarmic/arm_dynarmic_cp15.h index 9233438642..30ab08ac85 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_cp15.h +++ b/src/core/arm/dynarmic/arm_dynarmic_cp15.h @@ -8,13 +8,19 @@ #include #include "common/common_types.h" -struct ARMul_State; +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 DynarmicCP15 final : public Dynarmic::A32::Coprocessor { public: using CoprocReg = Dynarmic::A32::CoprocReg; - explicit DynarmicCP15(const std::shared_ptr&); + explicit DynarmicCP15(CP15State&); ~DynarmicCP15() override; std::optional CompileInternalOperation(bool two, unsigned opc1, CoprocReg CRd, @@ -32,5 +38,5 @@ public: std::optional option) override; private: - std::shared_ptr interpreter_state; + CP15State& state; }; diff --git a/src/core/core.cpp b/src/core/core.cpp index c1d635afe5..bd9e934936 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -267,7 +267,7 @@ System::ResultStatus System::Init(Frontend::EmuWindow& emu_window, u32 system_mo #ifdef ARCHITECTURE_x86_64 for (std::size_t i = 0; i < num_cores; ++i) { cpu_cores.push_back( - std::make_shared(this, *memory, USER32MODE, i, timing->GetTimer(i))); + std::make_shared(this, *memory, i, timing->GetTimer(i))); } #else for (std::size_t i = 0; i < num_cores; ++i) {