From b9a852b048632ba7efcbf2eea4d33f07169d551e Mon Sep 17 00:00:00 2001 From: MerryMage Date: Sun, 20 Mar 2016 02:59:31 +0000 Subject: [PATCH] JitX64: Initial implementation of JitX64 compiler --- src/core/CMakeLists.txt | 25 ++ src/core/arm/jit_x64/cond.cpp | 145 +++++++ src/core/arm/jit_x64/instructions/barrier.cpp | 13 + src/core/arm/jit_x64/instructions/branch.cpp | 16 + .../arm/jit_x64/instructions/coprocessor.cpp | 17 + .../jit_x64/instructions/data_processing.cpp | 58 +++ .../instructions/exception_generating.cpp | 15 + .../arm/jit_x64/instructions/extension.cpp | 22 ++ src/core/arm/jit_x64/instructions/hint.cpp | 13 + .../arm/jit_x64/instructions/load_store.cpp | 43 ++ src/core/arm/jit_x64/instructions/misc.cpp | 14 + .../arm/jit_x64/instructions/multiply.cpp | 43 ++ src/core/arm/jit_x64/instructions/packing.cpp | 11 + .../parallel_add_subtract_halving.cpp | 22 ++ .../parallel_add_subtract_modulo.cpp | 22 ++ .../parallel_add_subtract_saturating.cpp | 23 ++ .../arm/jit_x64/instructions/qadd_qsub.cpp | 14 + .../arm/jit_x64/instructions/reversal.cpp | 14 + .../arm/jit_x64/instructions/saturation.cpp | 14 + .../jit_x64/instructions/status_register.cpp | 16 + .../jit_x64/instructions/synchronisation.cpp | 20 + src/core/arm/jit_x64/instructions/thumb.cpp | 12 + src/core/arm/jit_x64/instructions/usad.cpp | 12 + src/core/arm/jit_x64/interpret.cpp | 73 ++++ src/core/arm/jit_x64/jit_x64.cpp | 174 +++++++++ src/core/arm/jit_x64/jit_x64.h | 368 ++++++++++++++++++ 26 files changed, 1219 insertions(+) create mode 100644 src/core/arm/jit_x64/cond.cpp create mode 100644 src/core/arm/jit_x64/instructions/barrier.cpp create mode 100644 src/core/arm/jit_x64/instructions/branch.cpp create mode 100644 src/core/arm/jit_x64/instructions/coprocessor.cpp create mode 100644 src/core/arm/jit_x64/instructions/data_processing.cpp create mode 100644 src/core/arm/jit_x64/instructions/exception_generating.cpp create mode 100644 src/core/arm/jit_x64/instructions/extension.cpp create mode 100644 src/core/arm/jit_x64/instructions/hint.cpp create mode 100644 src/core/arm/jit_x64/instructions/load_store.cpp create mode 100644 src/core/arm/jit_x64/instructions/misc.cpp create mode 100644 src/core/arm/jit_x64/instructions/multiply.cpp create mode 100644 src/core/arm/jit_x64/instructions/packing.cpp create mode 100644 src/core/arm/jit_x64/instructions/parallel_add_subtract_halving.cpp create mode 100644 src/core/arm/jit_x64/instructions/parallel_add_subtract_modulo.cpp create mode 100644 src/core/arm/jit_x64/instructions/parallel_add_subtract_saturating.cpp create mode 100644 src/core/arm/jit_x64/instructions/qadd_qsub.cpp create mode 100644 src/core/arm/jit_x64/instructions/reversal.cpp create mode 100644 src/core/arm/jit_x64/instructions/saturation.cpp create mode 100644 src/core/arm/jit_x64/instructions/status_register.cpp create mode 100644 src/core/arm/jit_x64/instructions/synchronisation.cpp create mode 100644 src/core/arm/jit_x64/instructions/thumb.cpp create mode 100644 src/core/arm/jit_x64/instructions/usad.cpp create mode 100644 src/core/arm/jit_x64/interpret.cpp create mode 100644 src/core/arm/jit_x64/jit_x64.cpp create mode 100644 src/core/arm/jit_x64/jit_x64.h diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 938524add..a824e135d 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -266,11 +266,36 @@ set(HEADERS if(ARCHITECTURE_x86_64) set(SRCS ${SRCS} + arm/jit_x64/cond.cpp + arm/jit_x64/instructions/barrier.cpp + arm/jit_x64/instructions/branch.cpp + arm/jit_x64/instructions/coprocessor.cpp + arm/jit_x64/instructions/data_processing.cpp + arm/jit_x64/instructions/exception_generating.cpp + arm/jit_x64/instructions/extension.cpp + arm/jit_x64/instructions/hint.cpp + arm/jit_x64/instructions/load_store.cpp + arm/jit_x64/instructions/misc.cpp + arm/jit_x64/instructions/usad.cpp + arm/jit_x64/instructions/packing.cpp + arm/jit_x64/instructions/reversal.cpp + arm/jit_x64/instructions/saturation.cpp + arm/jit_x64/instructions/multiply.cpp + arm/jit_x64/instructions/parallel_add_subtract_modulo.cpp + arm/jit_x64/instructions/parallel_add_subtract_saturating.cpp + arm/jit_x64/instructions/parallel_add_subtract_halving.cpp + arm/jit_x64/instructions/qadd_qsub.cpp + arm/jit_x64/instructions/synchronisation.cpp + arm/jit_x64/instructions/status_register.cpp + arm/jit_x64/instructions/thumb.cpp + arm/jit_x64/interpret.cpp + arm/jit_x64/jit_x64.cpp arm/jit_x64/reg_alloc.cpp ) set(HEADERS ${HEADERS} arm/jit_x64/common.h + arm/jit_x64/jit_x64.h arm/jit_x64/reg_alloc.h ) endif() diff --git a/src/core/arm/jit_x64/cond.cpp b/src/core/arm/jit_x64/cond.cpp new file mode 100644 index 000000000..376b27f26 --- /dev/null +++ b/src/core/arm/jit_x64/cond.cpp @@ -0,0 +1,145 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/assert.h" + +#include "core/arm/jit_x64/jit_x64.h" +#include "core/memory.h" + +namespace JitX64 { + +using namespace Gen; + +void JitX64::CondManager::Init(JitX64* jit_) { + jit = jit_; + current_cond = ConditionCode::AL; + flags_dirty = false; + current_cond_fixup = {}; +} + +void JitX64::CondManager::CompileCond(const ConditionCode new_cond) { + if (current_cond == new_cond && !flags_dirty) + return; + + if (current_cond != ConditionCode::AL && current_cond != ConditionCode::NV) { + jit->reg_alloc.FlushEverything(); + ASSERT(current_cond_fixup.ptr); + jit->code->SetJumpTarget(current_cond_fixup); + current_cond_fixup.ptr = nullptr; + } + + if (new_cond != ConditionCode::AL && new_cond != ConditionCode::NV) { + CCFlags cc; + + switch (new_cond) { + case ConditionCode::EQ: //z + jit->code->CMP(8, jit->MJitStateZFlag(), Imm8(0)); + cc = CC_E; + break; + case ConditionCode::NE: //!z + jit->code->CMP(8, jit->MJitStateZFlag(), Imm8(0)); + cc = CC_NE; + break; + case ConditionCode::CS: //c + jit->code->CMP(8, jit->MJitStateCFlag(), Imm8(0)); + cc = CC_E; + break; + case ConditionCode::CC: //!c + jit->code->CMP(8, jit->MJitStateCFlag(), Imm8(0)); + cc = CC_NE; + break; + case ConditionCode::MI: //n + jit->code->CMP(8, jit->MJitStateNFlag(), Imm8(0)); + cc = CC_E; + break; + case ConditionCode::PL: //!n + jit->code->CMP(8, jit->MJitStateNFlag(), Imm8(0)); + cc = CC_NE; + break; + case ConditionCode::VS: //v + jit->code->CMP(8, jit->MJitStateVFlag(), Imm8(0)); + cc = CC_E; + break; + case ConditionCode::VC: //!v + jit->code->CMP(8, jit->MJitStateVFlag(), Imm8(0)); + cc = CC_NE; + break; + case ConditionCode::HI: { //c & !z + const X64Reg tmp = jit->reg_alloc.AllocAndLockTemp(); + jit->code->MOVZX(64, 8, tmp, jit->MJitStateZFlag()); + jit->code->CMP(8, jit->MJitStateCFlag(), R(tmp)); + cc = CC_BE; + jit->reg_alloc.UnlockTemp(tmp); + break; + } + case ConditionCode::LS: { //!c | z + const X64Reg tmp = jit->reg_alloc.AllocAndLockTemp(); + jit->code->MOVZX(64, 8, tmp, jit->MJitStateZFlag()); + jit->code->CMP(8, jit->MJitStateCFlag(), R(tmp)); + cc = CC_A; + jit->reg_alloc.UnlockTemp(tmp); + break; + } + case ConditionCode::GE: { // n == v + const X64Reg tmp = jit->reg_alloc.AllocAndLockTemp(); + jit->code->MOVZX(64, 8, tmp, jit->MJitStateVFlag()); + jit->code->CMP(8, jit->MJitStateNFlag(), R(tmp)); + cc = CC_NE; + jit->reg_alloc.UnlockTemp(tmp); + break; + } + case ConditionCode::LT: { // n != v + const X64Reg tmp = jit->reg_alloc.AllocAndLockTemp(); + jit->code->MOVZX(64, 8, tmp, jit->MJitStateVFlag()); + jit->code->CMP(8, jit->MJitStateNFlag(), R(tmp)); + cc = CC_E; + jit->reg_alloc.UnlockTemp(tmp); + break; + } + case ConditionCode::GT: { // !z & (n == v) + const X64Reg tmp = jit->reg_alloc.AllocAndLockTemp(); + jit->code->MOVZX(64, 8, tmp, jit->MJitStateNFlag()); + jit->code->XOR(8, R(tmp), jit->MJitStateVFlag()); + jit->code->OR(8, R(tmp), jit->MJitStateZFlag()); + jit->code->TEST(8, R(tmp), R(tmp)); + cc = CC_NZ; + jit->reg_alloc.UnlockTemp(tmp); + break; + } + case ConditionCode::LE: { // z | (n != v) + X64Reg tmp = jit->reg_alloc.AllocAndLockTemp(); + jit->code->MOVZX(64, 8, tmp, jit->MJitStateNFlag()); + jit->code->XOR(8, R(tmp), jit->MJitStateVFlag()); + jit->code->OR(8, R(tmp), jit->MJitStateZFlag()); + jit->code->TEST(8, R(tmp), R(tmp)); + cc = CC_Z; + jit->reg_alloc.UnlockTemp(tmp); + break; + } + default: + UNREACHABLE(); + break; + } + + jit->reg_alloc.FlushEverything(); + this->current_cond_fixup = jit->code->J_CC(cc, true); + } + + current_cond = new_cond; + flags_dirty = false; +} + +void JitX64::CondManager::Always() { + CompileCond(ConditionCode::AL); +} + +void JitX64::CondManager::FlagsDirty() { + flags_dirty = true; +} + +ConditionCode JitX64::CondManager::CurrentCond() { + return current_cond; +} + +} diff --git a/src/core/arm/jit_x64/instructions/barrier.cpp b/src/core/arm/jit_x64/instructions/barrier.cpp new file mode 100644 index 000000000..8034bb181 --- /dev/null +++ b/src/core/arm/jit_x64/instructions/barrier.cpp @@ -0,0 +1,13 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/arm/jit_x64/jit_x64.h" + +namespace JitX64 { + +void JitX64::DMB() { CompileInterpretInstruction(); } +void JitX64::DSB() { CompileInterpretInstruction(); } +void JitX64::ISB() { CompileInterpretInstruction(); } + +} diff --git a/src/core/arm/jit_x64/instructions/branch.cpp b/src/core/arm/jit_x64/instructions/branch.cpp new file mode 100644 index 000000000..f08128da6 --- /dev/null +++ b/src/core/arm/jit_x64/instructions/branch.cpp @@ -0,0 +1,16 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/arm/jit_x64/jit_x64.h" + +namespace JitX64 { + +void JitX64::B(Cond cond, ArmImm24 imm24) { CompileInterpretInstruction(); } +void JitX64::BL(Cond cond, ArmImm24 imm24) { CompileInterpretInstruction(); } +void JitX64::BLX_imm(bool H, ArmImm24 imm24) { CompileInterpretInstruction(); } +void JitX64::BLX_reg(Cond cond, ArmReg Rm) { CompileInterpretInstruction(); } +void JitX64::BX(Cond cond, ArmReg Rm) { CompileInterpretInstruction(); } +void JitX64::BXJ(Cond cond, ArmReg Rm) { CompileInterpretInstruction(); } + +} diff --git a/src/core/arm/jit_x64/instructions/coprocessor.cpp b/src/core/arm/jit_x64/instructions/coprocessor.cpp new file mode 100644 index 000000000..8531bd027 --- /dev/null +++ b/src/core/arm/jit_x64/instructions/coprocessor.cpp @@ -0,0 +1,17 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/arm/jit_x64/jit_x64.h" + +namespace JitX64 { + +void JitX64::CDP() { CompileInterpretInstruction(); } +void JitX64::LDC() { CompileInterpretInstruction(); } +void JitX64::MCR() { CompileInterpretInstruction(); } +void JitX64::MCRR() { CompileInterpretInstruction(); } +void JitX64::MRC() { CompileInterpretInstruction(); } +void JitX64::MRRC() { CompileInterpretInstruction(); } +void JitX64::STC() { CompileInterpretInstruction(); } + +} diff --git a/src/core/arm/jit_x64/instructions/data_processing.cpp b/src/core/arm/jit_x64/instructions/data_processing.cpp new file mode 100644 index 000000000..3d2346b6e --- /dev/null +++ b/src/core/arm/jit_x64/instructions/data_processing.cpp @@ -0,0 +1,58 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/arm/jit_x64/jit_x64.h" + +namespace JitX64 { + +void JitX64::ADC_imm(Cond cond, bool S, ArmReg Rn, ArmReg Rd, int rotate, ArmImm8 imm8) { CompileInterpretInstruction(); } +void JitX64::ADC_reg(Cond cond, bool S, ArmReg Rn, ArmReg Rd, ArmImm5 imm5, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } +void JitX64::ADC_rsr(Cond cond, bool S, ArmReg Rn, ArmReg Rd, ArmReg Rs, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } +void JitX64::ADD_imm(Cond cond, bool S, ArmReg Rn, ArmReg Rd, int rotate, ArmImm8 imm8) { CompileInterpretInstruction(); } +void JitX64::ADD_reg(Cond cond, bool S, ArmReg Rn, ArmReg Rd, ArmImm5 imm5, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } +void JitX64::ADD_rsr(Cond cond, bool S, ArmReg Rn, ArmReg Rd, ArmReg Rs, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } +void JitX64::AND_imm(Cond cond, bool S, ArmReg Rn, ArmReg Rd, int rotate, ArmImm8 imm8) { CompileInterpretInstruction(); } +void JitX64::AND_reg(Cond cond, bool S, ArmReg Rn, ArmReg Rd, ArmImm5 imm5, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } +void JitX64::AND_rsr(Cond cond, bool S, ArmReg Rn, ArmReg Rd, ArmReg Rs, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } +void JitX64::BIC_imm(Cond cond, bool S, ArmReg Rn, ArmReg Rd, int rotate, ArmImm8 imm8) { CompileInterpretInstruction(); } +void JitX64::BIC_reg(Cond cond, bool S, ArmReg Rn, ArmReg Rd, ArmImm5 imm5, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } +void JitX64::BIC_rsr(Cond cond, bool S, ArmReg Rn, ArmReg Rd, ArmReg Rs, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } +void JitX64::CMN_imm(Cond cond, ArmReg Rn, int rotate, ArmImm8 imm8) { CompileInterpretInstruction(); } +void JitX64::CMN_reg(Cond cond, ArmReg Rn, ArmImm5 imm5, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } +void JitX64::CMN_rsr(Cond cond, ArmReg Rn, ArmReg Rs, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } +void JitX64::CMP_imm(Cond cond, ArmReg Rn, int rotate, ArmImm8 imm8) { CompileInterpretInstruction(); } +void JitX64::CMP_reg(Cond cond, ArmReg Rn, ArmImm5 imm5, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } +void JitX64::CMP_rsr(Cond cond, ArmReg Rn, ArmReg Rs, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } +void JitX64::EOR_imm(Cond cond, bool S, ArmReg Rn, ArmReg Rd, int rotate, ArmImm8 imm8) { CompileInterpretInstruction(); } +void JitX64::EOR_reg(Cond cond, bool S, ArmReg Rn, ArmReg Rd, ArmImm5 imm5, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } +void JitX64::EOR_rsr(Cond cond, bool S, ArmReg Rn, ArmReg Rd, ArmReg Rs, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } +void JitX64::MOV_imm(Cond cond, bool S, ArmReg Rd, int rotate, ArmImm8 imm8) { CompileInterpretInstruction(); } +void JitX64::MOV_reg(Cond cond, bool S, ArmReg Rd, ArmImm5 imm5, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } +void JitX64::MOV_rsr(Cond cond, bool S, ArmReg Rd, ArmReg Rs, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } +void JitX64::MVN_imm(Cond cond, bool S, ArmReg Rd, int rotate, ArmImm8 imm8) { CompileInterpretInstruction(); } +void JitX64::MVN_reg(Cond cond, bool S, ArmReg Rd, ArmImm5 imm5, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } +void JitX64::MVN_rsr(Cond cond, bool S, ArmReg Rd, ArmReg Rs, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } +void JitX64::ORR_imm(Cond cond, bool S, ArmReg Rn, ArmReg Rd, int rotate, ArmImm8 imm8) { CompileInterpretInstruction(); } +void JitX64::ORR_reg(Cond cond, bool S, ArmReg Rn, ArmReg Rd, ArmImm5 imm5, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } +void JitX64::ORR_rsr(Cond cond, bool S, ArmReg Rn, ArmReg Rd, ArmReg Rs, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } +void JitX64::RSB_imm(Cond cond, bool S, ArmReg Rn, ArmReg Rd, int rotate, ArmImm8 imm8) { CompileInterpretInstruction(); } +void JitX64::RSB_reg(Cond cond, bool S, ArmReg Rn, ArmReg Rd, ArmImm5 imm5, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } +void JitX64::RSB_rsr(Cond cond, bool S, ArmReg Rn, ArmReg Rd, ArmReg Rs, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } +void JitX64::RSC_imm(Cond cond, bool S, ArmReg Rn, ArmReg Rd, int rotate, ArmImm8 imm8) { CompileInterpretInstruction(); } +void JitX64::RSC_reg(Cond cond, bool S, ArmReg Rn, ArmReg Rd, ArmImm5 imm5, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } +void JitX64::RSC_rsr(Cond cond, bool S, ArmReg Rn, ArmReg Rd, ArmReg Rs, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } +void JitX64::SBC_imm(Cond cond, bool S, ArmReg Rn, ArmReg Rd, int rotate, ArmImm8 imm8) { CompileInterpretInstruction(); } +void JitX64::SBC_reg(Cond cond, bool S, ArmReg Rn, ArmReg Rd, ArmImm5 imm5, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } +void JitX64::SBC_rsr(Cond cond, bool S, ArmReg Rn, ArmReg Rd, ArmReg Rs, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } +void JitX64::SUB_imm(Cond cond, bool S, ArmReg Rn, ArmReg Rd, int rotate, ArmImm8 imm8) { CompileInterpretInstruction(); } +void JitX64::SUB_reg(Cond cond, bool S, ArmReg Rn, ArmReg Rd, ArmImm5 imm5, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } +void JitX64::SUB_rsr(Cond cond, bool S, ArmReg Rn, ArmReg Rd, ArmReg Rs, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } +void JitX64::TEQ_imm(Cond cond, ArmReg Rn, int rotate, ArmImm8 imm8) { CompileInterpretInstruction(); } +void JitX64::TEQ_reg(Cond cond, ArmReg Rn, ArmImm5 imm5, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } +void JitX64::TEQ_rsr(Cond cond, ArmReg Rn, ArmReg Rs, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } +void JitX64::TST_imm(Cond cond, ArmReg Rn, int rotate, ArmImm8 imm8) { CompileInterpretInstruction(); } +void JitX64::TST_reg(Cond cond, ArmReg Rn, ArmImm5 imm5, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } +void JitX64::TST_rsr(Cond cond, ArmReg Rn, ArmReg Rs, ShiftType shift, ArmReg Rm) { CompileInterpretInstruction(); } + +} diff --git a/src/core/arm/jit_x64/instructions/exception_generating.cpp b/src/core/arm/jit_x64/instructions/exception_generating.cpp new file mode 100644 index 000000000..111ee3263 --- /dev/null +++ b/src/core/arm/jit_x64/instructions/exception_generating.cpp @@ -0,0 +1,15 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/arm/jit_x64/jit_x64.h" + +namespace JitX64 { + +void JitX64::BKPT() { CompileInterpretInstruction(); } +void JitX64::HVC() { CompileInterpretInstruction(); } +void JitX64::SMC() { CompileInterpretInstruction(); } +void JitX64::SVC() { CompileInterpretInstruction(); } +void JitX64::UDF() { CompileInterpretInstruction(); } + +} diff --git a/src/core/arm/jit_x64/instructions/extension.cpp b/src/core/arm/jit_x64/instructions/extension.cpp new file mode 100644 index 000000000..f5a3d1faf --- /dev/null +++ b/src/core/arm/jit_x64/instructions/extension.cpp @@ -0,0 +1,22 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/arm/jit_x64/jit_x64.h" + +namespace JitX64 { + +void JitX64::SXTAB() { CompileInterpretInstruction(); } +void JitX64::SXTAB16() { CompileInterpretInstruction(); } +void JitX64::SXTAH() { CompileInterpretInstruction(); } +void JitX64::SXTB() { CompileInterpretInstruction(); } +void JitX64::SXTB16() { CompileInterpretInstruction(); } +void JitX64::SXTH() { CompileInterpretInstruction(); } +void JitX64::UXTAB() { CompileInterpretInstruction(); } +void JitX64::UXTAB16() { CompileInterpretInstruction(); } +void JitX64::UXTAH() { CompileInterpretInstruction(); } +void JitX64::UXTB() { CompileInterpretInstruction(); } +void JitX64::UXTB16() { CompileInterpretInstruction(); } +void JitX64::UXTH() { CompileInterpretInstruction(); } + +} diff --git a/src/core/arm/jit_x64/instructions/hint.cpp b/src/core/arm/jit_x64/instructions/hint.cpp new file mode 100644 index 000000000..101bd1c38 --- /dev/null +++ b/src/core/arm/jit_x64/instructions/hint.cpp @@ -0,0 +1,13 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/arm/jit_x64/jit_x64.h" + +namespace JitX64 { + +void JitX64::DBG() { CompileInterpretInstruction(); } +void JitX64::PLD() { CompileInterpretInstruction(); } +void JitX64::PLI() { CompileInterpretInstruction(); } + +} diff --git a/src/core/arm/jit_x64/instructions/load_store.cpp b/src/core/arm/jit_x64/instructions/load_store.cpp new file mode 100644 index 000000000..6b069fd93 --- /dev/null +++ b/src/core/arm/jit_x64/instructions/load_store.cpp @@ -0,0 +1,43 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/arm/jit_x64/jit_x64.h" + +namespace JitX64 { + +// Load/Store instructions +void JitX64::LDR_imm() { CompileInterpretInstruction(); } +void JitX64::LDR_reg() { CompileInterpretInstruction(); } +void JitX64::LDRB_imm() { CompileInterpretInstruction(); } +void JitX64::LDRB_reg() { CompileInterpretInstruction(); } +void JitX64::LDRBT() { CompileInterpretInstruction(); } +void JitX64::LDRD_imm() { CompileInterpretInstruction(); } +void JitX64::LDRD_reg() { CompileInterpretInstruction(); } +void JitX64::LDRH_imm() { CompileInterpretInstruction(); } +void JitX64::LDRH_reg() { CompileInterpretInstruction(); } +void JitX64::LDRHT() { CompileInterpretInstruction(); } +void JitX64::LDRSB_imm() { CompileInterpretInstruction(); } +void JitX64::LDRSB_reg() { CompileInterpretInstruction(); } +void JitX64::LDRSBT() { CompileInterpretInstruction(); } +void JitX64::LDRSH_imm() { CompileInterpretInstruction(); } +void JitX64::LDRSH_reg() { CompileInterpretInstruction(); } +void JitX64::LDRSHT() { CompileInterpretInstruction(); } +void JitX64::LDRT() { CompileInterpretInstruction(); } +void JitX64::STR_imm() { CompileInterpretInstruction(); } +void JitX64::STR_reg() { CompileInterpretInstruction(); } +void JitX64::STRB_imm() { CompileInterpretInstruction(); } +void JitX64::STRB_reg() { CompileInterpretInstruction(); } +void JitX64::STRBT() { CompileInterpretInstruction(); } +void JitX64::STRD_imm() { CompileInterpretInstruction(); } +void JitX64::STRD_reg() { CompileInterpretInstruction(); } +void JitX64::STRH_imm() { CompileInterpretInstruction(); } +void JitX64::STRH_reg() { CompileInterpretInstruction(); } +void JitX64::STRHT() { CompileInterpretInstruction(); } +void JitX64::STRT() { CompileInterpretInstruction(); } + +// Load/Store multiple instructions +void JitX64::LDM() { CompileInterpretInstruction(); } +void JitX64::STM() { CompileInterpretInstruction(); } + +} diff --git a/src/core/arm/jit_x64/instructions/misc.cpp b/src/core/arm/jit_x64/instructions/misc.cpp new file mode 100644 index 000000000..85fb3a1a8 --- /dev/null +++ b/src/core/arm/jit_x64/instructions/misc.cpp @@ -0,0 +1,14 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/arm/jit_x64/jit_x64.h" + +namespace JitX64 { + +void JitX64::CLZ() { CompileInterpretInstruction(); } +void JitX64::ERET() { CompileInterpretInstruction(); } +void JitX64::NOP() { CompileInterpretInstruction(); } +void JitX64::SEL() { CompileInterpretInstruction(); } + +} diff --git a/src/core/arm/jit_x64/instructions/multiply.cpp b/src/core/arm/jit_x64/instructions/multiply.cpp new file mode 100644 index 000000000..86b23fb90 --- /dev/null +++ b/src/core/arm/jit_x64/instructions/multiply.cpp @@ -0,0 +1,43 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/arm/jit_x64/jit_x64.h" + +namespace JitX64 { + +// Multiply (Normal) instructions +void JitX64::MLA() { CompileInterpretInstruction(); } +void JitX64::MLS() { CompileInterpretInstruction(); } +void JitX64::MUL() { CompileInterpretInstruction(); } + +// Multiply (Long) instructions +void JitX64::SMLAL() { CompileInterpretInstruction(); } +void JitX64::SMULL() { CompileInterpretInstruction(); } +void JitX64::UMAAL() { CompileInterpretInstruction(); } +void JitX64::UMLAL() { CompileInterpretInstruction(); } +void JitX64::UMULL() { CompileInterpretInstruction(); } + +// Multiply (Halfword) instructions +void JitX64::SMLALxy() { CompileInterpretInstruction(); } +void JitX64::SMLAxy() { CompileInterpretInstruction(); } +void JitX64::SMULxy() { CompileInterpretInstruction(); } + +// Multiply (word by halfword) instructions +void JitX64::SMLAWy() { CompileInterpretInstruction(); } +void JitX64::SMULWy() { CompileInterpretInstruction(); } + +// Multiply (Most significant word) instructions +void JitX64::SMMLA() { CompileInterpretInstruction(); } +void JitX64::SMMLS() { CompileInterpretInstruction(); } +void JitX64::SMMUL() { CompileInterpretInstruction(); } + +// Multiply (Dual) instructions +void JitX64::SMLAD() { CompileInterpretInstruction(); } +void JitX64::SMLALD() { CompileInterpretInstruction(); } +void JitX64::SMLSD() { CompileInterpretInstruction(); } +void JitX64::SMLSLD() { CompileInterpretInstruction(); } +void JitX64::SMUAD() { CompileInterpretInstruction(); } +void JitX64::SMUSD() { CompileInterpretInstruction(); } + +} diff --git a/src/core/arm/jit_x64/instructions/packing.cpp b/src/core/arm/jit_x64/instructions/packing.cpp new file mode 100644 index 000000000..097b0e1ae --- /dev/null +++ b/src/core/arm/jit_x64/instructions/packing.cpp @@ -0,0 +1,11 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/arm/jit_x64/jit_x64.h" + +namespace JitX64 { + +void JitX64::PKH() { CompileInterpretInstruction(); } + +} diff --git a/src/core/arm/jit_x64/instructions/parallel_add_subtract_halving.cpp b/src/core/arm/jit_x64/instructions/parallel_add_subtract_halving.cpp new file mode 100644 index 000000000..f3e6e1f54 --- /dev/null +++ b/src/core/arm/jit_x64/instructions/parallel_add_subtract_halving.cpp @@ -0,0 +1,22 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/arm/jit_x64/jit_x64.h" + +namespace JitX64 { + +void JitX64::SHADD8() { CompileInterpretInstruction(); } +void JitX64::SHADD16() { CompileInterpretInstruction(); } +void JitX64::SHASX() { CompileInterpretInstruction(); } +void JitX64::SHSAX() { CompileInterpretInstruction(); } +void JitX64::SHSUB8() { CompileInterpretInstruction(); } +void JitX64::SHSUB16() { CompileInterpretInstruction(); } +void JitX64::UHADD8() { CompileInterpretInstruction(); } +void JitX64::UHADD16() { CompileInterpretInstruction(); } +void JitX64::UHASX() { CompileInterpretInstruction(); } +void JitX64::UHSAX() { CompileInterpretInstruction(); } +void JitX64::UHSUB8() { CompileInterpretInstruction(); } +void JitX64::UHSUB16() { CompileInterpretInstruction(); } + +} diff --git a/src/core/arm/jit_x64/instructions/parallel_add_subtract_modulo.cpp b/src/core/arm/jit_x64/instructions/parallel_add_subtract_modulo.cpp new file mode 100644 index 000000000..096fe64d0 --- /dev/null +++ b/src/core/arm/jit_x64/instructions/parallel_add_subtract_modulo.cpp @@ -0,0 +1,22 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/arm/jit_x64/jit_x64.h" + +namespace JitX64 { + +void JitX64::SADD8() { CompileInterpretInstruction(); } +void JitX64::SADD16() { CompileInterpretInstruction(); } +void JitX64::SASX() { CompileInterpretInstruction(); } +void JitX64::SSAX() { CompileInterpretInstruction(); } +void JitX64::SSUB8() { CompileInterpretInstruction(); } +void JitX64::SSUB16() { CompileInterpretInstruction(); } +void JitX64::UADD8() { CompileInterpretInstruction(); } +void JitX64::UADD16() { CompileInterpretInstruction(); } +void JitX64::UASX() { CompileInterpretInstruction(); } +void JitX64::USAX() { CompileInterpretInstruction(); } +void JitX64::USUB8() { CompileInterpretInstruction(); } +void JitX64::USUB16() { CompileInterpretInstruction(); } + +} diff --git a/src/core/arm/jit_x64/instructions/parallel_add_subtract_saturating.cpp b/src/core/arm/jit_x64/instructions/parallel_add_subtract_saturating.cpp new file mode 100644 index 000000000..bc816f7dc --- /dev/null +++ b/src/core/arm/jit_x64/instructions/parallel_add_subtract_saturating.cpp @@ -0,0 +1,23 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/arm/jit_x64/jit_x64.h" + +namespace JitX64 { + +void JitX64::QADD8() { CompileInterpretInstruction(); } +void JitX64::QADD16() { CompileInterpretInstruction(); } +void JitX64::QASX() { CompileInterpretInstruction(); } +void JitX64::QSAX() { CompileInterpretInstruction(); } +void JitX64::QSUB8() { CompileInterpretInstruction(); } +void JitX64::QSUB16() { CompileInterpretInstruction(); } +void JitX64::UQADD8() { CompileInterpretInstruction(); } +void JitX64::UQADD16() { CompileInterpretInstruction(); } +void JitX64::UQASX() { CompileInterpretInstruction(); } +void JitX64::UQSAX() { CompileInterpretInstruction(); } +void JitX64::UQSUB8() { CompileInterpretInstruction(); } +void JitX64::UQSUB16() { CompileInterpretInstruction(); } + + +} diff --git a/src/core/arm/jit_x64/instructions/qadd_qsub.cpp b/src/core/arm/jit_x64/instructions/qadd_qsub.cpp new file mode 100644 index 000000000..47ba82a49 --- /dev/null +++ b/src/core/arm/jit_x64/instructions/qadd_qsub.cpp @@ -0,0 +1,14 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/arm/jit_x64/jit_x64.h" + +namespace JitX64 { + +void JitX64::QADD() { CompileInterpretInstruction(); } +void JitX64::QSUB() { CompileInterpretInstruction(); } +void JitX64::QDADD() { CompileInterpretInstruction(); } +void JitX64::QDSUB() { CompileInterpretInstruction(); } + +} diff --git a/src/core/arm/jit_x64/instructions/reversal.cpp b/src/core/arm/jit_x64/instructions/reversal.cpp new file mode 100644 index 000000000..5021f23f8 --- /dev/null +++ b/src/core/arm/jit_x64/instructions/reversal.cpp @@ -0,0 +1,14 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/arm/jit_x64/jit_x64.h" + +namespace JitX64 { + +void JitX64::RBIT() { CompileInterpretInstruction(); } +void JitX64::REV() { CompileInterpretInstruction(); } +void JitX64::REV16() { CompileInterpretInstruction(); } +void JitX64::REVSH() { CompileInterpretInstruction(); } + +} diff --git a/src/core/arm/jit_x64/instructions/saturation.cpp b/src/core/arm/jit_x64/instructions/saturation.cpp new file mode 100644 index 000000000..0dffa1912 --- /dev/null +++ b/src/core/arm/jit_x64/instructions/saturation.cpp @@ -0,0 +1,14 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/arm/jit_x64/jit_x64.h" + +namespace JitX64 { + +void JitX64::SSAT() { CompileInterpretInstruction(); } +void JitX64::SSAT16() { CompileInterpretInstruction(); } +void JitX64::USAT() { CompileInterpretInstruction(); } +void JitX64::USAT16() { CompileInterpretInstruction(); } + +} diff --git a/src/core/arm/jit_x64/instructions/status_register.cpp b/src/core/arm/jit_x64/instructions/status_register.cpp new file mode 100644 index 000000000..e1707e042 --- /dev/null +++ b/src/core/arm/jit_x64/instructions/status_register.cpp @@ -0,0 +1,16 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/arm/jit_x64/jit_x64.h" + +namespace JitX64 { + +void JitX64::CPS() { CompileInterpretInstruction(); } +void JitX64::MRS() { CompileInterpretInstruction(); } +void JitX64::MSR() { CompileInterpretInstruction(); } +void JitX64::RFE() { CompileInterpretInstruction(); } +void JitX64::SETEND() { CompileInterpretInstruction(); } +void JitX64::SRS() { CompileInterpretInstruction(); } + +} diff --git a/src/core/arm/jit_x64/instructions/synchronisation.cpp b/src/core/arm/jit_x64/instructions/synchronisation.cpp new file mode 100644 index 000000000..f164b28df --- /dev/null +++ b/src/core/arm/jit_x64/instructions/synchronisation.cpp @@ -0,0 +1,20 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/arm/jit_x64/jit_x64.h" + +namespace JitX64 { + +void JitX64::CLREX() { CompileInterpretInstruction(); } +void JitX64::LDREX() { CompileInterpretInstruction(); } +void JitX64::LDREXB() { CompileInterpretInstruction(); } +void JitX64::LDREXD() { CompileInterpretInstruction(); } +void JitX64::LDREXH() { CompileInterpretInstruction(); } +void JitX64::STREX() { CompileInterpretInstruction(); } +void JitX64::STREXB() { CompileInterpretInstruction(); } +void JitX64::STREXD() { CompileInterpretInstruction(); } +void JitX64::STREXH() { CompileInterpretInstruction(); } +void JitX64::SWP() { CompileInterpretInstruction(); } + +} \ No newline at end of file diff --git a/src/core/arm/jit_x64/instructions/thumb.cpp b/src/core/arm/jit_x64/instructions/thumb.cpp new file mode 100644 index 000000000..27a81e04b --- /dev/null +++ b/src/core/arm/jit_x64/instructions/thumb.cpp @@ -0,0 +1,12 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/arm/jit_x64/jit_x64.h" + +namespace JitX64 { + +void JitX64::thumb_BLX_prefix(ArmImm11 imm11) { CompileInterpretInstruction(); } +void JitX64::thumb_BLX_suffix(bool L, ArmImm11 imm11) { CompileInterpretInstruction(); } + +} diff --git a/src/core/arm/jit_x64/instructions/usad.cpp b/src/core/arm/jit_x64/instructions/usad.cpp new file mode 100644 index 000000000..262573709 --- /dev/null +++ b/src/core/arm/jit_x64/instructions/usad.cpp @@ -0,0 +1,12 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/arm/jit_x64/jit_x64.h" + +namespace JitX64 { + +void JitX64::USAD8() { CompileInterpretInstruction(); } +void JitX64::USADA8() { CompileInterpretInstruction(); } + +} diff --git a/src/core/arm/jit_x64/interpret.cpp b/src/core/arm/jit_x64/interpret.cpp new file mode 100644 index 000000000..5684b8b81 --- /dev/null +++ b/src/core/arm/jit_x64/interpret.cpp @@ -0,0 +1,73 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/x64/abi.h" + +#include "core/arm/jit_x64/jit_x64.h" + +extern unsigned InterpreterMainLoop(ARMul_State* cpu); + +namespace JitX64 { + +using namespace Gen; + +static JitState* CallInterpreter(JitState* jit_state, u64 pc, u64 TFlag, u64 EFlag) { + ARMul_State* cpu = &jit_state->cpu_state; + + cpu->Reg[15] = pc; + + cpu->Cpsr = (cpu->Cpsr & 0x0fffffdf) | + (cpu->NFlag << 31) | + (cpu->ZFlag << 30) | + (cpu->CFlag << 29) | + (cpu->VFlag << 28) | + (cpu->TFlag << 5); + + if (jit_state->cycles_remaining > 0) { +#if 0 + cpu->NumInstrsToExecute = jit_state->cycles_remaining; + if (cpu->NumInstrsToExecute > 100) cpu->NumInstrsToExecute = 100; + jit_state->cycles_remaining -= InterpreterMainLoop(cpu); +#else + cpu->NumInstrsToExecute = 1; + jit_state->cycles_remaining -= InterpreterMainLoop(cpu); +#endif + } + + return jit_state; +} + +void JitX64::CompileInterpretInstruction() { + cond_manager.Always(); + reg_alloc.FlushEverything(); + + CompileUpdateCycles(); + + ASSERT(reg_alloc.JitStateReg() != RSP); + code->MOV(64, R(RSP), MJitStateHostReturnRSP()); + code->MOV(64, R(Gen::ABI_PARAM1), R(reg_alloc.JitStateReg())); + code->MOV(64, R(Gen::ABI_PARAM2), Imm64(current.arm_pc)); + code->MOV(64, R(Gen::ABI_PARAM3), Imm64(current.TFlag)); + code->MOV(64, R(Gen::ABI_PARAM4), Imm64(current.EFlag)); + + const void *const fn = &CallInterpreter; + + const u64 distance = reinterpret_cast(fn) - (reinterpret_cast(code->GetCodePtr()) + 5); + if (distance >= 0x0000000080000000ULL && distance < 0xFFFFFFFF80000000ULL) { + // Far call + code->MOV(64, R(RAX), ImmPtr(fn)); + code->CALLptr(R(RAX)); + } else { + code->CALL(fn); + } + + code->MOV(64, R(reg_alloc.JitStateReg()), R(Gen::ABI_RETURN)); + + // Return to dispatch + code->JMPptr(MJitStateHostReturnRIP()); + + stop_compilation = true; +} + +} diff --git a/src/core/arm/jit_x64/jit_x64.cpp b/src/core/arm/jit_x64/jit_x64.cpp new file mode 100644 index 000000000..aab4829fa --- /dev/null +++ b/src/core/arm/jit_x64/jit_x64.cpp @@ -0,0 +1,174 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/arm/jit_x64/jit_x64.h" +#include "core/memory.h" + +namespace JitX64 { + +using namespace Gen; + +JitX64::JitX64(XEmitter* code_) : code(code_) {} + +CodePtr JitX64::GetBB(u32 pc, bool TFlag, bool EFlag) { + const LocationDescriptor desc = { pc, TFlag, EFlag }; + + if (basic_blocks.find(desc) == basic_blocks.end()) { + return Compile(pc, TFlag, EFlag); + } + + return basic_blocks[desc]; +} + +CodePtr JitX64::Compile(u32 pc, bool TFlag, bool EFlag) { + const CodePtr bb = code->GetWritableCodePtr(); + const LocationDescriptor desc = { pc, TFlag, EFlag }; + ASSERT(basic_blocks.find(desc) == basic_blocks.end()); + basic_blocks[desc] = bb; + Patch(desc, bb); + + reg_alloc.Init(code); + cond_manager.Init(this); + current = desc; + instructions_compiled = 0; + stop_compilation = false; + + do { + instructions_compiled++; + + if (current.TFlag) { + CompileSingleThumbInstruction(); + } else { + CompileSingleArmInstruction(); + } + } while (!stop_compilation && ((current.arm_pc & 0xFFF) != 0)); + + if (!stop_compilation) { + // We're stopping compilation because we've reached a page boundary. + cond_manager.Always(); + CompileUpdateCycles(); + CompileJumpToBB(current.arm_pc); + } + + // Insert easily searchable byte sequence for ease of lookup in memory dumps. + code->NOP(); + code->INT3(); + code->NOP(); + + return bb; +} + +void JitX64::CompileUpdateCycles() { + // We're just taking one instruction == one cycle. + if (instructions_compiled) { + code->SUB(32, MJitStateCycleCount(), Imm32(instructions_compiled)); + } + instructions_compiled = 0; +} + +void JitX64::CompileJumpToBB(u32 new_pc) { + ASSERT(instructions_compiled == 0); + + reg_alloc.FlushEverything(); + code->CMP(32, MJitStateCycleCount(), Imm8(0)); + + const LocationDescriptor new_desc = { new_pc, current.TFlag, current.EFlag }; + patch_jmp_locations[new_desc].emplace_back(code->GetWritableCodePtr()); + if (basic_blocks.find(new_desc) == basic_blocks.end()) { + code->NOP(6); // Leave enough space for a jg instruction. + } else { + code->J_CC(CC_G, basic_blocks[new_desc], true); + } + + code->MOV(32, MJitStateArmPC(), Imm32(new_pc)); + code->JMPptr(MJitStateHostReturnRIP()); +} + +void JitX64::Patch(LocationDescriptor desc, CodePtr bb) { + const CodePtr save_code_ptr = code->GetWritableCodePtr(); + + for (CodePtr location : patch_jmp_locations[desc]) { + code->SetCodePtr(location); + code->J_CC(CC_G, bb, true); + ASSERT(code->GetCodePtr() - location == 6); + } + + code->SetCodePtr(save_code_ptr); +} + +void JitX64::CompileSingleArmInstruction() { + u32 inst = Memory::Read32(current.arm_pc & 0xFFFFFFFC); + + ArmDecoder::DecodeArm(inst).Visit(this, inst); +} + +void JitX64::CompileSingleThumbInstruction() { + u32 inst_u32 = Memory::Read32(current.arm_pc & 0xFFFFFFFC); + if ((current.arm_pc & 0x3) != 0) { + inst_u32 >>= 16; + } + inst_u32 &= 0xFFFFF; + u16 inst = inst_u32; + + ArmDecoder::DecodeThumb(inst).Visit(this, inst); +} + +// Convenience functions: +// We static_assert types because anything that calls these functions makes those assumptions. +// If the types of the variables are changed please update all code that calls these functions. + +Gen::OpArg JitX64::MJitStateCycleCount() { + static_assert(std::is_same::value, "JitState::cycles_remaining must be s32"); + + return Gen::MDisp(reg_alloc.JitStateReg(), offsetof(JitState, cycles_remaining)); +} + +Gen::OpArg JitX64::MJitStateArmPC() { + static_assert(std::is_same::value, "JitState::cpu_state must be ARMul_State"); + static_assert(std::is_same>::value, "ARMul_State::Reg must be std::array"); + + return Gen::MDisp(reg_alloc.JitStateReg(), offsetof(JitState, cpu_state) + offsetof(ARMul_State, Reg) + 15 * sizeof(u32)); +} + +Gen::OpArg JitX64::MJitStateHostReturnRIP() { + static_assert(std::is_same::value, "JitState::return_RIP must be u64"); + + return Gen::MDisp(reg_alloc.JitStateReg(), offsetof(JitState, return_RIP)); +} + +Gen::OpArg JitX64::MJitStateHostReturnRSP() { + static_assert(std::is_same::value, "JitState::save_host_RSP must be u64"); + + return Gen::MDisp(reg_alloc.JitStateReg(), offsetof(JitState, save_host_RSP)); +} + +Gen::OpArg JitX64::MJitStateZFlag() { + static_assert(std::is_same::value, "JitState::cpu_state must be ARMul_State"); + static_assert(std::is_same::value, "ZFlag must be u32"); + + return Gen::MDisp(reg_alloc.JitStateReg(), offsetof(JitState, cpu_state) + offsetof(ARMul_State, ZFlag)); +} + +Gen::OpArg JitX64::MJitStateCFlag() { + static_assert(std::is_same::value, "JitState::cpu_state must be ARMul_State"); + static_assert(std::is_same::value, "CFlag must be u32"); + + return Gen::MDisp(reg_alloc.JitStateReg(), offsetof(JitState, cpu_state) + offsetof(ARMul_State, CFlag)); +} + +Gen::OpArg JitX64::MJitStateNFlag() { + static_assert(std::is_same::value, "JitState::cpu_state must be ARMul_State"); + static_assert(std::is_same::value, "NFlag must be u32"); + + return Gen::MDisp(reg_alloc.JitStateReg(), offsetof(JitState, cpu_state) + offsetof(ARMul_State, NFlag)); +} + +Gen::OpArg JitX64::MJitStateVFlag() { + static_assert(std::is_same::value, "JitState::cpu_state must be ARMul_State"); + static_assert(std::is_same::value, "VFlag must be u32"); + + return Gen::MDisp(reg_alloc.JitStateReg(), offsetof(JitState, cpu_state) + offsetof(ARMul_State, VFlag)); +} + +} diff --git a/src/core/arm/jit_x64/jit_x64.h b/src/core/arm/jit_x64/jit_x64.h new file mode 100644 index 000000000..fe4d3bb4e --- /dev/null +++ b/src/core/arm/jit_x64/jit_x64.h @@ -0,0 +1,368 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include + +#include "common/common_types.h" +#include "common/x64/emitter.h" + +#include "core/arm/decoder/decoder.h" +#include "core/arm/jit_x64/common.h" +#include "core/arm/jit_x64/reg_alloc.h" + +namespace JitX64 { + +using CodePtr = u8*; + +struct LocationDescriptor { + u32 arm_pc; + bool TFlag; ///< Thumb / ARM + bool EFlag; ///< Big / Little Endian + + bool operator == (const LocationDescriptor& o) const { + return std::tie(arm_pc, TFlag, EFlag) == std::tie(o.arm_pc, o.TFlag, o.EFlag); + } +}; + +struct LocationDescriptorHash { + size_t operator()(const LocationDescriptor& x) const { + return std::hash()((u64)x.arm_pc ^ ((u64)x.TFlag << 32) ^ ((u64)x.EFlag << 33)); + } +}; + +class JitX64 final : private ArmDecoder::Visitor { +private: + Gen::XEmitter* code; + + RegAlloc reg_alloc; + + /// ARM pc -> x64 code block + std::unordered_map basic_blocks; + +public: + JitX64() = delete; + JitX64(Gen::XEmitter* code_); + virtual ~JitX64() override {} + + CodePtr GetBB(u32 pc, bool TFlag, bool EFlag); + + /// Returns a pointer to the compiled basic block. + CodePtr Compile(u32 pc, bool TFlag, bool EFlag); + +private: + LocationDescriptor current; + unsigned instructions_compiled; + bool stop_compilation; + + size_t GetInstSize() { return current.TFlag ? 2 : 4; } + void CompileSingleArmInstruction(); + void CompileSingleThumbInstruction(); + + /// Updates the cycle count in JitState and sets instructions_compiled to zero. + void CompileUpdateCycles(); + + /// If a basic_block starting at ARM pc is compiled -> these locations need to be patched + std::unordered_map, LocationDescriptorHash> patch_jmp_locations; + /// Update JitState cycle count before calling this function. This function may instead update JitState PC and return to dispatcher. + void CompileJumpToBB(u32 arm_pc); + /// Patch missing jumps (fill in after CompileJumpToBB). + void Patch(LocationDescriptor desc, CodePtr bb); + +private: + /// Convenience functions + Gen::OpArg MJitStateCycleCount(); + Gen::OpArg MJitStateArmPC(); + Gen::OpArg MJitStateHostReturnRIP(); + Gen::OpArg MJitStateHostReturnRSP(); + Gen::OpArg MJitStateZFlag(); + Gen::OpArg MJitStateCFlag(); + Gen::OpArg MJitStateNFlag(); + Gen::OpArg MJitStateVFlag(); + +private: + struct CondManager { + private: + JitX64* jit; + ConditionCode current_cond; + bool flags_dirty; + Gen::FixupBranch current_cond_fixup; + public: + void Init(JitX64* jit_); + void CompileCond(ConditionCode cond); + void Always(); + void FlagsDirty(); + ConditionCode CurrentCond(); + } cond_manager; + +private: + void CompileInterpretInstruction(); + + // Barrier instructions + virtual void DMB() override; + virtual void DSB() override; + virtual void ISB() override; + + // Branch instructions + virtual void B(Cond cond, ArmImm24 imm24) override; + virtual void BL(Cond cond, ArmImm24 imm24) override; + virtual void BLX_imm(bool H, ArmImm24 imm24) override; + virtual void BLX_reg(Cond cond, ArmReg Rm) override; + virtual void BX(Cond cond, ArmReg Rm) override; + virtual void BXJ(Cond cond, ArmReg Rm) override; + + // Coprocessor instructions + virtual void CDP() override; + virtual void LDC() override; + virtual void MCR() override; + virtual void MCRR() override; + virtual void MRC() override; + virtual void MRRC() override; + virtual void STC() override; + + // Data processing instructions + virtual void ADC_imm(Cond cond, bool S, ArmReg Rn, ArmReg Rd, int rotate, ArmImm8 imm8) override; + virtual void ADC_reg(Cond cond, bool S, ArmReg Rn, ArmReg Rd, ArmImm5 imm5, ShiftType shift, ArmReg Rm) override; + virtual void ADC_rsr(Cond cond, bool S, ArmReg Rn, ArmReg Rd, ArmReg Rs, ShiftType shift, ArmReg Rm) override; + virtual void ADD_imm(Cond cond, bool S, ArmReg Rn, ArmReg Rd, int rotate, ArmImm8 imm8) override; + virtual void ADD_reg(Cond cond, bool S, ArmReg Rn, ArmReg Rd, ArmImm5 imm5, ShiftType shift, ArmReg Rm) override; + virtual void ADD_rsr(Cond cond, bool S, ArmReg Rn, ArmReg Rd, ArmReg Rs, ShiftType shift, ArmReg Rm) override; + virtual void AND_imm(Cond cond, bool S, ArmReg Rn, ArmReg Rd, int rotate, ArmImm8 imm8) override; + virtual void AND_reg(Cond cond, bool S, ArmReg Rn, ArmReg Rd, ArmImm5 imm5, ShiftType shift, ArmReg Rm) override; + virtual void AND_rsr(Cond cond, bool S, ArmReg Rn, ArmReg Rd, ArmReg Rs, ShiftType shift, ArmReg Rm) override; + virtual void BIC_imm(Cond cond, bool S, ArmReg Rn, ArmReg Rd, int rotate, ArmImm8 imm8) override; + virtual void BIC_reg(Cond cond, bool S, ArmReg Rn, ArmReg Rd, ArmImm5 imm5, ShiftType shift, ArmReg Rm) override; + virtual void BIC_rsr(Cond cond, bool S, ArmReg Rn, ArmReg Rd, ArmReg Rs, ShiftType shift, ArmReg Rm) override; + virtual void CMN_imm(Cond cond, ArmReg Rn, int rotate, ArmImm8 imm8) override; + virtual void CMN_reg(Cond cond, ArmReg Rn, ArmImm5 imm5, ShiftType shift, ArmReg Rm) override; + virtual void CMN_rsr(Cond cond, ArmReg Rn, ArmReg Rs, ShiftType shift, ArmReg Rm) override; + virtual void CMP_imm(Cond cond, ArmReg Rn, int rotate, ArmImm8 imm8) override; + virtual void CMP_reg(Cond cond, ArmReg Rn, ArmImm5 imm5, ShiftType shift, ArmReg Rm) override; + virtual void CMP_rsr(Cond cond, ArmReg Rn, ArmReg Rs, ShiftType shift, ArmReg Rm) override; + virtual void EOR_imm(Cond cond, bool S, ArmReg Rn, ArmReg Rd, int rotate, ArmImm8 imm8) override; + virtual void EOR_reg(Cond cond, bool S, ArmReg Rn, ArmReg Rd, ArmImm5 imm5, ShiftType shift, ArmReg Rm) override; + virtual void EOR_rsr(Cond cond, bool S, ArmReg Rn, ArmReg Rd, ArmReg Rs, ShiftType shift, ArmReg Rm) override; + virtual void MOV_imm(Cond cond, bool S, ArmReg Rd, int rotate, ArmImm8 imm8) override; + virtual void MOV_reg(Cond cond, bool S, ArmReg Rd, ArmImm5 imm5, ShiftType shift, ArmReg Rm) override; + virtual void MOV_rsr(Cond cond, bool S, ArmReg Rd, ArmReg Rs, ShiftType shift, ArmReg Rm) override; + virtual void MVN_imm(Cond cond, bool S, ArmReg Rd, int rotate, ArmImm8 imm8) override; + virtual void MVN_reg(Cond cond, bool S, ArmReg Rd, ArmImm5 imm5, ShiftType shift, ArmReg Rm) override; + virtual void MVN_rsr(Cond cond, bool S, ArmReg Rd, ArmReg Rs, ShiftType shift, ArmReg Rm) override; + virtual void ORR_imm(Cond cond, bool S, ArmReg Rn, ArmReg Rd, int rotate, ArmImm8 imm8) override; + virtual void ORR_reg(Cond cond, bool S, ArmReg Rn, ArmReg Rd, ArmImm5 imm5, ShiftType shift, ArmReg Rm) override; + virtual void ORR_rsr(Cond cond, bool S, ArmReg Rn, ArmReg Rd, ArmReg Rs, ShiftType shift, ArmReg Rm) override; + virtual void RSB_imm(Cond cond, bool S, ArmReg Rn, ArmReg Rd, int rotate, ArmImm8 imm8) override; + virtual void RSB_reg(Cond cond, bool S, ArmReg Rn, ArmReg Rd, ArmImm5 imm5, ShiftType shift, ArmReg Rm) override; + virtual void RSB_rsr(Cond cond, bool S, ArmReg Rn, ArmReg Rd, ArmReg Rs, ShiftType shift, ArmReg Rm) override; + virtual void RSC_imm(Cond cond, bool S, ArmReg Rn, ArmReg Rd, int rotate, ArmImm8 imm8) override; + virtual void RSC_reg(Cond cond, bool S, ArmReg Rn, ArmReg Rd, ArmImm5 imm5, ShiftType shift, ArmReg Rm) override; + virtual void RSC_rsr(Cond cond, bool S, ArmReg Rn, ArmReg Rd, ArmReg Rs, ShiftType shift, ArmReg Rm) override; + virtual void SBC_imm(Cond cond, bool S, ArmReg Rn, ArmReg Rd, int rotate, ArmImm8 imm8) override; + virtual void SBC_reg(Cond cond, bool S, ArmReg Rn, ArmReg Rd, ArmImm5 imm5, ShiftType shift, ArmReg Rm) override; + virtual void SBC_rsr(Cond cond, bool S, ArmReg Rn, ArmReg Rd, ArmReg Rs, ShiftType shift, ArmReg Rm) override; + virtual void SUB_imm(Cond cond, bool S, ArmReg Rn, ArmReg Rd, int rotate, ArmImm8 imm8) override; + virtual void SUB_reg(Cond cond, bool S, ArmReg Rn, ArmReg Rd, ArmImm5 imm5, ShiftType shift, ArmReg Rm) override; + virtual void SUB_rsr(Cond cond, bool S, ArmReg Rn, ArmReg Rd, ArmReg Rs, ShiftType shift, ArmReg Rm) override; + virtual void TEQ_imm(Cond cond, ArmReg Rn, int rotate, ArmImm8 imm8) override; + virtual void TEQ_reg(Cond cond, ArmReg Rn, ArmImm5 imm5, ShiftType shift, ArmReg Rm) override; + virtual void TEQ_rsr(Cond cond, ArmReg Rn, ArmReg Rs, ShiftType shift, ArmReg Rm) override; + virtual void TST_imm(Cond cond, ArmReg Rn, int rotate, ArmImm8 imm8) override; + virtual void TST_reg(Cond cond, ArmReg Rn, ArmImm5 imm5, ShiftType shift, ArmReg Rm) override; + virtual void TST_rsr(Cond cond, ArmReg Rn, ArmReg Rs, ShiftType shift, ArmReg Rm) override; + + // Exception generation instructions + virtual void BKPT() override; + virtual void HVC() override; + virtual void SMC() override; + virtual void SVC() override; + virtual void UDF() override; + + // Extension functions + virtual void SXTAB() override; + virtual void SXTAB16() override; + virtual void SXTAH() override; + virtual void SXTB() override; + virtual void SXTB16() override; + virtual void SXTH() override; + virtual void UXTAB() override; + virtual void UXTAB16() override; + virtual void UXTAH() override; + virtual void UXTB() override; + virtual void UXTB16() override; + virtual void UXTH() override; + + // Hint instructions + virtual void DBG() override; + virtual void PLD() override; + virtual void PLI() override; + + // Load/Store instructions + virtual void LDR_imm() override; + virtual void LDR_reg() override; + virtual void LDRB_imm() override; + virtual void LDRB_reg() override; + virtual void LDRBT() override; + virtual void LDRD_imm() override; + virtual void LDRD_reg() override; + virtual void LDRH_imm() override; + virtual void LDRH_reg() override; + virtual void LDRHT() override; + virtual void LDRSB_imm() override; + virtual void LDRSB_reg() override; + virtual void LDRSBT() override; + virtual void LDRSH_imm() override; + virtual void LDRSH_reg() override; + virtual void LDRSHT() override; + virtual void LDRT() override; + virtual void STR_imm() override; + virtual void STR_reg() override; + virtual void STRB_imm() override; + virtual void STRB_reg() override; + virtual void STRBT() override; + virtual void STRD_imm() override; + virtual void STRD_reg() override; + virtual void STRH_imm() override; + virtual void STRH_reg() override; + virtual void STRHT() override; + virtual void STRT() override; + + // Load/Store multiple instructions + virtual void LDM() override; + virtual void STM() override; + + // Miscellaneous instructions + virtual void CLZ() override; + virtual void ERET() override; + virtual void NOP() override; + virtual void SEL() override; + + // Unsigned sum of absolute difference functions + virtual void USAD8() override; + virtual void USADA8() override; + + // Packing instructions + virtual void PKH() override; + + // Reversal instructions + virtual void RBIT() override; + virtual void REV() override; + virtual void REV16() override; + virtual void REVSH() override; + + // Saturation instructions + virtual void SSAT() override; + virtual void SSAT16() override; + virtual void USAT() override; + virtual void USAT16() override; + + // Multiply (Normal) instructions + virtual void MLA() override; + virtual void MLS() override; + virtual void MUL() override; + + // Multiply (Long) instructions + virtual void SMLAL() override; + virtual void SMULL() override; + virtual void UMAAL() override; + virtual void UMLAL() override; + virtual void UMULL() override; + + // Multiply (Halfword) instructions + virtual void SMLALxy() override; + virtual void SMLAxy() override; + virtual void SMULxy() override; + + // Multiply (word by halfword) instructions + virtual void SMLAWy() override; + virtual void SMULWy() override; + + // Multiply (Most significant word) instructions + virtual void SMMLA() override; + virtual void SMMLS() override; + virtual void SMMUL() override; + + // Multiply (Dual) instructions + virtual void SMLAD() override; + virtual void SMLALD() override; + virtual void SMLSD() override; + virtual void SMLSLD() override; + virtual void SMUAD() override; + virtual void SMUSD() override; + + // Parallel Add/Subtract (Modulo arithmetic) instructions + virtual void SADD8() override; + virtual void SADD16() override; + virtual void SASX() override; + virtual void SSAX() override; + virtual void SSUB8() override; + virtual void SSUB16() override; + virtual void UADD8() override; + virtual void UADD16() override; + virtual void UASX() override; + virtual void USAX() override; + virtual void USUB8() override; + virtual void USUB16() override; + + // Parallel Add/Subtract (Saturating) instructions + virtual void QADD8() override; + virtual void QADD16() override; + virtual void QASX() override; + virtual void QSAX() override; + virtual void QSUB8() override; + virtual void QSUB16() override; + virtual void UQADD8() override; + virtual void UQADD16() override; + virtual void UQASX() override; + virtual void UQSAX() override; + virtual void UQSUB8() override; + virtual void UQSUB16() override; + + // Parallel Add/Subtract (Halving) instructions + virtual void SHADD8() override; + virtual void SHADD16() override; + virtual void SHASX() override; + virtual void SHSAX() override; + virtual void SHSUB8() override; + virtual void SHSUB16() override; + virtual void UHADD8() override; + virtual void UHADD16() override; + virtual void UHASX() override; + virtual void UHSAX() override; + virtual void UHSUB8() override; + virtual void UHSUB16() override; + + // Saturated Add/Subtract instructions + virtual void QADD() override; + virtual void QSUB() override; + virtual void QDADD() override; + virtual void QDSUB() override; + + // Synchronization Primitive instructions + virtual void CLREX() override; + virtual void LDREX() override; + virtual void LDREXB() override; + virtual void LDREXD() override; + virtual void LDREXH() override; + virtual void STREX() override; + virtual void STREXB() override; + virtual void STREXD() override; + virtual void STREXH() override; + virtual void SWP() override; + + // Status register access instructions + virtual void CPS() override; + virtual void MRS() override; + virtual void MSR() override; + virtual void RFE() override; + virtual void SETEND() override; + virtual void SRS() override; + + // Thumb specific instructions + virtual void thumb_BLX_prefix(ArmImm11 imm11) override; + virtual void thumb_BLX_suffix(bool L, ArmImm11 imm11) override; +}; + +}