diff --git a/src/Cafe/HW/Espresso/Recompiler/BackendAArch64/BackendAArch64.cpp b/src/Cafe/HW/Espresso/Recompiler/BackendAArch64/BackendAArch64.cpp index 8bab96e8..bd41a148 100644 --- a/src/Cafe/HW/Espresso/Recompiler/BackendAArch64/BackendAArch64.cpp +++ b/src/Cafe/HW/Espresso/Recompiler/BackendAArch64/BackendAArch64.cpp @@ -7,44 +7,49 @@ #include "Common/precompiled.h" #include "HW/Espresso/Interpreter/PPCInterpreterInternal.h" #include "HW/Espresso/PPCState.h" +#include "HW/Espresso/Recompiler/IML/IMLInstruction.h" #pragma push_macro("CSIZE") #undef CSIZE #include #include +#include +#include using namespace Xbyak_aarch64; #pragma pop_macro("CSIZE") -constexpr uint32_t TEMP_REGISTER_ID = 16; -constexpr uint32_t TEMP_REGISTER_2_ID = 17; -constexpr uint32_t PPC_RECOMPILER_INSTANCE_DATA_REG_ID = 19; -constexpr uint32_t MEMORY_BASE_REG_ID = 20; -constexpr uint32_t HCPU_REG_ID = 21; +constexpr uint32_t TEMP_REGISTER_ID = 25; +constexpr uint32_t TEMP_REGISTER_2_ID = 26; +constexpr uint32_t PPC_RECOMPILER_INSTANCE_DATA_REG_ID = 27; +constexpr uint32_t MEMORY_BASE_REG_ID = 28; +constexpr uint32_t HCPU_REG_ID = 29; // FPR -constexpr uint32_t TEMP_VECTOR_REGISTER_ID = 16; +constexpr uint32_t TEMP_VECTOR_REGISTER_ID = 29; +constexpr uint32_t TEMP_VECTOR_REGISTER_2_ID = 30; +constexpr uint32_t ASM_ROUTINE_REGISTER_ID = 31; -constexpr uint64_t DOUBLE_1_0 = 0x3ff0000000000000; // 1.0 +constexpr uint64_t DOUBLE_1_0 = std::bit_cast(1.0); struct AArch64GenContext_t : CodeGenerator { - AArch64GenContext_t() : CodeGenerator(4096, AutoGrow) + AArch64GenContext_t() + : CodeGenerator(4096, AutoGrow) { } - IMLSegment *currentSegment{}; - std::unordered_map labels; + IMLSegment* currentSegment{}; + std::unordered_map labels; }; - -void PPCRecompilerAArch64Gen_imlInstruction_r_name(PPCRecFunction_t *PPCRecFunction, ppcImlGenContext_t *ppcImlGenContext, AArch64GenContext_t *aarch64GenContext, IMLInstruction *imlInstruction) +void PPCRecompilerAArch64Gen_imlInstruction_r_name(PPCRecFunction_t* PPCRecFunction, ppcImlGenContext_t* ppcImlGenContext, AArch64GenContext_t* aarch64GenContext, IMLInstruction* imlInstruction) { uint32 name = imlInstruction->op_r_name.name; auto regId = imlInstruction->op_r_name.regR.GetRegID(); auto hcpuReg = XReg(HCPU_REG_ID); - cemu_assert_debug(regId < 16); + if (imlInstruction->op_r_name.regR.GetBaseFormat() == IMLRegFormat::I64) { auto regR = WReg(regId); @@ -105,7 +110,7 @@ void PPCRecompilerAArch64Gen_imlInstruction_r_name(PPCRecFunction_t *PPCRecFunct aarch64GenContext->add(tempReg, tempReg, hcpuReg); aarch64GenContext->ld1(regR.d2, AdrNoOfs(tempReg)); } - else if (name >= PPCREC_NAME_TEMPORARY_FPR0 || name < (PPCREC_NAME_TEMPORARY_FPR0 + 8)) + else if (name >= PPCREC_NAME_TEMPORARY_FPR0 && name < (PPCREC_NAME_TEMPORARY_FPR0 + 8)) { aarch64GenContext->mov(tempReg, offsetof(PPCInterpreter_t, temporaryFPR) + sizeof(FPR_t) * (name - PPCREC_NAME_TEMPORARY_FPR0)); aarch64GenContext->add(tempReg, tempReg, hcpuReg); @@ -122,12 +127,11 @@ void PPCRecompilerAArch64Gen_imlInstruction_r_name(PPCRecFunction_t *PPCRecFunct } } -void PPCRecompilerAArch64Gen_imlInstruction_name_r(PPCRecFunction_t *PPCRecFunction, ppcImlGenContext_t *ppcImlGenContext, AArch64GenContext_t *aarch64GenContext, IMLInstruction *imlInstruction) +void PPCRecompilerAArch64Gen_imlInstruction_name_r(PPCRecFunction_t* PPCRecFunction, ppcImlGenContext_t* ppcImlGenContext, AArch64GenContext_t* aarch64GenContext, IMLInstruction* imlInstruction) { uint32 name = imlInstruction->op_r_name.name; IMLRegID regId = imlInstruction->op_r_name.regR.GetRegID(); auto hcpuReg = XReg(HCPU_REG_ID); - cemu_assert_debug(regId < 16); if (imlInstruction->op_r_name.regR.GetBaseFormat() == IMLRegFormat::I64) { @@ -164,8 +168,7 @@ void PPCRecompilerAArch64Gen_imlInstruction_name_r(PPCRecFunction_t *PPCRecFunct } else if (name >= PPCREC_NAME_CR && name <= PPCREC_NAME_CR_LAST) { - aarch64GenContext->strb(regR, AdrImm(hcpuReg, offsetof(PPCInterpreter_t, cr) + - (name - PPCREC_NAME_CR))); + aarch64GenContext->strb(regR, AdrImm(hcpuReg, offsetof(PPCInterpreter_t, cr) + (name - PPCREC_NAME_CR))); } else if (name == PPCREC_NAME_CPU_MEMRES_EA) { @@ -207,14 +210,15 @@ void PPCRecompilerAArch64Gen_imlInstruction_name_r(PPCRecFunction_t *PPCRecFunct } } -bool PPCRecompilerAArch64Gen_imlInstruction_r_r(PPCRecFunction_t *PPCRecFunction, ppcImlGenContext_t *ppcImlGenContext, AArch64GenContext_t *aarch64GenContext, IMLInstruction *imlInstruction) +bool PPCRecompilerAArch64Gen_imlInstruction_r_r(PPCRecFunction_t* PPCRecFunction, ppcImlGenContext_t* ppcImlGenContext, AArch64GenContext_t* aarch64GenContext, IMLInstruction* imlInstruction) { auto regR = WReg(imlInstruction->op_r_r.regR.GetRegID()); auto regA = WReg(imlInstruction->op_r_r.regA.GetRegID()); if (imlInstruction->operation == PPCREC_IML_OP_ASSIGN) { - aarch64GenContext->mov(regR, regA); + if (imlInstruction->op_r_r.regR.GetRegID() != imlInstruction->op_r_r.regA.GetRegID()) + aarch64GenContext->mov(regR, regA); } else if (imlInstruction->operation == PPCREC_IML_OP_ENDIAN_SWAP) { @@ -244,8 +248,7 @@ bool PPCRecompilerAArch64Gen_imlInstruction_r_r(PPCRecFunction_t *PPCRecFunction { cemu_assert_suspicious(); // TODO: Implement this - aarch64GenContext->nop(); - return true; + return false; } else { @@ -255,100 +258,98 @@ bool PPCRecompilerAArch64Gen_imlInstruction_r_r(PPCRecFunction_t *PPCRecFunction return true; } -bool PPCRecompilerAArch64Gen_imlInstruction_r_s32(PPCRecFunction_t *PPCRecFunction, ppcImlGenContext_t *ppcImlGenContext, AArch64GenContext_t *aarch64GenContext, IMLInstruction *imlInstruction) +bool PPCRecompilerAArch64Gen_imlInstruction_r_s32(PPCRecFunction_t* PPCRecFunction, ppcImlGenContext_t* ppcImlGenContext, AArch64GenContext_t* aarch64GenContext, IMLInstruction* imlInstruction) { - uint32 imm32 = imlInstruction->op_r_immS32.immS32; + sint32 imm32 = imlInstruction->op_r_immS32.immS32; auto reg = WReg(imlInstruction->op_r_immS32.regR.GetRegID()); + if (imlInstruction->operation == PPCREC_IML_OP_ASSIGN) { aarch64GenContext->mov(reg, imm32); } else if (imlInstruction->operation == PPCREC_IML_OP_LEFT_ROTATE) { - cemu_assert_debug(imm32 <= 32); - aarch64GenContext->ror(reg, reg, 32 - imm32); + aarch64GenContext->ror(reg, reg, 32 - (imm32 & 0x1f)); } else { - debug_printf("PPCRecompilerAArch64Gen_imlInstruction_r_s32(): Unsupported operation 0x%x\n", - imlInstruction->operation); + debug_printf("PPCRecompilerAArch64Gen_imlInstruction_r_s32(): Unsupported operation 0x%x\n", imlInstruction->operation); return false; } return true; } -bool PPCRecompilerAArch64Gen_imlInstruction_conditional_r_s32(PPCRecFunction_t *PPCRecFunction, ppcImlGenContext_t *ppcImlGenContext, AArch64GenContext_t *aarch64GenContext, IMLInstruction *imlInstruction) +bool PPCRecompilerAArch64Gen_imlInstruction_conditional_r_s32(PPCRecFunction_t* PPCRecFunction, ppcImlGenContext_t* ppcImlGenContext, AArch64GenContext_t* aarch64GenContext, IMLInstruction* imlInstruction) { cemu_assert_unimplemented(); return false; } -bool PPCRecompilerAArch64Gen_imlInstruction_r_r_s32(PPCRecFunction_t *PPCRecFunction, ppcImlGenContext_t *ppcImlGenContext, AArch64GenContext_t *aarch64GenContext, IMLInstruction *imlInstruction) +bool PPCRecompilerAArch64Gen_imlInstruction_r_r_s32(PPCRecFunction_t* PPCRecFunction, ppcImlGenContext_t* ppcImlGenContext, AArch64GenContext_t* aarch64GenContext, IMLInstruction* imlInstruction) { auto regR = WReg(imlInstruction->op_r_r_s32.regR.GetRegID()); auto regA = WReg(imlInstruction->op_r_r_s32.regA.GetRegID()); auto tempReg32 = WReg(TEMP_REGISTER_ID); - uint32 immU32 = imlInstruction->op_r_r_s32.immS32; - aarch64GenContext->mov(tempReg32, immU32); + sint32 immS32 = imlInstruction->op_r_r_s32.immS32; if (imlInstruction->operation == PPCREC_IML_OP_ADD) { + aarch64GenContext->mov(tempReg32, immS32); aarch64GenContext->add(regR, regA, tempReg32); } else if (imlInstruction->operation == PPCREC_IML_OP_SUB) { + aarch64GenContext->mov(tempReg32, immS32); aarch64GenContext->sub(regR, regA, tempReg32); } else if (imlInstruction->operation == PPCREC_IML_OP_AND) { + aarch64GenContext->mov(tempReg32, immS32); aarch64GenContext->and_(regR, regA, tempReg32); } else if (imlInstruction->operation == PPCREC_IML_OP_OR) { + aarch64GenContext->mov(tempReg32, immS32); aarch64GenContext->orr(regR, regA, tempReg32); } else if (imlInstruction->operation == PPCREC_IML_OP_XOR) { + aarch64GenContext->mov(tempReg32, immS32); aarch64GenContext->eor(regR, regA, tempReg32); } else if (imlInstruction->operation == PPCREC_IML_OP_RLWIMI) { - // TODO: implement this? - /* - // registerResult = ((registerResult<<op_r_r_s32.immS32; + uint32 vImm = (uint32)immS32; uint32 mb = (vImm >> 0) & 0xFF; uint32 me = (vImm >> 8) & 0xFF; uint32 sh = (vImm >> 16) & 0xFF; uint32 mask = ppc_mask(mb, me); - // copy rS to temporary register - x64Gen_mov_reg64_reg64(x64GenContext, REG_RESV_TEMP, regA); - // rotate destination register if (sh) - x64Gen_rol_reg64Low32_imm8(x64GenContext, REG_RESV_TEMP, (uint8)sh & 0x1F); - // AND destination register with inverted mask - x64Gen_and_reg64Low32_imm32(x64GenContext, regR, ~mask); - // AND temporary rS register with mask - x64Gen_and_reg64Low32_imm32(x64GenContext, REG_RESV_TEMP, mask); - // OR result with temporary - x64Gen_or_reg64Low32_reg64Low32(x64GenContext, regR, REG_RESV_TEMP);*/ - cemu_assert_suspicious(); - aarch64GenContext->nop(); + aarch64GenContext->ror(tempReg32, regA, 32 - (sh & 0x1F)); + else + aarch64GenContext->mov(tempReg32, regA); + aarch64GenContext->and_(regR, regR, ~mask); + aarch64GenContext->and_(tempReg32, tempReg32, mask); + aarch64GenContext->orr(regR, regR, tempReg32); } else if (imlInstruction->operation == PPCREC_IML_OP_MULTIPLY_SIGNED) { + aarch64GenContext->mov(tempReg32, immS32); aarch64GenContext->mul(regR, regA, tempReg32); } else if (imlInstruction->operation == PPCREC_IML_OP_LEFT_SHIFT) { + aarch64GenContext->mov(tempReg32, immS32); aarch64GenContext->lsl(regR, regA, tempReg32); } else if (imlInstruction->operation == PPCREC_IML_OP_RIGHT_SHIFT_U) { + aarch64GenContext->mov(tempReg32, immS32); aarch64GenContext->lsr(regR, regA, tempReg32); } else if (imlInstruction->operation == PPCREC_IML_OP_RIGHT_SHIFT_S) { + aarch64GenContext->mov(tempReg32, immS32); aarch64GenContext->asr(regR, regA, tempReg32); } else @@ -359,28 +360,28 @@ bool PPCRecompilerAArch64Gen_imlInstruction_r_r_s32(PPCRecFunction_t *PPCRecFunc return true; } -bool PPCRecompilerAArch64Gen_imlInstruction_r_r_s32_carry(PPCRecFunction_t *PPCRecFunction, ppcImlGenContext_t *ppcImlGenContext, AArch64GenContext_t *aarch64GenContext, IMLInstruction *imlInstruction) +bool PPCRecompilerAArch64Gen_imlInstruction_r_r_s32_carry(PPCRecFunction_t* PPCRecFunction, ppcImlGenContext_t* ppcImlGenContext, AArch64GenContext_t* aarch64GenContext, IMLInstruction* imlInstruction) { auto regR = WReg(imlInstruction->op_r_r_s32_carry.regR.GetRegID()); auto regA = WReg(imlInstruction->op_r_r_s32_carry.regA.GetRegID()); - auto regCarry = WReg(imlInstruction->op_r_r_s32_carry.regCarry.GetRegID()); + auto regCarry = XReg(imlInstruction->op_r_r_s32_carry.regCarry.GetRegID()); auto tempReg32 = WReg(TEMP_REGISTER_ID); - uint32 immU32 = imlInstruction->op_r_r_s32_carry.immS32; - aarch64GenContext->mov(tempReg32, immU32); - + auto tempReg64 = XReg(TEMP_REGISTER_ID); + sint32 immS32 = imlInstruction->op_r_r_s32_carry.immS32; if (imlInstruction->operation == PPCREC_IML_OP_ADD) { + aarch64GenContext->mov(tempReg32, immS32); aarch64GenContext->adds(regR, regA, tempReg32); aarch64GenContext->cset(regCarry, Cond::CS); } else if (imlInstruction->operation == PPCREC_IML_OP_ADD_WITH_CARRY) { - aarch64GenContext->adds(regR, regA, regCarry); + aarch64GenContext->mrs(tempReg64, 0b11, 0b011, 0b0100, 0b0010, 0b000); // NZCV + aarch64GenContext->bfi(tempReg64, regCarry, 29, 1); + aarch64GenContext->msr(0b11, 0b011, 0b0100, 0b0010, 0b000, tempReg64); + aarch64GenContext->mov(tempReg32, immS32); + aarch64GenContext->adcs(regR, regA, tempReg32); aarch64GenContext->cset(regCarry, Cond::CS); - aarch64GenContext->adds(regR, regR, tempReg32); - aarch64GenContext->cinc(regCarry, regCarry, Cond::CS); - aarch64GenContext->cmp(regCarry, 0x0); - aarch64GenContext->cset(regCarry, Cond::GT); } else { @@ -391,11 +392,12 @@ bool PPCRecompilerAArch64Gen_imlInstruction_r_r_s32_carry(PPCRecFunction_t *PPCR return true; } -bool PPCRecompilerAArch64Gen_imlInstruction_r_r_r(PPCRecFunction_t *PPCRecFunction, ppcImlGenContext_t *ppcImlGenContext, AArch64GenContext_t *aarch64GenContext, IMLInstruction *imlInstruction) +bool PPCRecompilerAArch64Gen_imlInstruction_r_r_r(PPCRecFunction_t* PPCRecFunction, ppcImlGenContext_t* ppcImlGenContext, AArch64GenContext_t* aarch64GenContext, IMLInstruction* imlInstruction) { auto regResult = WReg(imlInstruction->op_r_r_r.regR.GetRegID()); auto regOperand1 = WReg(imlInstruction->op_r_r_r.regA.GetRegID()); auto regOperand2 = WReg(imlInstruction->op_r_r_r.regB.GetRegID()); + auto regOperand2_64 = WReg(imlInstruction->op_r_r_r.regB.GetRegID()); auto tempReg32 = WReg(TEMP_REGISTER_ID); if (imlInstruction->operation == PPCREC_IML_OP_ADD) @@ -424,16 +426,19 @@ bool PPCRecompilerAArch64Gen_imlInstruction_r_r_r(PPCRecFunction_t *PPCRecFuncti } else if (imlInstruction->operation == PPCREC_IML_OP_SLW) { + aarch64GenContext->tst(regOperand2_64, 32); aarch64GenContext->lsl(regResult, regOperand1, regOperand2); + aarch64GenContext->csel(regResult, regResult, aarch64GenContext->wzr, Cond::EQ); } else if (imlInstruction->operation == PPCREC_IML_OP_SRW) { + aarch64GenContext->tst(regOperand2_64, 32); aarch64GenContext->lsr(regResult, regOperand1, regOperand2); + aarch64GenContext->csel(regResult, regResult, aarch64GenContext->wzr, Cond::EQ); } else if (imlInstruction->operation == PPCREC_IML_OP_LEFT_ROTATE) { - aarch64GenContext->mov(tempReg32, 32ULL); - aarch64GenContext->sub(tempReg32, tempReg32, regOperand2); + aarch64GenContext->neg(tempReg32, regOperand2); aarch64GenContext->ror(regResult, regOperand1, tempReg32); } else if (imlInstruction->operation == PPCREC_IML_OP_RIGHT_SHIFT_S) @@ -480,13 +485,13 @@ bool PPCRecompilerAArch64Gen_imlInstruction_r_r_r(PPCRecFunction_t *PPCRecFuncti return true; } -bool PPCRecompilerAArch64Gen_imlInstruction_r_r_r_carry(PPCRecFunction_t *PPCRecFunction, ppcImlGenContext_t *ppcImlGenContext, AArch64GenContext_t *aarch64GenContext, IMLInstruction *imlInstruction) +bool PPCRecompilerAArch64Gen_imlInstruction_r_r_r_carry(PPCRecFunction_t* PPCRecFunction, ppcImlGenContext_t* ppcImlGenContext, AArch64GenContext_t* aarch64GenContext, IMLInstruction* imlInstruction) { auto regR = WReg(imlInstruction->op_r_r_r_carry.regR.GetRegID()); auto regA = WReg(imlInstruction->op_r_r_r_carry.regA.GetRegID()); auto regB = WReg(imlInstruction->op_r_r_r_carry.regB.GetRegID()); - auto regCarry = WReg(imlInstruction->op_r_r_r_carry.regCarry.GetRegID()); - auto tempReg = WReg(TEMP_REGISTER_ID); + auto regCarry = XReg(imlInstruction->op_r_r_r_carry.regCarry.GetRegID()); + auto tempReg64 = XReg(TEMP_REGISTER_ID); if (imlInstruction->operation == PPCREC_IML_OP_ADD) { aarch64GenContext->adds(regR, regA, regB); @@ -494,13 +499,11 @@ bool PPCRecompilerAArch64Gen_imlInstruction_r_r_r_carry(PPCRecFunction_t *PPCRec } else if (imlInstruction->operation == PPCREC_IML_OP_ADD_WITH_CARRY) { - aarch64GenContext->adds(tempReg, regA, regCarry); + aarch64GenContext->mrs(tempReg64, 0b11, 0b011, 0b0100, 0b0010, 0b000); // NZCV + aarch64GenContext->bfi(tempReg64, regCarry, 29, 1); + aarch64GenContext->msr(0b11, 0b011, 0b0100, 0b0010, 0b000, tempReg64); + aarch64GenContext->adcs(regR, regA, regB); aarch64GenContext->cset(regCarry, Cond::CS); - aarch64GenContext->adds(tempReg, tempReg, regB); - aarch64GenContext->cinc(regCarry, regCarry, Cond::CS); - aarch64GenContext->cmp(regCarry, 0x0); - aarch64GenContext->cset(regCarry, Cond::GT); - aarch64GenContext->mov(regR, tempReg); } else { @@ -515,21 +518,27 @@ Cond ImlCondToArm64Cond(IMLCondition condition) { switch (condition) { - case IMLCondition::EQ: return Cond::EQ; - case IMLCondition::NEQ: return Cond::NE; - case IMLCondition::UNSIGNED_GT: return Cond::HI; - case IMLCondition::UNSIGNED_LT: return Cond::CC; - case IMLCondition::SIGNED_GT: return Cond::GT; - case IMLCondition::SIGNED_LT: return Cond::LT; - default: - { - cemu_assert_suspicious(); - return Cond::EQ; - } + case IMLCondition::EQ: + return Cond::EQ; + case IMLCondition::NEQ: + return Cond::NE; + case IMLCondition::UNSIGNED_GT: + return Cond::HI; + case IMLCondition::UNSIGNED_LT: + return Cond::LO; + case IMLCondition::SIGNED_GT: + return Cond::GT; + case IMLCondition::SIGNED_LT: + return Cond::LT; + default: + { + cemu_assert_suspicious(); + return Cond::EQ; + } } } -bool PPCRecompilerAArch64Gen_imlInstruction_compare(PPCRecFunction_t *PPCRecFunction, ppcImlGenContext_t *ppcImlGenContext, AArch64GenContext_t *aarch64GenContext, IMLInstruction *imlInstruction) +bool PPCRecompilerAArch64Gen_imlInstruction_compare(PPCRecFunction_t* PPCRecFunction, ppcImlGenContext_t* ppcImlGenContext, AArch64GenContext_t* aarch64GenContext, IMLInstruction* imlInstruction) { auto regR = WReg(imlInstruction->op_compare.regR.GetRegID()); auto regA = WReg(imlInstruction->op_compare.regA.GetRegID()); @@ -540,12 +549,12 @@ bool PPCRecompilerAArch64Gen_imlInstruction_compare(PPCRecFunction_t *PPCRecFunc return true; } -bool PPCRecompilerAArch64Gen_imlInstruction_compare_s32(PPCRecFunction_t *PPCRecFunction, ppcImlGenContext_t *ppcImlGenContext, AArch64GenContext_t *aarch64GenContext, IMLInstruction *imlInstruction) +bool PPCRecompilerAArch64Gen_imlInstruction_compare_s32(PPCRecFunction_t* PPCRecFunction, ppcImlGenContext_t* ppcImlGenContext, AArch64GenContext_t* aarch64GenContext, IMLInstruction* imlInstruction) { auto regR = WReg(imlInstruction->op_compare.regR.GetRegID()); auto regA = WReg(imlInstruction->op_compare.regA.GetRegID()); auto tempReg = WReg(TEMP_REGISTER_ID); - uint32_t imm = imlInstruction->op_compare_s32.immS32; + sint32 imm = imlInstruction->op_compare_s32.immS32; auto cond = ImlCondToArm64Cond(imlInstruction->op_compare.cond); aarch64GenContext->mov(tempReg, imm); aarch64GenContext->cmp(regA, tempReg); @@ -553,53 +562,58 @@ bool PPCRecompilerAArch64Gen_imlInstruction_compare_s32(PPCRecFunction_t *PPCRec return true; } -bool PPCRecompilerAArch64Gen_imlInstruction_cjump2(PPCRecFunction_t *PPCRecFunction, ppcImlGenContext_t *ppcImlGenContext, AArch64GenContext_t *aarch64GenContext, IMLInstruction *imlInstruction, IMLSegment *imlSegment) +void PPCRecompilerAArch64Gen_imlInstruction_cjump2(PPCRecFunction_t* PPCRecFunction, ppcImlGenContext_t* ppcImlGenContext, AArch64GenContext_t* aarch64GenContext, IMLInstruction* imlInstruction, IMLSegment* imlSegment) { if (imlSegment->nextSegmentBranchTaken == aarch64GenContext->currentSegment) cemu_assert_suspicious(); - Label &label = aarch64GenContext->labels.at(imlSegment->nextSegmentBranchTaken); + Label& label = aarch64GenContext->labels.at(imlSegment->nextSegmentBranchTaken); auto regBool = WReg(imlInstruction->op_conditional_jump.registerBool.GetRegID()); - auto cond = imlInstruction->op_conditional_jump.mustBeTrue ? Cond::EQ : Cond::NE; - aarch64GenContext->cmp(regBool, 0x1); - aarch64GenContext->b(cond, label); - return true; -} - -bool PPCRecompilerAArch64Gen_imlInstruction_jump2(PPCRecFunction_t *PPCRecFunction, ppcImlGenContext_t *ppcImlGenContext, AArch64GenContext_t *aarch64GenContext, IMLInstruction *imlInstruction, IMLSegment *imlSegment) -{ - Label &label = aarch64GenContext->labels.at(imlSegment->nextSegmentBranchTaken); + Label skipJump; + if (imlInstruction->op_conditional_jump.mustBeTrue) + aarch64GenContext->cbz(regBool, skipJump); + else + aarch64GenContext->cbnz(regBool, skipJump); aarch64GenContext->b(label); - return true; + aarch64GenContext->L(skipJump); } -bool PPCRecompilerAArch64Gen_imlInstruction_conditionalJumpCycleCheck(PPCRecFunction_t *PPCRecFunction, ppcImlGenContext_t *ppcImlGenContext, AArch64GenContext_t *aarch64GenContext, IMLInstruction *imlInstruction) +void PPCRecompilerAArch64Gen_imlInstruction_jump2(PPCRecFunction_t* PPCRecFunction, ppcImlGenContext_t* ppcImlGenContext, AArch64GenContext_t* aarch64GenContext, IMLInstruction* imlInstruction, IMLSegment* imlSegment) { - Label &label = aarch64GenContext->labels.at(aarch64GenContext->currentSegment->nextSegmentBranchTaken); + Label& label = aarch64GenContext->labels.at(imlSegment->nextSegmentBranchTaken); + aarch64GenContext->b(label); +} + +bool PPCRecompilerAArch64Gen_imlInstruction_conditionalJumpCycleCheck(PPCRecFunction_t* PPCRecFunction, ppcImlGenContext_t* ppcImlGenContext, AArch64GenContext_t* aarch64GenContext, IMLInstruction* imlInstruction) +{ + Label positiveRegCycles; + Label& label = aarch64GenContext->labels.at(aarch64GenContext->currentSegment->nextSegmentBranchTaken); WReg regCycles = WReg(TEMP_REGISTER_ID); + Label skipJump; aarch64GenContext->ldr(regCycles, AdrImm(XReg(HCPU_REG_ID), offsetof(PPCInterpreter_t, remainingCycles))); - aarch64GenContext->cmp(regCycles, 0x0); - aarch64GenContext->ble(label); + aarch64GenContext->tbz(regCycles, 31, skipJump); + aarch64GenContext->b(label); + aarch64GenContext->L(skipJump); return true; } -void ATTR_MS_ABI PPCRecompiler_getTBL(PPCInterpreter_t *hCPU, uint32 gprIndex) +void ATTR_MS_ABI PPCRecompiler_getTBL(PPCInterpreter_t* hCPU, uint32 gprIndex) { uint64 coreTime = coreinit::coreinit_getTimerTick(); hCPU->gpr[gprIndex] = (uint32)(coreTime & 0xFFFFFFFF); } -void ATTR_MS_ABI PPCRecompiler_getTBU(PPCInterpreter_t *hCPU, uint32 gprIndex) +void ATTR_MS_ABI PPCRecompiler_getTBU(PPCInterpreter_t* hCPU, uint32 gprIndex) { uint64 coreTime = coreinit::coreinit_getTimerTick(); hCPU->gpr[gprIndex] = (uint32)((coreTime >> 32) & 0xFFFFFFFF); } -void *ATTR_MS_ABI PPCRecompiler_virtualHLE(PPCInterpreter_t *hCPU, uint32 hleFuncId) +void* ATTR_MS_ABI PPCRecompiler_virtualHLE(PPCInterpreter_t* hCPU, uint32 hleFuncId) { - void *prevRSPTemp = hCPU->rspTemp; + void* prevRSPTemp = hCPU->rspTemp; if (hleFuncId == 0xFFD0) { - hCPU->remainingCycles -= 500; // let subtract about 500 cycles for each HLE call + hCPU->remainingCycles -= 500; // let subtract about 500 cycles for each HLE call hCPU->gpr[3] = 0; PPCInterpreter_nextInstruction(hCPU); return PPCInterpreter_getCurrentInstance(); @@ -614,12 +628,15 @@ void *ATTR_MS_ABI PPCRecompiler_virtualHLE(PPCInterpreter_t *hCPU, uint32 hleFun return PPCInterpreter_getCurrentInstance(); } -bool PPCRecompilerAArch64Gen_imlInstruction_macro(PPCRecFunction_t *PPCRecFunction, ppcImlGenContext_t *ppcImlGenContext, AArch64GenContext_t *aarch64GenContext, IMLInstruction *imlInstruction) +bool PPCRecompilerAArch64Gen_imlInstruction_macro(PPCRecFunction_t* PPCRecFunction, ppcImlGenContext_t* ppcImlGenContext, AArch64GenContext_t* aarch64GenContext, IMLInstruction* imlInstruction) { if (imlInstruction->operation == PPCREC_IML_MACRO_B_TO_REG) { - auto branchDstReg = XReg(imlInstruction->op_macro.paramReg.GetRegID()); + auto branchDstRegId = imlInstruction->op_macro.paramReg.GetRegID(); + auto branchDstReg = XReg(branchDstRegId); + aarch64GenContext->mov(aarch64GenContext->x1, branchDstReg); auto tempReg = XReg(TEMP_REGISTER_ID); + aarch64GenContext->mov(tempReg, offsetof(PPCRecompilerInstanceData_t, ppcRecompilerDirectJumpTable)); aarch64GenContext->add(tempReg, tempReg, branchDstReg); aarch64GenContext->add(tempReg, tempReg, branchDstReg); @@ -638,6 +655,7 @@ bool PPCRecompilerAArch64Gen_imlInstruction_macro(PPCRecFunction_t *PPCRecFuncti uint32 newIP = imlInstruction->op_macro.param2; auto tempReg64 = XReg(TEMP_REGISTER_ID); uint64 lookupOffset = (uint64)offsetof(PPCRecompilerInstanceData_t, ppcRecompilerDirectJumpTable) + (uint64)newIP * 2ULL; + aarch64GenContext->mov(aarch64GenContext->w1, newIP); aarch64GenContext->mov(tempReg64, lookupOffset); aarch64GenContext->add(tempReg64, tempReg64, XReg(PPC_RECOMPILER_INSTANCE_DATA_REG_ID)); aarch64GenContext->ldr(tempReg64, AdrNoOfs(tempReg64)); @@ -649,6 +667,7 @@ bool PPCRecompilerAArch64Gen_imlInstruction_macro(PPCRecFunction_t *PPCRecFuncti uint32 newIP = imlInstruction->op_macro.param2; auto tempReg = XReg(TEMP_REGISTER_ID); uint64 lookupOffset = (uint64)offsetof(PPCRecompilerInstanceData_t, ppcRecompilerDirectJumpTable) + (uint64)newIP * 2ULL; + aarch64GenContext->mov(aarch64GenContext->w1, newIP); aarch64GenContext->mov(tempReg, lookupOffset); aarch64GenContext->add(tempReg, tempReg, XReg(PPC_RECOMPILER_INSTANCE_DATA_REG_ID)); aarch64GenContext->ldr(tempReg, AdrNoOfs(tempReg)); @@ -659,8 +678,9 @@ bool PPCRecompilerAArch64Gen_imlInstruction_macro(PPCRecFunction_t *PPCRecFuncti { uint32 currentInstructionAddress = imlInstruction->op_macro.param; auto tempReg = XReg(TEMP_REGISTER_ID); - uint32 newIP = 0; // special value for recompiler exit + uint32 newIP = 0; // special value for recompiler exit uint64 lookupOffset = (uint64)offsetof(PPCRecompilerInstanceData_t, ppcRecompilerDirectJumpTable) + (uint64)newIP * 2ULL; + aarch64GenContext->mov(aarch64GenContext->w1, currentInstructionAddress); aarch64GenContext->mov(tempReg, lookupOffset); aarch64GenContext->add(tempReg, tempReg, XReg(PPC_RECOMPILER_INSTANCE_DATA_REG_ID)); aarch64GenContext->ldr(tempReg, AdrNoOfs(tempReg)); @@ -703,8 +723,9 @@ bool PPCRecompilerAArch64Gen_imlInstruction_macro(PPCRecFunction_t *PPCRecFuncti aarch64GenContext->str(aarch64GenContext->x1, AdrImm(spReg, 16)); aarch64GenContext->mov(aarch64GenContext->x0, hcpuReg); - aarch64GenContext->mov(aarch64GenContext->x1, funcId); + aarch64GenContext->mov(aarch64GenContext->w1, funcId); // call HLE function + aarch64GenContext->mov(tempReg64, (uint64)PPCRecompiler_virtualHLE); aarch64GenContext->blr(tempReg64); @@ -721,7 +742,7 @@ bool PPCRecompilerAArch64Gen_imlInstruction_macro(PPCRecFunction_t *PPCRecFuncti aarch64GenContext->mov(XReg(MEMORY_BASE_REG_ID), (uint64)memory_base); // check if cycles where decreased beyond zero, if yes -> leave recompiler aarch64GenContext->ldr(tempReg32, AdrImm(hcpuReg, offsetof(PPCInterpreter_t, remainingCycles))); - aarch64GenContext->cmp(tempReg32, 0); // check if negative + aarch64GenContext->cmp(tempReg32, 0); // check if negative aarch64GenContext->bgt(cyclesLeftLabel); aarch64GenContext->ldr(aarch64GenContext->w1, AdrImm(hcpuReg, offsetof(PPCInterpreter_t, instructionPointer))); @@ -777,9 +798,7 @@ bool PPCRecompilerAArch64Gen_imlInstruction_macro(PPCRecFunction_t *PPCRecFuncti aarch64GenContext->sub(spReg, spReg, 16); aarch64GenContext->str(aarch64GenContext->x30, AdrNoOfs(spReg)); - aarch64GenContext->str(hcpuReg, AdrImm(spReg, 8)); aarch64GenContext->blr(tempReg64); - aarch64GenContext->ldr(hcpuReg, AdrImm(spReg, 8)); aarch64GenContext->ldr(aarch64GenContext->x30, AdrNoOfs(spReg)); aarch64GenContext->add(spReg, spReg, 16); @@ -797,7 +816,7 @@ bool PPCRecompilerAArch64Gen_imlInstruction_macro(PPCRecFunction_t *PPCRecFuncti return false; } -bool PPCRecompilerAArch64Gen_imlInstruction_load(PPCRecFunction_t *PPCRecFunction, ppcImlGenContext_t *ppcImlGenContext, AArch64GenContext_t *aarch64GenContext, IMLInstruction *imlInstruction, bool indexed) +bool PPCRecompilerAArch64Gen_imlInstruction_load(PPCRecFunction_t* PPCRecFunction, ppcImlGenContext_t* ppcImlGenContext, AArch64GenContext_t* aarch64GenContext, IMLInstruction* imlInstruction, bool indexed) { cemu_assert_debug(imlInstruction->op_storeLoad.registerData.GetRegFormat() == IMLRegFormat::I32); cemu_assert_debug(imlInstruction->op_storeLoad.registerMem.GetRegFormat() == IMLRegFormat::I32); @@ -807,54 +826,52 @@ bool PPCRecompilerAArch64Gen_imlInstruction_load(PPCRecFunction_t *PPCRecFunctio IMLRegID dataRegId = imlInstruction->op_storeLoad.registerData.GetRegID(); IMLRegID memRegId = imlInstruction->op_storeLoad.registerMem.GetRegID(); IMLRegID memOffsetRegId = indexed ? imlInstruction->op_storeLoad.registerMem2.GetRegID() : PPC_REC_INVALID_REGISTER; - uint64 memOffset = imlInstruction->op_storeLoad.immS32; + sint32 memOffset = imlInstruction->op_storeLoad.immS32; bool signExtend = imlInstruction->op_storeLoad.flags2.signExtend; bool switchEndian = imlInstruction->op_storeLoad.flags2.swapEndian; - if (memRegId == memOffsetRegId) - { - return false; - } - - if (indexed && dataRegId == memOffsetRegId) - { - // for indexed memory access dataRegId must not be the same register as the second memory register, - // this can easily be fixed by swapping the logic of dataRegId and memOffsetRegId - std::swap(memRegId, memOffsetRegId); - } - - auto memReg = XReg(memRegId); auto memoryBaseReg = XReg(MEMORY_BASE_REG_ID); - auto temp2Reg64 = XReg(TEMP_REGISTER_2_ID); - auto tempReg64 = XReg(TEMP_REGISTER_ID); + auto memReg = WReg(memRegId); + auto tempReg32 = WReg(TEMP_REGISTER_ID); auto dataReg32 = WReg(dataRegId); - auto dataReg64 = XReg(dataRegId); - aarch64GenContext->mov(tempReg64, memOffset); - aarch64GenContext->add(tempReg64, tempReg64, memReg); - aarch64GenContext->add(tempReg64, tempReg64, memoryBaseReg); + aarch64GenContext->mov(tempReg32, memOffset); + aarch64GenContext->add(tempReg32, tempReg32, memReg); if (indexed) - aarch64GenContext->add(tempReg64, tempReg64, XReg(memOffsetRegId)); + aarch64GenContext->add(tempReg32, tempReg32, WReg(memOffsetRegId)); + auto adr = AdrExt(memoryBaseReg, tempReg32, ExtMod::UXTW); if (imlInstruction->op_storeLoad.copyWidth == 32) { - aarch64GenContext->ldr(dataReg32, AdrNoOfs(tempReg64)); + aarch64GenContext->ldr(dataReg32, adr); if (switchEndian) - aarch64GenContext->rev32(dataReg64, dataReg64); + aarch64GenContext->rev(dataReg32, dataReg32); } else if (imlInstruction->op_storeLoad.copyWidth == 16) { - aarch64GenContext->ldrh(dataReg32, AdrNoOfs(tempReg64)); if (switchEndian) - aarch64GenContext->rev16(dataReg32, dataReg32); - if (signExtend) - aarch64GenContext->sxth(dataReg32, dataReg32); + { + aarch64GenContext->ldrh(dataReg32, adr); + aarch64GenContext->rev(dataReg32, dataReg32); + if (signExtend) + aarch64GenContext->asr(dataReg32, dataReg32, 16); + else + aarch64GenContext->lsr(dataReg32, dataReg32, 16); + } + else + { + if (signExtend) + aarch64GenContext->ldrsh(dataReg32, adr); + else + aarch64GenContext->ldrh(dataReg32, adr); + } } else if (imlInstruction->op_storeLoad.copyWidth == 8) { - aarch64GenContext->ldrb(dataReg32, AdrNoOfs(tempReg64)); if (signExtend) - aarch64GenContext->sxtb(dataReg32, dataReg32); + aarch64GenContext->ldrsb(dataReg32, adr); + else + aarch64GenContext->ldrb(dataReg32, adr); } else { @@ -863,7 +880,7 @@ bool PPCRecompilerAArch64Gen_imlInstruction_load(PPCRecFunction_t *PPCRecFunctio return true; } -bool PPCRecompilerAArch64Gen_imlInstruction_store(PPCRecFunction_t *PPCRecFunction, ppcImlGenContext_t *ppcImlGenContext, AArch64GenContext_t *aarch64GenContext, IMLInstruction *imlInstruction, bool indexed) +bool PPCRecompilerAArch64Gen_imlInstruction_store(PPCRecFunction_t* PPCRecFunction, ppcImlGenContext_t* ppcImlGenContext, AArch64GenContext_t* aarch64GenContext, IMLInstruction* imlInstruction, bool indexed) { cemu_assert_debug(imlInstruction->op_storeLoad.registerData.GetRegFormat() == IMLRegFormat::I32); cemu_assert_debug(imlInstruction->op_storeLoad.registerMem.GetRegFormat() == IMLRegFormat::I32); @@ -874,51 +891,46 @@ bool PPCRecompilerAArch64Gen_imlInstruction_store(PPCRecFunction_t *PPCRecFuncti IMLRegID memRegId = imlInstruction->op_storeLoad.registerMem.GetRegID(); IMLRegID memOffsetRegId = indexed ? imlInstruction->op_storeLoad.registerMem2.GetRegID() : 0; - if (memRegId == memOffsetRegId) - { - return false; - } - - if (indexed && dataRegId == memRegId) - { - // for indexed memory access dataRegId must not be the same register as the second memory register, - // this can easily be fixed by swapping the logic of realRegisterMem and memRegId - std::swap(memRegId, memOffsetRegId); - } - - auto tempReg64 = XReg(TEMP_REGISTER_ID); auto tempReg32 = WReg(TEMP_REGISTER_ID); - auto temp2Reg64 = XReg(TEMP_REGISTER_2_ID); + auto temp2Reg32 = WReg(TEMP_REGISTER_2_ID); auto dataReg = WReg(dataRegId); - auto memBaseReg = XReg(MEMORY_BASE_REG_ID); - auto memReg = XReg(memRegId); + auto memReg = WReg(memRegId); sint32 memOffset = imlInstruction->op_storeLoad.immS32; bool swapEndian = imlInstruction->op_storeLoad.flags2.swapEndian; - aarch64GenContext->mov(temp2Reg64, memOffset); - aarch64GenContext->add(temp2Reg64, temp2Reg64, memReg); - aarch64GenContext->add(temp2Reg64, temp2Reg64, memBaseReg); + aarch64GenContext->mov(tempReg32, memOffset); + aarch64GenContext->add(tempReg32, tempReg32, memReg); if (indexed) - aarch64GenContext->add(temp2Reg64, temp2Reg64, XReg(memOffsetRegId)); - + aarch64GenContext->add(tempReg32, tempReg32, WReg(memOffsetRegId)); + auto adr = AdrExt(XReg(MEMORY_BASE_REG_ID), tempReg32, ExtMod::UXTW); if (imlInstruction->op_storeLoad.copyWidth == 32) { - aarch64GenContext->mov(tempReg32, dataReg); if (swapEndian) - aarch64GenContext->rev32(tempReg64, tempReg64); - aarch64GenContext->str(tempReg32, AdrNoOfs(temp2Reg64)); + { + aarch64GenContext->rev(temp2Reg32, dataReg); + aarch64GenContext->str(temp2Reg32, adr); + } + else + { + aarch64GenContext->str(dataReg, adr); + } } else if (imlInstruction->op_storeLoad.copyWidth == 16) { - aarch64GenContext->mov(tempReg32, dataReg); if (swapEndian) - aarch64GenContext->rev16(tempReg32, tempReg32); - aarch64GenContext->strh(tempReg32, AdrNoOfs(temp2Reg64)); + { + aarch64GenContext->rev(temp2Reg32, dataReg); + aarch64GenContext->lsr(temp2Reg32, temp2Reg32, 16); + aarch64GenContext->strh(temp2Reg32, adr); + } + else + { + aarch64GenContext->strh(dataReg, adr); + } } else if (imlInstruction->op_storeLoad.copyWidth == 8) { - aarch64GenContext->mov(tempReg32, dataReg); - aarch64GenContext->strb(tempReg32, AdrNoOfs(temp2Reg64)); + aarch64GenContext->strb(dataReg, adr); } else { @@ -927,37 +939,42 @@ bool PPCRecompilerAArch64Gen_imlInstruction_store(PPCRecFunction_t *PPCRecFuncti return true; } -bool PPCRecompilerAArch64Gen_imlInstruction_atomic_cmp_store(PPCRecFunction_t *PPCRecFunction, ppcImlGenContext_t *ppcImlGenContext, AArch64GenContext_t *aarch64GenContext, IMLInstruction *imlInstruction) +void PPCRecompilerAArch64Gen_imlInstruction_atomic_cmp_store(PPCRecFunction_t* PPCRecFunction, ppcImlGenContext_t* ppcImlGenContext, AArch64GenContext_t* aarch64GenContext, IMLInstruction* imlInstruction) { auto outReg = WReg(imlInstruction->op_atomic_compare_store.regBoolOut.GetRegID()); auto eaReg = XReg(imlInstruction->op_atomic_compare_store.regEA.GetRegID()); auto valReg = WReg(imlInstruction->op_atomic_compare_store.regWriteValue.GetRegID()); auto cmpValReg = WReg(imlInstruction->op_atomic_compare_store.regCompareValue.GetRegID()); auto tempReg64 = XReg(TEMP_REGISTER_ID); - auto tempReg32 = WReg(TEMP_REGISTER_ID); - // cemu_assert_suspicious(); - Label notEqualLabel; - Label storeFailedLabel; - aarch64GenContext->L(storeFailedLabel); - aarch64GenContext->add(tempReg64, XReg(MEMORY_BASE_REG_ID), eaReg); - aarch64GenContext->ldxr(outReg, AdrNoOfs(tempReg64)); - aarch64GenContext->cmp(outReg, cmpValReg); - aarch64GenContext->cset(outReg, Cond::EQ); - aarch64GenContext->bne(notEqualLabel); - aarch64GenContext->stxr(tempReg32, valReg, AdrNoOfs(tempReg64)); - aarch64GenContext->cbnz(tempReg32, storeFailedLabel); - aarch64GenContext->L(notEqualLabel); + auto temp2Reg32 = WReg(TEMP_REGISTER_2_ID); - return true; + Label endCmpStore; + Label notEqual; + Label storeFailed; + + aarch64GenContext->add(tempReg64, XReg(MEMORY_BASE_REG_ID), eaReg); + aarch64GenContext->ldxr(temp2Reg32, AdrNoOfs(tempReg64)); + aarch64GenContext->cmp(temp2Reg32, cmpValReg); + aarch64GenContext->bne(notEqual); + aarch64GenContext->L(storeFailed); + aarch64GenContext->stlxr(temp2Reg32, valReg, AdrNoOfs(tempReg64)); + aarch64GenContext->cbnz(temp2Reg32, storeFailed); + aarch64GenContext->mov(outReg, 1); + aarch64GenContext->b(endCmpStore); + + aarch64GenContext->L(notEqual); + aarch64GenContext->mov(outReg, 0); + aarch64GenContext->L(endCmpStore); } -void PPCRecompilerAArch64Gen_imlInstr_gqr_generateScaleCode(ppcImlGenContext_t *ppcImlGenContext, AArch64GenContext_t *aarch64GenContext, VReg &dataReg, bool isLoad, bool scalePS1, IMLReg registerGQR) +void PPCRecompilerAArch64Gen_imlInstr_gqr_generateScaleCode(ppcImlGenContext_t* ppcImlGenContext, AArch64GenContext_t* aarch64GenContext, VReg& dataReg, bool isLoad, bool scalePS1, IMLReg registerGQR) { auto tempReg64 = XReg(TEMP_REGISTER_ID); auto tempReg32 = WReg(TEMP_REGISTER_ID); + auto tempReg64_2 = XReg(TEMP_REGISTER_2_ID); auto gqrReg = XReg(registerGQR.GetRegID()); auto recDataReg = XReg(PPC_RECOMPILER_INSTANCE_DATA_REG_ID); - auto tempVectorReg = VReg(TEMP_VECTOR_REGISTER_ID); + auto tempVectorReg = VReg(TEMP_VECTOR_REGISTER_2_ID); // load GQR aarch64GenContext->mov(tempReg64, gqrReg); // extract scale field and multiply by 16 to get array offset @@ -968,52 +985,50 @@ void PPCRecompilerAArch64Gen_imlInstr_gqr_generateScaleCode(ppcImlGenContext_t * if (isLoad) { if (scalePS1) - aarch64GenContext->add(tempReg64, tempReg64, offsetof(PPCRecompilerInstanceData_t, _psq_ld_scale_ps0_ps1)); + aarch64GenContext->mov(tempReg64_2, offsetof(PPCRecompilerInstanceData_t, _psq_ld_scale_ps0_ps1)); else - aarch64GenContext->add(tempReg64, tempReg64, offsetof(PPCRecompilerInstanceData_t, _psq_ld_scale_ps0_1)); + aarch64GenContext->mov(tempReg64_2, offsetof(PPCRecompilerInstanceData_t, _psq_ld_scale_ps0_1)); } else { if (scalePS1) - aarch64GenContext->add(tempReg64, tempReg64, offsetof(PPCRecompilerInstanceData_t, _psq_st_scale_ps0_ps1)); + aarch64GenContext->mov(tempReg64_2, offsetof(PPCRecompilerInstanceData_t, _psq_st_scale_ps0_ps1)); else - aarch64GenContext->add(tempReg64, tempReg64, offsetof(PPCRecompilerInstanceData_t, _psq_st_scale_ps0_1)); + aarch64GenContext->mov(tempReg64_2, offsetof(PPCRecompilerInstanceData_t, _psq_st_scale_ps0_1)); } + aarch64GenContext->add(tempReg64, tempReg64, tempReg64_2); aarch64GenContext->ld1(tempVectorReg.d2, AdrNoOfs(tempReg64)); aarch64GenContext->fmul(dataReg.d2, dataReg.d2, tempVectorReg.d2); } // generate code for PSQ load for a particular type // if scaleGQR is -1 then a scale of 1.0 is assumed (no scale) -void PPCRecompilerAArch64Gen_imlInstr_psq_load(ppcImlGenContext_t *ppcImlGenContext, AArch64GenContext_t *aarch64GenContext, uint8 mode, VReg &dataReg, XReg &memReg, XReg &indexReg, sint32 memImmS32, bool indexed, IMLReg registerGQR = IMLREG_INVALID) +void PPCRecompilerAArch64Gen_imlInstr_psq_load(ppcImlGenContext_t* ppcImlGenContext, AArch64GenContext_t* aarch64GenContext, uint8 mode, VReg& dataReg, WReg& memReg, WReg& indexReg, sint32 memImmS32, bool indexed, IMLReg registerGQR = IMLREG_INVALID) { auto memBaseReg = XReg(MEMORY_BASE_REG_ID); auto tempReg32 = WReg(TEMP_REGISTER_ID); auto tempReg64 = XReg(TEMP_REGISTER_ID); - auto recompilerInstanceDataReg = XReg(PPC_RECOMPILER_INSTANCE_DATA_REG_ID); if (mode == PPCREC_FPR_LD_MODE_PSQ_FLOAT_PS0_PS1) { - aarch64GenContext->mov(tempReg64, memImmS32); - aarch64GenContext->add(tempReg64, tempReg64, memBaseReg); - aarch64GenContext->add(tempReg64, tempReg64, memReg); + aarch64GenContext->mov(tempReg32, memImmS32); + aarch64GenContext->add(tempReg32, tempReg32, memReg); if (indexed) cemu_assert_suspicious(); - aarch64GenContext->ldr(tempReg64, AdrNoOfs(tempReg64)); + aarch64GenContext->ldr(tempReg64, AdrExt(memBaseReg, tempReg32, ExtMod::UXTW)); aarch64GenContext->rev(tempReg64, tempReg64); - aarch64GenContext->ror(tempReg64, tempReg64, 32); // swap upper and lower DWORD + aarch64GenContext->ror(tempReg64, tempReg64, 32); // swap upper and lower DWORD aarch64GenContext->mov(dataReg.d[0], tempReg64); aarch64GenContext->fcvtl(dataReg.d2, dataReg.s2); // note: floats are not scaled } else if (mode == PPCREC_FPR_LD_MODE_PSQ_FLOAT_PS0) { - aarch64GenContext->mov(tempReg64, memImmS32); - aarch64GenContext->add(tempReg64, tempReg64, memBaseReg); - aarch64GenContext->add(tempReg64, tempReg64, memReg); + aarch64GenContext->mov(tempReg32, memImmS32); + aarch64GenContext->add(tempReg32, tempReg32, memReg); if (indexed) - aarch64GenContext->add(tempReg64, tempReg64, indexReg); - aarch64GenContext->ldr(tempReg32, AdrNoOfs(tempReg64)); - aarch64GenContext->rev32(tempReg64, tempReg64); + cemu_assert_suspicious(); + aarch64GenContext->ldr(tempReg32, AdrExt(memBaseReg, tempReg32, ExtMod::UXTW)); + aarch64GenContext->rev(tempReg32, tempReg32); aarch64GenContext->mov(dataReg.s[0], tempReg32); aarch64GenContext->fcvtl(dataReg.d2, dataReg.s2); @@ -1053,37 +1068,48 @@ void PPCRecompilerAArch64Gen_imlInstr_psq_load(ppcImlGenContext_t *ppcImlGenCont return; } - bool loadPS1 = (mode == PPCREC_FPR_LD_MODE_PSQ_S16_PS0_PS1 || mode == PPCREC_FPR_LD_MODE_PSQ_U16_PS0_PS1 || mode == PPCREC_FPR_LD_MODE_PSQ_U8_PS0_PS1 || mode == PPCREC_FPR_LD_MODE_PSQ_S8_PS0_PS1); + bool loadPS1 = mode == PPCREC_FPR_LD_MODE_PSQ_S16_PS0_PS1 || + mode == PPCREC_FPR_LD_MODE_PSQ_U16_PS0_PS1 || + mode == PPCREC_FPR_LD_MODE_PSQ_U8_PS0_PS1 || + mode == PPCREC_FPR_LD_MODE_PSQ_S8_PS0_PS1; if (indexed) cemu_assert_suspicious(); - // read from memory - if (loadPS1 == false) + for (sint32 wordIndex = 0; wordIndex < 2; wordIndex++) { - // store constant 1 - aarch64GenContext->mov(tempReg64, 1); - aarch64GenContext->mov(dataReg.d[1], tempReg64); + // read from memory + if (wordIndex == 1 && !loadPS1) + { + // store constant 1 + aarch64GenContext->mov(tempReg64, 1); + aarch64GenContext->mov(dataReg.d[wordIndex], tempReg64); + } + else + { + sint32 memOffset = memImmS32 + wordIndex * (readSize / 8); + aarch64GenContext->mov(tempReg32, memOffset); + aarch64GenContext->add(tempReg32, tempReg32, memReg); + auto adr = AdrExt(memBaseReg, tempReg32, ExtMod::UXTW); + if (readSize == 16) + { + // half word + aarch64GenContext->ldrh(tempReg32, adr); + aarch64GenContext->rev(tempReg32, tempReg32); // endian swap + aarch64GenContext->lsr(tempReg32, tempReg32, 16); + if (isSigned) + aarch64GenContext->sxth(tempReg64, tempReg32); + } + else + { + // byte + if (isSigned) + aarch64GenContext->ldrsb(tempReg64, adr); + else + aarch64GenContext->ldrb(tempReg32, adr); + } + // store + aarch64GenContext->mov(dataReg.d[wordIndex], tempReg64); + } } - uint32 memOffset = memImmS32 + (readSize / 8); - aarch64GenContext->mov(tempReg64, memOffset); - aarch64GenContext->add(tempReg64, tempReg64, memBaseReg); - aarch64GenContext->add(tempReg64, tempReg64, memReg); - if (readSize == 16) - { - // half word - aarch64GenContext->ldrh(tempReg32, AdrNoOfs(tempReg64)); - aarch64GenContext->rev16(tempReg32, tempReg32); // endian swap - if (isSigned) - aarch64GenContext->sxth(tempReg64, tempReg32); - } - else if (readSize == 8) - { - // byte - aarch64GenContext->ldrb(tempReg32, AdrNoOfs(tempReg64)); - if (isSigned) - aarch64GenContext->sxtb(tempReg64, tempReg32); - } - // store - aarch64GenContext->mov(dataReg.d[0], tempReg64); // convert the two integers to doubles aarch64GenContext->scvtf(dataReg.d2, dataReg.d2); // scale @@ -1092,10 +1118,9 @@ void PPCRecompilerAArch64Gen_imlInstr_psq_load(ppcImlGenContext_t *ppcImlGenCont } } -void PPCRecompilerAArch64Gen_imlInstr_psq_load_generic(ppcImlGenContext_t *ppcImlGenContext, AArch64GenContext_t *aarch64GenContext, uint8 mode, VReg &dataReg, XReg &memReg, XReg &indexReg, sint32 memImmS32, bool indexed, IMLReg registerGQR) +void PPCRecompilerAArch64Gen_imlInstr_psq_load_generic(ppcImlGenContext_t* ppcImlGenContext, AArch64GenContext_t* aarch64GenContext, uint8 mode, VReg& dataReg, WReg& memReg, WReg& indexReg, sint32 memImmS32, bool indexed, IMLReg registerGQR) { bool loadPS1 = (mode == PPCREC_FPR_LD_MODE_PSQ_GENERIC_PS0_PS1); - auto tempReg64 = XReg(TEMP_REGISTER_ID); auto tempReg32 = WReg(TEMP_REGISTER_ID); Label u8FormatLabel, u16FormatLabel, s8FormatLabel, s16FormatLabel, casesEndLabel; @@ -1104,16 +1129,16 @@ void PPCRecompilerAArch64Gen_imlInstr_psq_load_generic(ppcImlGenContext_t *ppcIm aarch64GenContext->and_(tempReg32, tempReg32, 7); // jump cases - aarch64GenContext->cmp(tempReg32, 4); // type 4 -> u8 + aarch64GenContext->cmp(tempReg32, 4); // type 4 -> u8 aarch64GenContext->beq(u8FormatLabel); - aarch64GenContext->cmp(tempReg32, 5); // type 5 -> u16 + aarch64GenContext->cmp(tempReg32, 5); // type 5 -> u16 aarch64GenContext->beq(u16FormatLabel); - aarch64GenContext->cmp(tempReg32, 6); // type 6 -> s8 + aarch64GenContext->cmp(tempReg32, 6); // type 6 -> s8 aarch64GenContext->beq(s8FormatLabel); - aarch64GenContext->cmp(tempReg32, 7); // type 7 -> s16 + aarch64GenContext->cmp(tempReg32, 7); // type 7 -> s16 aarch64GenContext->beq(s16FormatLabel); // default case -> float @@ -1140,11 +1165,11 @@ void PPCRecompilerAArch64Gen_imlInstr_psq_load_generic(ppcImlGenContext_t *ppcIm aarch64GenContext->L(casesEndLabel); } -bool PPCRecompilerAArch64Gen_imlInstruction_fpr_load(PPCRecFunction_t *PPCRecFunction, ppcImlGenContext_t *ppcImlGenContext, AArch64GenContext_t *aarch64GenContext, IMLInstruction *imlInstruction, bool indexed) +bool PPCRecompilerAArch64Gen_imlInstruction_fpr_load(PPCRecFunction_t* PPCRecFunction, ppcImlGenContext_t* ppcImlGenContext, AArch64GenContext_t* aarch64GenContext, IMLInstruction* imlInstruction, bool indexed) { auto dataReg = VReg(imlInstruction->op_storeLoad.registerData.GetRegID()); - auto realRegisterMem = XReg(imlInstruction->op_storeLoad.registerMem.GetRegID()); - auto realRegisterMem2 = indexed ? XReg(imlInstruction->op_storeLoad.registerMem2.GetRegID()) : aarch64GenContext->xzr; + auto realRegisterMem = WReg(imlInstruction->op_storeLoad.registerMem.GetRegID()); + auto realRegisterMem2 = indexed ? WReg(imlInstruction->op_storeLoad.registerMem2.GetRegID()) : aarch64GenContext->wzr; auto memBaseReg = XReg(MEMORY_BASE_REG_ID); auto tempReg64 = XReg(TEMP_REGISTER_ID); auto tempReg32 = WReg(TEMP_REGISTER_ID); @@ -1153,14 +1178,12 @@ bool PPCRecompilerAArch64Gen_imlInstruction_fpr_load(PPCRecFunction_t *PPCRecFun if (mode == PPCREC_FPR_LD_MODE_SINGLE_INTO_PS0_PS1) { - // load byte swapped single into temporary FPR - aarch64GenContext->mov(tempReg64, adrOffset); - aarch64GenContext->add(tempReg64, tempReg64, memBaseReg); - aarch64GenContext->add(tempReg64, tempReg64, realRegisterMem); + aarch64GenContext->mov(tempReg32, adrOffset); + aarch64GenContext->add(tempReg32, tempReg32, realRegisterMem); if (indexed) - aarch64GenContext->add(tempReg64, tempReg64, realRegisterMem2); - aarch64GenContext->ldr(tempReg32, AdrNoOfs(tempReg64)); - aarch64GenContext->rev32(tempReg64, tempReg64); + aarch64GenContext->add(tempReg32, tempReg32, realRegisterMem2); + aarch64GenContext->ldr(tempReg32, AdrExt(memBaseReg, tempReg32, ExtMod::UXTW)); + aarch64GenContext->rev(tempReg32, tempReg32); aarch64GenContext->mov(dataReg.s[0], tempReg32); if (imlInstruction->op_storeLoad.flags2.notExpanded) @@ -1170,36 +1193,34 @@ bool PPCRecompilerAArch64Gen_imlInstruction_fpr_load(PPCRecFunction_t *PPCRecFun else { aarch64GenContext->fcvtl(dataReg.d2, dataReg.s2); - aarch64GenContext->dup(dataReg.d2, dataReg.d[0]); + aarch64GenContext->mov(dataReg.d[1], dataReg.d[0]); } } else if (mode == PPCREC_FPR_LD_MODE_DOUBLE_INTO_PS0) { - aarch64GenContext->mov(tempReg64, adrOffset); - aarch64GenContext->add(tempReg64, tempReg64, memBaseReg); - aarch64GenContext->add(tempReg64, tempReg64, realRegisterMem); + aarch64GenContext->mov(tempReg32, adrOffset); + aarch64GenContext->add(tempReg32, tempReg32, realRegisterMem); if (indexed) - aarch64GenContext->add(tempReg64, tempReg64, realRegisterMem2); - aarch64GenContext->ldr(tempReg64, AdrNoOfs(tempReg64)); - aarch64GenContext->rev64(tempReg64, tempReg64); + aarch64GenContext->add(tempReg32, tempReg32, realRegisterMem2); + aarch64GenContext->ldr(tempReg64, AdrExt(memBaseReg, tempReg32, ExtMod::UXTW)); + aarch64GenContext->rev(tempReg64, tempReg64); aarch64GenContext->mov(dataReg.d[0], tempReg64); } else if (mode == PPCREC_FPR_LD_MODE_PSQ_FLOAT_PS0_PS1 || - mode == PPCREC_FPR_LD_MODE_PSQ_FLOAT_PS0 || - mode == PPCREC_FPR_LD_MODE_PSQ_S16_PS0 || - mode == PPCREC_FPR_LD_MODE_PSQ_S16_PS0_PS1 || - mode == PPCREC_FPR_LD_MODE_PSQ_S16_PS0 || - mode == PPCREC_FPR_LD_MODE_PSQ_U16_PS0 || - mode == PPCREC_FPR_LD_MODE_PSQ_U16_PS0_PS1 || - mode == PPCREC_FPR_LD_MODE_PSQ_S8_PS0 || - mode == PPCREC_FPR_LD_MODE_PSQ_S8_PS0_PS1 || - mode == PPCREC_FPR_LD_MODE_PSQ_S8_PS0 || - mode == PPCREC_FPR_LD_MODE_PSQ_U8_PS0_PS1) + mode == PPCREC_FPR_LD_MODE_PSQ_FLOAT_PS0 || + mode == PPCREC_FPR_LD_MODE_PSQ_S16_PS0 || + mode == PPCREC_FPR_LD_MODE_PSQ_S16_PS0_PS1 || + mode == PPCREC_FPR_LD_MODE_PSQ_U16_PS0 || + mode == PPCREC_FPR_LD_MODE_PSQ_U16_PS0_PS1 || + mode == PPCREC_FPR_LD_MODE_PSQ_S8_PS0 || + mode == PPCREC_FPR_LD_MODE_PSQ_S8_PS0_PS1 || + mode == PPCREC_FPR_LD_MODE_PSQ_U8_PS0 || + mode == PPCREC_FPR_LD_MODE_PSQ_U8_PS0_PS1) { PPCRecompilerAArch64Gen_imlInstr_psq_load(ppcImlGenContext, aarch64GenContext, mode, dataReg, realRegisterMem, realRegisterMem2, imlInstruction->op_storeLoad.immS32, indexed); } else if (mode == PPCREC_FPR_LD_MODE_PSQ_GENERIC_PS0_PS1 || - mode == PPCREC_FPR_LD_MODE_PSQ_GENERIC_PS0) + mode == PPCREC_FPR_LD_MODE_PSQ_GENERIC_PS0) { PPCRecompilerAArch64Gen_imlInstr_psq_load_generic(ppcImlGenContext, aarch64GenContext, mode, dataReg, realRegisterMem, realRegisterMem2, imlInstruction->op_storeLoad.immS32, indexed, imlInstruction->op_storeLoad.registerGQR); } @@ -1210,82 +1231,104 @@ bool PPCRecompilerAArch64Gen_imlInstruction_fpr_load(PPCRecFunction_t *PPCRecFun return true; } -void PPCRecompilerAArch64Gen_imlInstr_psq_store(ppcImlGenContext_t *ppcImlGenContext, AArch64GenContext_t *aarch64GenContext, uint8 mode, VReg &dataReg, XReg &memReg, XReg &indexReg, sint32 memOffset, bool indexed, IMLReg registerGQR = IMLREG_INVALID) +void PPCRecompilerAArch64Gen_imlInstr_psq_store(ppcImlGenContext_t* ppcImlGenContext, AArch64GenContext_t* aarch64GenContext, uint8 mode, IMLRegID dataRegId, WReg& memReg, WReg& indexReg, sint32 memOffset, bool indexed, IMLReg registerGQR = IMLREG_INVALID) { auto tempReg32 = WReg(TEMP_REGISTER_ID); - auto tempReg64 = XReg(TEMP_REGISTER_ID); - auto temp2Reg = XReg(TEMP_REGISTER_2_ID); - auto tempFPReg = VReg(TEMP_VECTOR_REGISTER_ID); + auto temp2Reg64 = XReg(TEMP_REGISTER_2_ID); + auto temp2Reg32 = WReg(TEMP_REGISTER_2_ID); + auto dataVReg = VReg(dataRegId); + auto dataDReg = DReg(dataRegId); + auto tempFPVReg = VReg(TEMP_VECTOR_REGISTER_ID); + auto tempFPSReg = SReg(TEMP_VECTOR_REGISTER_ID); auto memBaseReg = XReg(MEMORY_BASE_REG_ID); bool storePS1 = (mode == PPCREC_FPR_ST_MODE_PSQ_FLOAT_PS0_PS1 || - mode == PPCREC_FPR_ST_MODE_PSQ_S8_PS0_PS1 || - mode == PPCREC_FPR_ST_MODE_PSQ_U8_PS0_PS1 || - mode == PPCREC_FPR_ST_MODE_PSQ_U16_PS0_PS1 || - mode == PPCREC_FPR_ST_MODE_PSQ_S16_PS0_PS1); + mode == PPCREC_FPR_ST_MODE_PSQ_S8_PS0_PS1 || + mode == PPCREC_FPR_ST_MODE_PSQ_U8_PS0_PS1 || + mode == PPCREC_FPR_ST_MODE_PSQ_U16_PS0_PS1 || + mode == PPCREC_FPR_ST_MODE_PSQ_S16_PS0_PS1); bool isFloat = mode == PPCREC_FPR_ST_MODE_PSQ_FLOAT_PS0 || mode == PPCREC_FPR_ST_MODE_PSQ_FLOAT_PS0_PS1; - aarch64GenContext->add(tempReg64, XReg(HCPU_REG_ID), offsetof(PPCInterpreter_t, temporaryFPR)); - aarch64GenContext->st1(dataReg.d2, AdrNoOfs(tempReg64)); if (registerGQR.IsValid()) { + // move to temporary reg and update data reg + aarch64GenContext->mov(tempFPVReg.b16, dataVReg.b16); + dataVReg = tempFPVReg; // apply scale if (!isFloat) - PPCRecompilerAArch64Gen_imlInstr_gqr_generateScaleCode(ppcImlGenContext, aarch64GenContext, dataReg, false, storePS1, registerGQR); + PPCRecompilerAArch64Gen_imlInstr_gqr_generateScaleCode(ppcImlGenContext, aarch64GenContext, dataVReg, false, storePS1, registerGQR); } if (mode == PPCREC_FPR_ST_MODE_PSQ_FLOAT_PS0) { - aarch64GenContext->mov(temp2Reg, memOffset); - aarch64GenContext->add(temp2Reg, temp2Reg, memBaseReg); - aarch64GenContext->add(temp2Reg, temp2Reg, memReg); + aarch64GenContext->mov(tempReg32, memOffset); + aarch64GenContext->add(tempReg32, tempReg32, memReg); if (indexed) - aarch64GenContext->sub(temp2Reg, temp2Reg, indexReg); - aarch64GenContext->fcvtn(tempFPReg.s2, dataReg.d2); - aarch64GenContext->mov(tempReg32, tempFPReg.s[0]); - aarch64GenContext->rev64(tempReg64, tempReg64); - aarch64GenContext->str(tempReg32, AdrNoOfs(temp2Reg)); + aarch64GenContext->add(tempReg32, tempReg32, indexReg); + aarch64GenContext->fcvt(tempFPSReg, dataDReg); + aarch64GenContext->fmov(temp2Reg32, tempFPSReg); + aarch64GenContext->rev(temp2Reg32, temp2Reg32); + aarch64GenContext->str(temp2Reg32, AdrExt(memBaseReg, tempReg32, ExtMod::UXTW)); } else if (mode == PPCREC_FPR_ST_MODE_PSQ_FLOAT_PS0_PS1) { - aarch64GenContext->mov(temp2Reg, memOffset); - aarch64GenContext->add(temp2Reg, temp2Reg, memBaseReg); - aarch64GenContext->add(temp2Reg, temp2Reg, memReg); + aarch64GenContext->mov(tempReg32, memOffset); + aarch64GenContext->add(tempReg32, tempReg32, memReg); if (indexed) - cemu_assert_suspicious(); // todo? - aarch64GenContext->fcvtn(tempFPReg.s2, dataReg.d2); - aarch64GenContext->mov(tempReg64, tempFPReg.d[0]); - aarch64GenContext->ror(tempReg64, tempReg64, 32); // swap upper and lower DWORD - aarch64GenContext->rev64(tempReg64, tempReg64); - aarch64GenContext->str(tempReg64, AdrNoOfs(temp2Reg)); + aarch64GenContext->add(tempReg32, tempReg32, indexReg); + aarch64GenContext->fcvtn(tempFPVReg.s2, dataVReg.d2); + aarch64GenContext->mov(temp2Reg64, tempFPVReg.d[0]); + aarch64GenContext->ror(temp2Reg64, temp2Reg64, 32); // swap upper and lower DWORD + aarch64GenContext->rev(temp2Reg64, temp2Reg64); + aarch64GenContext->str(temp2Reg64, AdrExt(memBaseReg, tempReg32, ExtMod::UXTW)); } else { // store as integer - // get limit from mode - uint32 clampMin, clampMax; - uint32 bitWriteSize; + // set clamp from mode + sint32 bitWriteSize; + std::function clamp; if (mode == PPCREC_FPR_ST_MODE_PSQ_S8_PS0 || mode == PPCREC_FPR_ST_MODE_PSQ_S8_PS0_PS1) { - clampMin = 0xffffff80; // -128 - clampMax = 0x7f; // 127 + clamp = [&]() { + aarch64GenContext->mov(temp2Reg32, -128); + aarch64GenContext->cmn(tempReg32, 128); + aarch64GenContext->csel(temp2Reg32, tempReg32, temp2Reg32, Cond::GT); + aarch64GenContext->mov(tempReg32, 127); + aarch64GenContext->cmp(temp2Reg32, 127); + aarch64GenContext->csel(temp2Reg32, temp2Reg32, tempReg32, Cond::LT); + }; bitWriteSize = 8; } else if (mode == PPCREC_FPR_ST_MODE_PSQ_U8_PS0 || mode == PPCREC_FPR_ST_MODE_PSQ_U8_PS0_PS1) { - clampMin = 0x0; // 0 - clampMax = 0xff; // 255 + clamp = [&]() { + aarch64GenContext->mov(temp2Reg32, 255); + aarch64GenContext->bic(tempReg32, tempReg32, tempReg32, ShMod::ASR, 31); + aarch64GenContext->cmp(tempReg32, 255); + aarch64GenContext->csel(temp2Reg32, tempReg32, temp2Reg32, Cond::LT); + }; bitWriteSize = 8; } else if (mode == PPCREC_FPR_ST_MODE_PSQ_U16_PS0 || mode == PPCREC_FPR_ST_MODE_PSQ_U16_PS0_PS1) { - clampMin = 0x0; - clampMax = 0xFFFF; + clamp = [&]() { + aarch64GenContext->mov(temp2Reg32, 65535); + aarch64GenContext->bic(tempReg32, tempReg32, tempReg32, ShMod::ASR, 31); + aarch64GenContext->cmp(tempReg32, temp2Reg32); + aarch64GenContext->csel(temp2Reg32, tempReg32, temp2Reg32, Cond::LT); + }; bitWriteSize = 16; } else if (mode == PPCREC_FPR_ST_MODE_PSQ_S16_PS0 || mode == PPCREC_FPR_ST_MODE_PSQ_S16_PS0_PS1) { - clampMin = 0xffff8000; // -32768 - clampMax = 0x7fff; // 32767 + clamp = [&]() { + aarch64GenContext->mov(temp2Reg32, -32768); + aarch64GenContext->cmn(tempReg32, 8, 12); + aarch64GenContext->csel(temp2Reg32, tempReg32, temp2Reg32, Cond::GT); + aarch64GenContext->mov(tempReg32, 32767); + aarch64GenContext->cmp(temp2Reg32, tempReg32); + aarch64GenContext->csel(temp2Reg32, temp2Reg32, tempReg32, Cond::LT); + }; bitWriteSize = 16; } else @@ -1295,154 +1338,155 @@ void PPCRecompilerAArch64Gen_imlInstr_psq_store(ppcImlGenContext_t *ppcImlGenCon } if (indexed) - cemu_assert_suspicious(); // unsupported - - aarch64GenContext->add(memReg, memReg, memBaseReg); - aarch64GenContext->fcvtzs(dataReg.d2, dataReg.d2); + cemu_assert_suspicious(); // unsupported + aarch64GenContext->fcvtn(tempFPVReg.s2, dataVReg.d2); + aarch64GenContext->fcvtzs(tempFPVReg.s2, tempFPVReg.s2); for (sint32 valueIndex = 0; valueIndex < (storePS1 ? 2 : 1); valueIndex++) { // todo - multiply by GQR scale? - Label clampMaxLabel, clampEndLabel; - // max(i, clampMin) - aarch64GenContext->mov(tempReg64, dataReg.d[valueIndex]); - aarch64GenContext->cmp(tempReg32, clampMin); - aarch64GenContext->bge(clampMaxLabel); - aarch64GenContext->mov(tempReg32, clampMin); - aarch64GenContext->b(clampEndLabel); - // min(i, clampMax) - aarch64GenContext->L(clampMaxLabel); - aarch64GenContext->cmp(tempReg32, clampMax); - aarch64GenContext->ble(clampMaxLabel); - aarch64GenContext->mov(tempReg32, clampMax); - aarch64GenContext->L(clampEndLabel); + aarch64GenContext->mov(tempReg32, tempFPVReg.s[valueIndex]); + // clamp value in tempReg32 and store in temp2Reg32 + clamp(); if (bitWriteSize == 16) - aarch64GenContext->rev16(tempReg32, tempReg32); // endian swap - aarch64GenContext->mov(temp2Reg, memOffset + valueIndex * (bitWriteSize / 8)); - aarch64GenContext->add(temp2Reg, temp2Reg, memReg); + { + // endian swap + aarch64GenContext->rev(temp2Reg32, temp2Reg32); + aarch64GenContext->lsr(temp2Reg32, temp2Reg32, 16); + } + sint32 address = memOffset + valueIndex * (bitWriteSize / 8); + aarch64GenContext->mov(tempReg32, address); + aarch64GenContext->add(tempReg32, tempReg32, memReg); + auto adr = AdrExt(memBaseReg, tempReg32, ExtMod::UXTW); // write to memory if (bitWriteSize == 8) - aarch64GenContext->strb(tempReg32, AdrNoOfs(temp2Reg)); + aarch64GenContext->strb(temp2Reg32, adr); else if (bitWriteSize == 16) - aarch64GenContext->strh(tempReg32, AdrNoOfs(temp2Reg)); + aarch64GenContext->strh(temp2Reg32, adr); } - aarch64GenContext->sub(memReg, memReg, memBaseReg); } - aarch64GenContext->add(tempReg64, XReg(HCPU_REG_ID), offsetof(PPCInterpreter_t, temporaryFPR)); - aarch64GenContext->ld1(dataReg.d2, AdrNoOfs(tempReg64)); } -void PPCRecompilerAArch64Gen_imlInstr_psq_store_generic(ppcImlGenContext_t *ppcImlGenContext, AArch64GenContext_t *aarch64GenContext, uint8 mode, VReg &dataReg, XReg &memReg, XReg &indexReg, sint32 memOffset, bool indexed, IMLReg registerGQR) +void PPCRecompilerAArch64Gen_imlInstr_psq_store_generic(ppcImlGenContext_t* ppcImlGenContext, AArch64GenContext_t* aarch64GenContext, uint8 mode, IMLRegID dataRegId, WReg& memReg, WReg& indexReg, sint32 memOffset, bool indexed, IMLReg registerGQR) { bool storePS1 = (mode == PPCREC_FPR_ST_MODE_PSQ_GENERIC_PS0_PS1); auto tempReg32 = WReg(TEMP_REGISTER_ID); Label u8FormatLabel, u16FormatLabel, s8FormatLabel, s16FormatLabel, casesEndLabel; - // load GQR & extract store type field aarch64GenContext->and_(tempReg32, WReg(registerGQR.GetRegID()), 7); // jump cases - aarch64GenContext->cmp(tempReg32, 4); // type 4 -> u8 + aarch64GenContext->cmp(tempReg32, 4); // type 4 -> u8 aarch64GenContext->beq(u8FormatLabel); - aarch64GenContext->cmp(tempReg32, 5); // type 5 -> u16 + aarch64GenContext->cmp(tempReg32, 5); // type 5 -> u16 aarch64GenContext->beq(u16FormatLabel); - aarch64GenContext->cmp(tempReg32, 6); // type 6 -> s8 + aarch64GenContext->cmp(tempReg32, 6); // type 6 -> s8 aarch64GenContext->beq(s8FormatLabel); - aarch64GenContext->cmp(tempReg32, 7); // type 7 -> s16 + aarch64GenContext->cmp(tempReg32, 7); // type 7 -> s16 aarch64GenContext->beq(s16FormatLabel); // default case -> float // generate cases - PPCRecompilerAArch64Gen_imlInstr_psq_store(ppcImlGenContext, aarch64GenContext, storePS1 ? PPCREC_FPR_ST_MODE_PSQ_FLOAT_PS0_PS1 : PPCREC_FPR_ST_MODE_PSQ_FLOAT_PS0, dataReg, memReg, indexReg, memOffset, indexed, registerGQR); + PPCRecompilerAArch64Gen_imlInstr_psq_store(ppcImlGenContext, aarch64GenContext, storePS1 ? PPCREC_FPR_ST_MODE_PSQ_FLOAT_PS0_PS1 : PPCREC_FPR_ST_MODE_PSQ_FLOAT_PS0, dataRegId, memReg, indexReg, memOffset, indexed, registerGQR); aarch64GenContext->b(casesEndLabel); aarch64GenContext->L(u16FormatLabel); - PPCRecompilerAArch64Gen_imlInstr_psq_store(ppcImlGenContext, aarch64GenContext, storePS1 ? PPCREC_FPR_ST_MODE_PSQ_U16_PS0_PS1 : PPCREC_FPR_ST_MODE_PSQ_U16_PS0, dataReg, memReg, indexReg, memOffset, indexed, registerGQR); + PPCRecompilerAArch64Gen_imlInstr_psq_store(ppcImlGenContext, aarch64GenContext, storePS1 ? PPCREC_FPR_ST_MODE_PSQ_U16_PS0_PS1 : PPCREC_FPR_ST_MODE_PSQ_U16_PS0, dataRegId, memReg, indexReg, memOffset, indexed, registerGQR); aarch64GenContext->b(casesEndLabel); aarch64GenContext->L(s16FormatLabel); - PPCRecompilerAArch64Gen_imlInstr_psq_store(ppcImlGenContext, aarch64GenContext, storePS1 ? PPCREC_FPR_ST_MODE_PSQ_S16_PS0_PS1 : PPCREC_FPR_ST_MODE_PSQ_S16_PS0, dataReg, memReg, indexReg, memOffset, indexed, registerGQR); + PPCRecompilerAArch64Gen_imlInstr_psq_store(ppcImlGenContext, aarch64GenContext, storePS1 ? PPCREC_FPR_ST_MODE_PSQ_S16_PS0_PS1 : PPCREC_FPR_ST_MODE_PSQ_S16_PS0, dataRegId, memReg, indexReg, memOffset, indexed, registerGQR); aarch64GenContext->b(casesEndLabel); aarch64GenContext->L(u8FormatLabel); - PPCRecompilerAArch64Gen_imlInstr_psq_store(ppcImlGenContext, aarch64GenContext, storePS1 ? PPCREC_FPR_ST_MODE_PSQ_U8_PS0_PS1 : PPCREC_FPR_ST_MODE_PSQ_U8_PS0, dataReg, memReg, indexReg, memOffset, indexed, registerGQR); + PPCRecompilerAArch64Gen_imlInstr_psq_store(ppcImlGenContext, aarch64GenContext, storePS1 ? PPCREC_FPR_ST_MODE_PSQ_U8_PS0_PS1 : PPCREC_FPR_ST_MODE_PSQ_U8_PS0, dataRegId, memReg, indexReg, memOffset, indexed, registerGQR); aarch64GenContext->b(casesEndLabel); aarch64GenContext->L(s8FormatLabel); - PPCRecompilerAArch64Gen_imlInstr_psq_store(ppcImlGenContext, aarch64GenContext, storePS1 ? PPCREC_FPR_ST_MODE_PSQ_S8_PS0_PS1 : PPCREC_FPR_ST_MODE_PSQ_S8_PS0, dataReg, memReg, indexReg, memOffset, indexed, registerGQR); + PPCRecompilerAArch64Gen_imlInstr_psq_store(ppcImlGenContext, aarch64GenContext, storePS1 ? PPCREC_FPR_ST_MODE_PSQ_S8_PS0_PS1 : PPCREC_FPR_ST_MODE_PSQ_S8_PS0, dataRegId, memReg, indexReg, memOffset, indexed, registerGQR); aarch64GenContext->L(casesEndLabel); } // store to memory -bool PPCRecompilerAArch64Gen_imlInstruction_fpr_store(PPCRecFunction_t *PPCRecFunction, ppcImlGenContext_t *ppcImlGenContext, AArch64GenContext_t *aarch64GenContext, IMLInstruction *imlInstruction, bool indexed) +bool PPCRecompilerAArch64Gen_imlInstruction_fpr_store(PPCRecFunction_t* PPCRecFunction, ppcImlGenContext_t* ppcImlGenContext, AArch64GenContext_t* aarch64GenContext, IMLInstruction* imlInstruction, bool indexed) { + auto dataRegId = imlInstruction->op_storeLoad.registerData.GetRegID(); auto dataReg = VReg(imlInstruction->op_storeLoad.registerData.GetRegID()); - auto memReg = XReg(imlInstruction->op_storeLoad.registerMem.GetRegID()); - auto indexReg = indexed ? XReg(imlInstruction->op_storeLoad.registerMem2.GetRegID()) : aarch64GenContext->xzr; + auto dataDReg = DReg(dataRegId); + auto memReg = WReg(imlInstruction->op_storeLoad.registerMem.GetRegID()); + auto indexReg = indexed ? WReg(imlInstruction->op_storeLoad.registerMem2.GetRegID()) : aarch64GenContext->wzr; auto tempReg32 = WReg(TEMP_REGISTER_ID); - auto tempReg64 = XReg(TEMP_REGISTER_ID); - auto temp2Reg = XReg(TEMP_REGISTER_2_ID); + auto temp2Reg32 = WReg(TEMP_REGISTER_2_ID); + auto temp2Reg64 = XReg(TEMP_REGISTER_2_ID); auto memBaseReg = XReg(MEMORY_BASE_REG_ID); - auto tempFPReg = VReg(TEMP_VECTOR_REGISTER_ID); + auto tempFPSReg = SReg(TEMP_VECTOR_REGISTER_ID); sint32 memOffset = imlInstruction->op_storeLoad.immS32; uint8 mode = imlInstruction->op_storeLoad.mode; - aarch64GenContext->mov(temp2Reg, memOffset); - aarch64GenContext->add(temp2Reg, temp2Reg, memReg); - aarch64GenContext->add(temp2Reg, temp2Reg, memBaseReg); - if (indexed) - aarch64GenContext->add(temp2Reg, temp2Reg, indexReg); - if (mode == PPCREC_FPR_ST_MODE_SINGLE_FROM_PS0) { + aarch64GenContext->mov(tempReg32, memOffset); + aarch64GenContext->add(tempReg32, tempReg32, memReg); + if (indexed) + aarch64GenContext->add(tempReg32, tempReg32, indexReg); + auto adr = AdrExt(memBaseReg, tempReg32, ExtMod::UXTW); if (imlInstruction->op_storeLoad.flags2.notExpanded) { // value is already in single format - aarch64GenContext->mov(tempReg32, dataReg.s[0]); + aarch64GenContext->mov(temp2Reg32, dataReg.s[0]); } else { - aarch64GenContext->fcvtn(tempFPReg.s2, dataReg.d2); - aarch64GenContext->mov(tempReg32, tempFPReg.s[0]); + aarch64GenContext->fcvt(tempFPSReg, dataDReg); + aarch64GenContext->fmov(temp2Reg32, tempFPSReg); } - aarch64GenContext->rev32(tempReg64, tempReg64); - aarch64GenContext->str(tempReg32, AdrNoOfs(temp2Reg)); + aarch64GenContext->rev(temp2Reg32, temp2Reg32); + aarch64GenContext->str(temp2Reg32, adr); } else if (mode == PPCREC_FPR_ST_MODE_DOUBLE_FROM_PS0) { - aarch64GenContext->rev64(tempFPReg.s2, dataReg.s2); - aarch64GenContext->st1(tempFPReg.d1, AdrNoOfs(temp2Reg)); + aarch64GenContext->mov(tempReg32, memOffset); + aarch64GenContext->add(tempReg32, tempReg32, memReg); + if (indexed) + aarch64GenContext->add(tempReg32, tempReg32, indexReg); + aarch64GenContext->mov(temp2Reg64, dataReg.d[0]); + aarch64GenContext->rev(temp2Reg64, temp2Reg64); + aarch64GenContext->str(temp2Reg64, AdrExt(memBaseReg, tempReg32, ExtMod::UXTW)); } else if (mode == PPCREC_FPR_ST_MODE_UI32_FROM_PS0) { - aarch64GenContext->mov(tempReg32, dataReg.s[0]); - aarch64GenContext->rev32(tempReg64, tempReg64); - aarch64GenContext->str(tempReg32, AdrNoOfs(temp2Reg)); + aarch64GenContext->mov(tempReg32, memOffset); + aarch64GenContext->add(tempReg32, tempReg32, memReg); + if (indexed) + aarch64GenContext->add(tempReg32, tempReg32, indexReg); + aarch64GenContext->mov(temp2Reg32, dataReg.s[0]); + aarch64GenContext->rev(temp2Reg32, temp2Reg32); + aarch64GenContext->str(temp2Reg32, AdrExt(memBaseReg, tempReg32, ExtMod::UXTW)); } else if (mode == PPCREC_FPR_ST_MODE_PSQ_FLOAT_PS0_PS1 || - mode == PPCREC_FPR_ST_MODE_PSQ_FLOAT_PS0 || - mode == PPCREC_FPR_ST_MODE_PSQ_S8_PS0 || - mode == PPCREC_FPR_ST_MODE_PSQ_S8_PS0_PS1 || - mode == PPCREC_FPR_ST_MODE_PSQ_U8_PS0 || - mode == PPCREC_FPR_ST_MODE_PSQ_U8_PS0_PS1 || - mode == PPCREC_FPR_ST_MODE_PSQ_S16_PS0 || - mode == PPCREC_FPR_ST_MODE_PSQ_S16_PS0_PS1 || - mode == PPCREC_FPR_ST_MODE_PSQ_U16_PS0 || - mode == PPCREC_FPR_ST_MODE_PSQ_U16_PS0_PS1) + mode == PPCREC_FPR_ST_MODE_PSQ_FLOAT_PS0 || + mode == PPCREC_FPR_ST_MODE_PSQ_S8_PS0 || + mode == PPCREC_FPR_ST_MODE_PSQ_S8_PS0_PS1 || + mode == PPCREC_FPR_ST_MODE_PSQ_U8_PS0 || + mode == PPCREC_FPR_ST_MODE_PSQ_U8_PS0_PS1 || + mode == PPCREC_FPR_ST_MODE_PSQ_S16_PS0 || + mode == PPCREC_FPR_ST_MODE_PSQ_S16_PS0_PS1 || + mode == PPCREC_FPR_ST_MODE_PSQ_U16_PS0 || + mode == PPCREC_FPR_ST_MODE_PSQ_U16_PS0_PS1) { cemu_assert_debug(imlInstruction->op_storeLoad.flags2.notExpanded == false); - PPCRecompilerAArch64Gen_imlInstr_psq_store(ppcImlGenContext, aarch64GenContext, mode, dataReg, memReg, indexReg, imlInstruction->op_storeLoad.immS32, indexed); + PPCRecompilerAArch64Gen_imlInstr_psq_store(ppcImlGenContext, aarch64GenContext, mode, dataRegId, memReg, indexReg, imlInstruction->op_storeLoad.immS32, indexed); } else if (mode == PPCREC_FPR_ST_MODE_PSQ_GENERIC_PS0_PS1 || - mode == PPCREC_FPR_ST_MODE_PSQ_GENERIC_PS0) + mode == PPCREC_FPR_ST_MODE_PSQ_GENERIC_PS0) { - PPCRecompilerAArch64Gen_imlInstr_psq_store_generic(ppcImlGenContext, aarch64GenContext, mode, dataReg, memReg, indexReg, imlInstruction->op_storeLoad.immS32, indexed, imlInstruction->op_storeLoad.registerGQR); + PPCRecompilerAArch64Gen_imlInstr_psq_store_generic(ppcImlGenContext, aarch64GenContext, mode, dataRegId, memReg, indexReg, imlInstruction->op_storeLoad.immS32, indexed, imlInstruction->op_storeLoad.registerGQR); } else { @@ -1454,120 +1498,145 @@ bool PPCRecompilerAArch64Gen_imlInstruction_fpr_store(PPCRecFunction_t *PPCRecFu } // FPR op FPR -void PPCRecompilerAArch64Gen_imlInstruction_fpr_r_r(PPCRecFunction_t *PPCRecFunction, ppcImlGenContext_t *ppcImlGenContext, AArch64GenContext_t *aarch64GenContext, IMLInstruction *imlInstruction) +void PPCRecompilerAArch64Gen_imlInstruction_fpr_r_r(PPCRecFunction_t* PPCRecFunction, ppcImlGenContext_t* ppcImlGenContext, AArch64GenContext_t* aarch64GenContext, IMLInstruction* imlInstruction) { - auto regR = VReg(imlInstruction->op_fpr_r_r.regR.GetRegID()); - auto regA = VReg(imlInstruction->op_fpr_r_r.regA.GetRegID()); + auto regRVReg = VReg(imlInstruction->op_fpr_r_r.regR.GetRegID()); + auto regAVReg = VReg(imlInstruction->op_fpr_r_r.regA.GetRegID()); + auto regADReg = DReg(imlInstruction->op_fpr_r_r.regA.GetRegID()); auto tempFPReg = VReg(TEMP_VECTOR_REGISTER_ID); - + auto tempReg64 = XReg(TEMP_REGISTER_ID); + auto tempReg32 = WReg(TEMP_REGISTER_ID); + auto temp2Reg64 = XReg(TEMP_REGISTER_2_ID); + auto asmRoutineVReg = VReg(ASM_ROUTINE_REGISTER_ID); if (imlInstruction->operation == PPCREC_IML_OP_FPR_COPY_BOTTOM_TO_BOTTOM_AND_TOP) { - aarch64GenContext->dup(regR.d2, regA.d[0]); + aarch64GenContext->dup(regRVReg.d2, regAVReg.d[0]); } else if (imlInstruction->operation == PPCREC_IML_OP_FPR_COPY_TOP_TO_BOTTOM_AND_TOP) { - aarch64GenContext->dup(regR.d2, regA.d[1]); + aarch64GenContext->dup(regRVReg.d2, regAVReg.d[1]); } else if (imlInstruction->operation == PPCREC_IML_OP_FPR_COPY_BOTTOM_TO_BOTTOM) { - aarch64GenContext->mov(regR.d[0], regA.d[0]); + aarch64GenContext->mov(regRVReg.d[0], regAVReg.d[0]); } else if (imlInstruction->operation == PPCREC_IML_OP_FPR_COPY_BOTTOM_TO_TOP) { - aarch64GenContext->mov(regR.d[1], regA.d[0]); + aarch64GenContext->mov(regRVReg.d[1], regAVReg.d[0]); } else if (imlInstruction->operation == PPCREC_IML_OP_FPR_COPY_BOTTOM_AND_TOP_SWAPPED) { - aarch64GenContext->mov(tempFPReg.b16, regA.b16); - aarch64GenContext->mov(regR.d[0], tempFPReg.d[1]); - aarch64GenContext->mov(regR.d[1], tempFPReg.d[0]); + aarch64GenContext->mov(tempFPReg.b16, regAVReg.b16); + aarch64GenContext->mov(regRVReg.d[0], tempFPReg.d[1]); + aarch64GenContext->mov(regRVReg.d[1], tempFPReg.d[0]); } else if (imlInstruction->operation == PPCREC_IML_OP_FPR_COPY_TOP_TO_TOP) { - aarch64GenContext->mov(regR.d[1], regA.d[1]); + aarch64GenContext->mov(regRVReg.d[1], regAVReg.d[1]); } else if (imlInstruction->operation == PPCREC_IML_OP_FPR_COPY_TOP_TO_BOTTOM) { - aarch64GenContext->mov(regR.d[0], regA.d[1]); + aarch64GenContext->mov(regRVReg.d[0], regAVReg.d[1]); } else if (imlInstruction->operation == PPCREC_IML_OP_FPR_MULTIPLY_BOTTOM) { - aarch64GenContext->mov(tempFPReg.b16, regA.b16); - aarch64GenContext->fmul(tempFPReg.d2, regR.d2, tempFPReg.d2); - aarch64GenContext->mov(regR.d[0], tempFPReg.d[0]); + aarch64GenContext->mov(tempFPReg.b16, regAVReg.b16); + aarch64GenContext->fmul(tempFPReg.d2, regRVReg.d2, tempFPReg.d2); + aarch64GenContext->mov(regRVReg.d[0], tempFPReg.d[0]); } else if (imlInstruction->operation == PPCREC_IML_OP_FPR_MULTIPLY_PAIR) { - aarch64GenContext->fmul(regR.d2, regR.d2, regA.d2); + aarch64GenContext->fmul(regRVReg.d2, regRVReg.d2, regAVReg.d2); } else if (imlInstruction->operation == PPCREC_IML_OP_FPR_DIVIDE_BOTTOM) { - aarch64GenContext->mov(tempFPReg.b16, regA.b16); - aarch64GenContext->fdiv(tempFPReg.d2, regR.d2, tempFPReg.d2); - aarch64GenContext->mov(regR.d[0], tempFPReg.d[0]); + aarch64GenContext->mov(tempFPReg.b16, regAVReg.b16); + aarch64GenContext->fdiv(tempFPReg.d2, regRVReg.d2, tempFPReg.d2); + aarch64GenContext->mov(regRVReg.d[0], tempFPReg.d[0]); } else if (imlInstruction->operation == PPCREC_IML_OP_FPR_DIVIDE_PAIR) { - aarch64GenContext->fdiv(regR.d2, regR.d2, regA.d2); + aarch64GenContext->fdiv(regRVReg.d2, regRVReg.d2, regAVReg.d2); } else if (imlInstruction->operation == PPCREC_IML_OP_FPR_ADD_BOTTOM) { - aarch64GenContext->mov(tempFPReg.b16, regA.b16); - aarch64GenContext->add(tempFPReg.d2, regR.d2, tempFPReg.d2); - aarch64GenContext->mov(regR.d[0], tempFPReg.d[0]); + aarch64GenContext->mov(tempFPReg.b16, regAVReg.b16); + aarch64GenContext->fadd(tempFPReg.d2, regRVReg.d2, tempFPReg.d2); + aarch64GenContext->mov(regRVReg.d[0], tempFPReg.d[0]); } else if (imlInstruction->operation == PPCREC_IML_OP_FPR_ADD_PAIR) { - aarch64GenContext->add(tempFPReg.d2, regR.d2, tempFPReg.d2); + aarch64GenContext->fadd(regRVReg.d2, regRVReg.d2, regAVReg.d2); } else if (imlInstruction->operation == PPCREC_IML_OP_FPR_SUB_PAIR) { - aarch64GenContext->sub(regR.d2, regR.d2, regA.d2); + aarch64GenContext->fsub(regRVReg.d2, regRVReg.d2, regAVReg.d2); } else if (imlInstruction->operation == PPCREC_IML_OP_FPR_SUB_BOTTOM) { - aarch64GenContext->mov(tempFPReg.b16, regA.b16); - aarch64GenContext->sub(tempFPReg.d2, regR.d2, tempFPReg.d2); - aarch64GenContext->mov(regR.d[0], tempFPReg.d[0]); + aarch64GenContext->mov(tempFPReg.b16, regAVReg.b16); + aarch64GenContext->fsub(tempFPReg.d2, regRVReg.d2, tempFPReg.d2); + aarch64GenContext->mov(regRVReg.d[0], tempFPReg.d[0]); } else if (imlInstruction->operation == PPCREC_IML_OP_ASSIGN) { - aarch64GenContext->mov(regR.b16, regA.b16); + if (imlInstruction->op_fpr_r_r.regR.GetRegID() != imlInstruction->op_fpr_r_r.regA.GetRegID()) + aarch64GenContext->mov(regRVReg.b16, regAVReg.b16); } else if (imlInstruction->operation == PPCREC_IML_OP_FPR_BOTTOM_FCTIWZ) { - aarch64GenContext->fcvtzs(tempFPReg.d2, regA.d2); - aarch64GenContext->mov(regR.d[0], tempFPReg.d[0]); + aarch64GenContext->fcvtzs(tempReg32, regADReg); + aarch64GenContext->mov(regRVReg.d[0], tempReg64); } else if (imlInstruction->operation == PPCREC_IML_OP_FPR_BOTTOM_FRES_TO_BOTTOM_AND_TOP) { - // TODO: implement this: - aarch64GenContext->frecpe(regR.d2, regA.d2); - aarch64GenContext->dup(regR.d2, regR.d[0]); + aarch64GenContext->mov(temp2Reg64, aarch64GenContext->x30); + aarch64GenContext->mov(tempReg64, (uint64)recompiler_fres); + aarch64GenContext->mov(asmRoutineVReg.d[0], regAVReg.d[0]); + aarch64GenContext->blr(tempReg64); + aarch64GenContext->dup(regRVReg.d2, asmRoutineVReg.d[0]); + aarch64GenContext->mov(aarch64GenContext->x30, temp2Reg64); } else if (imlInstruction->operation == PPCREC_IML_OP_FPR_BOTTOM_RECIPROCAL_SQRT) { - // TODO: implement this: - aarch64GenContext->frsqrte(tempFPReg.d2, regA.d2); - aarch64GenContext->mov(regR.d[0], tempFPReg.d[0]); + aarch64GenContext->mov(temp2Reg64, aarch64GenContext->x30); + aarch64GenContext->mov(tempReg64, (uint64)recompiler_frsqrte); + aarch64GenContext->mov(asmRoutineVReg.d[0], regAVReg.d[0]); + aarch64GenContext->blr(tempReg64); + aarch64GenContext->mov(regRVReg.d[0], asmRoutineVReg.d[0]); + aarch64GenContext->mov(aarch64GenContext->x30, temp2Reg64); } else if (imlInstruction->operation == PPCREC_IML_OP_FPR_NEGATE_PAIR) { - aarch64GenContext->fneg(regR.d2, regA.d2); + aarch64GenContext->fneg(regRVReg.d2, regAVReg.d2); } else if (imlInstruction->operation == PPCREC_IML_OP_FPR_ABS_PAIR) { - aarch64GenContext->fabs(regR.d2, regA.d2); + aarch64GenContext->fabs(regRVReg.d2, regAVReg.d2); } else if (imlInstruction->operation == PPCREC_IML_OP_FPR_FRES_PAIR) { - // TODO: implement this: - aarch64GenContext->frecpe(regR.d2, regA.d2); + aarch64GenContext->mov(temp2Reg64, aarch64GenContext->x30); + aarch64GenContext->mov(tempReg64, (uint64)recompiler_fres); + aarch64GenContext->mov(asmRoutineVReg.d[0], regAVReg.d[0]); + aarch64GenContext->blr(tempReg64); + aarch64GenContext->mov(regRVReg.d[0], asmRoutineVReg.d[0]); + aarch64GenContext->mov(asmRoutineVReg.d[0], regAVReg.d[1]); + aarch64GenContext->blr(tempReg64); + aarch64GenContext->mov(regRVReg.d[1], asmRoutineVReg.d[0]); + aarch64GenContext->mov(aarch64GenContext->x30, temp2Reg64); } else if (imlInstruction->operation == PPCREC_IML_OP_FPR_FRSQRTE_PAIR) { - // TODO: implement this: - aarch64GenContext->frsqrte(regR.d2, regA.d2); + aarch64GenContext->mov(temp2Reg64, aarch64GenContext->x30); + aarch64GenContext->mov(tempReg64, (uint64)recompiler_frsqrte); + aarch64GenContext->mov(asmRoutineVReg.d[0], regAVReg.d[0]); + aarch64GenContext->blr(tempReg64); + aarch64GenContext->mov(regRVReg.d[0], asmRoutineVReg.d[0]); + aarch64GenContext->mov(asmRoutineVReg.d[0], regAVReg.d[1]); + aarch64GenContext->blr(tempReg64); + aarch64GenContext->mov(regRVReg.d[1], asmRoutineVReg.d[0]); + aarch64GenContext->mov(aarch64GenContext->x30, temp2Reg64); } else { @@ -1575,7 +1644,7 @@ void PPCRecompilerAArch64Gen_imlInstruction_fpr_r_r(PPCRecFunction_t *PPCRecFunc } } -void PPCRecompilerAArch64Gen_imlInstruction_fpr_r_r_r(PPCRecFunction_t *PPCRecFunction, ppcImlGenContext_t *ppcImlGenContext, AArch64GenContext_t *aarch64GenContext, IMLInstruction *imlInstruction) +void PPCRecompilerAArch64Gen_imlInstruction_fpr_r_r_r(PPCRecFunction_t* PPCRecFunction, ppcImlGenContext_t* ppcImlGenContext, AArch64GenContext_t* aarch64GenContext, IMLInstruction* imlInstruction) { auto regR = VReg(imlInstruction->op_fpr_r_r_r.regR.GetRegID()); auto regA = VReg(imlInstruction->op_fpr_r_r_r.regA.GetRegID()); @@ -1589,16 +1658,17 @@ void PPCRecompilerAArch64Gen_imlInstruction_fpr_r_r_r(PPCRecFunction_t *PPCRecFu } else if (imlInstruction->operation == PPCREC_IML_OP_FPR_ADD_BOTTOM) { - aarch64GenContext->add(tempFPReg.d2, regA.d2, regB.d2); + aarch64GenContext->fadd(tempFPReg.d2, regA.d2, regB.d2); aarch64GenContext->mov(regR.d[0], tempFPReg.d[0]); + aarch64GenContext->mov(regR.d[1], regA.d[1]); } else if (imlInstruction->operation == PPCREC_IML_OP_FPR_SUB_PAIR) { - aarch64GenContext->sub(regR.d2, regA.d2, regB.d2); + aarch64GenContext->fsub(regR.d2, regA.d2, regB.d2); } else if (imlInstruction->operation == PPCREC_IML_OP_FPR_SUB_BOTTOM) { - aarch64GenContext->sub(tempFPReg.d2, regA.d2, regB.d2); + aarch64GenContext->fsub(tempFPReg.d2, regA.d2, regB.d2); aarch64GenContext->mov(regR.d[0], tempFPReg.d[0]); } else @@ -1608,98 +1678,67 @@ void PPCRecompilerAArch64Gen_imlInstruction_fpr_r_r_r(PPCRecFunction_t *PPCRecFu /* * FPR = op (fprA, fprB, fprC) */ -void PPCRecompilerAArch64Gen_imlInstruction_fpr_r_r_r_r(PPCRecFunction_t *PPCRecFunction, ppcImlGenContext_t *ppcImlGenContext, AArch64GenContext_t *aarch64GenContext, IMLInstruction *imlInstruction) +void PPCRecompilerAArch64Gen_imlInstruction_fpr_r_r_r_r(PPCRecFunction_t* PPCRecFunction, ppcImlGenContext_t* ppcImlGenContext, AArch64GenContext_t* aarch64GenContext, IMLInstruction* imlInstruction) { auto regR = VReg(imlInstruction->op_fpr_r_r_r_r.regR.GetRegID()); auto regA = VReg(imlInstruction->op_fpr_r_r_r_r.regA.GetRegID()); auto regB = VReg(imlInstruction->op_fpr_r_r_r_r.regB.GetRegID()); auto regC = VReg(imlInstruction->op_fpr_r_r_r_r.regC.GetRegID()); - auto tempReg = XReg(TEMP_REGISTER_ID); - auto tempFPReg = VReg(TEMP_VECTOR_REGISTER_ID); + auto tempFpReg = VReg(TEMP_VECTOR_REGISTER_ID); if (imlInstruction->operation == PPCREC_IML_OP_FPR_SUM0) { - aarch64GenContext->mov(tempFPReg.d[0], regB.d[1]); - aarch64GenContext->add(tempFPReg.d2, tempFPReg.d2, regA.d2); - aarch64GenContext->mov(tempFPReg.d[1], regC.d[1]); - aarch64GenContext->mov(regR.b16, tempFPReg.b16); + aarch64GenContext->mov(tempFpReg.d[0], regB.d[1]); + aarch64GenContext->fadd(tempFpReg.d2, tempFpReg.d2, regA.d2); + aarch64GenContext->mov(tempFpReg.d[1], regC.d[1]); + aarch64GenContext->mov(regR.b16, tempFpReg.b16); } else if (imlInstruction->operation == PPCREC_IML_OP_FPR_SUM1) { - aarch64GenContext->mov(tempFPReg.d[1], regA.d[0]); - aarch64GenContext->add(tempFPReg.d2, tempFPReg.d2, regB.d2); - aarch64GenContext->mov(tempFPReg.d[0], regC.d[0]); - aarch64GenContext->mov(regR.b16, tempFPReg.b16); + aarch64GenContext->mov(tempFpReg.d[1], regA.d[0]); + aarch64GenContext->fadd(tempFpReg.d2, tempFpReg.d2, regB.d2); + aarch64GenContext->mov(tempFpReg.d[0], regC.d[0]); + aarch64GenContext->mov(regR.b16, tempFpReg.b16); } else if (imlInstruction->operation == PPCREC_IML_OP_FPR_SELECT_BOTTOM) { - Label endSelectLabel, selectCLabel; - aarch64GenContext->fcmlt(tempFPReg.d2, regA.d2, 0.0); - aarch64GenContext->mov(tempReg, tempFPReg.d[0]); - aarch64GenContext->cmp(tempReg, 0); - aarch64GenContext->bne(selectCLabel); - // select B - aarch64GenContext->mov(regR.d[0], regB.d[0]); - aarch64GenContext->b(endSelectLabel); - // select C - aarch64GenContext->L(selectCLabel); - aarch64GenContext->mov(regR.d[0], regC.d[0]); - // end - aarch64GenContext->L(endSelectLabel); + auto regADReg = DReg(imlInstruction->op_fpr_r_r_r_r.regA.GetRegID()); + auto regBDReg = DReg(imlInstruction->op_fpr_r_r_r_r.regB.GetRegID()); + auto regCDReg = DReg(imlInstruction->op_fpr_r_r_r_r.regC.GetRegID()); + auto tempFpDReg = DReg(TEMP_VECTOR_REGISTER_ID); + aarch64GenContext->fcmp(regADReg, 0.0); + aarch64GenContext->fcsel(tempFpDReg, regCDReg, regBDReg, Cond::GE); + aarch64GenContext->mov(regR.d[0], tempFpReg.d[0]); } else if (imlInstruction->operation == PPCREC_IML_OP_FPR_SELECT_PAIR) { - Label endSelectBottomLabel, selectCBottomLabel, selectCTopLabel, endSelectTopLabel; - - aarch64GenContext->fcmlt(tempFPReg.d2, regA.d2, 0.0); - - aarch64GenContext->mov(tempReg, tempFPReg.d[0]); - aarch64GenContext->cmp(tempReg, 0); - aarch64GenContext->bne(selectCBottomLabel); - // select B bottom - aarch64GenContext->mov(regR.d[0], regB.d[0]); - aarch64GenContext->b(endSelectBottomLabel); - // select C bottom - aarch64GenContext->L(selectCBottomLabel); - aarch64GenContext->mov(regR.d[0], regC.d[0]); - // end bottom - aarch64GenContext->L(endSelectBottomLabel); - - aarch64GenContext->mov(tempReg, tempFPReg.d[1]); - aarch64GenContext->cmp(tempReg, 0); - aarch64GenContext->bne(selectCTopLabel); - // select B top - aarch64GenContext->mov(regR.d[1], regB.d[1]); - aarch64GenContext->b(endSelectTopLabel); - // select C top - aarch64GenContext->L(selectCTopLabel); - aarch64GenContext->mov(regR.d[1], regC.d[1]); - // end top - aarch64GenContext->L(endSelectTopLabel); + aarch64GenContext->fcmge(tempFpReg.d2, regA.d2, 0.0); + aarch64GenContext->bsl(tempFpReg.b16, regC.b16, regB.b16); + aarch64GenContext->mov(regR.b16, tempFpReg.b16); } else assert_dbg(); } -void PPCRecompilerAArch64Gen_imlInstruction_fpr_r(PPCRecFunction_t *PPCRecFunction, ppcImlGenContext_t *ppcImlGenContext, AArch64GenContext_t *aarch64GenContext, IMLInstruction *imlInstruction) +void PPCRecompilerAArch64Gen_imlInstruction_fpr_r(PPCRecFunction_t* PPCRecFunction, ppcImlGenContext_t* ppcImlGenContext, AArch64GenContext_t* aarch64GenContext, IMLInstruction* imlInstruction) { auto regR = VReg(imlInstruction->op_fpr_r.regR.GetRegID()); auto tempFPReg = VReg(TEMP_VECTOR_REGISTER_ID); if (imlInstruction->operation == PPCREC_IML_OP_FPR_NEGATE_BOTTOM) { - aarch64GenContext->neg(tempFPReg.d2, regR.d2); + aarch64GenContext->fneg(tempFPReg.d2, regR.d2); aarch64GenContext->mov(regR.d[0], tempFPReg.d[0]); } else if (imlInstruction->operation == PPCREC_IML_OP_FPR_ABS_BOTTOM) { - aarch64GenContext->abs(tempFPReg.d2, regR.d2); + aarch64GenContext->fabs(tempFPReg.d2, regR.d2); aarch64GenContext->mov(regR.d[0], tempFPReg.d[0]); } else if (imlInstruction->operation == PPCREC_IML_OP_FPR_NEGATIVE_ABS_BOTTOM) { - aarch64GenContext->abs(tempFPReg.d2, regR.d2); - aarch64GenContext->neg(tempFPReg.d2, tempFPReg.d2); + aarch64GenContext->fabs(tempFPReg.d2, regR.d2); + aarch64GenContext->fneg(tempFPReg.d2, tempFPReg.d2); aarch64GenContext->mov(regR.d[0], tempFPReg.d[0]); } else if (imlInstruction->operation == PPCREC_IML_OP_FPR_ROUND_TO_SINGLE_PRECISION_BOTTOM) @@ -1717,8 +1756,7 @@ void PPCRecompilerAArch64Gen_imlInstruction_fpr_r(PPCRecFunction_t *PPCRecFuncti // convert back to 64bit doubles aarch64GenContext->fcvtl(regR.d2, regR.s2); } - else if (imlInstruction->operation == - PPCREC_IML_OP_FPR_EXPAND_BOTTOM32_TO_BOTTOM64_AND_TOP64) + else if (imlInstruction->operation == PPCREC_IML_OP_FPR_EXPAND_BOTTOM32_TO_BOTTOM64_AND_TOP64) { // convert bottom to 64bit double aarch64GenContext->fcvtl(regR.d2, regR.s2); @@ -1735,19 +1773,23 @@ Cond ImlFPCondToArm64Cond(IMLCondition cond) { switch (cond) { - case IMLCondition::UNORDERED_GT: return Cond::GE; - case IMLCondition::UNORDERED_LT: return Cond::LS; - case IMLCondition::UNORDERED_EQ: return Cond::EQ; - case IMLCondition::UNORDERED_U: return Cond::VS; - default: - { - cemu_assert_suspicious(); - return Cond::EQ; - } + case IMLCondition::UNORDERED_GT: + return Cond::GT; + case IMLCondition::UNORDERED_LT: + return Cond::MI; + case IMLCondition::UNORDERED_EQ: + return Cond::EQ; + case IMLCondition::UNORDERED_U: + return Cond::VS; + default: + { + cemu_assert_suspicious(); + return Cond::EQ; + } } } -void PPCRecompilerAArch64Gen_imlInstruction_fpr_compare(PPCRecFunction_t *PPCRecFunction, ppcImlGenContext_t *ppcImlGenContext, AArch64GenContext_t *aarch64GenContext, IMLInstruction *imlInstruction) +void PPCRecompilerAArch64Gen_imlInstruction_fpr_compare(PPCRecFunction_t* PPCRecFunction, ppcImlGenContext_t* ppcImlGenContext, AArch64GenContext_t* aarch64GenContext, IMLInstruction* imlInstruction) { auto regR = XReg(imlInstruction->op_fpr_compare.regR.GetRegID()); auto regA = DReg(imlInstruction->op_fpr_compare.regA.GetRegID()); @@ -1757,23 +1799,23 @@ void PPCRecompilerAArch64Gen_imlInstruction_fpr_compare(PPCRecFunction_t *PPCRec aarch64GenContext->cset(regR, cond); } -uint8 *codeMemoryBlock = nullptr; +uint8* codeMemoryBlock = nullptr; sint32 codeMemoryBlockIndex = 0; sint32 codeMemoryBlockSize = 0; std::mutex mtx_allocExecutableMemory; -uint8 *PPCRecompilerX86_allocateExecutableMemory(sint32 size) +uint8* PPCRecompilerX86_allocateExecutableMemory(sint32 size) { std::lock_guard lck(mtx_allocExecutableMemory); if (codeMemoryBlockIndex + size > codeMemoryBlockSize) { // allocate new block - codeMemoryBlockSize = std::max(1024 * 1024 * 4, size + 1024); // 4MB (or more if the function is larger than 4MB) + codeMemoryBlockSize = std::max(1024 * 1024 * 4, size + 1024); // 4MB (or more if the function is larger than 4MB) codeMemoryBlockIndex = 0; - codeMemoryBlock = (uint8 *)MemMapper::AllocateMemory(nullptr, codeMemoryBlockSize, MemMapper::PAGE_PERMISSION::P_RWX); + codeMemoryBlock = (uint8*)MemMapper::AllocateMemory(nullptr, codeMemoryBlockSize, MemMapper::PAGE_PERMISSION::P_RWX); } - uint8 *codeMem = codeMemoryBlock + codeMemoryBlockIndex; + uint8* codeMem = codeMemoryBlock + codeMemoryBlockIndex; codeMemoryBlockIndex += size; // pad to 4 byte alignment while (codeMemoryBlockIndex & 3) @@ -1784,16 +1826,22 @@ uint8 *PPCRecompilerX86_allocateExecutableMemory(sint32 size) return codeMem; } -bool PPCRecompiler_generateAArch64Code(struct PPCRecFunction_t *PPCRecFunction, struct ppcImlGenContext_t *ppcImlGenContext) +bool PPCRecompiler_generateAArch64Code(struct PPCRecFunction_t* PPCRecFunction, struct ppcImlGenContext_t* ppcImlGenContext) { AArch64GenContext_t aarch64GenContext{}; - for (IMLSegment *segIt : ppcImlGenContext->segmentList2) - aarch64GenContext.labels[segIt] = Label(); - + for (IMLSegment* segIt : ppcImlGenContext->segmentList2) + { + if (segIt->nextSegmentBranchTaken != nullptr) + { + aarch64GenContext.labels[segIt->nextSegmentBranchTaken] = Label(); + } + } // generate iml instruction code bool codeGenerationFailed = false; - for (IMLSegment *segIt : ppcImlGenContext->segmentList2) + for (IMLSegment* segIt : ppcImlGenContext->segmentList2) { + if (codeGenerationFailed) + break; aarch64GenContext.currentSegment = segIt; segIt->x64Offset = aarch64GenContext.getSize(); @@ -1804,105 +1852,101 @@ bool PPCRecompiler_generateAArch64Code(struct PPCRecFunction_t *PPCRecFunction, for (size_t i = 0; i < segIt->imlList.size(); i++) { - IMLInstruction *imlInstruction = segIt->imlList.data() + i; + IMLInstruction* imlInstruction = segIt->imlList.data() + i; if (imlInstruction->type == PPCREC_IML_TYPE_R_NAME) { - PPCRecompilerAArch64Gen_imlInstruction_r_name(PPCRecFunction, ppcImlGenContext, &aarch64GenContext, imlInstruction); + PPCRecompilerAArch64Gen_imlInstruction_r_name(PPCRecFunction, ppcImlGenContext, &aarch64GenContext, imlInstruction); } else if (imlInstruction->type == PPCREC_IML_TYPE_NAME_R) { - PPCRecompilerAArch64Gen_imlInstruction_name_r(PPCRecFunction, ppcImlGenContext, &aarch64GenContext, imlInstruction); + PPCRecompilerAArch64Gen_imlInstruction_name_r(PPCRecFunction, ppcImlGenContext, &aarch64GenContext, imlInstruction); } else if (imlInstruction->type == PPCREC_IML_TYPE_R_R) { - if (!PPCRecompilerAArch64Gen_imlInstruction_r_r(PPCRecFunction, ppcImlGenContext, &aarch64GenContext, imlInstruction)) + if (!PPCRecompilerAArch64Gen_imlInstruction_r_r(PPCRecFunction, ppcImlGenContext, &aarch64GenContext, imlInstruction)) codeGenerationFailed = true; } else if (imlInstruction->type == PPCREC_IML_TYPE_R_S32) { - if (!PPCRecompilerAArch64Gen_imlInstruction_r_s32(PPCRecFunction, ppcImlGenContext, &aarch64GenContext, imlInstruction)) + if (!PPCRecompilerAArch64Gen_imlInstruction_r_s32(PPCRecFunction, ppcImlGenContext, &aarch64GenContext, imlInstruction)) codeGenerationFailed = true; } else if (imlInstruction->type == PPCREC_IML_TYPE_CONDITIONAL_R_S32) { - if (!PPCRecompilerAArch64Gen_imlInstruction_conditional_r_s32(PPCRecFunction, ppcImlGenContext, &aarch64GenContext, imlInstruction)) + if (!PPCRecompilerAArch64Gen_imlInstruction_conditional_r_s32(PPCRecFunction, ppcImlGenContext, &aarch64GenContext, imlInstruction)) codeGenerationFailed = true; } else if (imlInstruction->type == PPCREC_IML_TYPE_R_R_S32) { - if (!PPCRecompilerAArch64Gen_imlInstruction_r_r_s32(PPCRecFunction, ppcImlGenContext, &aarch64GenContext, imlInstruction)) + if (!PPCRecompilerAArch64Gen_imlInstruction_r_r_s32(PPCRecFunction, ppcImlGenContext, &aarch64GenContext, imlInstruction)) codeGenerationFailed = true; } else if (imlInstruction->type == PPCREC_IML_TYPE_R_R_S32_CARRY) { - if (!PPCRecompilerAArch64Gen_imlInstruction_r_r_s32_carry(PPCRecFunction, ppcImlGenContext, &aarch64GenContext, imlInstruction)) + if (!PPCRecompilerAArch64Gen_imlInstruction_r_r_s32_carry(PPCRecFunction, ppcImlGenContext, &aarch64GenContext, imlInstruction)) codeGenerationFailed = true; } else if (imlInstruction->type == PPCREC_IML_TYPE_R_R_R) { - if (!PPCRecompilerAArch64Gen_imlInstruction_r_r_r(PPCRecFunction, ppcImlGenContext, &aarch64GenContext, imlInstruction)) + if (!PPCRecompilerAArch64Gen_imlInstruction_r_r_r(PPCRecFunction, ppcImlGenContext, &aarch64GenContext, imlInstruction)) codeGenerationFailed = true; } else if (imlInstruction->type == PPCREC_IML_TYPE_R_R_R_CARRY) { - if (!PPCRecompilerAArch64Gen_imlInstruction_r_r_r_carry(PPCRecFunction, ppcImlGenContext, &aarch64GenContext, imlInstruction)) + if (!PPCRecompilerAArch64Gen_imlInstruction_r_r_r_carry(PPCRecFunction, ppcImlGenContext, &aarch64GenContext, imlInstruction)) codeGenerationFailed = true; } else if (imlInstruction->type == PPCREC_IML_TYPE_COMPARE) { - PPCRecompilerAArch64Gen_imlInstruction_compare(PPCRecFunction, ppcImlGenContext, &aarch64GenContext, imlInstruction); + PPCRecompilerAArch64Gen_imlInstruction_compare(PPCRecFunction, ppcImlGenContext, &aarch64GenContext, imlInstruction); } else if (imlInstruction->type == PPCREC_IML_TYPE_COMPARE_S32) { - PPCRecompilerAArch64Gen_imlInstruction_compare_s32(PPCRecFunction, ppcImlGenContext, &aarch64GenContext, imlInstruction); + PPCRecompilerAArch64Gen_imlInstruction_compare_s32(PPCRecFunction, ppcImlGenContext, &aarch64GenContext, imlInstruction); } else if (imlInstruction->type == PPCREC_IML_TYPE_CONDITIONAL_JUMP) { - if (!PPCRecompilerAArch64Gen_imlInstruction_cjump2(PPCRecFunction, ppcImlGenContext, &aarch64GenContext, imlInstruction, segIt)) - codeGenerationFailed = true; + PPCRecompilerAArch64Gen_imlInstruction_cjump2(PPCRecFunction, ppcImlGenContext, &aarch64GenContext, imlInstruction, segIt); } else if (imlInstruction->type == PPCREC_IML_TYPE_JUMP) { - if (!PPCRecompilerAArch64Gen_imlInstruction_jump2(PPCRecFunction, ppcImlGenContext, &aarch64GenContext, imlInstruction, segIt)) - codeGenerationFailed = true; + PPCRecompilerAArch64Gen_imlInstruction_jump2(PPCRecFunction, ppcImlGenContext, &aarch64GenContext, imlInstruction, segIt); } else if (imlInstruction->type == PPCREC_IML_TYPE_CJUMP_CYCLE_CHECK) { - PPCRecompilerAArch64Gen_imlInstruction_conditionalJumpCycleCheck(PPCRecFunction, ppcImlGenContext, &aarch64GenContext, imlInstruction); + PPCRecompilerAArch64Gen_imlInstruction_conditionalJumpCycleCheck(PPCRecFunction, ppcImlGenContext, &aarch64GenContext, imlInstruction); } else if (imlInstruction->type == PPCREC_IML_TYPE_MACRO) { - if (!PPCRecompilerAArch64Gen_imlInstruction_macro(PPCRecFunction, ppcImlGenContext, &aarch64GenContext, imlInstruction)) + if (!PPCRecompilerAArch64Gen_imlInstruction_macro(PPCRecFunction, ppcImlGenContext, &aarch64GenContext, imlInstruction)) codeGenerationFailed = true; } else if (imlInstruction->type == PPCREC_IML_TYPE_LOAD) { - if (!PPCRecompilerAArch64Gen_imlInstruction_load(PPCRecFunction, ppcImlGenContext, &aarch64GenContext, imlInstruction, false)) + if (!PPCRecompilerAArch64Gen_imlInstruction_load(PPCRecFunction, ppcImlGenContext, &aarch64GenContext, imlInstruction, false)) codeGenerationFailed = true; } else if (imlInstruction->type == PPCREC_IML_TYPE_LOAD_INDEXED) { - if (!PPCRecompilerAArch64Gen_imlInstruction_load(PPCRecFunction, ppcImlGenContext, &aarch64GenContext, imlInstruction, true)) + if (!PPCRecompilerAArch64Gen_imlInstruction_load(PPCRecFunction, ppcImlGenContext, &aarch64GenContext, imlInstruction, true)) codeGenerationFailed = true; } else if (imlInstruction->type == PPCREC_IML_TYPE_STORE) { - if (!PPCRecompilerAArch64Gen_imlInstruction_store(PPCRecFunction, ppcImlGenContext, &aarch64GenContext, imlInstruction, false)) + if (!PPCRecompilerAArch64Gen_imlInstruction_store(PPCRecFunction, ppcImlGenContext, &aarch64GenContext, imlInstruction, false)) codeGenerationFailed = true; } else if (imlInstruction->type == PPCREC_IML_TYPE_STORE_INDEXED) { - if (!PPCRecompilerAArch64Gen_imlInstruction_store(PPCRecFunction, ppcImlGenContext, &aarch64GenContext, imlInstruction, true)) + if (!PPCRecompilerAArch64Gen_imlInstruction_store(PPCRecFunction, ppcImlGenContext, &aarch64GenContext, imlInstruction, true)) codeGenerationFailed = true; } else if (imlInstruction->type == PPCREC_IML_TYPE_ATOMIC_CMP_STORE) { - if (!PPCRecompilerAArch64Gen_imlInstruction_atomic_cmp_store(PPCRecFunction, ppcImlGenContext, &aarch64GenContext, imlInstruction)) - codeGenerationFailed = true; + PPCRecompilerAArch64Gen_imlInstruction_atomic_cmp_store(PPCRecFunction, ppcImlGenContext, &aarch64GenContext, imlInstruction); } else if (imlInstruction->type == PPCREC_IML_TYPE_NO_OP) { - aarch64GenContext.nop(); } else if (imlInstruction->type == PPCREC_IML_TYPE_FPR_LOAD) { @@ -1946,8 +1990,9 @@ bool PPCRecompiler_generateAArch64Code(struct PPCRecFunction_t *PPCRecFunction, } else { + codeGenerationFailed = true; + // cemu_assert_suspicious(); debug_printf("PPCRecompiler_generateX64Code(): Unsupported iml type 0x%x\n", imlInstruction->type); - assert_dbg(); } } } @@ -1957,10 +2002,12 @@ bool PPCRecompiler_generateAArch64Code(struct PPCRecFunction_t *PPCRecFunction, { return false; } - aarch64GenContext.readyRE(); + aarch64GenContext.ready(AArch64GenContext_t::PROTECT_RWE); + // TODO: implement without PPCRecompilerX86_allocateExecutableMemory // allocate executable memory - uint8 *executableMemory = PPCRecompilerX86_allocateExecutableMemory(aarch64GenContext.getSize()); + uint8* executableMemory = PPCRecompilerX86_allocateExecutableMemory(aarch64GenContext.getSize()); memcpy(executableMemory, aarch64GenContext.getCode(), aarch64GenContext.getSize()); + // set code PPCRecFunction->x86Code = executableMemory; PPCRecFunction->x86Size = aarch64GenContext.getSize(); @@ -1971,54 +2018,54 @@ void PPCRecompilerAArch64Gen_generateEnterRecompilerCode() { AArch64GenContext_t aarch64GenContext; - constexpr uint32 REG_COUNT = 16; auto spReg = XReg(SP_IDX); Label recompilerStartLabel; std::vector regIds; - for (uint32 index = 0; index < REG_COUNT; index++) + for (uint32 index = 0; index <= 30; index++) regIds.push_back(index); - - regIds.push_back(TEMP_REGISTER_ID); - regIds.push_back(TEMP_REGISTER_2_ID); - regIds.push_back(PPC_RECOMPILER_INSTANCE_DATA_REG_ID); - regIds.push_back(MEMORY_BASE_REG_ID); - regIds.push_back(HCPU_REG_ID); - regIds.push_back(30); - - uint64 stackSize = std::ceil(regIds.size() / 2.) * 2 * 8; + std::vector fpRegIds; + for (uint32 index = 0; index <= 31; index++) + fpRegIds.push_back(index); + uint64 stackSize = std::ceil((fpRegIds.size() + regIds.size()) / 2.) * 2 * 8; // start of recompiler entry function aarch64GenContext.sub(spReg, spReg, stackSize); - for (auto index = 0; index < regIds.size(); index++) - aarch64GenContext.str(XReg(regIds.at(index)), AdrImm(spReg, index * 8)); + size_t spIndex = 0; + for (auto index = 0; index < regIds.size(); index++, spIndex++) + aarch64GenContext.str(XReg(regIds.at(index)), AdrImm(spReg, spIndex * 8)); + for (auto index = 0; index < fpRegIds.size(); index++, spIndex++) + aarch64GenContext.str(DReg(fpRegIds.at(index)), AdrImm(spReg, spIndex * 8)); // MOV RSP, RDX (ppc interpreter instance) - aarch64GenContext.mov(XReg(HCPU_REG_ID), aarch64GenContext.x1); // call argument 2 + aarch64GenContext.mov(XReg(HCPU_REG_ID), aarch64GenContext.x1); // call argument 2 // MOV R15, ppcRecompilerInstanceData aarch64GenContext.mov(XReg(PPC_RECOMPILER_INSTANCE_DATA_REG_ID), (uint64)ppcRecompilerInstanceData); // MOV R13, memory_base aarch64GenContext.mov(XReg(MEMORY_BASE_REG_ID), (uint64)memory_base); aarch64GenContext.mov(WReg(TEMP_REGISTER_ID), 0); - // JMP recFunc - aarch64GenContext.blr(aarch64GenContext.x0); // call argument 1 + aarch64GenContext.blr(aarch64GenContext.x0); // call argument 1 // recompilerExit1: - for (auto index = 0; index < regIds.size(); index++) - aarch64GenContext.ldr(XReg(regIds.at(index)), AdrImm(spReg, index * 8)); + spIndex = 0; + for (auto index = 0; index < regIds.size(); index++, spIndex++) + aarch64GenContext.ldr(XReg(regIds.at(index)), AdrImm(spReg, spIndex * 8)); + for (auto index = 0; index < fpRegIds.size(); index++, spIndex++) + aarch64GenContext.ldr(DReg(fpRegIds.at(index)), AdrImm(spReg, spIndex * 8)); aarch64GenContext.add(spReg, spReg, stackSize); // RET aarch64GenContext.ret(); - aarch64GenContext.readyRE(); + aarch64GenContext.ready(AArch64GenContext_t::PROTECT_RWE); - uint8 *executableMemory = PPCRecompilerX86_allocateExecutableMemory(aarch64GenContext.getSize()); + uint8* executableMemory = PPCRecompilerX86_allocateExecutableMemory(aarch64GenContext.getSize()); // copy code to executable memory memcpy(executableMemory, aarch64GenContext.getCode(), aarch64GenContext.getSize()); + PPCRecompiler_enterRecompilerCode = (void ATTR_MS_ABI (*)(uint64, uint64))executableMemory; } -void *PPCRecompilerAArch64Gen_generateLeaveRecompilerCode() +void* PPCRecompilerAArch64Gen_generateLeaveRecompilerCode() { AArch64GenContext_t aarch64GenContext; @@ -2028,8 +2075,8 @@ void *PPCRecompilerAArch64Gen_generateLeaveRecompilerCode() // RET aarch64GenContext.ret(); - aarch64GenContext.readyRE(); - uint8 *executableMemory = PPCRecompilerX86_allocateExecutableMemory(aarch64GenContext.getSize()); + aarch64GenContext.ready(AArch64GenContext_t::PROTECT_RWE); + uint8* executableMemory = PPCRecompilerX86_allocateExecutableMemory(aarch64GenContext.getSize()); // copy code to executable memory memcpy(executableMemory, aarch64GenContext.getCode(), aarch64GenContext.getSize()); return executableMemory; diff --git a/src/Cafe/HW/Espresso/Recompiler/PPCRecompiler.cpp b/src/Cafe/HW/Espresso/Recompiler/PPCRecompiler.cpp index 22ab3885..5a6e73c6 100644 --- a/src/Cafe/HW/Espresso/Recompiler/PPCRecompiler.cpp +++ b/src/Cafe/HW/Espresso/Recompiler/PPCRecompiler.cpp @@ -305,11 +305,11 @@ void PPCRecompiler_NativeRegisterAllocatorPass(ppcImlGenContext_t& ppcImlGenCont fprPhysPool.SetAvailable(IMLArchX86::PHYSREG_FPR_BASE + 14); #elif defined(__aarch64__) auto& gprPhysPool = raParam.GetPhysRegPool(IMLRegFormat::I64); - for (int i = 0; i < 12; i++) + for (int i = 0; i <= 24; i++) gprPhysPool.SetAvailable(i); auto& fprPhysPool = raParam.GetPhysRegPool(IMLRegFormat::F64); - for (int i = 0; i < 15; i++) + for (int i = 0; i <= 28; i++) fprPhysPool.SetAvailable(i); #endif diff --git a/src/asm/CMakeLists.txt b/src/asm/CMakeLists.txt index dfe2a367..aa8387bd 100644 --- a/src/asm/CMakeLists.txt +++ b/src/asm/CMakeLists.txt @@ -43,7 +43,8 @@ if (CMAKE_SYSTEM_PROCESSOR MATCHES "(x86)|(X86)|(amd64)|(AMD64)") endif() elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "(aarch64)|(AARCH64)") - add_library(CemuAsm stub.cpp) + enable_language(C ASM) + add_library(CemuAsm aarch64util.s) else() message(STATUS "CemuAsm - Unsupported arch: ${CMAKE_SYSTEM_PROCESSOR}") endif() diff --git a/src/asm/aarch64util.s b/src/asm/aarch64util.s new file mode 100644 index 00000000..5ae0f817 --- /dev/null +++ b/src/asm/aarch64util.s @@ -0,0 +1,198 @@ +.section .text + +.global recompiler_fres + +asmFresLookupTable: + .word 0x07ff800, 0x03e1 + .word 0x0783800, 0x03a7 + .word 0x070ea00, 0x0371 + .word 0x06a0800, 0x0340 + .word 0x0638800, 0x0313 + .word 0x05d6200, 0x02ea + .word 0x0579000, 0x02c4 + .word 0x0520800, 0x02a0 + .word 0x04cc800, 0x027f + .word 0x047ca00, 0x0261 + .word 0x0430800, 0x0245 + .word 0x03e8000, 0x022a + .word 0x03a2c00, 0x0212 + .word 0x0360800, 0x01fb + .word 0x0321400, 0x01e5 + .word 0x02e4a00, 0x01d1 + .word 0x02aa800, 0x01be + .word 0x0272c00, 0x01ac + .word 0x023d600, 0x019b + .word 0x0209e00, 0x018b + .word 0x01d8800, 0x017c + .word 0x01a9000, 0x016e + .word 0x017ae00, 0x015b + .word 0x014f800, 0x015b + .word 0x0124400, 0x0143 + .word 0x00fbe00, 0x0143 + .word 0x00d3800, 0x012d + .word 0x00ade00, 0x012d + .word 0x0088400, 0x011a + .word 0x0065000, 0x011a + .word 0x0041c00, 0x0108 + .word 0x0020c00, 0x0106 + +recompiler_fres: + sub sp, sp, #48 + stp x0, x1, [sp] + fmov x0, d31 + ubfx x1, x0, #52, #11 + cmp w1, #2047 + b.eq fres_nan_or_inf + cbnz w1, fres_lookup + orr x0, x0, #0x7ff0000000000000 + fmov d31, x0 + ldp x0, x1, [sp] + add sp, sp, #48 + ret + +fres_nan_or_inf: + stp q0, q1, [sp, #16] + movi v0.2d, #0xffffffffffffffff + movi d1, #0000000000000000 + tst x0, #0xfffffffffffff + fneg v0.2d, v0.2d + bsl v0.16b, v1.16b, v0.16b + fcsel d31, d1, d31, eq + ldp q0, q1, [sp, #16] + add sp, sp, #48 + ret + +fres_lookup : + stp x2, x3, [sp, #16] + stp x4, x5, [sp, #32] + ubfx x2, x0, #47, #5 + adrp x3, asmFresLookupTable + add x3, x3, :lo12:asmFresLookupTable + ubfx x4, x0, #37, #10 + mov w5, #1 + and x0, x0, #0x8000000000000000 + add x2, x3, x2, lsl #3 + ldp w2, w3, [x2] + madd w3, w3, w4, w5 + mov w4, #2045 + sub w1, w4, w1 + orr x0, x0, x1, lsl #52 + sub w2, w2, w3, lsr #1 + add x0, x0, x2, lsl #29 + fmov d31, x0 + ldp x2, x3, [sp, #16] + ldp x4, x5, [sp, #32] + ldp x0, x1, [sp] + add sp, sp, #48 + ret + + + +asmFrsqrteLookupTable: + .word 0x01a7e800, 0x0568 + .word 0x017cb800, 0x04f3 + .word 0x01552800, 0x048d + .word 0x0130c000, 0x0435 + .word 0x010f2000, 0x03e7 + .word 0x0eff000, 0x03a2 + .word 0x0d2e000, 0x0365 + .word 0x0b7c000, 0x032e + .word 0x09e5000, 0x02fc + .word 0x0867000, 0x02d0 + .word 0x06ff000, 0x02a8 + .word 0x05ab800, 0x0283 + .word 0x046a000, 0x0261 + .word 0x0339800, 0x0243 + .word 0x0218800, 0x0226 + .word 0x0105800, 0x020b + .word 0x03ffa000, 0x07a4 + .word 0x03c29000, 0x0700 + .word 0x038aa000, 0x0670 + .word 0x03572000, 0x05f2 + .word 0x03279000, 0x0584 + .word 0x02fb7000, 0x0524 + .word 0x02d26000, 0x04cc + .word 0x02ac0000, 0x047e + .word 0x02881000, 0x043a + .word 0x02665000, 0x03fa + .word 0x02468000, 0x03c2 + .word 0x02287000, 0x038e + .word 0x020c1000, 0x035e + .word 0x01f12000, 0x0332 + .word 0x01d79000, 0x030a + .word 0x01bf4000, 0x02e6 + +.global recompiler_frsqrte + +recompiler_frsqrte: + sub sp, sp, #48 + stp x0, x1, [sp] + fcmp d31, #0.0 + fmov x0, d31 + b.ne frsqrte_not_zero + // result is inf or -inf + orr x0, x0, #0x7ff0000000000000 + fmov d31, x0 + ldp x0, x1, [sp] + add sp, sp, #48 + ret + +frsqrte_not_zero: + stp x2, x3, [sp, #16] + lsr x1, x0, #52 + mov w2, #2047 + bics wzr, w2, w1 + // branch to frsqrte_lookup if not NaN or Inf + b.ne frsqrte_lookup + // branch to frsqrte_inf if not NaN + tst x0, #0xfffffffffffff + b.eq frsqrte_inf + // result is NaN with same sign and same mantissa + ldp x0, x1, [sp] + ldp x2, x3, [sp, #16] + add sp, sp, #48 + ret + +frsqrte_inf: + // if -INF result is +NaN (#9221120237041090560) + // if +INF result is +0.0 + str q0, [sp, #32] + movi d31, #0000000000000000 + mov x1, #9221120237041090560 + cmp x0, #0 + fmov d0, x1 + fcsel d31, d0, d31, lt + ldp x0, x1, [sp] + ldp x2, x3, [sp, #16] + ldr q0, [sp, #32] + add sp, sp, #48 + ret + +frsqrte_lookup: + tbnz x0, #63, frsqrte_negative_input + ubfx x2, x0, #48, #5 + adrp x3, asmFrsqrteLookupTable + add x3, x3, :lo12:asmFrsqrteLookupTable + ubfx x0, x0, #37, #11 + add x2, x3, x2, lsl #3 + ldp w2, w3, [x2] + msub w0, w3, w0, w2 + mov w2, #7171 + add w1, w1, w2 + mov w2, #1023 + sub w1, w2, w1, lsr #1 + sbfiz x0, x0, #26, #32 + add x0, x0, x1, lsl #52 + fmov d31, x0 + ldp x0, x1, [sp] + ldp x2, x3, [sp, #16] + add sp, sp, #48 + ret + +frsqrte_negative_input: + mov x0, #9221120237041090560 + fmov d31, x0 + ldp x0, x1, [sp] + ldp x2, x3, [sp, #16] + add sp, sp, #48 + ret \ No newline at end of file diff --git a/src/asm/x64util.h b/src/asm/x64util.h index 885c2f63..1a5e165c 100644 --- a/src/asm/x64util.h +++ b/src/asm/x64util.h @@ -1,20 +1,14 @@ #pragma once -#if defined(ARCH_X86_64) extern "C" void recompiler_fres(); extern "C" void recompiler_frsqrte(); +// #if defined(ARCH_X86_64) -#else - -// stubbed on non-x86 for now -static void recompiler_fres() -{ - cemu_assert_unimplemented(); -} -static void recompiler_frsqrte() -{ - cemu_assert_unimplemented(); -} - -#endif +// #else +// // stubbed on non-x86 for now +// static void recompiler_frsqrte() +// { +// cemu_assert_unimplemented(); +// } +// #endif