void Interpreter::ps_abs(UGeckoInstruction inst) { const auto& b = rPS(inst.FB); rPS(inst.FD).SetBoth(b.PS0AsU64() & ~(UINT64_C(1) << 63), b.PS1AsU64() & ~(UINT64_C(1) << 63)); if (inst.Rc) Helper_UpdateCR1(); }
void Interpreter::ps_merge11(UGeckoInstruction inst) { const auto& a = rPS(inst.FA); const auto& b = rPS(inst.FB); rPS(inst.FD).SetBoth(a.PS1AsDouble(), b.PS1AsDouble()); if (inst.Rc) Helper_UpdateCR1(); }
// These "binary instructions" do not alter FPSCR. void Interpreter::ps_sel(UGeckoInstruction inst) { const auto& a = rPS(inst.FA); const auto& b = rPS(inst.FB); const auto& c = rPS(inst.FC); rPS(inst.FD).SetBoth(a.PS0AsDouble() >= -0.0 ? c.PS0AsDouble() : b.PS0AsDouble(), a.PS1AsDouble() >= -0.0 ? c.PS1AsDouble() : b.PS1AsDouble()); if (inst.Rc) Helper_UpdateCR1(); }
void JitArm::faddx(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(FloatingPoint) ARMReg vD = fpr.R0(inst.FD); ARMReg vA = fpr.R0(inst.FA); ARMReg vB = fpr.R0(inst.FB); VADD(vD, vA, vB); if (inst.Rc) Helper_UpdateCR1(vD); }
void JitArm::fmulx(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(FloatingPoint) ARMReg vD0 = fpr.R0(inst.FD); ARMReg vA = fpr.R0(inst.FA); ARMReg vC = fpr.R0(inst.FC); VMUL(vD0, vA, vC); if (inst.Rc) Helper_UpdateCR1(vD0); }
void JitArm::fmrx(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(FloatingPoint) Default(inst); return; ARMReg vD = fpr.R0(inst.FD); ARMReg vB = fpr.R0(inst.FB); VMOV(vD, vB); if (inst.Rc) Helper_UpdateCR1(vD); }
void Interpreter::ps_add(UGeckoInstruction inst) { const auto& a = rPS(inst.FA); const auto& b = rPS(inst.FB); const double ps0 = ForceSingle(NI_add(a.PS0AsDouble(), b.PS0AsDouble()).value); const double ps1 = ForceSingle(NI_add(a.PS1AsDouble(), b.PS1AsDouble()).value); rPS(inst.FD).SetBoth(ps0, ps1); PowerPC::UpdateFPRF(ps0); if (inst.Rc) Helper_UpdateCR1(); }
void JitArm::fsubsx(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(FloatingPoint) ARMReg vA = fpr.R0(inst.FA); ARMReg vB = fpr.R0(inst.FB); ARMReg vD0 = fpr.R0(inst.FD); ARMReg vD1 = fpr.R1(inst.FD); VSUB(vD0, vA, vB); VMOV(vD1, vD0); if (inst.Rc) Helper_UpdateCR1(vD0); }
void Interpreter::ps_muls1(UGeckoInstruction inst) { const auto& a = rPS(inst.FA); const auto& c = rPS(inst.FC); const double c1 = Force25Bit(c.PS1AsDouble()); const double ps0 = ForceSingle(NI_mul(a.PS0AsDouble(), c1).value); const double ps1 = ForceSingle(NI_mul(a.PS1AsDouble(), c1).value); rPS(inst.FD).SetBoth(ps0, ps1); PowerPC::UpdateFPRF(ps0); if (inst.Rc) Helper_UpdateCR1(); }
void Interpreter::ps_nmadd(UGeckoInstruction inst) { const auto& a = rPS(inst.FA); const auto& b = rPS(inst.FB); const auto& c = rPS(inst.FC); const double c0 = Force25Bit(c.PS0AsDouble()); const double c1 = Force25Bit(c.PS1AsDouble()); const double tmp0 = ForceSingle(NI_madd(a.PS0AsDouble(), c0, b.PS0AsDouble()).value); const double tmp1 = ForceSingle(NI_madd(a.PS1AsDouble(), c1, b.PS1AsDouble()).value); const double ps0 = std::isnan(tmp0) ? tmp0 : -tmp0; const double ps1 = std::isnan(tmp1) ? tmp1 : -tmp1; rPS(inst.FD).SetBoth(ps0, ps1); PowerPC::UpdateFPRF(ps0); if (inst.Rc) Helper_UpdateCR1(); }
void JitArm::fctiwx(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(bJITFloatingPointOff) u32 b = inst.FB; u32 d = inst.FD; ARMReg vB = fpr.R0(b); ARMReg vD = fpr.R0(d); ARMReg V0 = fpr.GetReg(); ARMReg V1 = fpr.GetReg(); ARMReg V2 = fpr.GetReg(); ARMReg rA = gpr.GetReg(); ARMReg fpscrReg = gpr.GetReg(); FixupBranch DoneMax, DoneMin; LDR(fpscrReg, R9, PPCSTATE_OFF(fpscr)); MOVI2R(rA, (u32)minmaxFloat); // Check if greater than max float { VLDR(V0, rA, 8); // Load Max VCMPE(vB, V0); VMRS(_PC); // Loads in to APSR FixupBranch noException = B_CC(CC_LE); VMOV(vD, V0); // Set to max SetFPException(fpscrReg, FPSCR_VXCVI); DoneMax = B(); SetJumpTarget(noException); } // Check if less than min float { VLDR(V0, rA, 0); VCMPE(vB, V0); VMRS(_PC); FixupBranch noException = B_CC(CC_GE); VMOV(vD, V0); SetFPException(fpscrReg, FPSCR_VXCVI); DoneMin = B(); SetJumpTarget(noException); } // Within ranges, convert to integer // Set rounding mode first // PPC <-> ARM rounding modes // 0, 1, 2, 3 <-> 0, 3, 1, 2 ARMReg rB = gpr.GetReg(); VMRS(rA); // Bits 22-23 BIC(rA, rA, Operand2(3, 5)); LDR(rB, R9, PPCSTATE_OFF(fpscr)); AND(rB, rB, 0x3); // Get the FPSCR rounding bits CMP(rB, 1); SetCC(CC_EQ); // zero ORR(rA, rA, Operand2(3, 5)); SetCC(CC_NEQ); CMP(rB, 2); // +inf SetCC(CC_EQ); ORR(rA, rA, Operand2(1, 5)); SetCC(CC_NEQ); CMP(rB, 3); // -inf SetCC(CC_EQ); ORR(rA, rA, Operand2(2, 5)); SetCC(); VMSR(rA); ORR(rA, rA, Operand2(3, 5)); VCVT(vD, vB, TO_INT | IS_SIGNED); VMSR(rA); gpr.Unlock(rB); VCMPE(vD, vB); VMRS(_PC); SetCC(CC_EQ); BIC(fpscrReg, fpscrReg, FRFIMask); FixupBranch DoneEqual = B(); SetCC(); SetFPException(fpscrReg, FPSCR_XX); ORR(fpscrReg, fpscrReg, FIMask); VABS(V1, vB); VABS(V2, vD); VCMPE(V2, V1); VMRS(_PC); SetCC(CC_GT); ORR(fpscrReg, fpscrReg, FRMask); SetCC(); SetJumpTarget(DoneEqual); SetJumpTarget(DoneMax); SetJumpTarget(DoneMin); MOVI2R(rA, (u32)&doublenum); VLDR(V0, rA, 0); NEONXEmitter nemit(this); nemit.VORR(vD, vD, V0); if (inst.Rc) Helper_UpdateCR1(fpscrReg, rA); STR(fpscrReg, R9, PPCSTATE_OFF(fpscr)); gpr.Unlock(rA); gpr.Unlock(fpscrReg); fpr.Unlock(V0); fpr.Unlock(V1); fpr.Unlock(V2); }
void JitArm::fctiwzx(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(bJITFloatingPointOff) u32 b = inst.FB; u32 d = inst.FD; ARMReg vB = fpr.R0(b); ARMReg vD = fpr.R0(d); ARMReg V0 = fpr.GetReg(); ARMReg V1 = fpr.GetReg(); ARMReg V2 = fpr.GetReg(); ARMReg rA = gpr.GetReg(); ARMReg fpscrReg = gpr.GetReg(); FixupBranch DoneMax, DoneMin; LDR(fpscrReg, R9, PPCSTATE_OFF(fpscr)); MOVI2R(rA, (u32)minmaxFloat); // Check if greater than max float { VLDR(V0, rA, 8); // Load Max VCMPE(vB, V0); VMRS(_PC); // Loads in to APSR FixupBranch noException = B_CC(CC_LE); VMOV(vD, V0); // Set to max SetFPException(fpscrReg, FPSCR_VXCVI); DoneMax = B(); SetJumpTarget(noException); } // Check if less than min float { VLDR(V0, rA, 0); VCMPE(vB, V0); VMRS(_PC); FixupBranch noException = B_CC(CC_GE); VMOV(vD, V0); SetFPException(fpscrReg, FPSCR_VXCVI); DoneMin = B(); SetJumpTarget(noException); } // Within ranges, convert to integer VCVT(vD, vB, TO_INT | IS_SIGNED | ROUND_TO_ZERO); VCMPE(vD, vB); VMRS(_PC); SetCC(CC_EQ); BIC(fpscrReg, fpscrReg, FRFIMask); FixupBranch DoneEqual = B(); SetCC(); SetFPException(fpscrReg, FPSCR_XX); ORR(fpscrReg, fpscrReg, FIMask); VABS(V1, vB); VABS(V2, vD); VCMPE(V2, V1); VMRS(_PC); SetCC(CC_GT); ORR(fpscrReg, fpscrReg, FRMask); SetCC(); SetJumpTarget(DoneEqual); SetJumpTarget(DoneMax); SetJumpTarget(DoneMin); MOVI2R(rA, (u32)&doublenum); VLDR(V0, rA, 0); NEONXEmitter nemit(this); nemit.VORR(vD, vD, V0); if (inst.Rc) Helper_UpdateCR1(fpscrReg, rA); STR(fpscrReg, R9, PPCSTATE_OFF(fpscr)); gpr.Unlock(rA); gpr.Unlock(fpscrReg); fpr.Unlock(V0); fpr.Unlock(V1); fpr.Unlock(V2); }