aboutsummaryrefslogtreecommitdiff
path: root/target/ppc/fpu_helper.c
diff options
context:
space:
mode:
Diffstat (limited to 'target/ppc/fpu_helper.c')
-rw-r--r--target/ppc/fpu_helper.c42
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)