File nan-sign.patch of Package aranym
From 789f038532fc23c1e0bfc0b6d4b37790425a39c3 Mon Sep 17 00:00:00 2001
From: Andreas Schwab <schwab@linux-m68k.org>
Date: Sat, 22 Aug 2015 13:28:40 +0200
Subject: [PATCH] Properly track sign bit of NaN in mpfr fpu emulator
---
ChangeLog | 4 +++
src/uae_cpu/fpu/fpu_mpfr.cpp | 68 ++++++++++++++++++++++++++++++++++----------
src/uae_cpu/fpu/types.h | 1 +
3 files changed, 58 insertions(+), 15 deletions(-)
Index: aranym-1.0.2/src/uae_cpu/fpu/fpu_mpfr.cpp
===================================================================
--- aranym-1.0.2.orig/src/uae_cpu/fpu/fpu_mpfr.cpp
+++ aranym-1.0.2/src/uae_cpu/fpu/fpu_mpfr.cpp
@@ -112,10 +112,17 @@ get_cur_prec ()
#define DEFAULT_NAN_BITS 0xffffffffffffffffULL
static void
-set_nan (fpu_register ®, uae_u64 nan_bits)
+set_nan (fpu_register ®, uae_u64 nan_bits, int nan_sign)
{
mpfr_set_nan (reg.f);
reg.nan_bits = nan_bits;
+ reg.nan_sign = nan_sign;
+}
+
+static void
+set_nan (fpu_register ®)
+{
+ set_nan (reg, DEFAULT_NAN_BITS, 0);
}
static bool fpu_inited;
@@ -189,7 +196,7 @@ fpu_reset ()
fpu.instruction_address = 0;
for (int i = 0; i < 8; i++)
- set_nan (fpu.registers[i], DEFAULT_NAN_BITS);
+ set_nan (fpu.registers[i]);
}
fpu_register::operator long double ()
@@ -267,7 +274,7 @@ set_from_single (fpu_register &value, ua
{
if (!(m & 0x400000))
cur_exceptions |= FPSR_EXCEPTION_SNAN;
- set_nan (value, (uae_u64) (m | 0xc00000) << (32 + 8));
+ set_nan (value, (uae_u64) (m | 0xc00000) << (32 + 8), s);
}
else
mpfr_set_inf (value.f, 0);
@@ -300,7 +307,7 @@ set_from_double (fpu_register &value, ua
if (!(m & 0x80000))
cur_exceptions |= FPSR_EXCEPTION_SNAN;
set_nan (value, (((uae_u64) (m | 0x180000) << (32 + 11))
- | ((uae_u64) words[1] << 11)));
+ | ((uae_u64) words[1] << 11)), s);
}
else
mpfr_set_inf (value.f, 0);
@@ -336,7 +343,7 @@ set_from_extended (fpu_register &value,
cur_exceptions |= FPSR_EXCEPTION_SNAN;
words[1] |= 0x40000000;
}
- set_nan (value, ((uae_u64) words[1] << 32) | words[2]);
+ set_nan (value, ((uae_u64) words[1] << 32) | words[2], s);
}
else
mpfr_set_inf (value.f, 0);
@@ -367,7 +374,8 @@ set_from_packed (fpu_register &value, ua
{
if ((words[1] & 0x40000000) == 0)
cur_exceptions |= FPSR_EXCEPTION_SNAN;
- set_nan (value, ((uae_u64) (words[1] | 0x40000000) << 32) | words[2]);
+ set_nan (value, ((uae_u64) (words[1] | 0x40000000) << 32) | words[2],
+ sm);
}
else
mpfr_set_inf (value.f, 0);
@@ -410,6 +418,7 @@ get_fp_value (uae_u32 opcode, uae_u32 ex
{
mpfr_set (value.f, fpu.registers[(extra >> 10) & 7].f, MPFR_RNDN);
value.nan_bits = fpu.registers[(extra >> 10) & 7].nan_bits;
+ value.nan_sign = fpu.registers[(extra >> 10) & 7].nan_sign;
/* Check for SNaN. */
if (mpfr_nan_p (value.f) && (value.nan_bits & (1ULL << 62)) == 0)
{
@@ -572,12 +581,13 @@ update_exceptions ()
}
static void
-set_fp_register (int reg, mpfr_t value, uae_u64 nan_bits,
+set_fp_register (int reg, mpfr_t value, uae_u64 nan_bits, int nan_sign,
int t, mpfr_rnd_t rnd, bool do_flags)
{
mpfr_subnormalize (value, t, rnd);
mpfr_set (fpu.registers[reg].f, value, rnd);
fpu.registers[reg].nan_bits = nan_bits;
+ fpu.registers[reg].nan_sign = nan_sign;
if (do_flags)
{
uae_u32 flags = 0;
@@ -594,6 +604,20 @@ set_fp_register (int reg, mpfr_t value,
}
}
+static void
+set_fp_register (int reg, mpfr_t value, int t, mpfr_rnd_t rnd, bool do_flags)
+{
+ set_fp_register (reg, value, DEFAULT_NAN_BITS, 0, t, rnd, do_flags);
+}
+
+static void
+set_fp_register (int reg, fpu_register &value, int t, mpfr_rnd_t rnd,
+ bool do_flags)
+{
+ set_fp_register (reg, value.f, value.nan_bits, value.nan_sign, t, rnd,
+ do_flags);
+}
+
static uae_u32
extract_to_single (fpu_register &value)
{
@@ -619,6 +643,8 @@ extract_to_single (fpu_register &value)
cur_exceptions |= FPSR_EXCEPTION_SNAN;
}
word = 0x7f800000 | ((value.nan_bits >> (32 + 8)) & 0x7fffff);
+ if (value.nan_sign)
+ word |= 0x80000000;
}
else if (mpfr_zero_p (single))
word = 0;
@@ -679,6 +705,8 @@ extract_to_double (fpu_register &value,
}
words[0] = 0x7ff00000 | ((value.nan_bits >> (32 + 11)) & 0xfffff);
words[1] = value.nan_bits >> 11;
+ if (value.nan_sign)
+ words[0] |= 0x80000000;
}
else if (mpfr_zero_p (dbl))
{
@@ -730,6 +758,8 @@ extract_to_extended (fpu_register &value
words[0] = 0x7fff0000;
words[1] = value.nan_bits >> 32;
words[2] = value.nan_bits;
+ if (value.nan_sign)
+ words[0] |= 0x80000000;
}
else if (mpfr_zero_p (value.f))
{
@@ -781,6 +811,8 @@ extract_to_packed (fpu_register &value,
words[0] = 0x7fff0000;
words[1] = value.nan_bits >> 32;
words[2] = value.nan_bits;
+ if (value.nan_sign)
+ words[0] |= 0x80000000;
}
else if (mpfr_zero_p (value.f))
{
@@ -1471,6 +1503,7 @@ fpuop_general (uae_u32 opcode, uae_u32 e
mpfr_init2 (value.f, prec);
value.nan_bits = DEFAULT_NAN_BITS;
+ value.nan_sign = 0;
mpfr_clear_flags ();
set_format (prec);
@@ -1486,7 +1519,7 @@ fpuop_general (uae_u32 opcode, uae_u32 e
t = mpfr_set (value.f, fpu_constant_rom[rom_index - 32], rnd);
else
mpfr_set_zero (value.f, 0);
- set_fp_register (reg, value.f, value.nan_bits, t, rnd, true);
+ set_fp_register (reg, value, t, rnd, true);
}
else if (extra & 0x40)
{
@@ -1580,7 +1613,7 @@ fpuop_general (uae_u32 opcode, uae_u32 e
t = mpfr_sub (value2, fpu.registers[reg].f, value.f, rnd);
break;
}
- set_fp_register (reg, value2, value.nan_bits, t, rnd, true);
+ set_fp_register (reg, value2, t, rnd, true);
}
else if ((extra & 0x30) == 0x30)
{
@@ -1605,8 +1638,8 @@ fpuop_general (uae_u32 opcode, uae_u32 e
cur_exceptions |= FPSR_EXCEPTION_OPERR;
t = mpfr_sin_cos (value.f, value2, value.f, rnd);
if (reg2 != reg)
- set_fp_register (reg2, value2, value.nan_bits, t >> 2, rnd, false);
- set_fp_register (reg, value.f, value.nan_bits, t & 3, rnd, true);
+ set_fp_register (reg2, value2, t >> 2, rnd, false);
+ set_fp_register (reg, value, t & 3, rnd, true);
}
else if ((extra & 15) == 8)
// FCMP
@@ -1727,12 +1760,14 @@ fpuop_general (uae_u32 opcode, uae_u32 e
break;
case 24: // FABS
t = mpfr_abs (value.f, value.f, rnd);
+ value.nan_sign = 0;
break;
case 25: // FCOSH
t = mpfr_cosh (value.f, value.f, rnd);
break;
case 26: // FNEG
t = mpfr_neg (value.f, value.f, rnd);
+ value.nan_sign = !value.nan_sign;
break;
case 28: // FACOS
if (mpfr_cmpabs (value.f, FPU_CONSTANT_ONE) > 0)
@@ -1820,7 +1855,7 @@ fpuop_general (uae_u32 opcode, uae_u32 e
t = mpfr_sub (value.f, fpu.registers[reg].f, value.f, rnd);
break;
}
- set_fp_register (reg, value.f, value.nan_bits, t, rnd, true);
+ set_fp_register (reg, value, t, rnd, true);
}
update_exceptions ();
ret = true;
Index: aranym-1.0.2/src/uae_cpu/fpu/types.h
===================================================================
--- aranym-1.0.2.orig/src/uae_cpu/fpu/types.h
+++ aranym-1.0.2/src/uae_cpu/fpu/types.h
@@ -166,6 +166,7 @@ typedef uae_f32 fpu_single;
struct fpu_register {
mpfr_t f;
uae_u64 nan_bits;
+ int nan_sign;
operator long double ();
};