mirror of
https://github.com/izzy2lost/dolphin.git
synced 2026-06-19 01:16:48 -07:00
Merge pull request #1911 from Sonicadvance1/AArch64_paired_loadstores
[AArch64] Implements paired loadstores
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -82,6 +82,8 @@ inline bool IsQuad(ARM64Reg reg) { return (reg & 0xC0) == 0xC0; }
|
||||
inline bool IsVector(ARM64Reg reg) { return (reg & 0xC0) != 0; }
|
||||
inline ARM64Reg DecodeReg(ARM64Reg reg) { return (ARM64Reg)(reg & 0x1F); }
|
||||
inline ARM64Reg EncodeRegTo64(ARM64Reg reg) { return (ARM64Reg)(reg | 0x20); }
|
||||
inline ARM64Reg EncodeRegToDouble(ARM64Reg reg) { return (ARM64Reg)((reg & ~0xC0) | 0x80); }
|
||||
inline ARM64Reg EncodeRegToQuad(ARM64Reg reg) { return (ARM64Reg)(reg | 0xC0); }
|
||||
|
||||
enum OpType
|
||||
{
|
||||
@@ -217,10 +219,24 @@ private:
|
||||
u32 m_shift;
|
||||
|
||||
public:
|
||||
ArithOption(ARM64Reg Rd)
|
||||
ArithOption(ARM64Reg Rd, bool index = false)
|
||||
{
|
||||
// Indexed registers are a certain feature of AARch64
|
||||
// On Loadstore instructions that use a register offset
|
||||
// We can have the register as an index
|
||||
// If we are indexing then the offset register will
|
||||
// be shifted to the left so we are indexing at intervals
|
||||
// of the size of what we are loading
|
||||
// 8-bit: Index does nothing
|
||||
// 16-bit: Index LSL 1
|
||||
// 32-bit: Index LSL 2
|
||||
// 64-bit: Index LSL 3
|
||||
if (index)
|
||||
m_shift = 4;
|
||||
else
|
||||
m_shift = 0;
|
||||
|
||||
m_destReg = Rd;
|
||||
m_shift = 0;
|
||||
m_type = TYPE_EXTENDEDREG;
|
||||
if (Is64Bit(Rd))
|
||||
{
|
||||
@@ -256,18 +272,20 @@ public:
|
||||
{
|
||||
return m_type;
|
||||
}
|
||||
ARM64Reg GetReg()
|
||||
{
|
||||
return m_destReg;
|
||||
}
|
||||
u32 GetData() const
|
||||
{
|
||||
switch (m_type)
|
||||
{
|
||||
case TYPE_EXTENDEDREG:
|
||||
return (m_width == WIDTH_64BIT ? (1 << 31) : 0) |
|
||||
(m_extend << 13) |
|
||||
return (m_extend << 13) |
|
||||
(m_shift << 10);
|
||||
break;
|
||||
case TYPE_SHIFTEDREG:
|
||||
return (m_width == WIDTH_64BIT ? (1 << 31) : 0) |
|
||||
(m_shifttype << 22) |
|
||||
return (m_shifttype << 22) |
|
||||
(m_shift << 10);
|
||||
break;
|
||||
default:
|
||||
@@ -309,7 +327,7 @@ private:
|
||||
void EncodeLoadStoreIndexedInst(u32 op, ARM64Reg Rt, ARM64Reg Rn, s32 imm, u8 size);
|
||||
void EncodeMOVWideInst(u32 op, ARM64Reg Rd, u32 imm, ShiftAmount pos);
|
||||
void EncodeBitfieldMOVInst(u32 op, ARM64Reg Rd, ARM64Reg Rn, u32 immr, u32 imms);
|
||||
void EncodeLoadStoreRegisterOffset(u32 size, u32 opc, ARM64Reg Rt, ARM64Reg Rn, ARM64Reg Rm, ExtendType extend);
|
||||
void EncodeLoadStoreRegisterOffset(u32 size, u32 opc, ARM64Reg Rt, ARM64Reg Rn, ArithOption Rm);
|
||||
void EncodeAddSubImmInst(u32 op, bool flags, u32 shift, u32 imm, ARM64Reg Rn, ARM64Reg Rd);
|
||||
void EncodeLogicalImmInst(u32 op, ARM64Reg Rd, ARM64Reg Rn, u32 immr, u32 imms);
|
||||
void EncodeLoadStorePair(u32 op, u32 load, IndexType type, ARM64Reg Rt, ARM64Reg Rt2, ARM64Reg Rn, s32 imm);
|
||||
@@ -505,6 +523,8 @@ public:
|
||||
void SXTB(ARM64Reg Rd, ARM64Reg Rn);
|
||||
void SXTH(ARM64Reg Rd, ARM64Reg Rn);
|
||||
void SXTW(ARM64Reg Rd, ARM64Reg Rn);
|
||||
void UXTB(ARM64Reg Rd, ARM64Reg Rn);
|
||||
void UXTH(ARM64Reg Rd, ARM64Reg Rn);
|
||||
|
||||
// Load Register (Literal)
|
||||
void LDR(ARM64Reg Rt, u32 imm);
|
||||
@@ -551,16 +571,16 @@ public:
|
||||
void LDRSW(IndexType type, ARM64Reg Rt, ARM64Reg Rn, s32 imm);
|
||||
|
||||
// Load/Store register (register offset)
|
||||
void STRB(ARM64Reg Rt, ARM64Reg Rn, ARM64Reg Rm, ExtendType extend = EXTEND_LSL);
|
||||
void LDRB(ARM64Reg Rt, ARM64Reg Rn, ARM64Reg Rm, ExtendType extend = EXTEND_LSL);
|
||||
void LDRSB(ARM64Reg Rt, ARM64Reg Rn, ARM64Reg Rm, ExtendType extend = EXTEND_LSL);
|
||||
void STRH(ARM64Reg Rt, ARM64Reg Rn, ARM64Reg Rm, ExtendType extend = EXTEND_LSL);
|
||||
void LDRH(ARM64Reg Rt, ARM64Reg Rn, ARM64Reg Rm, ExtendType extend = EXTEND_LSL);
|
||||
void LDRSH(ARM64Reg Rt, ARM64Reg Rn, ARM64Reg Rm, ExtendType extend = EXTEND_LSL);
|
||||
void STR(ARM64Reg Rt, ARM64Reg Rn, ARM64Reg Rm, ExtendType extend = EXTEND_LSL);
|
||||
void LDR(ARM64Reg Rt, ARM64Reg Rn, ARM64Reg Rm, ExtendType extend = EXTEND_LSL);
|
||||
void LDRSW(ARM64Reg Rt, ARM64Reg Rn, ARM64Reg Rm, ExtendType extend = EXTEND_LSL);
|
||||
void PRFM(ARM64Reg Rt, ARM64Reg Rn, ARM64Reg Rm, ExtendType extend = EXTEND_LSL);
|
||||
void STRB(ARM64Reg Rt, ARM64Reg Rn, ArithOption Rm);
|
||||
void LDRB(ARM64Reg Rt, ARM64Reg Rn, ArithOption Rm);
|
||||
void LDRSB(ARM64Reg Rt, ARM64Reg Rn, ArithOption Rm);
|
||||
void STRH(ARM64Reg Rt, ARM64Reg Rn, ArithOption Rm);
|
||||
void LDRH(ARM64Reg Rt, ARM64Reg Rn, ArithOption Rm);
|
||||
void LDRSH(ARM64Reg Rt, ARM64Reg Rn, ArithOption Rm);
|
||||
void STR(ARM64Reg Rt, ARM64Reg Rn, ArithOption Rm);
|
||||
void LDR(ARM64Reg Rt, ARM64Reg Rn, ArithOption Rm);
|
||||
void LDRSW(ARM64Reg Rt, ARM64Reg Rn, ArithOption Rm);
|
||||
void PRFM(ARM64Reg Rt, ARM64Reg Rn, ArithOption Rm);
|
||||
|
||||
// Load/Store pair
|
||||
void LDP(IndexType type, ARM64Reg Rt, ARM64Reg Rt2, ARM64Reg Rn, s32 imm);
|
||||
@@ -588,11 +608,21 @@ public:
|
||||
void STR(u8 size, IndexType type, ARM64Reg Rt, ARM64Reg Rn, s32 imm);
|
||||
|
||||
// Loadstore single structure
|
||||
void LD1(u8 size, ARM64Reg Rt, u8 index, ARM64Reg Rn);
|
||||
void LD1(u8 size, ARM64Reg Rt, u8 index, ARM64Reg Rn, ARM64Reg Rm);
|
||||
void LD1R(u8 size, ARM64Reg Rt, ARM64Reg Rn);
|
||||
void ST1(u8 size, ARM64Reg Rt, u8 index, ARM64Reg Rn);
|
||||
void ST1(u8 size, ARM64Reg Rt, u8 index, ARM64Reg Rn, ARM64Reg Rm);
|
||||
|
||||
// Loadstore multiple structure
|
||||
void LD1(u8 size, u8 count, ARM64Reg Rt, ARM64Reg Rn);
|
||||
|
||||
// Scalar - 2 Source
|
||||
void FMUL(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm);
|
||||
|
||||
// Scalar floating point immediate
|
||||
void FMOV(ARM64Reg Rd, u32 imm);
|
||||
|
||||
// Vector
|
||||
void AND(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm);
|
||||
void BSL(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm);
|
||||
@@ -600,6 +630,9 @@ public:
|
||||
void FABS(u8 size, ARM64Reg Rd, ARM64Reg Rn);
|
||||
void FADD(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm);
|
||||
void FCVTL(u8 size, ARM64Reg Rd, ARM64Reg Rn);
|
||||
void FCVTN(u8 dest_size, ARM64Reg Rd, ARM64Reg Rn);
|
||||
void FCVTZS(u8 size, ARM64Reg Rd, ARM64Reg Rn);
|
||||
void FCVTZU(u8 size, ARM64Reg Rd, ARM64Reg Rn);
|
||||
void FDIV(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm);
|
||||
void FMUL(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm);
|
||||
void FNEG(u8 size, ARM64Reg Rd, ARM64Reg Rn);
|
||||
@@ -610,17 +643,24 @@ public:
|
||||
void REV16(u8 size, ARM64Reg Rd, ARM64Reg Rn);
|
||||
void REV32(u8 size, ARM64Reg Rd, ARM64Reg Rn);
|
||||
void REV64(u8 size, ARM64Reg Rd, ARM64Reg Rn);
|
||||
void SCVTF(u8 size, ARM64Reg Rd, ARM64Reg Rn);
|
||||
void UCVTF(u8 size, ARM64Reg Rd, ARM64Reg Rn);
|
||||
void XTN(u8 dest_size, ARM64Reg Rd, ARM64Reg Rn);
|
||||
|
||||
// Move
|
||||
void DUP(u8 size, ARM64Reg Rd, ARM64Reg Rn);
|
||||
void INS(u8 size, ARM64Reg Rd, u8 index, ARM64Reg Rn);
|
||||
void INS(u8 size, ARM64Reg Rd, u8 index1, ARM64Reg Rn, u8 index2);
|
||||
void UMOV(u8 size, ARM64Reg Rd, ARM64Reg Rn, u8 index);
|
||||
void SMOV(u8 size, ARM64Reg Rd, ARM64Reg Rn, u8 index);
|
||||
|
||||
// One source
|
||||
void FCVT(u8 size_to, u8 size_from, ARM64Reg Rd, ARM64Reg Rn);
|
||||
|
||||
// Conversion between float and integer
|
||||
void FMOV(u8 size, bool top, ARM64Reg Rd, ARM64Reg Rn);
|
||||
void SCVTF(ARM64Reg Rd, ARM64Reg Rn);
|
||||
void UCVTF(ARM64Reg Rd, ARM64Reg Rn);
|
||||
|
||||
// Float comparison
|
||||
void FCMP(ARM64Reg Rn, ARM64Reg Rm);
|
||||
@@ -647,6 +687,13 @@ public:
|
||||
void TRN2(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm);
|
||||
void ZIP2(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm);
|
||||
|
||||
// Shift by immediate
|
||||
void SSHLL(u8 src_size, ARM64Reg Rd, ARM64Reg Rn, u32 shift);
|
||||
void USHLL(u8 src_size, ARM64Reg Rd, ARM64Reg Rn, u32 shift);
|
||||
void SHRN(u8 dest_size, ARM64Reg Rd, ARM64Reg Rn, u32 shift);
|
||||
void SXTL(u8 src_size, ARM64Reg Rd, ARM64Reg Rn);
|
||||
void UXTL(u8 src_size, ARM64Reg Rd, ARM64Reg Rn);
|
||||
|
||||
// ABI related
|
||||
void ABI_PushRegisters(BitSet32 registers);
|
||||
void ABI_PopRegisters(BitSet32 registers, BitSet32 ignore_mask = BitSet32(0));
|
||||
@@ -662,11 +709,15 @@ private:
|
||||
void EmitCopy(bool Q, u32 op, u32 imm5, u32 imm4, ARM64Reg Rd, ARM64Reg Rn);
|
||||
void Emit2RegMisc(bool U, u32 size, u32 opcode, ARM64Reg Rd, ARM64Reg Rn);
|
||||
void EmitLoadStoreSingleStructure(bool L, bool R, u32 opcode, bool S, u32 size, ARM64Reg Rt, ARM64Reg Rn);
|
||||
void EmitLoadStoreSingleStructure(bool L, bool R, u32 opcode, bool S, u32 size, ARM64Reg Rt, ARM64Reg Rn, ARM64Reg Rm);
|
||||
void Emit1Source(bool M, bool S, u32 type, u32 opcode, ARM64Reg Rd, ARM64Reg Rn);
|
||||
void EmitConversion(bool sf, bool S, u32 type, u32 rmode, u32 opcode, ARM64Reg Rd, ARM64Reg Rn);
|
||||
void EmitCompare(bool M, bool S, u32 op, u32 opcode2, ARM64Reg Rn, ARM64Reg Rm);
|
||||
void EmitCondSelect(bool M, bool S, CCFlags cond, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm);
|
||||
void EmitPermute(u32 size, u32 op, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm);
|
||||
void EmitScalarImm(bool M, bool S, u32 type, u32 imm5, ARM64Reg Rd, u32 imm);
|
||||
void EmitShiftImm(bool U, u32 immh, u32 immb, u32 opcode, ARM64Reg Rd, ARM64Reg Rn);
|
||||
void EmitLoadStoreMultipleStructure(u32 size, bool L, u32 opcode, ARM64Reg Rt, ARM64Reg Rn);
|
||||
};
|
||||
|
||||
class ARM64CodeBlock : public CodeBlock<ARM64XEmitter>
|
||||
|
||||
@@ -165,6 +165,7 @@ set(SRCS ActionReplay.cpp
|
||||
PowerPC/Interpreter/Interpreter_Paired.cpp
|
||||
PowerPC/Interpreter/Interpreter_SystemRegisters.cpp
|
||||
PowerPC/Interpreter/Interpreter_Tables.cpp
|
||||
PowerPC/JitCommon/JitAsmCommon.cpp
|
||||
PowerPC/JitCommon/JitBase.cpp
|
||||
PowerPC/JitCommon/JitCache.cpp
|
||||
PowerPC/JitILCommon/IR.cpp
|
||||
@@ -195,7 +196,6 @@ if(_M_X86)
|
||||
PowerPC/Jit64/Jit_Paired.cpp
|
||||
PowerPC/Jit64/JitRegCache.cpp
|
||||
PowerPC/Jit64/Jit_SystemRegisters.cpp
|
||||
PowerPC/JitCommon/JitAsmCommon.cpp
|
||||
PowerPC/JitCommon/JitBackpatch.cpp
|
||||
PowerPC/JitCommon/Jit_Util.cpp
|
||||
PowerPC/JitCommon/TrampolineCache.cpp)
|
||||
@@ -230,6 +230,7 @@ elseif(_M_ARM_64)
|
||||
PowerPC/JitArm64/JitArm64_LoadStore.cpp
|
||||
PowerPC/JitArm64/JitArm64_LoadStoreFloating.cpp
|
||||
PowerPC/JitArm64/JitArm64_Paired.cpp
|
||||
PowerPC/JitArm64/JitArm64_LoadStorePaired.cpp
|
||||
PowerPC/JitArm64/JitArm64_SystemRegisters.cpp
|
||||
PowerPC/JitArm64/JitArm64_Tables.cpp)
|
||||
endif()
|
||||
|
||||
@@ -33,7 +33,7 @@ void JitArm::psq_l(UGeckoInstruction inst)
|
||||
UBFX(R12, R11, 16, 3); // Type
|
||||
LSL(R12, R12, 2);
|
||||
UBFX(R11, R11, 24, 6); // Scale
|
||||
LSL(R11, R11, 2);
|
||||
LSL(R11, R11, 3);
|
||||
|
||||
Operand2 off;
|
||||
if (TryMakeOperand2(offset, off))
|
||||
@@ -84,7 +84,7 @@ void JitArm::psq_lx(UGeckoInstruction inst)
|
||||
UBFX(R12, R11, 16, 3); // Type
|
||||
LSL(R12, R12, 2);
|
||||
UBFX(R11, R11, 24, 6); // Scale
|
||||
LSL(R11, R11, 2);
|
||||
LSL(R11, R11, 3);
|
||||
|
||||
if (inst.RA || update) // Always uses the register on update
|
||||
{
|
||||
@@ -136,7 +136,7 @@ void JitArm::psq_st(UGeckoInstruction inst)
|
||||
UBFX(R12, R11, 0, 3); // Type
|
||||
LSL(R12, R12, 2);
|
||||
UBFX(R11, R11, 8, 6); // Scale
|
||||
LSL(R11, R11, 2);
|
||||
LSL(R11, R11, 3);
|
||||
|
||||
Operand2 off;
|
||||
if (TryMakeOperand2(offset, off))
|
||||
@@ -187,7 +187,7 @@ void JitArm::psq_stx(UGeckoInstruction inst)
|
||||
UBFX(R12, R11, 0, 3); // Type
|
||||
LSL(R12, R12, 2);
|
||||
UBFX(R11, R11, 8, 6); // Scale
|
||||
LSL(R11, R11, 2);
|
||||
LSL(R11, R11, 3);
|
||||
|
||||
if (inst.RA || update) // Always uses the register on update
|
||||
{
|
||||
|
||||
@@ -27,46 +27,6 @@ using namespace ArmGen;
|
||||
|
||||
JitArmAsmRoutineManager asm_routines;
|
||||
|
||||
static const float GC_ALIGNED16(m_quantizeTableS[]) =
|
||||
{
|
||||
(1 << 0), (1 << 1), (1 << 2), (1 << 3),
|
||||
(1 << 4), (1 << 5), (1 << 6), (1 << 7),
|
||||
(1 << 8), (1 << 9), (1 << 10), (1 << 11),
|
||||
(1 << 12), (1 << 13), (1 << 14), (1 << 15),
|
||||
(1 << 16), (1 << 17), (1 << 18), (1 << 19),
|
||||
(1 << 20), (1 << 21), (1 << 22), (1 << 23),
|
||||
(1 << 24), (1 << 25), (1 << 26), (1 << 27),
|
||||
(1 << 28), (1 << 29), (1 << 30), (1 << 31),
|
||||
1.0 / (1ULL << 32), 1.0 / (1 << 31), 1.0 / (1 << 30), 1.0 / (1 << 29),
|
||||
1.0 / (1 << 28), 1.0 / (1 << 27), 1.0 / (1 << 26), 1.0 / (1 << 25),
|
||||
1.0 / (1 << 24), 1.0 / (1 << 23), 1.0 / (1 << 22), 1.0 / (1 << 21),
|
||||
1.0 / (1 << 20), 1.0 / (1 << 19), 1.0 / (1 << 18), 1.0 / (1 << 17),
|
||||
1.0 / (1 << 16), 1.0 / (1 << 15), 1.0 / (1 << 14), 1.0 / (1 << 13),
|
||||
1.0 / (1 << 12), 1.0 / (1 << 11), 1.0 / (1 << 10), 1.0 / (1 << 9),
|
||||
1.0 / (1 << 8), 1.0 / (1 << 7), 1.0 / (1 << 6), 1.0 / (1 << 5),
|
||||
1.0 / (1 << 4), 1.0 / (1 << 3), 1.0 / (1 << 2), 1.0 / (1 << 1),
|
||||
};
|
||||
|
||||
static const float GC_ALIGNED16(m_dequantizeTableS[]) =
|
||||
{
|
||||
1.0 / (1 << 0), 1.0 / (1 << 1), 1.0 / (1 << 2), 1.0 / (1 << 3),
|
||||
1.0 / (1 << 4), 1.0 / (1 << 5), 1.0 / (1 << 6), 1.0 / (1 << 7),
|
||||
1.0 / (1 << 8), 1.0 / (1 << 9), 1.0 / (1 << 10), 1.0 / (1 << 11),
|
||||
1.0 / (1 << 12), 1.0 / (1 << 13), 1.0 / (1 << 14), 1.0 / (1 << 15),
|
||||
1.0 / (1 << 16), 1.0 / (1 << 17), 1.0 / (1 << 18), 1.0 / (1 << 19),
|
||||
1.0 / (1 << 20), 1.0 / (1 << 21), 1.0 / (1 << 22), 1.0 / (1 << 23),
|
||||
1.0 / (1 << 24), 1.0 / (1 << 25), 1.0 / (1 << 26), 1.0 / (1 << 27),
|
||||
1.0 / (1 << 28), 1.0 / (1 << 29), 1.0 / (1 << 30), 1.0 / (1 << 31),
|
||||
(1ULL << 32), (1 << 31), (1 << 30), (1 << 29),
|
||||
(1 << 28), (1 << 27), (1 << 26), (1 << 25),
|
||||
(1 << 24), (1 << 23), (1 << 22), (1 << 21),
|
||||
(1 << 20), (1 << 19), (1 << 18), (1 << 17),
|
||||
(1 << 16), (1 << 15), (1 << 14), (1 << 13),
|
||||
(1 << 12), (1 << 11), (1 << 10), (1 << 9),
|
||||
(1 << 8), (1 << 7), (1 << 6), (1 << 5),
|
||||
(1 << 4), (1 << 3), (1 << 2), (1 << 1),
|
||||
};
|
||||
|
||||
static void WriteDual32(u32 value1, u32 value2, u32 address)
|
||||
{
|
||||
Memory::Write_U32(value1, address);
|
||||
|
||||
@@ -168,6 +168,10 @@ public:
|
||||
void ps_sum0(UGeckoInstruction inst);
|
||||
void ps_sum1(UGeckoInstruction inst);
|
||||
|
||||
// Loadstore paired
|
||||
void psq_l(UGeckoInstruction inst);
|
||||
void psq_st(UGeckoInstruction inst);
|
||||
|
||||
private:
|
||||
Arm64GPRCache gpr;
|
||||
Arm64FPRCache fpr;
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
// Copyright 2014 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "Common/Arm64Emitter.h"
|
||||
#include "Common/Common.h"
|
||||
#include "Common/StringUtil.h"
|
||||
|
||||
#include "Core/Core.h"
|
||||
#include "Core/CoreTiming.h"
|
||||
#include "Core/PowerPC/PowerPC.h"
|
||||
#include "Core/PowerPC/PPCTables.h"
|
||||
#include "Core/PowerPC/JitArm64/Jit.h"
|
||||
#include "Core/PowerPC/JitArm64/JitArm64_RegCache.h"
|
||||
#include "Core/PowerPC/JitArm64/JitAsm.h"
|
||||
|
||||
using namespace Arm64Gen;
|
||||
|
||||
void JitArm64::psq_l(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITLoadStorePairedOff);
|
||||
FALLBACK_IF(js.memcheck || !SConfig::GetInstance().m_LocalCoreStartupParameter.bFastmem);
|
||||
|
||||
// X30 is LR
|
||||
// X0 contains the scale
|
||||
// X1 is the address
|
||||
// X2 is a temporary
|
||||
// Q0 is the return register
|
||||
// Q1 is a temporary
|
||||
bool update = inst.OPCD == 57;
|
||||
s32 offset = inst.SIMM_12;
|
||||
|
||||
gpr.Lock(W0, W1, W2, W30);
|
||||
fpr.Lock(Q0, Q1);
|
||||
|
||||
ARM64Reg arm_addr = gpr.R(inst.RA);
|
||||
ARM64Reg scale_reg = W0;
|
||||
ARM64Reg addr_reg = W1;
|
||||
ARM64Reg type_reg = W2;
|
||||
|
||||
LDR(INDEX_UNSIGNED, scale_reg, X29, PPCSTATE_OFF(spr[SPR_GQR0 + inst.I]));
|
||||
|
||||
if (inst.RA || update) // Always uses the register on update
|
||||
{
|
||||
if (offset >= 0)
|
||||
ADD(addr_reg, gpr.R(inst.RA), offset);
|
||||
else
|
||||
SUB(addr_reg, gpr.R(inst.RA), std::abs(offset));
|
||||
}
|
||||
else
|
||||
{
|
||||
MOVI2R(addr_reg, (u32)offset);
|
||||
}
|
||||
|
||||
UBFM(type_reg, scale_reg, 16, 18); // Type
|
||||
UBFM(scale_reg, scale_reg, 24, 29); // Scale
|
||||
|
||||
if (update)
|
||||
MOV(arm_addr, addr_reg);
|
||||
|
||||
MOVI2R(X30, (u64)&asm_routines.pairedLoadQuantized[inst.W * 8]);
|
||||
LDR(X30, X30, ArithOption(EncodeRegTo64(type_reg), true));
|
||||
BLR(X30);
|
||||
|
||||
fpr.BindToRegister(inst.RS, false);
|
||||
ARM64Reg VS = fpr.R(inst.RS);
|
||||
m_float_emit.FCVTL(64, EncodeRegToDouble(VS), D0);
|
||||
if (inst.W)
|
||||
{
|
||||
m_float_emit.FMOV(D0, 0x70); // 1.0 as a Double
|
||||
m_float_emit.INS(64, VS, 1, Q0, 0);
|
||||
}
|
||||
|
||||
gpr.Unlock(W0, W1, W2, W30);
|
||||
fpr.Unlock(Q0, Q1);
|
||||
}
|
||||
|
||||
void JitArm64::psq_st(UGeckoInstruction inst)
|
||||
{
|
||||
INSTRUCTION_START
|
||||
JITDISABLE(bJITLoadStorePairedOff);
|
||||
FALLBACK_IF(js.memcheck || !SConfig::GetInstance().m_LocalCoreStartupParameter.bFastmem);
|
||||
|
||||
// X30 is LR
|
||||
// X0 contains the scale
|
||||
// X1 is the address
|
||||
// Q0 is the store register
|
||||
|
||||
bool update = inst.OPCD == 61;
|
||||
s32 offset = inst.SIMM_12;
|
||||
|
||||
gpr.Lock(W0, W1, W2, W30);
|
||||
fpr.Lock(Q0, Q1);
|
||||
|
||||
ARM64Reg arm_addr = gpr.R(inst.RA);
|
||||
ARM64Reg scale_reg = W0;
|
||||
ARM64Reg addr_reg = W1;
|
||||
ARM64Reg type_reg = gpr.GetReg();
|
||||
|
||||
LDR(INDEX_UNSIGNED, scale_reg, X29, PPCSTATE_OFF(spr[SPR_GQR0 + inst.I]));
|
||||
|
||||
if (inst.RA || update) // Always uses the register on update
|
||||
{
|
||||
if (offset >= 0)
|
||||
ADD(addr_reg, gpr.R(inst.RA), offset);
|
||||
else
|
||||
SUB(addr_reg, gpr.R(inst.RA), std::abs(offset));
|
||||
}
|
||||
else
|
||||
{
|
||||
MOVI2R(addr_reg, (u32)offset);
|
||||
}
|
||||
|
||||
UBFM(type_reg, scale_reg, 0, 2); // Type
|
||||
UBFM(scale_reg, scale_reg, 8, 13); // Scale
|
||||
|
||||
if (update)
|
||||
MOV(arm_addr, addr_reg);
|
||||
|
||||
ARM64Reg VS = fpr.R(inst.RS);
|
||||
m_float_emit.FCVTN(32, D0, VS);
|
||||
MOVI2R(X30, (u64)&asm_routines.pairedStoreQuantized[inst.W * 8]);
|
||||
LDR(X30, X30, ArithOption(EncodeRegTo64(type_reg), true));
|
||||
BLR(X30);
|
||||
|
||||
gpr.Unlock(W0, W1, W2, W30, type_reg);
|
||||
fpr.Unlock(Q0, Q1);
|
||||
}
|
||||
|
||||
@@ -94,10 +94,10 @@ static GekkoOPTemplate primarytable[] =
|
||||
{54, &JitArm64::stfXX}, //"stfd", OPTYPE_STOREFP, FL_IN_A}},
|
||||
{55, &JitArm64::stfXX}, //"stfdu", OPTYPE_STOREFP, FL_OUT_A | FL_IN_A}},
|
||||
|
||||
{56, &JitArm64::FallBackToInterpreter}, //"psq_l", OPTYPE_PS, FL_IN_A}},
|
||||
{57, &JitArm64::FallBackToInterpreter}, //"psq_lu", OPTYPE_PS, FL_OUT_A | FL_IN_A}},
|
||||
{60, &JitArm64::FallBackToInterpreter}, //"psq_st", OPTYPE_PS, FL_IN_A}},
|
||||
{61, &JitArm64::FallBackToInterpreter}, //"psq_stu", OPTYPE_PS, FL_OUT_A | FL_IN_A}},
|
||||
{56, &JitArm64::psq_l}, //"psq_l", OPTYPE_PS, FL_IN_A}},
|
||||
{57, &JitArm64::psq_l}, //"psq_lu", OPTYPE_PS, FL_OUT_A | FL_IN_A}},
|
||||
{60, &JitArm64::psq_st}, //"psq_st", OPTYPE_PS, FL_IN_A}},
|
||||
{61, &JitArm64::psq_st}, //"psq_stu", OPTYPE_PS, FL_OUT_A | FL_IN_A}},
|
||||
|
||||
//missing: 0, 5, 6, 9, 22, 30, 62, 58
|
||||
{0, &JitArm64::FallBackToInterpreter}, //"unknown_instruction", OPTYPE_UNKNOWN, 0}},
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "Core/PowerPC/PowerPC.h"
|
||||
#include "Core/PowerPC/JitArm64/Jit.h"
|
||||
#include "Core/PowerPC/JitArm64/JitAsm.h"
|
||||
#include "Core/PowerPC/JitCommon/JitAsmCommon.h"
|
||||
#include "Core/PowerPC/JitCommon/JitCache.h"
|
||||
|
||||
using namespace Arm64Gen;
|
||||
@@ -89,9 +90,428 @@ void JitArm64AsmRoutineManager::Generate()
|
||||
ABI_PopRegisters(regs_to_save);
|
||||
RET(X30);
|
||||
|
||||
GenerateCommon();
|
||||
|
||||
FlushIcache();
|
||||
}
|
||||
|
||||
void JitArm64AsmRoutineManager::GenerateCommon()
|
||||
{
|
||||
// X0 is the scale
|
||||
// X1 is address
|
||||
// X2 is a temporary on stores
|
||||
// X30 is LR
|
||||
// Q0 is the return for loads
|
||||
// is the register for stores
|
||||
// Q1 is a temporary
|
||||
ARM64Reg addr_reg = X1;
|
||||
ARM64Reg scale_reg = X0;
|
||||
ARM64FloatEmitter float_emit(this);
|
||||
const u32 GPR_CALLER_SAVE = 0x6007FFFF;
|
||||
|
||||
const u8* loadPairedIllegal = GetCodePtr();
|
||||
BRK(100);
|
||||
const u8* loadPairedFloatTwo = GetCodePtr();
|
||||
{
|
||||
MOVK(addr_reg, ((u64)Memory::base >> 32) & 0xFFFF, SHIFT_32);
|
||||
float_emit.LD1(32, 1, D0, addr_reg);
|
||||
float_emit.REV32(8, D0, D0);
|
||||
RET(X30);
|
||||
}
|
||||
const u8* loadPairedU8Two = GetCodePtr();
|
||||
{
|
||||
MOVK(addr_reg, ((u64)Memory::base >> 32) & 0xFFFF, SHIFT_32);
|
||||
float_emit.LDR(16, INDEX_UNSIGNED, D0, addr_reg, 0);
|
||||
float_emit.UXTL(8, D0, D0);
|
||||
float_emit.UXTL(16, D0, D0);
|
||||
float_emit.UCVTF(32, D0, D0);
|
||||
|
||||
MOVI2R(addr_reg, (u64)&m_dequantizeTableS);
|
||||
ADD(scale_reg, addr_reg, scale_reg, ArithOption(scale_reg, ST_LSL, 3));
|
||||
float_emit.LD1R(32, D1, scale_reg);
|
||||
float_emit.FMUL(32, D0, D0, D1);
|
||||
RET(X30);
|
||||
}
|
||||
const u8* loadPairedS8Two = GetCodePtr();
|
||||
{
|
||||
MOVK(addr_reg, ((u64)Memory::base >> 32) & 0xFFFF, SHIFT_32);
|
||||
float_emit.LDR(16, INDEX_UNSIGNED, D0, addr_reg, 0);
|
||||
float_emit.SXTL(8, D0, D0);
|
||||
float_emit.SXTL(16, D0, D0);
|
||||
float_emit.SCVTF(32, D0, D0);
|
||||
|
||||
MOVI2R(addr_reg, (u64)&m_dequantizeTableS);
|
||||
ADD(scale_reg, addr_reg, scale_reg, ArithOption(scale_reg, ST_LSL, 3));
|
||||
float_emit.LD1R(32, D1, scale_reg);
|
||||
float_emit.FMUL(32, D0, D0, D1);
|
||||
RET(X30);
|
||||
}
|
||||
const u8* loadPairedU16Two = GetCodePtr();
|
||||
{
|
||||
MOVK(addr_reg, ((u64)Memory::base >> 32) & 0xFFFF, SHIFT_32);
|
||||
float_emit.LD1(16, 1, D0, addr_reg);
|
||||
float_emit.REV16(8, D0, D0);
|
||||
float_emit.UXTL(16, D0, D0);
|
||||
float_emit.UCVTF(32, D0, D0);
|
||||
|
||||
MOVI2R(addr_reg, (u64)&m_dequantizeTableS);
|
||||
ADD(scale_reg, addr_reg, scale_reg, ArithOption(scale_reg, ST_LSL, 3));
|
||||
float_emit.LD1R(32, D1, scale_reg);
|
||||
float_emit.FMUL(32, D0, D0, D1);
|
||||
RET(X30);
|
||||
}
|
||||
const u8* loadPairedS16Two = GetCodePtr();
|
||||
{
|
||||
MOVK(addr_reg, ((u64)Memory::base >> 32) & 0xFFFF, SHIFT_32);
|
||||
float_emit.LD1(16, 1, D0, addr_reg);
|
||||
float_emit.REV16(8, D0, D0);
|
||||
float_emit.SXTL(16, D0, D0);
|
||||
float_emit.SCVTF(32, D0, D0);
|
||||
|
||||
MOVI2R(addr_reg, (u64)&m_dequantizeTableS);
|
||||
ADD(scale_reg, addr_reg, scale_reg, ArithOption(scale_reg, ST_LSL, 3));
|
||||
float_emit.LD1R(32, D1, scale_reg);
|
||||
float_emit.FMUL(32, D0, D0, D1);
|
||||
RET(X30);
|
||||
}
|
||||
|
||||
const u8* loadPairedFloatOne = GetCodePtr();
|
||||
{
|
||||
MOVK(addr_reg, ((u64)Memory::base >> 32) & 0xFFFF, SHIFT_32);
|
||||
float_emit.LDR(32, INDEX_UNSIGNED, D0, addr_reg, 0);
|
||||
float_emit.REV32(8, D0, D0);
|
||||
RET(X30);
|
||||
}
|
||||
const u8* loadPairedU8One = GetCodePtr();
|
||||
{
|
||||
MOVK(addr_reg, ((u64)Memory::base >> 32) & 0xFFFF, SHIFT_32);
|
||||
float_emit.LDR(8, INDEX_UNSIGNED, D0, addr_reg, 0);
|
||||
float_emit.UXTL(8, D0, D0);
|
||||
float_emit.UXTL(16, D0, D0);
|
||||
float_emit.UCVTF(32, D0, D0);
|
||||
|
||||
MOVI2R(addr_reg, (u64)&m_dequantizeTableS);
|
||||
ADD(scale_reg, addr_reg, scale_reg, ArithOption(scale_reg, ST_LSL, 3));
|
||||
float_emit.LD1R(32, D1, scale_reg);
|
||||
float_emit.FMUL(32, D0, D0, D1);
|
||||
RET(X30);
|
||||
}
|
||||
const u8* loadPairedS8One = GetCodePtr();
|
||||
{
|
||||
MOVK(addr_reg, ((u64)Memory::base >> 32) & 0xFFFF, SHIFT_32);
|
||||
float_emit.LDR(8, INDEX_UNSIGNED, D0, addr_reg, 0);
|
||||
float_emit.SXTL(8, D0, D0);
|
||||
float_emit.SXTL(16, D0, D0);
|
||||
float_emit.SCVTF(32, D0, D0);
|
||||
|
||||
MOVI2R(addr_reg, (u64)&m_dequantizeTableS);
|
||||
ADD(scale_reg, addr_reg, scale_reg, ArithOption(scale_reg, ST_LSL, 3));
|
||||
float_emit.LD1R(32, D1, scale_reg);
|
||||
float_emit.FMUL(32, D0, D0, D1);
|
||||
RET(X30);
|
||||
}
|
||||
const u8* loadPairedU16One = GetCodePtr();
|
||||
{
|
||||
MOVK(addr_reg, ((u64)Memory::base >> 32) & 0xFFFF, SHIFT_32);
|
||||
float_emit.LDR(16, INDEX_UNSIGNED, D0, addr_reg, 0);
|
||||
float_emit.REV16(8, D0, D0);
|
||||
float_emit.UXTL(16, D0, D0);
|
||||
float_emit.UCVTF(32, D0, D0);
|
||||
|
||||
MOVI2R(addr_reg, (u64)&m_dequantizeTableS);
|
||||
ADD(scale_reg, addr_reg, scale_reg, ArithOption(scale_reg, ST_LSL, 3));
|
||||
float_emit.LD1R(32, D1, scale_reg);
|
||||
float_emit.FMUL(32, D0, D0, D1);
|
||||
RET(X30);
|
||||
}
|
||||
const u8* loadPairedS16One = GetCodePtr();
|
||||
{
|
||||
MOVK(addr_reg, ((u64)Memory::base >> 32) & 0xFFFF, SHIFT_32);
|
||||
float_emit.LDR(16, INDEX_UNSIGNED, D0, addr_reg, 0);
|
||||
float_emit.REV16(8, D0, D0);
|
||||
float_emit.SXTL(16, D0, D0);
|
||||
float_emit.SCVTF(32, D0, D0);
|
||||
|
||||
MOVI2R(addr_reg, (u64)&m_dequantizeTableS);
|
||||
ADD(scale_reg, addr_reg, scale_reg, ArithOption(scale_reg, ST_LSL, 3));
|
||||
float_emit.LD1R(32, D1, scale_reg);
|
||||
float_emit.FMUL(32, D0, D0, D1);
|
||||
RET(X30);
|
||||
}
|
||||
|
||||
pairedLoadQuantized = reinterpret_cast<const u8**>(const_cast<u8*>(AlignCode16()));
|
||||
ReserveCodeSpace(16 * sizeof(u8*));
|
||||
|
||||
pairedLoadQuantized[0] = loadPairedFloatTwo;
|
||||
pairedLoadQuantized[1] = loadPairedIllegal;
|
||||
pairedLoadQuantized[2] = loadPairedIllegal;
|
||||
pairedLoadQuantized[3] = loadPairedIllegal;
|
||||
pairedLoadQuantized[4] = loadPairedU8Two;
|
||||
pairedLoadQuantized[5] = loadPairedU16Two;
|
||||
pairedLoadQuantized[6] = loadPairedS8Two;
|
||||
pairedLoadQuantized[7] = loadPairedS16Two;
|
||||
|
||||
pairedLoadQuantized[8] = loadPairedFloatOne;
|
||||
pairedLoadQuantized[9] = loadPairedIllegal;
|
||||
pairedLoadQuantized[10] = loadPairedIllegal;
|
||||
pairedLoadQuantized[11] = loadPairedIllegal;
|
||||
pairedLoadQuantized[12] = loadPairedU8One;
|
||||
pairedLoadQuantized[13] = loadPairedU16One;
|
||||
pairedLoadQuantized[14] = loadPairedS8One;
|
||||
pairedLoadQuantized[15] = loadPairedS16One;
|
||||
|
||||
// Stores
|
||||
const u8* storePairedIllegal = GetCodePtr();
|
||||
BRK(0x101);
|
||||
const u8* storePairedFloat = GetCodePtr();
|
||||
{
|
||||
BitSet32 gprs(GPR_CALLER_SAVE & ~7); // All except X0/X1/X2
|
||||
BitSet32 fprs(~3); // All except Q0/Q1
|
||||
|
||||
TST(DecodeReg(addr_reg), 6, 1);
|
||||
FixupBranch argh = B(CC_NEQ);
|
||||
|
||||
float_emit.REV32(8, D0, D0);
|
||||
MOVK(addr_reg, ((u64)Memory::base >> 32) & 0xFFFF, SHIFT_32);
|
||||
float_emit.ST1(32, Q0, 0, addr_reg, SP);
|
||||
float_emit.ST1(32, Q0, 1, addr_reg, SP);
|
||||
RET(X30);
|
||||
|
||||
SetJumpTarget(argh);
|
||||
|
||||
ABI_PushRegisters(gprs);
|
||||
float_emit.ABI_PushRegisters(fprs);
|
||||
float_emit.UMOV(64, X0, Q0, 0);
|
||||
ORR(X0, SP, X0, ArithOption(X0, ST_ROR, 32));
|
||||
MOVI2R(X30, (u64)Memory::Write_U64);
|
||||
BLR(X30);
|
||||
float_emit.ABI_PopRegisters(fprs);
|
||||
ABI_PopRegisters(gprs);
|
||||
RET(X30);
|
||||
}
|
||||
const u8* storePairedU8 = GetCodePtr();
|
||||
const u8* storePairedS8 = GetCodePtr();
|
||||
{
|
||||
BitSet32 gprs(GPR_CALLER_SAVE & ~7); // All except X0/X1/X2
|
||||
BitSet32 fprs(~3); // All except Q0/Q1
|
||||
|
||||
MOVI2R(X2, (u64)&m_quantizeTableS);
|
||||
ADD(scale_reg, X2, scale_reg, ArithOption(scale_reg, ST_LSL, 3));
|
||||
float_emit.LD1R(32, D1, scale_reg);
|
||||
float_emit.FMUL(32, D0, D0, D1);
|
||||
float_emit.FCVTZU(32, D0, D0);
|
||||
float_emit.XTN(16, D0, D0);
|
||||
float_emit.XTN(8, D0, D0);
|
||||
|
||||
TST(DecodeReg(addr_reg), 6, 1);
|
||||
FixupBranch argh = B(CC_NEQ);
|
||||
MOVK(addr_reg, ((u64)Memory::base >> 32) & 0xFFFF, SHIFT_32);
|
||||
float_emit.ST1(8, Q0, 0, addr_reg, SP);
|
||||
float_emit.ST1(8, Q0, 1, addr_reg, SP);
|
||||
RET(X30);
|
||||
|
||||
SetJumpTarget(argh);
|
||||
ABI_PushRegisters(gprs);
|
||||
float_emit.ABI_PushRegisters(fprs);
|
||||
float_emit.UMOV(16, W0, Q0, 0);
|
||||
REV16(W0, W0);
|
||||
MOVI2R(X30, (u64)Memory::Write_U16);
|
||||
BLR(X30);
|
||||
float_emit.ABI_PopRegisters(fprs);
|
||||
ABI_PopRegisters(gprs);
|
||||
RET(X30);
|
||||
}
|
||||
|
||||
const u8* storePairedU16 = GetCodePtr();
|
||||
const u8* storePairedS16 = GetCodePtr();
|
||||
{
|
||||
BitSet32 gprs(GPR_CALLER_SAVE & ~7); // All except X0/X1/X2
|
||||
BitSet32 fprs(~3); // All except Q0/Q1
|
||||
|
||||
MOVI2R(X2, (u64)&m_quantizeTableS);
|
||||
ADD(scale_reg, X2, scale_reg, ArithOption(scale_reg, ST_LSL, 3));
|
||||
float_emit.LD1R(32, D1, scale_reg);
|
||||
float_emit.FMUL(32, D0, D0, D1);
|
||||
float_emit.FCVTZU(32, D0, D0);
|
||||
float_emit.XTN(16, D0, D0);
|
||||
|
||||
TST(DecodeReg(addr_reg), 6, 1);
|
||||
FixupBranch argh = B(CC_NEQ);
|
||||
MOVK(addr_reg, ((u64)Memory::base >> 32) & 0xFFFF, SHIFT_32);
|
||||
float_emit.ST1(16, Q0, 0, addr_reg, SP);
|
||||
float_emit.ST1(16, Q0, 1, addr_reg, SP);
|
||||
RET(X30);
|
||||
|
||||
SetJumpTarget(argh);
|
||||
ABI_PushRegisters(gprs);
|
||||
float_emit.ABI_PushRegisters(fprs);
|
||||
float_emit.UMOV(32, W0, Q0, 0);
|
||||
REV32(W0, W0);
|
||||
MOVI2R(X30, (u64)Memory::Write_U32);
|
||||
BLR(X30);
|
||||
float_emit.ABI_PopRegisters(fprs);
|
||||
ABI_PopRegisters(gprs);
|
||||
RET(X30);
|
||||
}
|
||||
|
||||
const u8* storeSingleFloat = GetCodePtr();
|
||||
{
|
||||
BitSet32 gprs(GPR_CALLER_SAVE & ~7); // All except X0/X1/X2
|
||||
BitSet32 fprs(~3); // All except Q0/Q1
|
||||
|
||||
TST(DecodeReg(addr_reg), 6, 1);
|
||||
FixupBranch argh = B(CC_NEQ);
|
||||
|
||||
float_emit.REV32(8, D0, D0);
|
||||
MOVK(addr_reg, ((u64)Memory::base >> 32) & 0xFFFF, SHIFT_32);
|
||||
float_emit.STR(32, INDEX_UNSIGNED, D0, addr_reg, 0);
|
||||
RET(X30);
|
||||
|
||||
SetJumpTarget(argh);
|
||||
|
||||
ABI_PushRegisters(gprs);
|
||||
float_emit.ABI_PushRegisters(fprs);
|
||||
float_emit.UMOV(32, W0, Q0, 0);
|
||||
MOVI2R(X30, (u64)&Memory::Write_U32);
|
||||
BLR(X30);
|
||||
float_emit.ABI_PopRegisters(fprs);
|
||||
ABI_PopRegisters(gprs);
|
||||
RET(X30);
|
||||
}
|
||||
const u8* storeSingleU8 = GetCodePtr(); // Used by MKWii
|
||||
{
|
||||
BitSet32 gprs(GPR_CALLER_SAVE & ~7); // All except X0/X1/X2
|
||||
BitSet32 fprs(~3); // All except Q0/Q1
|
||||
|
||||
MOVI2R(X2, (u64)&m_quantizeTableS);
|
||||
ADD(scale_reg, X2, scale_reg, ArithOption(scale_reg, ST_LSL, 3));
|
||||
float_emit.LDR(32, INDEX_UNSIGNED, D1, scale_reg, 0);
|
||||
float_emit.FMUL(32, D0, D0, D1);
|
||||
float_emit.FCVTZU(32, D0, D0);
|
||||
float_emit.XTN(16, D0, D0);
|
||||
float_emit.XTN(8, D0, D0);
|
||||
|
||||
TST(DecodeReg(addr_reg), 6, 1);
|
||||
FixupBranch argh = B(CC_NEQ);
|
||||
MOVK(addr_reg, ((u64)Memory::base >> 32) & 0xFFFF, SHIFT_32);
|
||||
float_emit.ST1(8, Q0, 0, addr_reg);
|
||||
RET(X30);
|
||||
|
||||
SetJumpTarget(argh);
|
||||
ABI_PushRegisters(gprs);
|
||||
float_emit.ABI_PushRegisters(fprs);
|
||||
float_emit.UMOV(32, W0, Q0, 0);
|
||||
MOVI2R(X30, (u64)&Memory::Write_U8);
|
||||
BLR(X30);
|
||||
float_emit.ABI_PopRegisters(fprs);
|
||||
ABI_PopRegisters(gprs);
|
||||
RET(X30);
|
||||
}
|
||||
const u8* storeSingleS8 = GetCodePtr();
|
||||
{
|
||||
BitSet32 gprs(GPR_CALLER_SAVE & ~7); // All except X0/X1/X2
|
||||
BitSet32 fprs(~3); // All except Q0/Q1
|
||||
|
||||
MOVI2R(X2, (u64)&m_quantizeTableS);
|
||||
ADD(scale_reg, X2, scale_reg, ArithOption(scale_reg, ST_LSL, 3));
|
||||
float_emit.LDR(32, INDEX_UNSIGNED, D1, scale_reg, 0);
|
||||
float_emit.FMUL(32, D0, D0, D1);
|
||||
float_emit.FCVTZS(32, D0, D0);
|
||||
float_emit.XTN(16, D0, D0);
|
||||
float_emit.XTN(8, D0, D0);
|
||||
|
||||
TST(DecodeReg(addr_reg), 6, 1);
|
||||
FixupBranch argh = B(CC_NEQ);
|
||||
MOVK(addr_reg, ((u64)Memory::base >> 32) & 0xFFFF, SHIFT_32);
|
||||
float_emit.ST1(8, Q0, 0, addr_reg);
|
||||
RET(X30);
|
||||
|
||||
SetJumpTarget(argh);
|
||||
ABI_PushRegisters(gprs);
|
||||
float_emit.ABI_PushRegisters(fprs);
|
||||
float_emit.SMOV(32, W0, Q0, 0);
|
||||
MOVI2R(X30, (u64)&Memory::Write_U8);
|
||||
BLR(X30);
|
||||
float_emit.ABI_PopRegisters(fprs);
|
||||
ABI_PopRegisters(gprs);
|
||||
RET(X30);
|
||||
}
|
||||
const u8* storeSingleU16 = GetCodePtr(); // Used by MKWii
|
||||
{
|
||||
BitSet32 gprs(GPR_CALLER_SAVE & ~7); // All except X0/X1/X2
|
||||
BitSet32 fprs(~3); // All except Q0/Q1
|
||||
|
||||
MOVI2R(X2, (u64)&m_quantizeTableS);
|
||||
ADD(scale_reg, X2, scale_reg, ArithOption(scale_reg, ST_LSL, 3));
|
||||
float_emit.LDR(32, INDEX_UNSIGNED, D1, scale_reg, 0);
|
||||
float_emit.FMUL(32, D0, D0, D1);
|
||||
float_emit.FCVTZU(32, D0, D0);
|
||||
float_emit.XTN(16, D0, D0);
|
||||
|
||||
TST(DecodeReg(addr_reg), 6, 1);
|
||||
FixupBranch argh = B(CC_NEQ);
|
||||
MOVK(addr_reg, ((u64)Memory::base >> 32) & 0xFFFF, SHIFT_32);
|
||||
float_emit.ST1(16, Q0, 0, addr_reg);
|
||||
RET(X30);
|
||||
|
||||
SetJumpTarget(argh);
|
||||
ABI_PushRegisters(gprs);
|
||||
float_emit.ABI_PushRegisters(fprs);
|
||||
float_emit.UMOV(32, W0, Q0, 0);
|
||||
MOVI2R(X30, (u64)&Memory::Write_U16);
|
||||
BLR(X30);
|
||||
float_emit.ABI_PopRegisters(fprs);
|
||||
ABI_PopRegisters(gprs);
|
||||
RET(X30);
|
||||
}
|
||||
const u8* storeSingleS16 = GetCodePtr();
|
||||
{
|
||||
BitSet32 gprs(GPR_CALLER_SAVE & ~7); // All except X0/X1/X2
|
||||
BitSet32 fprs(~3); // All except Q0/Q1
|
||||
|
||||
MOVI2R(X2, (u64)&m_quantizeTableS);
|
||||
ADD(scale_reg, X2, scale_reg, ArithOption(scale_reg, ST_LSL, 3));
|
||||
float_emit.LDR(32, INDEX_UNSIGNED, D1, scale_reg, 0);
|
||||
float_emit.FMUL(32, D0, D0, D1);
|
||||
float_emit.FCVTZS(32, D0, D0);
|
||||
float_emit.XTN(16, D0, D0);
|
||||
|
||||
TST(DecodeReg(addr_reg), 6, 1);
|
||||
FixupBranch argh = B(CC_NEQ);
|
||||
MOVK(addr_reg, ((u64)Memory::base >> 32) & 0xFFFF, SHIFT_32);
|
||||
float_emit.ST1(16, Q0, 0, addr_reg);
|
||||
RET(X30);
|
||||
|
||||
SetJumpTarget(argh);
|
||||
ABI_PushRegisters(gprs);
|
||||
float_emit.ABI_PushRegisters(fprs);
|
||||
float_emit.SMOV(32, W0, Q0, 0);
|
||||
|
||||
MOVI2R(X30, (u64)&Memory::Write_U16);
|
||||
BLR(X30);
|
||||
float_emit.ABI_PopRegisters(fprs);
|
||||
ABI_PopRegisters(gprs);
|
||||
RET(X30);
|
||||
}
|
||||
|
||||
pairedStoreQuantized = reinterpret_cast<const u8**>(const_cast<u8*>(AlignCode16()));
|
||||
ReserveCodeSpace(16 * sizeof(u8*));
|
||||
|
||||
pairedStoreQuantized[0] = storePairedFloat;
|
||||
pairedStoreQuantized[1] = storePairedIllegal;
|
||||
pairedStoreQuantized[2] = storePairedIllegal;
|
||||
pairedStoreQuantized[3] = storePairedIllegal;
|
||||
pairedStoreQuantized[4] = storePairedU8;
|
||||
pairedStoreQuantized[5] = storePairedU16;
|
||||
pairedStoreQuantized[6] = storePairedS8;
|
||||
pairedStoreQuantized[7] = storePairedS16;
|
||||
|
||||
pairedStoreQuantized[8] = storeSingleFloat;
|
||||
pairedStoreQuantized[9] = storePairedIllegal;
|
||||
pairedStoreQuantized[10] = storePairedIllegal;
|
||||
pairedStoreQuantized[11] = storePairedIllegal;
|
||||
pairedStoreQuantized[12] = storeSingleU8;
|
||||
pairedStoreQuantized[13] = storeSingleU16;
|
||||
pairedStoreQuantized[14] = storeSingleS8;
|
||||
pairedStoreQuantized[15] = storeSingleS16;
|
||||
}
|
||||
|
||||
@@ -194,7 +194,7 @@ void CommonAsmRoutines::GenMfcr()
|
||||
const u8 GC_ALIGNED16(pbswapShuffle1x4[16]) = { 3, 2, 1, 0, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
|
||||
const u8 GC_ALIGNED16(pbswapShuffle2x4[16]) = { 3, 2, 1, 0, 7, 6, 5, 4, 8, 9, 10, 11, 12, 13, 14, 15 };
|
||||
|
||||
static const float GC_ALIGNED16(m_quantizeTableS[]) =
|
||||
const float GC_ALIGNED16(m_quantizeTableS[]) =
|
||||
{
|
||||
(1ULL << 0), (1ULL << 0), (1ULL << 1), (1ULL << 1), (1ULL << 2), (1ULL << 2), (1ULL << 3), (1ULL << 3),
|
||||
(1ULL << 4), (1ULL << 4), (1ULL << 5), (1ULL << 5), (1ULL << 6), (1ULL << 6), (1ULL << 7), (1ULL << 7),
|
||||
@@ -222,7 +222,7 @@ static const float GC_ALIGNED16(m_quantizeTableS[]) =
|
||||
1.0 / (1ULL << 2), 1.0 / (1ULL << 2), 1.0 / (1ULL << 1), 1.0 / (1ULL << 1),
|
||||
};
|
||||
|
||||
static const float GC_ALIGNED16(m_dequantizeTableS[]) =
|
||||
const float GC_ALIGNED16(m_dequantizeTableS[]) =
|
||||
{
|
||||
1.0 / (1ULL << 0), 1.0 / (1ULL << 0), 1.0 / (1ULL << 1), 1.0 / (1ULL << 1),
|
||||
1.0 / (1ULL << 2), 1.0 / (1ULL << 2), 1.0 / (1ULL << 3), 1.0 / (1ULL << 3),
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
extern const u8 GC_ALIGNED16(pbswapShuffle1x4[16]);
|
||||
extern const u8 GC_ALIGNED16(pbswapShuffle2x4[16]);
|
||||
extern const float GC_ALIGNED16(m_one[]);
|
||||
extern const float GC_ALIGNED16(m_quantizeTableS[]);
|
||||
extern const float GC_ALIGNED16(m_dequantizeTableS[]);
|
||||
|
||||
class CommonAsmRoutinesBase
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user