static void psArithGeneric(cpu::Core *state, Instruction instr) { const uint32_t oldFPSCR = state->fpscr.value; float d0, d1; const bool wrote0 = psArithSingle<op, 0, slotB0>(state, instr, &d0); const bool wrote1 = psArithSingle<op, 1, slotB1>(state, instr, &d1); if (wrote0 && wrote1) { state->fpr[instr.frD].paired0 = extend_float(d0); state->fpr[instr.frD].paired1 = extend_float(d1); } if (wrote0) { updateFPRF(state, d0); } updateFPSCR(state, oldFPSCR); if (instr.rc) { updateFloatConditionRegister(state); } }
static bool mergeGeneric(PPCEmuAssembler& a, Instruction instr) { if (flags & MergeValue0) { a.mov(a.zax, a.ppcfprps[instr.frA][1]); } else { a.mov(a.zax, a.ppcfprps[instr.frA][0]); } if (flags & MergeValue1) { a.mov(a.zcx, a.ppcfprps[instr.frB][1]); } else { a.mov(a.zcx, a.ppcfprps[instr.frB][0]); } a.mov(a.ppcfprps[instr.frD][0], a.zax); a.mov(a.ppcfprps[instr.frD][1], a.zcx); if (instr.rc) { updateFloatConditionRegister(a, a.zax, a.zcx); } return true; }
// Reciprocal Square Root static void ps_rsqrte(cpu::Core *state, Instruction instr) { const double b0 = state->fpr[instr.frB].paired0; const double b1 = state->fpr[instr.frB].paired1; const bool vxsnan0 = is_signalling_nan(b0); const bool vxsnan1 = is_signalling_nan(b1); const bool vxsqrt0 = !vxsnan0 && std::signbit(b0) && !is_zero(b0); const bool vxsqrt1 = !vxsnan1 && std::signbit(b1) && !is_zero(b1); const bool zx0 = is_zero(b0); const bool zx1 = is_zero(b1); const uint32_t oldFPSCR = state->fpscr.value; state->fpscr.vxsnan |= vxsnan0 || vxsnan1; state->fpscr.vxsqrt |= vxsqrt0 || vxsqrt1; state->fpscr.zx |= zx0 || zx1; double d0, d1; bool write = true; if (((vxsnan0 || vxsqrt0) && state->fpscr.ve) || (zx0 && state->fpscr.ze)) { write = false; } else { d0 = ppc_estimate_reciprocal_root(b0); updateFPRF(state, d0); } if (((vxsnan1 || vxsqrt1) && state->fpscr.ve) || (zx1 && state->fpscr.ze)) { write = false; } else { d1 = ppc_estimate_reciprocal_root(b1); } if (write) { // ps_rsqrte behaves strangely when the result's magnitude is out of // range: ps0 keeps its double-precision exponent, while ps1 appears // to get an arbitrary value from the floating-point circuitry. The // details of how ps1's exponent is affected are unknown, but the // logic below works for double-precision inputs 0x7FE...FFF (maximum // normal) and 0x000...001 (minimum denormal). auto bits0 = get_float_bits(d0); bits0.mantissa &= UINT64_C(0xFFFFFE0000000); state->fpr[instr.frD].paired0 = bits0.v; auto bits1 = get_float_bits(d1); if (bits1.exponent == 0) { // Leave as zero (reciprocal square root can never be a denormal). } else if (bits1.exponent < 1151) { int8_t exponent8 = (bits1.exponent - 1023) & 0xFF; bits1.exponent = 1023 + exponent8; } else if (bits1.exponent < 2047) { bits1.exponent = 1022; } bits1.mantissa &= UINT64_C(0xFFFFFE0000000); state->fpr[instr.frD].paired1 = bits1.v; } updateFPSCR(state, oldFPSCR); if (instr.rc) { updateFloatConditionRegister(state); } }