mirror of
https://github.com/citra-emu/citra.git
synced 2024-11-25 05:10:15 +00:00
JitX64: Implement synchronisation instructions
This commit is contained in:
parent
8bd590ed99
commit
1f8217a09b
@ -295,6 +295,7 @@ if(ARCHITECTURE_x86_64)
|
||||
|
||||
set(HEADERS ${HEADERS}
|
||||
arm/jit_x64/common.h
|
||||
arm/jit_x64/instructions/helper/load_store.h
|
||||
arm/jit_x64/interface.h
|
||||
arm/jit_x64/jit_x64.h
|
||||
arm/jit_x64/reg_alloc.h
|
||||
|
@ -114,7 +114,7 @@ static std::unique_ptr<Matcher> MakeMatcher(const char format[32], Function fn)
|
||||
return std::unique_ptr<Matcher>(std::move(ret));
|
||||
}
|
||||
|
||||
static const std::array<Instruction, 220> arm_instruction_table = {{
|
||||
static const std::array<Instruction, 221> arm_instruction_table = {{
|
||||
// Branch instructions
|
||||
{ "BLX (immediate)", MakeMatcher<2>("1111101hvvvvvvvvvvvvvvvvvvvvvvvv", &Visitor::BLX_imm) }, // ARMv5
|
||||
{ "BLX (register)", MakeMatcher<2>("cccc000100101111111111110011mmmm", &Visitor::BLX_reg) }, // ARMv5
|
||||
@ -217,15 +217,16 @@ static const std::array<Instruction, 220> arm_instruction_table = {{
|
||||
|
||||
// Synchronization Primitive instructions
|
||||
{ "CLREX", MakeMatcher<0>("11110101011111111111000000011111", &Visitor::CLREX) }, // ARMv6K
|
||||
{ "LDREX", MakeMatcher<0>("----00011001--------111110011111", &Visitor::LDREX) }, // ARMv6
|
||||
{ "LDREXB", MakeMatcher<0>("----00011101--------111110011111", &Visitor::LDREXB) }, // ARMv6K
|
||||
{ "LDREXD", MakeMatcher<0>("----00011011--------111110011111", &Visitor::LDREXD) }, // ARMv6K
|
||||
{ "LDREXH", MakeMatcher<0>("----00011111--------111110011111", &Visitor::LDREXH) }, // ARMv6K
|
||||
{ "STREX", MakeMatcher<0>("----00011000--------11111001----", &Visitor::STREX) }, // ARMv6
|
||||
{ "STREXB", MakeMatcher<0>("----00011100--------11111001----", &Visitor::STREXB) }, // ARMv6K
|
||||
{ "STREXD", MakeMatcher<0>("----00011010--------11111001----", &Visitor::STREXD) }, // ARMv6K
|
||||
{ "STREXH", MakeMatcher<0>("----00011110--------11111001----", &Visitor::STREXH) }, // ARMv6K
|
||||
{ "SWP", MakeMatcher<0>("----00010-00--------00001001----", &Visitor::SWP) }, // ARMv2S
|
||||
{ "LDREX", MakeMatcher<3>("cccc00011001nnnndddd111110011111", &Visitor::LDREX) }, // ARMv6
|
||||
{ "LDREXB", MakeMatcher<3>("cccc00011101nnnndddd111110011111", &Visitor::LDREXB) }, // ARMv6K
|
||||
{ "LDREXD", MakeMatcher<3>("cccc00011011nnnndddd111110011111", &Visitor::LDREXD) }, // ARMv6K
|
||||
{ "LDREXH", MakeMatcher<3>("cccc00011111nnnndddd111110011111", &Visitor::LDREXH) }, // ARMv6K
|
||||
{ "STREX", MakeMatcher<4>("cccc00011000nnnndddd11111001mmmm", &Visitor::STREX) }, // ARMv6
|
||||
{ "STREXB", MakeMatcher<4>("cccc00011100nnnndddd11111001mmmm", &Visitor::STREXB) }, // ARMv6K
|
||||
{ "STREXD", MakeMatcher<4>("cccc00011010nnnndddd11111001mmmm", &Visitor::STREXD) }, // ARMv6K
|
||||
{ "STREXH", MakeMatcher<4>("cccc00011110nnnndddd11111001mmmm", &Visitor::STREXH) }, // ARMv6K
|
||||
{ "SWP", MakeMatcher<4>("cccc00010000nnnndddd00001001mmmm", &Visitor::SWP) }, // ARMv2S (Deprecated in ARMv6)
|
||||
{ "SWPB", MakeMatcher<4>("cccc00010100nnnndddd00001001mmmm", &Visitor::SWPB) }, // ARMv2S (Deprecated in ARMv6)
|
||||
|
||||
// Load/Store instructions
|
||||
{ "LDR (imm)", MakeMatcher<7>("cccc010pu0w1nnnnddddvvvvvvvvvvvv", &Visitor::LDR_imm) },
|
||||
|
@ -302,15 +302,16 @@ public:
|
||||
|
||||
// Synchronization Primitive instructions
|
||||
virtual void CLREX() = 0;
|
||||
virtual void LDREX() = 0;
|
||||
virtual void LDREXB() = 0;
|
||||
virtual void LDREXD() = 0;
|
||||
virtual void LDREXH() = 0;
|
||||
virtual void STREX() = 0;
|
||||
virtual void STREXB() = 0;
|
||||
virtual void STREXD() = 0;
|
||||
virtual void STREXH() = 0;
|
||||
virtual void SWP() = 0;
|
||||
virtual void LDREX(Cond cond, Register Rn, Register Rd) = 0;
|
||||
virtual void LDREXB(Cond cond, Register Rn, Register Rd) = 0;
|
||||
virtual void LDREXD(Cond cond, Register Rn, Register Rd) = 0;
|
||||
virtual void LDREXH(Cond cond, Register Rn, Register Rd) = 0;
|
||||
virtual void STREX(Cond cond, Register Rn, Register Rd, Register Rm) = 0;
|
||||
virtual void STREXB(Cond cond, Register Rn, Register Rd, Register Rm) = 0;
|
||||
virtual void STREXD(Cond cond, Register Rn, Register Rd, Register Rm) = 0;
|
||||
virtual void STREXH(Cond cond, Register Rn, Register Rd, Register Rm) = 0;
|
||||
virtual void SWP(Cond cond, Register Rn, Register Rd, Register Rm) = 0;
|
||||
virtual void SWPB(Cond cond, Register Rn, Register Rd, Register Rm) = 0;
|
||||
|
||||
// Status register access instructions
|
||||
virtual void CPS() = 0;
|
||||
|
76
src/core/arm/jit_x64/instructions/helper/load_store.h
Normal file
76
src/core/arm/jit_x64/instructions/helper/load_store.h
Normal file
@ -0,0 +1,76 @@
|
||||
// Copyright 2016 Citra Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "common/swap.h"
|
||||
|
||||
#include "core/memory.h"
|
||||
|
||||
namespace JitX64 {
|
||||
|
||||
// TODO: Set up an appropriately mapped region of memory to use instead of compiling CALL instructions.
|
||||
|
||||
constexpr u32 RESERVATION_GRANULE_MASK = 0xFFFFFFF8;
|
||||
|
||||
static u64 Load64LE(u32 addr) {
|
||||
// TODO: Improve this.
|
||||
return Memory::Read32(addr) | (static_cast<u64>(Memory::Read32(addr + 4)) << 32);
|
||||
}
|
||||
|
||||
static u64 Load64BE(u32 addr) {
|
||||
// TODO: Improve this.
|
||||
return Common::swap32(Memory::Read32(addr)) | (static_cast<u64>(Common::swap32(Memory::Read32(addr + 4))) << 32);
|
||||
}
|
||||
|
||||
static void Store64LE(u32 addr, u32 v1, u32 v2) {
|
||||
Memory::Write32(addr, v1);
|
||||
Memory::Write32(addr + 4, v2);
|
||||
}
|
||||
|
||||
static void Store64BE(u32 addr, u32 v1, u32 v2) {
|
||||
Memory::Write32(addr, Common::swap32(v2));
|
||||
Memory::Write32(addr + 4, Common::swap32(v1));
|
||||
}
|
||||
|
||||
static u32 Load32LE(u32 addr) {
|
||||
return Memory::Read32(addr);
|
||||
}
|
||||
|
||||
static u32 Load32BE(u32 addr) {
|
||||
return Common::swap32(Memory::Read32(addr));
|
||||
}
|
||||
|
||||
static void Store32LE(u32 addr, u32 value) {
|
||||
Memory::Write32(addr, value);
|
||||
}
|
||||
|
||||
static void Store32BE(u32 addr, u32 value) {
|
||||
Memory::Write32(addr, Common::swap32(value));
|
||||
}
|
||||
|
||||
static u16 Load16LE(u32 addr) {
|
||||
return Memory::Read16(addr);
|
||||
}
|
||||
|
||||
static u16 Load16BE(u32 addr) {
|
||||
return Common::swap16(Memory::Read16(addr));
|
||||
}
|
||||
|
||||
static void Store16LE(u32 addr, u16 value) {
|
||||
Memory::Write16(addr, value);
|
||||
}
|
||||
|
||||
static void Store16BE(u32 addr, u16 value) {
|
||||
Memory::Write16(addr, Common::swap16(value));
|
||||
}
|
||||
|
||||
static u32 Load8(u32 addr) {
|
||||
return Memory::Read8(addr);
|
||||
}
|
||||
|
||||
static void Store8(u32 addr, u8 value) {
|
||||
Memory::Write8(addr, value);
|
||||
}
|
||||
|
||||
} // namespace JitX64
|
@ -7,11 +7,11 @@
|
||||
#include "common/x64/abi.h"
|
||||
|
||||
#include "core/arm/jit_x64/jit_x64.h"
|
||||
#include "core/memory.h"
|
||||
#include "core/arm/jit_x64/instructions/helper/load_store.h"
|
||||
|
||||
namespace JitX64 {
|
||||
|
||||
// TODO: Loads from constant memory regions can be turned into immediate constant loads.
|
||||
// TODO: Optimization: Loads from read-only memory regions can be turned into immediate constant loads.
|
||||
|
||||
using namespace Gen;
|
||||
|
||||
@ -168,68 +168,6 @@ void JitX64::LoadAndStoreWordOrUnsignedByte_ScaledRegisterPostIndexed(X64Reg des
|
||||
reg_alloc.UnlockArm(Rn_index);
|
||||
}
|
||||
|
||||
// TODO: Set up an appropriately mapped region of memory to use instead of compiling CALL instructions.
|
||||
|
||||
static u64 Load64LE(u32 addr) {
|
||||
// TODO: Improve this.
|
||||
return Memory::Read32(addr) | (static_cast<u64>(Memory::Read32(addr + 4)) << 32);
|
||||
}
|
||||
|
||||
static u64 Load64BE(u32 addr) {
|
||||
// TODO: Improve this.
|
||||
return Common::swap32(Memory::Read32(addr)) | (static_cast<u64>(Common::swap32(Memory::Read32(addr + 4))) << 32);
|
||||
}
|
||||
|
||||
static void Store64LE(u32 addr, u32 v1, u32 v2) {
|
||||
Memory::Write32(addr, v1);
|
||||
Memory::Write32(addr + 4, v2);
|
||||
}
|
||||
|
||||
static void Store64BE(u32 addr, u32 v1, u32 v2) {
|
||||
Memory::Write32(addr, Common::swap32(v1));
|
||||
Memory::Write32(addr+4, Common::swap32(v2));
|
||||
}
|
||||
|
||||
static u32 Load32LE(u32 addr) {
|
||||
return Memory::Read32(addr);
|
||||
}
|
||||
|
||||
static u32 Load32BE(u32 addr) {
|
||||
return Common::swap32(Memory::Read32(addr));
|
||||
}
|
||||
|
||||
static void Store32LE(u32 addr, u32 value) {
|
||||
Memory::Write32(addr, value);
|
||||
}
|
||||
|
||||
static void Store32BE(u32 addr, u32 value) {
|
||||
Memory::Write32(addr, Common::swap32(value));
|
||||
}
|
||||
|
||||
static u16 Load16LE(u32 addr) {
|
||||
return Memory::Read16(addr);
|
||||
}
|
||||
|
||||
static u16 Load16BE(u32 addr) {
|
||||
return Common::swap16(Memory::Read16(addr));
|
||||
}
|
||||
|
||||
static void Store16LE(u32 addr, u16 value) {
|
||||
Memory::Write16(addr, value);
|
||||
}
|
||||
|
||||
static void Store16BE(u32 addr, u16 value) {
|
||||
Memory::Write16(addr, Common::swap16(value));
|
||||
}
|
||||
|
||||
static u32 Load8(u32 addr) {
|
||||
return Memory::Read8(addr);
|
||||
}
|
||||
|
||||
static void Store8(u32 addr, u8 value) {
|
||||
Memory::Write8(addr, value);
|
||||
}
|
||||
|
||||
static void GetValueOfRegister(XEmitter* code, RegAlloc& reg_alloc, u32 r15_value, X64Reg x64_reg, ArmReg arm_reg) {
|
||||
if (arm_reg != 15) {
|
||||
OpArg Rd = reg_alloc.LockArmForRead(arm_reg);
|
||||
@ -389,9 +327,6 @@ void JitX64::LDRB_reg(Cond cond, bool P, bool U, bool W, ArmReg Rn_index, ArmReg
|
||||
}
|
||||
|
||||
void JitX64::STR_imm(Cond cond, bool P, bool U, bool W, ArmReg Rn_index, ArmReg Rd_index, ArmImm12 imm12) {
|
||||
CompileInterpretInstruction();
|
||||
return;
|
||||
|
||||
cond_manager.CompileCond((ConditionCode)cond);
|
||||
|
||||
// Rd_index == R15 is IMPLEMENTATION DEFINED
|
||||
@ -414,15 +349,10 @@ void JitX64::STR_imm(Cond cond, bool P, bool U, bool W, ArmReg Rn_index, ArmReg
|
||||
reg_alloc.UnlockX64(ABI_PARAM1);
|
||||
reg_alloc.UnlockX64(ABI_PARAM2);
|
||||
|
||||
// TODO: Exclusive stuff
|
||||
|
||||
current.arm_pc += GetInstSize();
|
||||
}
|
||||
|
||||
void JitX64::STR_reg(Cond cond, bool P, bool U, bool W, ArmReg Rn_index, ArmReg Rd_index, ArmImm5 imm5, ShiftType shift, ArmReg Rm_index) {
|
||||
CompileInterpretInstruction();
|
||||
return;
|
||||
|
||||
cond_manager.CompileCond((ConditionCode)cond);
|
||||
|
||||
// Rd_index == R15 is IMPLEMENTATION DEFINED
|
||||
@ -445,15 +375,10 @@ void JitX64::STR_reg(Cond cond, bool P, bool U, bool W, ArmReg Rn_index, ArmReg
|
||||
reg_alloc.UnlockX64(ABI_PARAM1);
|
||||
reg_alloc.UnlockX64(ABI_PARAM2);
|
||||
|
||||
// TODO: Exclusive stuff
|
||||
|
||||
current.arm_pc += GetInstSize();
|
||||
}
|
||||
|
||||
void JitX64::STRB_imm(Cond cond, bool P, bool U, bool W, ArmReg Rn_index, ArmReg Rd_index, ArmImm12 imm12) {
|
||||
CompileInterpretInstruction();
|
||||
return;
|
||||
|
||||
cond_manager.CompileCond((ConditionCode)cond);
|
||||
|
||||
ASSERT_MSG(Rd_index != 15, "UNPREDICTABLE");
|
||||
@ -476,15 +401,10 @@ void JitX64::STRB_imm(Cond cond, bool P, bool U, bool W, ArmReg Rn_index, ArmReg
|
||||
reg_alloc.UnlockX64(ABI_PARAM1);
|
||||
reg_alloc.UnlockX64(ABI_PARAM2);
|
||||
|
||||
//TODO: Exclusive stuff
|
||||
|
||||
current.arm_pc += GetInstSize();
|
||||
}
|
||||
|
||||
void JitX64::STRB_reg(Cond cond, bool P, bool U, bool W, ArmReg Rn_index, ArmReg Rd_index, ArmImm5 imm5, ShiftType shift, ArmReg Rm_index) {
|
||||
CompileInterpretInstruction();
|
||||
return;
|
||||
|
||||
cond_manager.CompileCond((ConditionCode)cond);
|
||||
|
||||
ASSERT_MSG(Rd_index != 15, "UNPREDICTABLE");
|
||||
@ -507,8 +427,6 @@ void JitX64::STRB_reg(Cond cond, bool P, bool U, bool W, ArmReg Rn_index, ArmReg
|
||||
reg_alloc.UnlockX64(ABI_PARAM1);
|
||||
reg_alloc.UnlockX64(ABI_PARAM2);
|
||||
|
||||
//TODO: Exclusive stuff
|
||||
|
||||
current.arm_pc += GetInstSize();
|
||||
}
|
||||
|
||||
@ -771,9 +689,6 @@ void JitX64::LDRSH_reg(Cond cond, bool P, bool U, bool W, ArmReg Rn_index, ArmRe
|
||||
}
|
||||
|
||||
void JitX64::STRD_imm(Cond cond, bool P, bool U, bool W, ArmReg Rn_index, ArmReg Rd_index, ArmImm4 imm8a, ArmImm4 imm8b) {
|
||||
CompileInterpretInstruction();
|
||||
return;
|
||||
|
||||
cond_manager.CompileCond((ConditionCode)cond);
|
||||
|
||||
ASSERT_MSG(Rd_index < 14, "UNPREDICTABLE");
|
||||
@ -799,15 +714,10 @@ void JitX64::STRD_imm(Cond cond, bool P, bool U, bool W, ArmReg Rn_index, ArmReg
|
||||
reg_alloc.UnlockX64(ABI_PARAM2);
|
||||
reg_alloc.UnlockX64(ABI_PARAM3);
|
||||
|
||||
// TODO: Exclusive stuff.
|
||||
|
||||
current.arm_pc += GetInstSize();
|
||||
}
|
||||
|
||||
void JitX64::STRD_reg(Cond cond, bool P, bool U, bool W, ArmReg Rn_index, ArmReg Rd_index, ArmReg Rm_index) {
|
||||
CompileInterpretInstruction();
|
||||
return;
|
||||
|
||||
cond_manager.CompileCond((ConditionCode)cond);
|
||||
|
||||
ASSERT_MSG(Rd_index < 14, "UNPREDICTABLE");
|
||||
@ -835,15 +745,10 @@ void JitX64::STRD_reg(Cond cond, bool P, bool U, bool W, ArmReg Rn_index, ArmReg
|
||||
reg_alloc.UnlockX64(ABI_PARAM2);
|
||||
reg_alloc.UnlockX64(ABI_PARAM3);
|
||||
|
||||
// TODO: Exclusive stuff.
|
||||
|
||||
current.arm_pc += GetInstSize();
|
||||
}
|
||||
|
||||
void JitX64::STRH_imm(Cond cond, bool P, bool U, bool W, ArmReg Rn_index, ArmReg Rd_index, ArmImm4 imm8a, ArmImm4 imm8b) {
|
||||
CompileInterpretInstruction();
|
||||
return;
|
||||
|
||||
cond_manager.CompileCond((ConditionCode)cond);
|
||||
|
||||
ASSERT_MSG(Rd_index != 15, "UNPREDICTABLE");
|
||||
@ -866,15 +771,10 @@ void JitX64::STRH_imm(Cond cond, bool P, bool U, bool W, ArmReg Rn_index, ArmReg
|
||||
reg_alloc.UnlockX64(ABI_PARAM1);
|
||||
reg_alloc.UnlockX64(ABI_PARAM2);
|
||||
|
||||
// TODO: Exclusive stuff.
|
||||
|
||||
current.arm_pc += GetInstSize();
|
||||
}
|
||||
|
||||
void JitX64::STRH_reg(Cond cond, bool P, bool U, bool W, ArmReg Rn_index, ArmReg Rd_index, ArmReg Rm_index) {
|
||||
CompileInterpretInstruction();
|
||||
return;
|
||||
|
||||
cond_manager.CompileCond((ConditionCode)cond);
|
||||
|
||||
ASSERT_MSG(Rd_index != 15, "UNPREDICTABLE");
|
||||
@ -897,8 +797,6 @@ void JitX64::STRH_reg(Cond cond, bool P, bool U, bool W, ArmReg Rn_index, ArmReg
|
||||
reg_alloc.UnlockX64(ABI_PARAM1);
|
||||
reg_alloc.UnlockX64(ABI_PARAM2);
|
||||
|
||||
// TODO: Exclusive stuff.
|
||||
|
||||
current.arm_pc += GetInstSize();
|
||||
}
|
||||
|
||||
@ -1114,9 +1012,6 @@ static void ExecuteSTMBE(u32 start_address, u16 reg_list, JitState* jit_state) {
|
||||
}
|
||||
|
||||
void JitX64::STM(Cond cond, bool P, bool U, bool W, ArmReg Rn_index, ArmRegList list) {
|
||||
CompileInterpretInstruction();
|
||||
return;
|
||||
|
||||
cond_manager.CompileCond((ConditionCode)cond);
|
||||
|
||||
ASSERT_MSG(Rn_index != 15, "UNPREDICTABLE");
|
||||
@ -1129,8 +1024,6 @@ void JitX64::STM(Cond cond, bool P, bool U, bool W, ArmReg Rn_index, ArmRegList
|
||||
LoadAndStoreMultiple_Helper(code, reg_alloc, P, U, W, Rn_index, list,
|
||||
[this](){ CompileCallHost(reinterpret_cast<const void* const>(!current.EFlag ? &ExecuteSTMLE : &ExecuteSTMBE)); });
|
||||
|
||||
// TODO: Exclusive stuff
|
||||
|
||||
current.arm_pc += GetInstSize();
|
||||
}
|
||||
|
||||
|
@ -2,19 +2,296 @@
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/x64/abi.h"
|
||||
|
||||
#include "core/arm/jit_x64/jit_x64.h"
|
||||
#include "core/arm/jit_x64/instructions/helper/load_store.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(); }
|
||||
using namespace Gen;
|
||||
|
||||
void JitX64::CLREX() {
|
||||
cond_manager.Always();
|
||||
|
||||
code->MOV(32, MJitStateExclusiveTag(), Imm32(0xFFFFFFFF));
|
||||
code->MOV(8, MJitStateExclusiveState(), Imm8(0));
|
||||
|
||||
current.arm_pc += GetInstSize();
|
||||
}
|
||||
|
||||
void ExclusiveLoadCommon(XEmitter* code, RegAlloc& reg_alloc, OpArg exclusive_state, OpArg exclusive_tag, ArmReg Rn_index, ArmReg Rd_index) {
|
||||
ASSERT_MSG(Rn_index != 15 && Rd_index != 15, "UNPREDICTABLE");
|
||||
|
||||
code->MOV(8, exclusive_state, Imm8(1));
|
||||
|
||||
reg_alloc.FlushX64(ABI_PARAM1);
|
||||
reg_alloc.LockX64(ABI_PARAM1);
|
||||
|
||||
OpArg Rn = reg_alloc.LockArmForRead(Rn_index);
|
||||
code->MOV(32, R(ABI_PARAM1), Rn);
|
||||
reg_alloc.UnlockArm(Rn_index);
|
||||
|
||||
code->MOV(32, exclusive_tag, R(ABI_PARAM1));
|
||||
code->AND(32, exclusive_tag, Imm32(RESERVATION_GRANULE_MASK));
|
||||
|
||||
reg_alloc.UnlockX64(ABI_PARAM1);
|
||||
}
|
||||
|
||||
void JitX64::LDREX(Cond cond, ArmReg Rn_index, ArmReg Rd_index) {
|
||||
cond_manager.CompileCond((ConditionCode)cond);
|
||||
|
||||
ASSERT_MSG(Rn_index != 15 && Rd_index != 15, "UNPREDICTABLE");
|
||||
|
||||
ExclusiveLoadCommon(code, reg_alloc, MJitStateExclusiveState(), MJitStateExclusiveTag(), Rn_index, Rd_index);
|
||||
CompileCallHost(reinterpret_cast<const void* const>(!current.EFlag ? &Load32LE : &Load32BE));
|
||||
|
||||
reg_alloc.LockX64(ABI_RETURN);
|
||||
|
||||
X64Reg Rd = reg_alloc.BindArmForWrite(Rd_index);
|
||||
code->MOV(32, R(Rd), R(ABI_RETURN));
|
||||
reg_alloc.UnlockArm(Rd_index);
|
||||
|
||||
reg_alloc.UnlockX64(ABI_RETURN);
|
||||
|
||||
current.arm_pc += GetInstSize();
|
||||
}
|
||||
|
||||
void JitX64::LDREXB(Cond cond, ArmReg Rn_index, ArmReg Rd_index) {
|
||||
cond_manager.CompileCond((ConditionCode)cond);
|
||||
|
||||
ASSERT_MSG(Rn_index != 15 && Rd_index != 15, "UNPREDICTABLE");
|
||||
|
||||
ExclusiveLoadCommon(code, reg_alloc, MJitStateExclusiveState(), MJitStateExclusiveTag(), Rn_index, Rd_index);
|
||||
CompileCallHost(reinterpret_cast<const void* const>(&Load8));
|
||||
|
||||
reg_alloc.LockX64(ABI_RETURN);
|
||||
|
||||
X64Reg Rd = reg_alloc.BindArmForWrite(Rd_index);
|
||||
code->MOVZX(32, 8, Rd, R(ABI_RETURN));
|
||||
reg_alloc.UnlockArm(Rd_index);
|
||||
|
||||
reg_alloc.UnlockX64(ABI_RETURN);
|
||||
|
||||
current.arm_pc += GetInstSize();
|
||||
}
|
||||
|
||||
void JitX64::LDREXD(Cond cond, ArmReg Rn_index, ArmReg Rd_index) {
|
||||
cond_manager.CompileCond((ConditionCode)cond);
|
||||
|
||||
ASSERT_MSG(Rd_index % 2 == 0, "UNPREDICTABLE");
|
||||
ASSERT_MSG(Rd_index < 14, "UNPREDICTABLE");
|
||||
ASSERT_MSG(Rn_index != 15, "UNPREDICTABLE");
|
||||
|
||||
ExclusiveLoadCommon(code, reg_alloc, MJitStateExclusiveState(), MJitStateExclusiveTag(), Rn_index, Rd_index);
|
||||
CompileCallHost(reinterpret_cast<const void* const>(!current.EFlag ? Load64LE : Load64BE));
|
||||
|
||||
reg_alloc.LockX64(ABI_RETURN);
|
||||
|
||||
X64Reg Rd0 = reg_alloc.BindArmForWrite(Rd_index + 0);
|
||||
X64Reg Rd1 = reg_alloc.BindArmForWrite(Rd_index + 1);
|
||||
code->MOV(64, R(Rd0), R(ABI_RETURN));
|
||||
code->SHR(64, R(ABI_RETURN), Imm8(32));
|
||||
code->MOV(32, R(Rd1), R(ABI_RETURN));
|
||||
reg_alloc.UnlockArm(Rd_index + 0);
|
||||
reg_alloc.UnlockArm(Rd_index + 1);
|
||||
|
||||
reg_alloc.UnlockX64(ABI_RETURN);
|
||||
|
||||
current.arm_pc += GetInstSize();
|
||||
}
|
||||
|
||||
void JitX64::LDREXH(Cond cond, ArmReg Rn_index, ArmReg Rd_index) {
|
||||
cond_manager.CompileCond((ConditionCode)cond);
|
||||
|
||||
ASSERT_MSG(Rn_index != 15 && Rd_index != 15, "UNPREDICTABLE");
|
||||
|
||||
ExclusiveLoadCommon(code, reg_alloc, MJitStateExclusiveState(), MJitStateExclusiveTag(), Rn_index, Rd_index);
|
||||
CompileCallHost(reinterpret_cast<const void* const>(!current.EFlag ? Load16LE : Load16BE));
|
||||
|
||||
reg_alloc.LockX64(ABI_RETURN);
|
||||
|
||||
X64Reg Rd = reg_alloc.BindArmForWrite(Rd_index);
|
||||
code->MOVZX(32, 16, Rd, R(ABI_RETURN));
|
||||
reg_alloc.UnlockArm(Rd_index);
|
||||
|
||||
reg_alloc.UnlockX64(ABI_RETURN);
|
||||
|
||||
current.arm_pc += GetInstSize();
|
||||
}
|
||||
|
||||
void ExclusiveStoreCommon(XEmitter* code, RegAlloc& reg_alloc, OpArg exclusive_state, OpArg exclusive_tag, ArmReg Rn_index, ArmReg Rd_index, std::function<void()> do_memory_access) {
|
||||
OpArg Rn = reg_alloc.LockArmForRead(Rn_index);
|
||||
OpArg Rd = reg_alloc.LockArmForWrite(Rd_index);
|
||||
|
||||
code->MOV(32, Rd, Imm8(1)); // First, assume we failed.
|
||||
|
||||
code->MOV(32, R(ABI_PARAM1), Rn);
|
||||
|
||||
code->BT(8, exclusive_state, Imm8(0));
|
||||
auto jmp_to_end1 = code->J_CC(CC_NC);
|
||||
|
||||
code->MOV(32, R(ABI_PARAM2), R(ABI_PARAM1));
|
||||
code->AND(32, R(ABI_PARAM2), Imm32(RESERVATION_GRANULE_MASK));
|
||||
code->CMP(32, R(ABI_PARAM2), exclusive_tag);
|
||||
auto jmp_to_end2 = code->J_CC(CC_NE);
|
||||
|
||||
// Exclsuive monitor pass
|
||||
code->MOV(32, Rd, Imm8(0)); // Okay, actually we passed.
|
||||
code->MOV(8, exclusive_state, Imm8(0)); // Unset exclusive memory acecss.
|
||||
code->MOV(32, exclusive_tag, Imm32(0xFFFFFFFF)); // Unset exclusive memory acecss.
|
||||
|
||||
do_memory_access();
|
||||
|
||||
code->SetJumpTarget(jmp_to_end1);
|
||||
code->SetJumpTarget(jmp_to_end2);
|
||||
|
||||
reg_alloc.UnlockArm(Rd_index);
|
||||
reg_alloc.UnlockArm(Rn_index);
|
||||
}
|
||||
|
||||
void JitX64::STREX(Cond cond, ArmReg Rn_index, ArmReg Rd_index, ArmReg Rm_index) {
|
||||
CompileInterpretInstruction();
|
||||
return;
|
||||
|
||||
cond_manager.CompileCond((ConditionCode)cond);
|
||||
|
||||
ASSERT_MSG(Rn_index != 15 && Rd_index != 15 && Rm_index != 15, "UNPREDICTABLE");
|
||||
ASSERT_MSG(Rd_index != Rn_index && Rd_index != Rm_index, "UNPREDICTABLE");
|
||||
|
||||
reg_alloc.FlushX64(ABI_PARAM1);
|
||||
reg_alloc.LockX64(ABI_PARAM1);
|
||||
reg_alloc.FlushX64(ABI_PARAM2);
|
||||
reg_alloc.LockX64(ABI_PARAM2);
|
||||
|
||||
OpArg Rm = reg_alloc.LockArmForRead(Rm_index);
|
||||
|
||||
ExclusiveStoreCommon(code, reg_alloc, MJitStateExclusiveState(), MJitStateExclusiveTag(),
|
||||
Rn_index, Rd_index,
|
||||
[&](){
|
||||
code->MOV(32, R(ABI_PARAM2), Rm);
|
||||
CompileCallHost(reinterpret_cast<const void* const>(!current.EFlag ? &Store32LE : &Store32BE));
|
||||
});
|
||||
|
||||
reg_alloc.UnlockArm(Rm_index);
|
||||
|
||||
reg_alloc.UnlockX64(ABI_PARAM2);
|
||||
reg_alloc.UnlockX64(ABI_PARAM1);
|
||||
|
||||
current.arm_pc += GetInstSize();
|
||||
}
|
||||
|
||||
void JitX64::STREXB(Cond cond, ArmReg Rn_index, ArmReg Rd_index, ArmReg Rm_index) {
|
||||
CompileInterpretInstruction();
|
||||
return;
|
||||
|
||||
cond_manager.CompileCond((ConditionCode)cond);
|
||||
|
||||
ASSERT_MSG(Rn_index != 15 && Rd_index != 15 && Rm_index != 15, "UNPREDICTABLE");
|
||||
ASSERT_MSG(Rd_index != Rn_index && Rd_index != Rm_index, "UNPREDICTABLE");
|
||||
|
||||
reg_alloc.FlushX64(ABI_PARAM1);
|
||||
reg_alloc.LockX64(ABI_PARAM1);
|
||||
reg_alloc.FlushX64(ABI_PARAM2);
|
||||
reg_alloc.LockX64(ABI_PARAM2);
|
||||
|
||||
OpArg Rm = reg_alloc.LockArmForRead(Rm_index);
|
||||
|
||||
ExclusiveStoreCommon(code, reg_alloc, MJitStateExclusiveState(), MJitStateExclusiveTag(),
|
||||
Rn_index, Rd_index,
|
||||
[&]() {
|
||||
code->MOV(32, R(ABI_PARAM2), Rm);
|
||||
CompileCallHost(reinterpret_cast<const void* const>(&Store8));
|
||||
});
|
||||
|
||||
reg_alloc.UnlockArm(Rm_index);
|
||||
|
||||
reg_alloc.UnlockX64(ABI_PARAM2);
|
||||
reg_alloc.UnlockX64(ABI_PARAM1);
|
||||
|
||||
current.arm_pc += GetInstSize();
|
||||
}
|
||||
|
||||
void JitX64::STREXD(Cond cond, ArmReg Rn_index, ArmReg Rd_index, ArmReg Rm_index) {
|
||||
CompileInterpretInstruction();
|
||||
return;
|
||||
|
||||
cond_manager.CompileCond((ConditionCode)cond);
|
||||
|
||||
ASSERT_MSG(Rn_index != 15 && Rd_index != 15 && Rm_index != 15, "UNPREDICTABLE");
|
||||
ASSERT_MSG(Rm_index != 14, "UNPREDICTABLE");
|
||||
ASSERT_MSG(Rd_index != Rn_index && Rd_index != Rm_index, "UNPREDICTABLE");
|
||||
ASSERT_MSG(Rd_index != Rm_index + 1, "UNPREDICTABLE");
|
||||
ASSERT_MSG(Rm_index % 2 == 0, "UNPREDICTABLE");
|
||||
|
||||
reg_alloc.FlushX64(ABI_PARAM1);
|
||||
reg_alloc.LockX64(ABI_PARAM1);
|
||||
reg_alloc.FlushX64(ABI_PARAM2);
|
||||
reg_alloc.LockX64(ABI_PARAM2);
|
||||
reg_alloc.FlushX64(ABI_PARAM3);
|
||||
reg_alloc.LockX64(ABI_PARAM3);
|
||||
|
||||
OpArg Rm0 = reg_alloc.LockArmForRead(Rm_index + 0);
|
||||
OpArg Rm1 = reg_alloc.LockArmForRead(Rm_index + 1);
|
||||
|
||||
ExclusiveStoreCommon(code, reg_alloc, MJitStateExclusiveState(), MJitStateExclusiveTag(),
|
||||
Rn_index, Rd_index,
|
||||
[&]() {
|
||||
code->MOV(32, R(ABI_PARAM2), Rm0);
|
||||
code->MOV(32, R(ABI_PARAM3), Rm1);
|
||||
CompileCallHost(reinterpret_cast<const void* const>(!current.EFlag ? &Store64LE : &Store64BE));
|
||||
});
|
||||
|
||||
reg_alloc.UnlockArm(Rm_index + 1);
|
||||
reg_alloc.UnlockArm(Rm_index + 0);
|
||||
|
||||
reg_alloc.UnlockX64(ABI_PARAM3);
|
||||
reg_alloc.UnlockX64(ABI_PARAM2);
|
||||
reg_alloc.UnlockX64(ABI_PARAM1);
|
||||
|
||||
current.arm_pc += GetInstSize();
|
||||
}
|
||||
|
||||
void JitX64::STREXH(Cond cond, ArmReg Rn_index, ArmReg Rd_index, ArmReg Rm_index) {
|
||||
CompileInterpretInstruction();
|
||||
return;
|
||||
|
||||
cond_manager.CompileCond((ConditionCode)cond);
|
||||
|
||||
ASSERT_MSG(Rn_index != 15 && Rd_index != 15 && Rm_index != 15, "UNPREDICTABLE");
|
||||
ASSERT_MSG(Rd_index != Rn_index && Rd_index != Rm_index, "UNPREDICTABLE");
|
||||
|
||||
reg_alloc.FlushX64(ABI_PARAM1);
|
||||
reg_alloc.LockX64(ABI_PARAM1);
|
||||
reg_alloc.FlushX64(ABI_PARAM2);
|
||||
reg_alloc.LockX64(ABI_PARAM2);
|
||||
|
||||
OpArg Rm = reg_alloc.LockArmForRead(Rm_index);
|
||||
|
||||
ExclusiveStoreCommon(code, reg_alloc, MJitStateExclusiveState(), MJitStateExclusiveTag(),
|
||||
Rn_index, Rd_index,
|
||||
[&]() {
|
||||
code->MOV(32, R(ABI_PARAM2), Rm);
|
||||
CompileCallHost(reinterpret_cast<const void* const>(!current.EFlag ? &Store16LE : &Store16BE));
|
||||
});
|
||||
|
||||
reg_alloc.UnlockArm(Rm_index);
|
||||
|
||||
reg_alloc.UnlockX64(ABI_PARAM2);
|
||||
reg_alloc.UnlockX64(ABI_PARAM1);
|
||||
|
||||
current.arm_pc += GetInstSize();
|
||||
}
|
||||
|
||||
void JitX64::SWP(Cond cond, ArmReg Rn_index, ArmReg Rd_index, ArmReg Rm_index) {
|
||||
CompileInterpretInstruction();
|
||||
}
|
||||
|
||||
void JitX64::SWPB(Cond cond, ArmReg Rn_index, ArmReg Rd_index, ArmReg Rm_index) {
|
||||
CompileInterpretInstruction();
|
||||
}
|
||||
|
||||
}
|
@ -51,7 +51,6 @@ CodePtr JitX64::Compile(u32 pc, bool TFlag, bool EFlag) {
|
||||
}
|
||||
|
||||
reg_alloc.AssertNoLocked();
|
||||
reg_alloc.FlushEverything();
|
||||
} while (!stop_compilation && ((current.arm_pc & 0xFFF) != 0));
|
||||
|
||||
if (!stop_compilation) {
|
||||
|
@ -399,15 +399,16 @@ private:
|
||||
|
||||
// Synchronization Primitive instructions
|
||||
void CLREX() override;
|
||||
void LDREX() override;
|
||||
void LDREXB() override;
|
||||
void LDREXD() override;
|
||||
void LDREXH() override;
|
||||
void STREX() override;
|
||||
void STREXB() override;
|
||||
void STREXD() override;
|
||||
void STREXH() override;
|
||||
void SWP() override;
|
||||
void LDREX(Cond cond, ArmReg Rn, ArmReg Rd) override;
|
||||
void LDREXB(Cond cond, ArmReg Rn, ArmReg Rd) override;
|
||||
void LDREXD(Cond cond, ArmReg Rn, ArmReg Rd) override;
|
||||
void LDREXH(Cond cond, ArmReg Rn, ArmReg Rd) override;
|
||||
void STREX(Cond cond, ArmReg Rn, ArmReg Rd, ArmReg Rm) override;
|
||||
void STREXB(Cond cond, ArmReg Rn, ArmReg Rd, ArmReg Rm) override;
|
||||
void STREXD(Cond cond, ArmReg Rn, ArmReg Rd, ArmReg Rm) override;
|
||||
void STREXH(Cond cond, ArmReg Rn, ArmReg Rd, ArmReg Rm) override;
|
||||
void SWP(Cond cond, ArmReg Rn, ArmReg Rd, ArmReg Rm) override;
|
||||
void SWPB(Cond cond, ArmReg Rn, ArmReg Rd, ArmReg Rm) override;
|
||||
|
||||
// Status register access instructions
|
||||
void CPS() override;
|
||||
|
Loading…
Reference in New Issue
Block a user