mirror of
				https://git.tardis.systems/mirrors/yuzu
				synced 2025-10-31 18:54:14 +01:00 
			
		
		
		
	arm_dynarmic: Implement core
This commit is contained in:
		
							parent
							
								
									056f987bcd
								
							
						
					
					
						commit
						d2fbc78320
					
				
							
								
								
									
										10
									
								
								externals/CMakeLists.txt
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										10
									
								
								externals/CMakeLists.txt
									
									
									
									
										vendored
									
									
								
							| @ -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() | ||||
|  | ||||
							
								
								
									
										2
									
								
								externals/dynarmic
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
								
							
						
						
									
										2
									
								
								externals/dynarmic
									
									
									
									
										vendored
									
									
								
							| @ -1 +1 @@ | ||||
| Subproject commit 305fba50babf736d77b71c5a44dd6b0ccb7f9d10 | ||||
| Subproject commit a5caa7cd8d5741d34dcf0b3447b5f1c3f7333d56 | ||||
| @ -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 + ") "; | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -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) | ||||
|  | ||||
| @ -4,6 +4,7 @@ | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <array> | ||||
| #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<u64, 31> cpu_registers; | ||||
|         u64 sp; | ||||
|         u64 pc; | ||||
|         u64 cpsr; | ||||
|         u128 fpu_registers[32]; | ||||
|         std::array<u128, 32> 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 | ||||
|  | ||||
| @ -2,43 +2,114 @@ | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #include <memory> | ||||
| #include <dynarmic/A64/a64.h> | ||||
| #include <dynarmic/A64/config.h> | ||||
| #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<ARM_Dynarmic_Callbacks>(*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() { | ||||
|  | ||||
| @ -4,12 +4,18 @@ | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <memory> | ||||
| #include <dynarmic/A64/a64.h> | ||||
| #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<ARM_Dynarmic_Callbacks> cb; | ||||
|     Dynarmic::A64::Jit jit; | ||||
|     ARM_Unicorn inner_unicorn; | ||||
| }; | ||||
|  | ||||
| @ -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); | ||||
| 
 | ||||
|  | ||||
| @ -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; | ||||
|  | ||||
| @ -6,6 +6,7 @@ | ||||
| #include <utility> | ||||
| #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<ARM_Unicorn>(); | ||||
|     // TODO: Configuration option
 | ||||
|     cpu_core = std::make_unique<ARM_Dynarmic>(); | ||||
|     telemetry_session = std::make_unique<Core::TelemetrySession>(); | ||||
| 
 | ||||
|     CoreTiming::Init(); | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user