mirror of
https://github.com/citra-emu/citra.git
synced 2024-11-25 11:30:13 +00:00
JitX64: Implement ARM_Jit
ARM_Jit is the ARM_Interface for the x64 recompiler.
This commit is contained in:
parent
4f012099a0
commit
25dfc94cb4
@ -288,6 +288,7 @@ if(ARCHITECTURE_x86_64)
|
|||||||
arm/jit_x64/instructions/synchronisation.cpp
|
arm/jit_x64/instructions/synchronisation.cpp
|
||||||
arm/jit_x64/instructions/status_register.cpp
|
arm/jit_x64/instructions/status_register.cpp
|
||||||
arm/jit_x64/instructions/thumb.cpp
|
arm/jit_x64/instructions/thumb.cpp
|
||||||
|
arm/jit_x64/interface.cpp
|
||||||
arm/jit_x64/interpret.cpp
|
arm/jit_x64/interpret.cpp
|
||||||
arm/jit_x64/jit_x64.cpp
|
arm/jit_x64/jit_x64.cpp
|
||||||
arm/jit_x64/reg_alloc.cpp
|
arm/jit_x64/reg_alloc.cpp
|
||||||
@ -295,6 +296,7 @@ if(ARCHITECTURE_x86_64)
|
|||||||
|
|
||||||
set(HEADERS ${HEADERS}
|
set(HEADERS ${HEADERS}
|
||||||
arm/jit_x64/common.h
|
arm/jit_x64/common.h
|
||||||
|
arm/jit_x64/interface.h
|
||||||
arm/jit_x64/jit_x64.h
|
arm/jit_x64/jit_x64.h
|
||||||
arm/jit_x64/reg_alloc.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;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user