From 25dfc94cb419f61fd30634ac45cf58e7f3742a31 Mon Sep 17 00:00:00 2001 From: MerryMage Date: Sun, 20 Mar 2016 03:04:02 +0000 Subject: [PATCH] JitX64: Implement ARM_Jit ARM_Jit is the ARM_Interface for the x64 recompiler. --- src/core/CMakeLists.txt | 2 + src/core/arm/jit_x64/interface.cpp | 225 +++++++++++++++++++++++++++++ src/core/arm/jit_x64/interface.h | 50 +++++++ 3 files changed, 277 insertions(+) create mode 100644 src/core/arm/jit_x64/interface.cpp create mode 100644 src/core/arm/jit_x64/interface.h diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index a824e135d..f9c31662c 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -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 ) diff --git a/src/core/arm/jit_x64/interface.cpp b/src/core/arm/jit_x64/interface.cpp new file mode 100644 index 000000000..bf4844145 --- /dev/null +++ b/src/core/arm/jit_x64/interface.cpp @@ -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(); +} + +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(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(); +} + +} diff --git a/src/core/arm/jit_x64/interface.h b/src/core/arm/jit_x64/interface.h new file mode 100644 index 000000000..4d91309fe --- /dev/null +++ b/src/core/arm/jit_x64/interface.h @@ -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 + +#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 state; +}; + +}