JitX64: Implement ARM_Jit

ARM_Jit is the ARM_Interface for the x64 recompiler.
This commit is contained in:
MerryMage 2016-03-20 03:04:02 +00:00
parent 4f012099a0
commit 25dfc94cb4
3 changed files with 277 additions and 0 deletions

View File

@ -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
)

View 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();
}
}

View 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;
};
}