// Reciprocal static void ps_res(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 zx0 = is_zero(b0); const bool zx1 = is_zero(b1); const uint32_t oldFPSCR = state->fpscr.value; state->fpscr.vxsnan |= vxsnan0 || vxsnan1; state->fpscr.zx |= zx0 || zx1; float d0, d1; auto write = true; if ((vxsnan0 && state->fpscr.ve) || (zx0 && state->fpscr.ze)) { write = false; } else { d0 = ppc_estimate_reciprocal(truncate_double(b0)); updateFPRF(state, d0); } if ((vxsnan1 && state->fpscr.ve) || (zx1 && state->fpscr.ze)) { write = false; } else { d1 = ppc_estimate_reciprocal(truncate_double(b1)); } if (write) { state->fpr[instr.frD].paired0 = extend_float(d0); state->fpr[instr.frD].paired1 = extend_float(d1); } if (std::fetestexcept(FE_INEXACT)) { // On inexact result, ps_res sets FPSCR[FI] without also setting // FPSCR[XX] (like fres). std::feclearexcept(FE_INEXACT); updateFPSCR(state, oldFPSCR); state->fpscr.fi = 1; } else { updateFPSCR(state, oldFPSCR); } if (instr.rc) { updateFloatConditionRegister(state); } }
// Floating Convert to Integer Word with Round toward Zero static void fctiwz(ThreadState *state, Instruction instr) { double b; int32_t bi; b = state->fpr[instr.frB].paired0; if (b > static_cast<double>(INT_MAX)) { bi = INT_MAX; state->fpscr.vxcvi = 1; } else if (b < static_cast<double>(INT_MIN)) { bi = INT_MIN; state->fpscr.vxcvi = 1; } else { bi = static_cast<int32_t>(std::trunc(b)); } auto vxsnan = is_signalling_nan(b); state->fpscr.vxsnan |= vxsnan; state->fpscr.vxcvi |= vxsnan; updateFPSCR(state); state->fpr[instr.frD].iw0 = bi; state->fpr[instr.frD].iw1 = 0xFFF80000 | (is_negative_zero(b) ? 1 : 0); if (instr.rc) { updateFloatConditionRegister(state); } }
// Floating Round to Single static void frsp(ThreadState *state, Instruction instr) { auto b = state->fpr[instr.frB].paired0; state->fpscr.vxsnan |= is_signalling_nan(b); auto d = static_cast<float>(b); updateFPSCR(state); updateFPRF(state, d); state->fpr[instr.frD].paired0 = static_cast<double>(d); if (instr.rc) { updateFloatConditionRegister(state); } }
// Floating Multiply-Add Single static void fmadds(ThreadState *state, Instruction instr) { double a, b, c, d; a = state->fpr[instr.frA].paired0; b = state->fpr[instr.frB].paired0; c = state->fpr[instr.frC].paired0; state->fpscr.vxsnan = is_signalling_nan(a) || is_signalling_nan(b) || is_signalling_nan(c); state->fpscr.vxisi = is_infinity(a * c) || is_infinity(c); state->fpscr.vximz = is_infinity(a * c) && is_zero(c); d = a * c; if (is_nan(d)) { if (is_nan(a)) { d = make_quiet(a); } else if (is_nan(b)) { d = make_quiet(b); } else if (is_nan(c)) { d = make_quiet(c); } else { d = make_nan<double>(); } } else { if (is_infinity(d) && is_infinity(b) && !(is_infinity(a) || is_infinity(c))) { d = b; } else { d = d + b; if (is_nan(d)) { if (is_nan(b)) { d = make_quiet(b); } else { d = make_nan<double>(); } } } } updateFPSCR(state); updateFPRF(state, d); state->fpr[instr.frD].paired0 = static_cast<float>(d); if (instr.rc) { updateFloatConditionRegister(state); } }
// Floating Reciprocal Estimate Single static void fres(ThreadState *state, Instruction instr) { double b, d; b = state->fpr[instr.frB].paired0; state->fpscr.vxsnan |= is_signalling_nan(b); d = ppc_estimate_reciprocal(b); updateFPSCR(state); updateFPRF(state, d); state->fpr[instr.frD].paired0 = d; if (instr.rc) { updateFloatConditionRegister(state); } }
// Floating Reciprocal Square Root Estimate static void frsqrte(ThreadState *state, Instruction instr) { double b, d; b = state->fpr[instr.frB].paired0; d = 1.0 / std::sqrt(b); auto vxsnan = is_signalling_nan(b); state->fpscr.vxsnan |= vxsnan; state->fpscr.vxsqrt |= vxsnan; updateFPSCR(state); updateFPRF(state, d); state->fpr[instr.frD].paired0 = d; if (instr.rc) { updateFloatConditionRegister(state); } }
// Floating Convert to Integer Word static void fctiw(ThreadState *state, Instruction instr) { double b; int32_t bi; b = state->fpr[instr.frB].paired0; if (b > static_cast<double>(INT_MAX)) { bi = INT_MAX; state->fpscr.vxcvi = 1; } else if (b < static_cast<double>(INT_MIN)) { bi = INT_MIN; state->fpscr.vxcvi = 1; } else { switch (state->fpscr.rn) { case FloatingPointRoundMode::Nearest: bi = static_cast<int32_t>(std::round(b)); break; case FloatingPointRoundMode::Positive: bi = static_cast<int32_t>(std::ceil(b)); break; case FloatingPointRoundMode::Negative: bi = static_cast<int32_t>(std::floor(b)); break; case FloatingPointRoundMode::Zero: bi = static_cast<int32_t>(std::trunc(b)); break; } } auto vxsnan = is_signalling_nan(b); state->fpscr.vxsnan |= vxsnan; state->fpscr.vxcvi |= vxsnan; updateFPSCR(state); state->fpr[instr.frD].iw0 = bi; state->fpr[instr.frD].iw1 = 0xFFF80000 | (is_negative_zero(b) ? 1 : 0); if (instr.rc) { updateFloatConditionRegister(state); } }
// Floating Negative Multiply-Sub static void fnmsub(ThreadState *state, Instruction instr) { double a, b, c, d; a = state->fpr[instr.frA].paired0; b = state->fpr[instr.frB].paired0; c = state->fpr[instr.frC].paired0; state->fpscr.vximz = is_infinity(a * c) && is_zero(c); state->fpscr.vxisi = is_infinity(a * c) || is_infinity(c); state->fpscr.vxsnan = is_signalling_nan(a) || is_signalling_nan(b) || is_signalling_nan(c); d = -((a * c) - b); updateFPSCR(state); updateFPRF(state, d); state->fpr[instr.frD].paired0 = d; if (instr.rc) { updateFloatConditionRegister(state); } }
static void fsubGeneric(ThreadState *state, Instruction instr) { double a, b, d; a = state->fpr[instr.frA].paired0; b = state->fpr[instr.frB].paired0; state->fpscr.vxisi = is_infinity(a) && is_infinity(b); state->fpscr.vxsnan = is_signalling_nan(a) || is_signalling_nan(b); d = static_cast<Type>(a - b); updateFPSCR(state); d = checkNan<Type>(d, a, b); updateFPRF(state, d); state->fpr[instr.frD].paired0 = d; if (instr.rc) { updateFloatConditionRegister(state); } }
static void fmulGeneric(ThreadState *state, Instruction instr) { double a, c, d; a = state->fpr[instr.frA].paired0; c = state->fpr[instr.frC].paired0; state->fpscr.vximz = is_infinity(a) && is_zero(c); state->fpscr.vxsnan = is_signalling_nan(a) || is_signalling_nan(c); d = static_cast<Type>(a * c); updateFPSCR(state); d = checkNan<Type>(d, a, c); updateFPRF(state, d); state->fpr[instr.frD].paired0 = d; if (instr.rc) { updateFloatConditionRegister(state); } }
static void fmaGeneric(cpu::Core *state, Instruction instr) { const uint32_t oldFPSCR = state->fpscr.value; float d0, d1; const bool wrote0 = fmaSingle<flags, 0, slotC0>(state, instr, &d0); const bool wrote1 = fmaSingle<flags, 1, slotC1>(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); } }
// 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); } }