From d2fbc7832080955598c9fb6f083414eca47f0f19 Mon Sep 17 00:00:00 2001 From: MerryMage Date: Tue, 9 Jan 2018 21:33:46 +0000 Subject: [PATCH] arm_dynarmic: Implement core --- externals/CMakeLists.txt | 10 +- externals/dynarmic | 2 +- src/citra_qt/debugger/wait_tree.cpp | 2 +- src/core/CMakeLists.txt | 2 +- src/core/arm/arm_interface.h | 12 +- src/core/arm/dynarmic/arm_dynarmic.cpp | 160 +++++++++++++++++++------ src/core/arm/dynarmic/arm_dynarmic.h | 16 ++- src/core/arm/unicorn/arm_unicorn.cpp | 20 ++-- src/core/arm/unicorn/arm_unicorn.h | 5 +- src/core/core.cpp | 4 +- 10 files changed, 171 insertions(+), 62 deletions(-) diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt index aa01acda8..dcf6c460f 100644 --- a/externals/CMakeLists.txt +++ b/externals/CMakeLists.txt @@ -10,6 +10,14 @@ target_include_directories(catch-single-include INTERFACE catch/single_include) # Crypto++ add_subdirectory(cryptopp) +# Dynarmic +if (ARCHITECTURE_x86_64) + add_library(xbyak INTERFACE) + set(DYNARMIC_TESTS OFF) + set(DYNARMIC_NO_BUNDLED_FMT ON) + add_subdirectory(dynarmic) +endif() + # libfmt add_subdirectory(fmt) @@ -49,7 +57,7 @@ target_include_directories(unicorn-headers INTERFACE ./unicorn/include) # Xbyak if (ARCHITECTURE_x86_64) # Defined before "dynarmic" above - add_library(xbyak INTERFACE) + # add_library(xbyak INTERFACE) target_include_directories(xbyak INTERFACE ./xbyak/xbyak) target_compile_definitions(xbyak INTERFACE XBYAK_NO_OP_NAMES) endif() diff --git a/externals/dynarmic b/externals/dynarmic index 305fba50b..a5caa7cd8 160000 --- a/externals/dynarmic +++ b/externals/dynarmic @@ -1 +1 @@ -Subproject commit 305fba50babf736d77b71c5a44dd6b0ccb7f9d10 +Subproject commit a5caa7cd8d5741d34dcf0b3447b5f1c3f7333d56 diff --git a/src/citra_qt/debugger/wait_tree.cpp b/src/citra_qt/debugger/wait_tree.cpp index c066a3e17..eefbcb9f1 100644 --- a/src/citra_qt/debugger/wait_tree.cpp +++ b/src/citra_qt/debugger/wait_tree.cpp @@ -168,7 +168,7 @@ QString WaitTreeThread::GetText() const { } QString pc_info = tr(" PC = 0x%1 LR = 0x%2") .arg(thread.context.pc, 8, 16, QLatin1Char('0')) - .arg(thread.context.lr, 8, 16, QLatin1Char('0')); + .arg(thread.context.cpu_registers[31], 8, 16, QLatin1Char('0')); return WaitTreeWaitObject::GetText() + pc_info + " (" + status + ") "; } diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 025177b89..e8e98a095 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -171,7 +171,7 @@ set(HEADERS create_directory_groups(${SRCS} ${HEADERS}) add_library(core STATIC ${SRCS} ${HEADERS}) -target_link_libraries(core PUBLIC common PRIVATE audio_core network video_core) +target_link_libraries(core PUBLIC common PRIVATE audio_core dynarmic network video_core) target_link_libraries(core PUBLIC Boost::boost PRIVATE cryptopp fmt lz4_static unicorn) if (ENABLE_WEB_SERVICE) target_link_libraries(core PUBLIC json-headers web_service) diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h index c0d6e2604..531875006 100644 --- a/src/core/arm/arm_interface.h +++ b/src/core/arm/arm_interface.h @@ -4,6 +4,7 @@ #pragma once +#include #include "common/common_types.h" #include "core/hle/kernel/vm_manager.h" @@ -13,15 +14,12 @@ public: virtual ~ARM_Interface() {} struct ThreadContext { - u64 cpu_registers[30]; - u64 lr; + std::array cpu_registers; u64 sp; u64 pc; u64 cpsr; - u128 fpu_registers[32]; + std::array fpu_registers; u64 fpscr; - u64 fpexc; - // TODO(bunnei): Fix once we have proper support for tpidrro_el0, etc. in the JIT VAddr tls_address; @@ -75,9 +73,9 @@ public: */ virtual void SetReg(int index, u64 value) = 0; - virtual const u128& GetExtReg(int index) const = 0; + virtual u128 GetExtReg(int index) const = 0; - virtual void SetExtReg(int index, u128& value) = 0; + virtual void SetExtReg(int index, u128 value) = 0; /** * Gets the value of a VFP register diff --git a/src/core/arm/dynarmic/arm_dynarmic.cpp b/src/core/arm/dynarmic/arm_dynarmic.cpp index 12b7fc926..c1a63e064 100644 --- a/src/core/arm/dynarmic/arm_dynarmic.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic.cpp @@ -2,43 +2,114 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include +#include +#include #include "core/arm/dynarmic/arm_dynarmic.h" +#include "core/core_timing.h" +#include "core/hle/kernel/svc.h" +#include "core/memory.h" -ARM_Dynarmic::ARM_Dynarmic() { - UNIMPLEMENTED(); +class ARM_Dynarmic_Callbacks : public Dynarmic::A64::UserCallbacks { +public: + explicit ARM_Dynarmic_Callbacks(ARM_Dynarmic& parent) : parent(parent) {} + ~ARM_Dynarmic_Callbacks() = default; + + virtual u8 MemoryRead8(u64 vaddr) override { + return Memory::Read8(vaddr); + } + virtual u16 MemoryRead16(u64 vaddr) override { + return Memory::Read16(vaddr); + } + virtual u32 MemoryRead32(u64 vaddr) override { + return Memory::Read32(vaddr); + } + virtual u64 MemoryRead64(u64 vaddr) override { + return Memory::Read64(vaddr); + } + + virtual void MemoryWrite8(u64 vaddr, u8 value) override { + Memory::Write8(vaddr, value); + } + virtual void MemoryWrite16(u64 vaddr, u16 value) override { + Memory::Write16(vaddr, value); + } + virtual void MemoryWrite32(u64 vaddr, u32 value) override { + Memory::Write32(vaddr, value); + } + virtual void MemoryWrite64(u64 vaddr, u64 value) override { + Memory::Write64(vaddr, value); + } + + virtual void InterpreterFallback(u64 pc, size_t num_instructions) override { + ARM_Interface::ThreadContext ctx; + parent.SaveContext(ctx); + parent.inner_unicorn.LoadContext(ctx); + parent.inner_unicorn.ExecuteInstructions(num_instructions); + parent.inner_unicorn.SaveContext(ctx); + parent.LoadContext(ctx); + num_interpreted_instructions += num_instructions; + } + + virtual void CallSVC(u32 swi) override { + printf("svc %x\n", swi); + Kernel::CallSVC(swi); + } + + virtual void AddTicks(u64 ticks) override { + if (ticks > ticks_remaining) { + ticks_remaining = 0; + return; + } + ticks -= ticks_remaining; + } + virtual u64 GetTicksRemaining() override { + return ticks_remaining; + } + + ARM_Dynarmic& parent; + size_t ticks_remaining = 0; + size_t num_interpreted_instructions = 0; + u64 tpidrr0_el0 = 0; +}; + +ARM_Dynarmic::ARM_Dynarmic() + : cb(std::make_unique(*this)), + jit(Dynarmic::A64::UserConfig{cb.get()}) { + ARM_Interface::ThreadContext ctx; + inner_unicorn.SaveContext(ctx); + LoadContext(ctx); } -void ARM_Dynarmic::MapBackingMemory(VAddr /*address*/, size_t /*size*/, u8* /*memory*/, - Kernel::VMAPermission /*perms*/) { - UNIMPLEMENTED(); +ARM_Dynarmic::~ARM_Dynarmic() = default; + +void ARM_Dynarmic::MapBackingMemory(u64 address, size_t size, u8* memory, + Kernel::VMAPermission perms) { + inner_unicorn.MapBackingMemory(address, size, memory, perms); } -void ARM_Dynarmic::SetPC(u64 /*pc*/) { - UNIMPLEMENTED(); +void ARM_Dynarmic::SetPC(u64 pc) { + jit.SetPC(pc); } u64 ARM_Dynarmic::GetPC() const { - UNIMPLEMENTED(); - return {}; + return jit.GetPC(); } -u64 ARM_Dynarmic::GetReg(int /*index*/) const { - UNIMPLEMENTED(); - return {}; +u64 ARM_Dynarmic::GetReg(int index) const { + return jit.GetRegister(index); } -void ARM_Dynarmic::SetReg(int /*index*/, u64 /*value*/) { - UNIMPLEMENTED(); +void ARM_Dynarmic::SetReg(int index, u64 value) { + jit.SetRegister(index, value); } -const u128& ARM_Dynarmic::GetExtReg(int /*index*/) const { - UNIMPLEMENTED(); - static constexpr u128 res{}; - return res; +u128 ARM_Dynarmic::GetExtReg(int index) const { + return jit.GetVector(index); } -void ARM_Dynarmic::SetExtReg(int /*index*/, u128& /*value*/) { - UNIMPLEMENTED(); +void ARM_Dynarmic::SetExtReg(int index, u128 value) { + jit.SetVector(index, value); } u32 ARM_Dynarmic::GetVFPReg(int /*index*/) const { @@ -51,41 +122,56 @@ void ARM_Dynarmic::SetVFPReg(int /*index*/, u32 /*value*/) { } u32 ARM_Dynarmic::GetCPSR() const { - UNIMPLEMENTED(); - return {}; + return jit.GetPstate(); } -void ARM_Dynarmic::SetCPSR(u32 /*cpsr*/) { - UNIMPLEMENTED(); +void ARM_Dynarmic::SetCPSR(u32 cpsr) { + jit.SetPstate(cpsr); } -VAddr ARM_Dynarmic::GetTlsAddress() const { - UNIMPLEMENTED(); - return {}; +u64 ARM_Dynarmic::GetTlsAddress() const { + return cb->tpidrr0_el0; } -void ARM_Dynarmic::SetTlsAddress(VAddr /*address*/) { - UNIMPLEMENTED(); +void ARM_Dynarmic::SetTlsAddress(u64 address) { + cb->tpidrr0_el0 = address; } -void ARM_Dynarmic::ExecuteInstructions(int /*num_instructions*/) { - UNIMPLEMENTED(); +void ARM_Dynarmic::ExecuteInstructions(int num_instructions) { + cb->ticks_remaining = num_instructions; + jit.Run(); + CoreTiming::AddTicks(num_instructions - cb->num_interpreted_instructions); + cb->num_interpreted_instructions = 0; } -void ARM_Dynarmic::SaveContext(ARM_Interface::ThreadContext& /*ctx*/) { - UNIMPLEMENTED(); +void ARM_Dynarmic::SaveContext(ARM_Interface::ThreadContext& ctx) { + ctx.cpu_registers = jit.GetRegisters(); + ctx.sp = jit.GetSP(); + ctx.pc = jit.GetPC(); + ctx.cpsr = jit.GetPstate(); + ctx.fpu_registers = jit.GetVectors(); + ctx.fpscr = jit.GetFpcr(); + ctx.tls_address = cb->tpidrr0_el0; } -void ARM_Dynarmic::LoadContext(const ARM_Interface::ThreadContext& /*ctx*/) { - UNIMPLEMENTED(); +void ARM_Dynarmic::LoadContext(const ARM_Interface::ThreadContext& ctx) { + jit.SetRegisters(ctx.cpu_registers); + jit.SetSP(ctx.sp); + jit.SetPC(ctx.pc); + jit.SetPstate(ctx.cpsr); + jit.SetVectors(ctx.fpu_registers); + jit.SetFpcr(ctx.fpscr); + cb->tpidrr0_el0 = ctx.tls_address; } void ARM_Dynarmic::PrepareReschedule() { - UNIMPLEMENTED(); + if (jit.IsExecuting()) { + jit.HaltExecution(); + } } void ARM_Dynarmic::ClearInstructionCache() { - UNIMPLEMENTED(); + jit.ClearCache(); } void ARM_Dynarmic::PageTableChanged() { diff --git a/src/core/arm/dynarmic/arm_dynarmic.h b/src/core/arm/dynarmic/arm_dynarmic.h index c62d02ec9..947fab3f4 100644 --- a/src/core/arm/dynarmic/arm_dynarmic.h +++ b/src/core/arm/dynarmic/arm_dynarmic.h @@ -4,12 +4,18 @@ #pragma once +#include +#include #include "common/common_types.h" #include "core/arm/arm_interface.h" +#include "core/arm/unicorn/arm_unicorn.h" + +class ARM_Dynarmic_Callbacks; class ARM_Dynarmic final : public ARM_Interface { public: ARM_Dynarmic(); + ~ARM_Dynarmic(); void MapBackingMemory(VAddr address, size_t size, u8* memory, Kernel::VMAPermission perms) override; @@ -18,8 +24,8 @@ public: u64 GetPC() const override; u64 GetReg(int index) const override; void SetReg(int index, u64 value) override; - const u128& GetExtReg(int index) const override; - void SetExtReg(int index, u128& value) override; + u128 GetExtReg(int index) const override; + void SetExtReg(int index, u128 value) override; u32 GetVFPReg(int index) const override; void SetVFPReg(int index, u32 value) override; u32 GetCPSR() const override; @@ -35,4 +41,10 @@ public: void ClearInstructionCache() override; void PageTableChanged() override; + +private: + friend class ARM_Dynarmic_Callbacks; + std::unique_ptr cb; + Dynarmic::A64::Jit jit; + ARM_Unicorn inner_unicorn; }; diff --git a/src/core/arm/unicorn/arm_unicorn.cpp b/src/core/arm/unicorn/arm_unicorn.cpp index 1d15152e5..dc886a4f7 100644 --- a/src/core/arm/unicorn/arm_unicorn.cpp +++ b/src/core/arm/unicorn/arm_unicorn.cpp @@ -108,13 +108,13 @@ void ARM_Unicorn::SetReg(int regn, u64 val) { CHECKED(uc_reg_write(uc, treg, &val)); } -const u128& ARM_Unicorn::GetExtReg(int /*index*/) const { +u128 ARM_Unicorn::GetExtReg(int /*index*/) const { UNIMPLEMENTED(); static constexpr u128 res{}; return res; } -void ARM_Unicorn::SetExtReg(int /*index*/, u128& /*value*/) { +void ARM_Unicorn::SetExtReg(int /*index*/, u128 /*value*/) { UNIMPLEMENTED(); } @@ -168,10 +168,12 @@ void ARM_Unicorn::SaveContext(ARM_Interface::ThreadContext& ctx) { uregs[i] = UC_ARM64_REG_X0 + i; tregs[i] = &ctx.cpu_registers[i]; } + uregs[29] = UC_ARM64_REG_X29; + tregs[29] = (void*)&ctx.cpu_registers[29]; + uregs[30] = UC_ARM64_REG_X30; + tregs[30] = (void*)&ctx.cpu_registers[30]; - CHECKED(uc_reg_read_batch(uc, uregs, tregs, 29)); - CHECKED(uc_reg_read(uc, UC_ARM64_REG_X29, &ctx.cpu_registers[29])); - CHECKED(uc_reg_read(uc, UC_ARM64_REG_X30, &ctx.lr)); + CHECKED(uc_reg_read_batch(uc, uregs, tregs, 31)); ctx.tls_address = GetTlsAddress(); @@ -195,10 +197,12 @@ void ARM_Unicorn::LoadContext(const ARM_Interface::ThreadContext& ctx) { uregs[i] = UC_ARM64_REG_X0 + i; tregs[i] = (void*)&ctx.cpu_registers[i]; } + uregs[29] = UC_ARM64_REG_X29; + tregs[29] = (void*)&ctx.cpu_registers[29]; + uregs[30] = UC_ARM64_REG_X30; + tregs[30] = (void*)&ctx.cpu_registers[30]; - CHECKED(uc_reg_write_batch(uc, uregs, tregs, 29)); - CHECKED(uc_reg_write(uc, UC_ARM64_REG_X29, &ctx.cpu_registers[29])); - CHECKED(uc_reg_write(uc, UC_ARM64_REG_X30, &ctx.lr)); + CHECKED(uc_reg_write_batch(uc, uregs, tregs, 31)); SetTlsAddress(ctx.tls_address); diff --git a/src/core/arm/unicorn/arm_unicorn.h b/src/core/arm/unicorn/arm_unicorn.h index 90db3eb7f..81cce0721 100644 --- a/src/core/arm/unicorn/arm_unicorn.h +++ b/src/core/arm/unicorn/arm_unicorn.h @@ -9,7 +9,6 @@ #include "core/arm/arm_interface.h" class ARM_Unicorn final : public ARM_Interface { - public: ARM_Unicorn(); ~ARM_Unicorn(); @@ -19,8 +18,8 @@ public: u64 GetPC() const override; u64 GetReg(int index) const override; void SetReg(int index, u64 value) override; - const u128& GetExtReg(int index) const override; - void SetExtReg(int index, u128& value) override; + u128 GetExtReg(int index) const override; + void SetExtReg(int index, u128 value) override; u32 GetVFPReg(int index) const override; void SetVFPReg(int index, u32 value) override; u32 GetCPSR() const override; diff --git a/src/core/core.cpp b/src/core/core.cpp index 40ef58f59..0240f946b 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -6,6 +6,7 @@ #include #include "audio_core/audio_core.h" #include "common/logging/log.h" +#include "core/arm/dynarmic/arm_dynarmic.h" #include "core/arm/unicorn/arm_unicorn.h" #include "core/core.h" #include "core/core_timing.h" @@ -139,7 +140,8 @@ void System::Reschedule() { System::ResultStatus System::Init(EmuWindow* emu_window, u32 system_mode) { LOG_DEBUG(HW_Memory, "initialized OK"); - cpu_core = std::make_unique(); + // TODO: Configuration option + cpu_core = std::make_unique(); telemetry_session = std::make_unique(); CoreTiming::Init();