JitX64: Implement ARM_Jit
ARM_Jit is the ARM_Interface for the x64 recompiler.
This commit is contained in:
		| @@ -288,6 +288,7 @@ if(ARCHITECTURE_x86_64) | ||||
|             arm/jit_x64/instructions/synchronisation.cpp | ||||
|             arm/jit_x64/instructions/status_register.cpp | ||||
|             arm/jit_x64/instructions/thumb.cpp | ||||
|             arm/jit_x64/interface.cpp | ||||
|             arm/jit_x64/interpret.cpp | ||||
|             arm/jit_x64/jit_x64.cpp | ||||
|             arm/jit_x64/reg_alloc.cpp | ||||
| @@ -295,6 +296,7 @@ if(ARCHITECTURE_x86_64) | ||||
|  | ||||
|     set(HEADERS ${HEADERS} | ||||
|             arm/jit_x64/common.h | ||||
|             arm/jit_x64/interface.h | ||||
|             arm/jit_x64/jit_x64.h | ||||
|             arm/jit_x64/reg_alloc.h | ||||
|             ) | ||||
|   | ||||
							
								
								
									
										225
									
								
								src/core/arm/jit_x64/interface.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										225
									
								
								src/core/arm/jit_x64/interface.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,225 @@ | ||||
|  | ||||
| // Copyright 2016 Citra Emulator Project | ||||
| // Licensed under GPLv2 or any later version | ||||
| // Refer to the license.txt file included. | ||||
|  | ||||
| #include "common/assert.h" | ||||
| #include "common/x64/abi.h" | ||||
| #include "common/x64/emitter.h" | ||||
|  | ||||
| #include "core/arm/jit_x64/common.h" | ||||
| #include "core/arm/jit_x64/interface.h" | ||||
| #include "core/arm/jit_x64/jit_x64.h" | ||||
| #include "core/core.h" | ||||
| #include "core/core_timing.h" | ||||
|  | ||||
| namespace Gen { | ||||
|  | ||||
| struct RunJittedCode final : private Gen::XCodeBlock { | ||||
| private: | ||||
|     const u8* run_jit; | ||||
|     const u8* return_from_run_jit; | ||||
|  | ||||
| public: | ||||
|     RunJittedCode() { | ||||
|         AllocCodeSpace(1024); | ||||
|  | ||||
|         run_jit = this->GetCodePtr(); | ||||
|  | ||||
|         ABI_PushRegistersAndAdjustStack(ABI_ALL_CALLEE_SAVED, 8); | ||||
|  | ||||
|         MOV(64, MDisp(ABI_PARAM1, offsetof(JitX64::JitState, save_host_RSP)), R(RSP)); | ||||
|         MOV(64, R(R15), R(ABI_PARAM1)); | ||||
|  | ||||
|         JMPptr(R(ABI_PARAM2)); | ||||
|         return_from_run_jit = this->GetCodePtr(); | ||||
|  | ||||
|         MOV(64, R(RSP), MDisp(R15, offsetof(JitX64::JitState, save_host_RSP))); | ||||
|         ABI_PopRegistersAndAdjustStack(ABI_ALL_CALLEE_SAVED, 8); | ||||
|         RET(); | ||||
|     } | ||||
|  | ||||
|     unsigned CallCode(JitX64::JitState* jit_state, void* bb, unsigned cycles_to_run, u32& new_pc) { | ||||
|         auto cpu = &jit_state->cpu_state; | ||||
|  | ||||
|         cpu->NFlag = (cpu->Cpsr >> 31); | ||||
|         cpu->ZFlag = (cpu->Cpsr >> 30) & 1; | ||||
|         cpu->CFlag = (cpu->Cpsr >> 29) & 1; | ||||
|         cpu->VFlag = (cpu->Cpsr >> 28) & 1; | ||||
|         cpu->TFlag = (cpu->Cpsr >> 5) & 1; | ||||
|  | ||||
|         jit_state->bb = bb; | ||||
|         jit_state->cycles_remaining = cycles_to_run; | ||||
|         jit_state->return_RIP = (u64)CallCodeReturnAddress(); | ||||
|  | ||||
|         auto fn = (void(*)(u64, void*))run_jit; | ||||
|         fn((u64)jit_state, bb); | ||||
|  | ||||
|         new_pc = cpu->Reg[15]; | ||||
|  | ||||
|         cpu->Cpsr = (cpu->Cpsr & 0x0fffffdf) | | ||||
|                     (cpu->NFlag << 31) | | ||||
|                     (cpu->ZFlag << 30) | | ||||
|                     (cpu->CFlag << 29) | | ||||
|                     (cpu->VFlag << 28) | | ||||
|                     (cpu->TFlag << 5); | ||||
|  | ||||
|         return cycles_to_run - jit_state->cycles_remaining; | ||||
|     } | ||||
|  | ||||
|     const u8* CallCodeReturnAddress() { | ||||
|         return return_from_run_jit; | ||||
|     } | ||||
| }; | ||||
|  | ||||
| struct BlockOfCode : Gen::XCodeBlock { | ||||
|     BlockOfCode() { | ||||
|         AllocCodeSpace(1024 * 1024 * 1024); | ||||
|     } | ||||
| }; | ||||
|  | ||||
| } | ||||
|  | ||||
| namespace JitX64 { | ||||
|  | ||||
| static Gen::RunJittedCode run_jit = {}; | ||||
| static Gen::BlockOfCode block_of_code = {}; | ||||
| static JitX64 compiler = { &block_of_code }; | ||||
|  | ||||
| ARM_Jit::ARM_Jit(PrivilegeMode initial_mode) { | ||||
|     ASSERT_MSG(initial_mode == PrivilegeMode::USER32MODE, "Unimplemented"); | ||||
|     state = std::make_unique<JitState>(); | ||||
| } | ||||
|  | ||||
| ARM_Jit::~ARM_Jit() { | ||||
| } | ||||
|  | ||||
| void ARM_Jit::SetPC(u32 pc) { | ||||
|     state->cpu_state.Reg[15] = pc; | ||||
| } | ||||
|  | ||||
| u32 ARM_Jit::GetPC() const { | ||||
|     return state->cpu_state.Reg[15]; | ||||
| } | ||||
|  | ||||
| u32 ARM_Jit::GetReg(int index) const { | ||||
|     if (index == 15) return GetPC(); | ||||
|     return state->cpu_state.Reg[index]; | ||||
| } | ||||
|  | ||||
| void ARM_Jit::SetReg(int index, u32 value) { | ||||
|     if (index == 15) return SetPC(value); | ||||
|     state->cpu_state.Reg[index] = value; | ||||
| } | ||||
|  | ||||
| u32 ARM_Jit::GetVFPReg(int index) const { | ||||
|     return state->cpu_state.ExtReg[index]; | ||||
| } | ||||
|  | ||||
| void ARM_Jit::SetVFPReg(int index, u32 value) { | ||||
|     state->cpu_state.ExtReg[index] = value; | ||||
| } | ||||
|  | ||||
| u32 ARM_Jit::GetVFPSystemReg(VFPSystemRegister reg) const { | ||||
|     return state->cpu_state.VFP[reg]; | ||||
| } | ||||
|  | ||||
| void ARM_Jit::SetVFPSystemReg(VFPSystemRegister reg, u32 value) { | ||||
|     state->cpu_state.VFP[reg] = value; | ||||
| } | ||||
|  | ||||
| u32 ARM_Jit::GetCPSR() const { | ||||
|     return state->cpu_state.Cpsr; | ||||
| } | ||||
|  | ||||
| void ARM_Jit::SetCPSR(u32 cpsr) { | ||||
|     state->cpu_state.Cpsr = cpsr; | ||||
| } | ||||
|  | ||||
| u32 ARM_Jit::GetCP15Register(CP15Register reg) { | ||||
|     return state->cpu_state.CP15[reg]; | ||||
| } | ||||
|  | ||||
| void ARM_Jit::SetCP15Register(CP15Register reg, u32 value) { | ||||
|     state->cpu_state.CP15[reg] = value; | ||||
| } | ||||
|  | ||||
| void ARM_Jit::AddTicks(u64 ticks) { | ||||
|     down_count -= ticks; | ||||
|     if (down_count < 0) | ||||
|         CoreTiming::Advance(); | ||||
| } | ||||
|  | ||||
| void ARM_Jit::ExecuteInstructions(int num_instructions) { | ||||
|     reschedule = false; | ||||
|  | ||||
|     do { | ||||
|         //state->page_table = reinterpret_cast<void*>(Memory::current_page_table->pointers.data()); | ||||
|  | ||||
|         state->cpu_state.TFlag = (state->cpu_state.Cpsr >> 5) & 1; | ||||
|  | ||||
|         if (!state->cpu_state.NirqSig) { | ||||
|             UNIMPLEMENTED(); | ||||
|         } | ||||
|  | ||||
|         if (state->cpu_state.TFlag) | ||||
|             state->cpu_state.Reg[15] &= 0xfffffffe; | ||||
|         else | ||||
|             state->cpu_state.Reg[15] &= 0xfffffffc; | ||||
|  | ||||
|         u8 *ptr = compiler.GetBB(state->cpu_state.Reg[15], state->cpu_state.TFlag, false); | ||||
|  | ||||
|         unsigned ticks_executed = run_jit.CallCode(state.get(), ptr, num_instructions, state->cpu_state.Reg[15]); | ||||
|         num_instructions -= ticks_executed; | ||||
|         AddTicks(ticks_executed); | ||||
|     } while (!reschedule && num_instructions > 0); | ||||
| } | ||||
|  | ||||
| void ARM_Jit::ResetContext(Core::ThreadContext& context, u32 stack_top, u32 entry_point, u32 arg) { | ||||
|     memset(&context, 0, sizeof(Core::ThreadContext)); | ||||
|  | ||||
|     context.cpu_registers[0] = arg; | ||||
|     context.pc = entry_point; | ||||
|     context.sp = stack_top; | ||||
|     context.cpsr = 0x1F; // Usermode | ||||
| } | ||||
|  | ||||
| void ARM_Jit::SaveContext(Core::ThreadContext& ctx) { | ||||
|     memcpy(ctx.cpu_registers, state->cpu_state.Reg.data(), sizeof(ctx.cpu_registers)); | ||||
|     memcpy(ctx.fpu_registers, state->cpu_state.ExtReg.data(), sizeof(ctx.fpu_registers)); | ||||
|  | ||||
|     ctx.sp = state->cpu_state.Reg[13]; | ||||
|     ctx.lr = state->cpu_state.Reg[14]; | ||||
|     ctx.pc = state->cpu_state.Reg[15]; | ||||
|  | ||||
|     ctx.cpsr = GetCPSR(); | ||||
|  | ||||
|     ctx.fpscr = state->cpu_state.VFP[1]; | ||||
|     ctx.fpexc = state->cpu_state.VFP[2]; | ||||
| } | ||||
|  | ||||
| void ARM_Jit::LoadContext(const Core::ThreadContext& ctx) { | ||||
|     memcpy(state->cpu_state.Reg.data(), ctx.cpu_registers, sizeof(ctx.cpu_registers)); | ||||
|     memcpy(state->cpu_state.ExtReg.data(), ctx.fpu_registers, sizeof(ctx.fpu_registers)); | ||||
|  | ||||
|     state->cpu_state.Reg[13] = ctx.sp; | ||||
|     state->cpu_state.Reg[14] = ctx.lr; | ||||
|     state->cpu_state.Reg[15] = ctx.pc; | ||||
|     SetCPSR(ctx.cpsr); | ||||
|  | ||||
|     state->cpu_state.VFP[1] = ctx.fpscr; | ||||
|     state->cpu_state.VFP[2] = ctx.fpexc; | ||||
| } | ||||
|  | ||||
| void ARM_Jit::PrepareReschedule() { | ||||
|     reschedule = true; | ||||
|     state->cpu_state.NumInstrsToExecute = 0; | ||||
| } | ||||
|  | ||||
| void ARM_Jit::ClearCache() { | ||||
|     UNIMPLEMENTED(); | ||||
|     // compiler.ClearCache(); | ||||
|     this->state->cpu_state.instruction_cache.clear(); | ||||
| } | ||||
|  | ||||
| } | ||||
							
								
								
									
										50
									
								
								src/core/arm/jit_x64/interface.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								src/core/arm/jit_x64/interface.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,50 @@ | ||||
| // Copyright 2016 Citra Emulator Project | ||||
| // Licensed under GPLv2 or any later version | ||||
| // Refer to the license.txt file included. | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include <memory> | ||||
|  | ||||
| #include "common/common_types.h" | ||||
|  | ||||
| #include "core/arm/arm_interface.h" | ||||
| #include "core/arm/jit_x64/common.h" | ||||
|  | ||||
| namespace JitX64 { | ||||
|  | ||||
| class ARM_Jit final : virtual public ARM_Interface { | ||||
| public: | ||||
|     ARM_Jit(PrivilegeMode initial_mode); | ||||
|     ~ARM_Jit(); | ||||
|  | ||||
|     void SetPC(u32 pc) override; | ||||
|     u32 GetPC() const override; | ||||
|     u32 GetReg(int index) const override; | ||||
|     void SetReg(int index, u32 value) override; | ||||
|     u32 GetVFPReg(int index) const override; | ||||
|     void SetVFPReg(int index, u32 value) override; | ||||
|     u32 GetVFPSystemReg(VFPSystemRegister reg) const override; | ||||
|     void SetVFPSystemReg(VFPSystemRegister reg, u32 value) override; | ||||
|     u32 GetCPSR() const override; | ||||
|     void SetCPSR(u32 cpsr) override; | ||||
|     u32 GetCP15Register(CP15Register reg) override; | ||||
|     void SetCP15Register(CP15Register reg, u32 value) override; | ||||
|  | ||||
|     void AddTicks(u64 ticks) override; | ||||
|  | ||||
|     void ResetContext(Core::ThreadContext& context, u32 stack_top, u32 entry_point, u32 arg) override; | ||||
|     void SaveContext(Core::ThreadContext& ctx) override; | ||||
|     void LoadContext(const Core::ThreadContext& ctx) override; | ||||
|  | ||||
|     void PrepareReschedule() override; | ||||
|     void ExecuteInstructions(int num_instructions) override; | ||||
|  | ||||
|     void ClearCache(); | ||||
|  | ||||
| private: | ||||
|     bool reschedule; | ||||
|     std::unique_ptr<JitState> state; | ||||
| }; | ||||
|  | ||||
| } | ||||
		Reference in New Issue
	
	Block a user
	 MerryMage
					MerryMage