diff options
Diffstat (limited to 'target/ppc/fpu_helper.c')
-rw-r--r-- | target/ppc/fpu_helper.c | 42 |
1 files changed, 31 insertions, 11 deletions
diff --git a/target/ppc/fpu_helper.c b/target/ppc/fpu_helper.c index f437c88aad..07bc9051b0 100644 --- a/target/ppc/fpu_helper.c +++ b/target/ppc/fpu_helper.c @@ -58,19 +58,35 @@ uint64_t helper_todouble(uint32_t arg) uint64_t ret; if (likely(abs_arg >= 0x00800000)) { - /* Normalized operand, or Inf, or NaN. */ - ret = (uint64_t)extract32(arg, 30, 2) << 62; - ret |= ((extract32(arg, 30, 1) ^ 1) * (uint64_t)7) << 59; - ret |= (uint64_t)extract32(arg, 0, 30) << 29; + if (unlikely(extract32(arg, 23, 8) == 0xff)) { + /* Inf or NAN. */ + ret = (uint64_t)extract32(arg, 31, 1) << 63; + ret |= (uint64_t)0x7ff << 52; + ret |= (uint64_t)extract32(arg, 0, 23) << 29; + } else { + /* Normalized operand. */ + ret = (uint64_t)extract32(arg, 30, 2) << 62; + ret |= ((extract32(arg, 30, 1) ^ 1) * (uint64_t)7) << 59; + ret |= (uint64_t)extract32(arg, 0, 30) << 29; + } } else { /* Zero or Denormalized operand. */ ret = (uint64_t)extract32(arg, 31, 1) << 63; if (unlikely(abs_arg != 0)) { - /* Denormalized operand. */ - int shift = clz32(abs_arg) - 9; - int exp = -126 - shift + 1023; + /* + * Denormalized operand. + * Shift fraction so that the msb is in the implicit bit position. + * Thus, shift is in the range [1:23]. + */ + int shift = clz32(abs_arg) - 8; + /* + * The first 3 terms compute the float64 exponent. We then bias + * this result by -1 so that we can swallow the implicit bit below. + */ + int exp = -126 - shift + 1023 - 1; + ret |= (uint64_t)exp << 52; - ret |= abs_arg << (shift + 29); + ret += (uint64_t)abs_arg << (52 - 23 + shift); } } return ret; @@ -403,7 +419,7 @@ void helper_fpscr_clrbit(CPUPPCState *env, uint32_t bit) if (prev == 1) { switch (bit) { case FPSCR_RN1: - case FPSCR_RN: + case FPSCR_RN0: fpscr_set_rounding_mode(env); break; case FPSCR_VXSNAN: @@ -557,7 +573,7 @@ void helper_fpscr_setbit(CPUPPCState *env, uint32_t bit) } break; case FPSCR_RN1: - case FPSCR_RN: + case FPSCR_RN0: fpscr_set_rounding_mode(env); break; default: @@ -2871,10 +2887,14 @@ void helper_xscvqpdp(CPUPPCState *env, uint32_t opcode, uint64_t helper_xscvdpspn(CPUPPCState *env, uint64_t xb) { + uint64_t result; + float_status tstat = env->fp_status; set_float_exception_flags(0, &tstat); - return (uint64_t)float64_to_float32(xb, &tstat) << 32; + result = (uint64_t)float64_to_float32(xb, &tstat); + /* hardware replicates result to both words of the doubleword result. */ + return (result << 32) | result; } uint64_t helper_xscvspdpn(CPUPPCState *env, uint64_t xb) |