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 &reg, uae_u64 nan_bits)
+set_nan (fpu_register &reg, 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 &reg)
+{
+  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 ();
 };