]> git.unchartedbackwaters.co.uk Git - francis/winuae.git/commitdiff
Softfloat FPU updates. New undocumented features emulated.
authorToni Wilen <twilen@winuae.net>
Mon, 23 Jul 2018 18:54:31 +0000 (21:54 +0300)
committerToni Wilen <twilen@winuae.net>
Mon, 23 Jul 2018 18:54:31 +0000 (21:54 +0300)
fpp.cpp
fpp_softfloat.cpp
include/fpp.h
softfloat/softfloat.cpp
softfloat/softfloat.h
softfloat/softfloat_fpsp.cpp

diff --git a/fpp.cpp b/fpp.cpp
index 545b1181af79c1a13bdc1326baff05fbebb02a72..f7d3c7fc77069d6ff572c09ea02afafbf0a648e1 100644 (file)
--- a/fpp.cpp
+++ b/fpp.cpp
@@ -431,9 +431,10 @@ static void fpsr_check_arithmetic_exception(uae_u32 mask, fpdata *src, uae_u32 o
        uae_u32 exception;
        // Any exception status bit and matching exception enable bits set?
        exception = regs.fpsr & regs.fpcr & 0xff00;
-       // Add 68040/68060 nonmaskable exceptions
-       if (currprefs.cpu_model >= 68040 && currprefs.fpu_model)
+       // Add 68040/68060 nonmaskable exceptions. Only if no unimplemented instruction emulation.
+       if (currprefs.cpu_model >= 68040 && currprefs.fpu_model && currprefs.fpu_no_unimplemented) {
                exception |= regs.fpsr & (FPSR_OVFL | FPSR_UNFL | mask);
+       }
 
        if (exception) {
                regs.fp_exp_pend = fpsr_get_vector(exception);
@@ -614,7 +615,7 @@ static uae_u32 fpsr_make_status(void)
 
        // return exceptions that interrupt calculation
        exception = regs.fpsr & regs.fpcr & (FPSR_SNAN | FPSR_OPERR | FPSR_DZ);
-       if (currprefs.cpu_model >= 68040 && currprefs.fpu_model)
+       if (currprefs.cpu_model >= 68040 && currprefs.fpu_model && currprefs.fpu_no_unimplemented)
                exception |= regs.fpsr & (FPSR_OVFL | FPSR_UNFL);
 
        return exception;
@@ -1000,7 +1001,7 @@ static void fp_unimp_datatype(uae_u16 opcode, uae_u16 extra, uae_u32 ea, uaecptr
        }
        if (warned > 0) {
                write_log (_T("FPU unimplemented datatype (%s): OP=%04X-%04X SRC=%08X-%08X-%08X EA=%08X PC=%08X\n"),
-                       packed ? "packed" : "denormal", opcode, extra,
+                       packed ? _T("packed") : _T("denormal"), opcode, extra,
                        packed ? fsave_data.fpt[2] : fsave_data.et[0], fsave_data.et[1], fsave_data.et[2], ea, oldpc);
 #if EXCEPTION_FPP == 0
                warned--;
@@ -1306,18 +1307,6 @@ static bool fault_if_68040_integer_nonmaskable(uae_u16 opcode, uae_u16 extra, ua
        return false;
 }
 
-#if 0
-// 68040/060 automatically converts infinity
-static void check_and_fix_infinity(fpdata *value)
-{
-       if (fpp_fix_infinity && (currprefs.fpu_model == 68040 || currprefs.fpu_model == 68060)) {
-               if (fpp_is_infinity(value)) {
-                       fpp_fix_infinity(value);
-               }
-       }
-}
-#endif
-
 static int get_fp_value (uae_u32 opcode, uae_u16 extra, fpdata *src, uaecptr oldpc, uae_u32 *adp)
 {
        int size, mode, reg;
@@ -1331,9 +1320,6 @@ static int get_fp_value (uae_u32 opcode, uae_u16 extra, fpdata *src, uaecptr old
                if (fault_if_no_fpu (opcode, extra, 0, oldpc))
                        return -1;
                *src = regs.fp[(extra >> 10) & 7];
-#if 0
-               check_and_fix_infinity(src);
-#endif
                normalize_or_fault_if_no_denormal_support(opcode, extra, 0, oldpc, src);
                return 1;
        }
@@ -3112,10 +3098,6 @@ static void fpuop_arithmetic2 (uae_u32 opcode, uae_u16 extra)
 
                        v = fp_arithmetic(&src, &dst, extra);
 
-#if 0
-                       check_and_fix_infinity(&dst);
-#endif
-
                        fpsr_check_arithmetic_exception(0, &src, opcode, extra, ad);
 
                        if (v)
@@ -3163,7 +3145,7 @@ void fpu_modechange(void)
                fpp_from_exten_fmovem(&regs.fp[i], &temp_ext[i][0], &temp_ext[i][1], &temp_ext[i][2]);
        }
        if (currprefs.fpu_mode > 0) {
-               fp_init_softfloat();
+               fp_init_softfloat(currprefs.fpu_model);
 #ifdef MSVC_LONG_DOUBLE
                use_long_double = false;
        } else if (currprefs.fpu_mode < 0) {
@@ -3201,7 +3183,7 @@ static void fpu_test(void)
 void fpu_reset (void)
 {
        if (currprefs.fpu_mode > 0) {
-               fp_init_softfloat();
+               fp_init_softfloat(currprefs.fpu_model);
 #ifdef MSVC_LONG_DOUBLE
                use_long_double = false;
        } else if (currprefs.fpu_mode < 0) {
index aa754c92a4fc91d5bc95f40239891ff1bbdb2aa9..e11a772ef12843d590ede48d5d02c0cac083e94a 100644 (file)
@@ -733,15 +733,15 @@ static void fp_from_pack(fpdata *fp, uae_u32 *wrd, int kfactor)
        }
 }
 
-void fp_init_softfloat(void)
+void fp_init_softfloat(int fpu_model)
 {
-       float_status fsx = { 0 };
-
-       fsx.fpu_model = currprefs.fpu_model;
-       fs.fpu_model = currprefs.fpu_model;
-
-       set_floatx80_rounding_precision(80, &fsx);
-       set_float_rounding_mode(float_round_to_zero, &fsx);
+       if (fpu_model == 68040) {
+               set_special_flags(cmp_signed_nan, &fs);
+       } else if (fpu_model == 68060) {
+               set_special_flags(infinity_clear_intbit, &fs);
+       } else {
+               set_special_flags(addsub_swap_inf, &fs);
+       }
 
        fpp_print = fp_print;
        fpp_unset_snan = fp_unset_snan;
index 32c8ca9b13bec545136b01addb3e699791fada76..49eaa34856e08383e0c237e1bec16678cea1a56b 100644 (file)
@@ -20,7 +20,7 @@ extern void fp_init_native(void);
 #ifdef MSVC_LONG_DOUBLE
 extern void fp_init_native_80(void);
 #endif
-extern void fp_init_softfloat(void);
+extern void fp_init_softfloat(int);
 extern void fpsr_set_exception(uae_u32 exception);
 extern void fpu_modechange(void);
 extern void fpu_clearstatus(void);
index 59f9e118b609f67c029c03fb37d48d82db9ee331..f2f0787ad7546d70ff61d1d73d84b1109f3d0881 100644 (file)
@@ -2157,16 +2157,17 @@ floatx80 floatx80_round_to_int(floatx80 a, float_status *status)
     flag aSign;
     int32_t aExp;
     uint64_t lastBitMask, roundBitsMask;
-    floatx80 z;
+       int8_t roundingMode;
+       floatx80 z;
 
-    if (floatx80_invalid_encoding(a)) {
-        float_raise(float_flag_invalid, status);
-        return floatx80_default_nan(status);
-    }
+       roundingMode = status->float_rounding_mode;
+       aSign = extractFloatx80Sign(a);
     aExp = extractFloatx80Exp( a );
     if ( 0x403E <= aExp ) {
-        if ( ( aExp == 0x7FFF ) && (uint64_t) ( extractFloatx80Frac( a )<<1 ) ) {
-            return propagateFloatx80NaNOneArg(a, status);
+        if ( aExp == 0x7FFF ) {
+                       if ((uint64_t) ( extractFloatx80Frac( a )<<1 ) )
+                               return propagateFloatx80NaNOneArg(a, status);
+                       return inf_clear_intbit(status) ? packFloatx80(aSign, aExp, 0) : a;
         }
         return a;
     }
@@ -2180,7 +2181,6 @@ floatx80 floatx80_round_to_int(floatx80 a, float_status *status)
            return a;
         }
         status->float_exception_flags |= float_flag_inexact;
-        aSign = extractFloatx80Sign( a );
         switch (status->float_rounding_mode) {
          case float_round_nearest_even:
             if ( ( aExp == 0x3FFE ) && (uint64_t) ( extractFloatx80Frac( a )<<1 )
@@ -2255,10 +2255,13 @@ floatx80 floatx80_round_to_int_toward_zero( floatx80 a, float_status *status)
     uint64_t lastBitMask, roundBitsMask;
     floatx80 z;
     
-    aExp = extractFloatx80Exp( a );
+       aSign = extractFloatx80Sign(a);
+       aExp = extractFloatx80Exp( a );
     if ( 0x403E <= aExp ) {
-        if ( ( aExp == 0x7FFF ) && (uint64_t) ( extractFloatx80Frac( a )<<1 ) ) {
-            return propagateFloatx80NaNOneArg( a, status );
+        if ( aExp == 0x7FFF ) {
+                       if ( (uint64_t) ( extractFloatx80Frac( a )<<1 ) )
+                   return propagateFloatx80NaNOneArg( a, status );
+                       return inf_clear_intbit(status) ? packFloatx80(aSign, aExp, 0) : a;
         }
         return a;
     }
@@ -2272,7 +2275,6 @@ floatx80 floatx80_round_to_int_toward_zero( floatx80 a, float_status *status)
             return a;
         }
         status->float_exception_flags |= float_flag_inexact;
-        aSign = extractFloatx80Sign( a );
         return packFloatx80( aSign, 0, 0 );
     }
     lastBitMask = 1;
@@ -2320,10 +2322,9 @@ static floatx80 addFloatx80Sigs(floatx80 a, floatx80 b, flag zSign,
     expDiff = aExp - bExp;
     if ( 0 < expDiff ) {
         if ( aExp == 0x7FFF ) {
-            if ((uint64_t)(aSig << 1)) {
+            if ((uint64_t)(aSig << 1))
                 return propagateFloatx80NaN(a, b, status);
-            }
-            return a;
+                       return inf_clear_intbit(status) ? packFloatx80(extractFloatx80Sign(a), aExp, 0) : a;
         }
 #ifndef SOFTFLOAT_68K
                if ( bExp == 0 ) --expDiff;
@@ -2333,10 +2334,10 @@ static floatx80 addFloatx80Sigs(floatx80 a, floatx80 b, flag zSign,
     }
     else if ( expDiff < 0 ) {
         if ( bExp == 0x7FFF ) {
-            if ((uint64_t)(bSig << 1)) {
+            if ((uint64_t)(bSig << 1))
                 return propagateFloatx80NaN(a, b, status);
-            }
-            return packFloatx80( zSign, 0x7FFF, floatx80_default_infinity_low );
+                       if (inf_clear_intbit(status)) bSig = 0;
+            return packFloatx80( zSign, bExp, bSig );
         }
 #ifndef SOFTFLOAT_68K
                if ( aExp == 0 ) ++expDiff;
@@ -2349,7 +2350,8 @@ static floatx80 addFloatx80Sigs(floatx80 a, floatx80 b, flag zSign,
             if ( (uint64_t) ( ( aSig | bSig )<<1 ) ) {
                 return propagateFloatx80NaN(a, b, status);
             }
-            return a;
+                       if (inf_clear_intbit(status)) return packFloatx80(extractFloatx80Sign(a), aExp, 0);
+                       return faddsub_swap_inf(status) ? b : a;
         }
         zSig1 = 0;
         zSig0 = aSig + bSig;
@@ -2418,11 +2420,10 @@ static floatx80 subFloatx80Sigs(floatx80 a, floatx80 b, flag zSign,
     return packFloatx80(status->float_rounding_mode == float_round_down, 0, 0);
  bExpBigger:
     if ( bExp == 0x7FFF ) {
-        if ((uint64_t)(bSig << 1)) {
-            return propagateFloatx80NaN(a, b, status);
-        }
-        return packFloatx80( zSign ^ 1, 0x7FFF, LIT64( 0x8000000000000000 ) );
-    }
+               if ((uint64_t)(bSig << 1)) return propagateFloatx80NaN(a, b, status);
+               if (inf_clear_intbit(status)) bSig = 0;
+               return packFloatx80(zSign ^ 1, bExp, bSig);
+       }
 #ifndef SOFTFLOAT_68K
        if ( aExp == 0 ) ++expDiff;
 #endif
@@ -2434,11 +2435,9 @@ static floatx80 subFloatx80Sigs(floatx80 a, floatx80 b, flag zSign,
     goto normalizeRoundAndPack;
  aExpBigger:
     if ( aExp == 0x7FFF ) {
-        if ((uint64_t)(aSig << 1)) {
-            return propagateFloatx80NaN(a, b, status);
-        }
-        return a;
-    }
+               if ((uint64_t)(aSig << 1)) return propagateFloatx80NaN(a, b, status);
+               return inf_clear_intbit(status) ? packFloatx80(extractFloatx80Sign(a), aExp, 0) : a;
+       }
 #ifndef SOFTFLOAT_68K
        if ( bExp == 0 ) --expDiff;
 #endif
@@ -2530,8 +2529,9 @@ floatx80 floatx80_mul(floatx80 a, floatx80 b, float_status *status)
             return propagateFloatx80NaN(a, b, status);
         }
         if ( ( bExp | bSig ) == 0 ) goto invalid;
-        return packFloatx80( zSign, 0x7FFF, floatx80_default_infinity_low );
-    }
+               if (inf_clear_intbit(status)) aSig = 0;
+               return packFloatx80(zSign, aExp, aSig);
+       }
     if ( bExp == 0x7FFF ) {
         if ((uint64_t)(bSig << 1)) {
             return propagateFloatx80NaN(a, b, status);
@@ -2541,8 +2541,9 @@ floatx80 floatx80_mul(floatx80 a, floatx80 b, float_status *status)
             float_raise(float_flag_invalid, status);
             return floatx80_default_nan(status);
         }
-        return packFloatx80( zSign, 0x7FFF, floatx80_default_infinity_low );
-    }
+               if (inf_clear_intbit(status)) bSig = 0;
+               return packFloatx80(zSign, bExp, bSig);
+       }
     if ( aExp == 0 ) {
         if ( aSig == 0 ) return packFloatx80( zSign, 0, 0 );
         normalizeFloatx80Subnormal( aSig, &aExp, &aSig );
@@ -2567,7 +2568,6 @@ floatx80 floatx80_sglmul( floatx80 a, floatx80 b, float_status *status )
        flag aSign, bSign, zSign;
        int32_t aExp, bExp, zExp;
        uint64_t aSig, bSig, zSig0, zSig1;
-       floatx80 z;
        
        aSig = extractFloatx80Frac( a );
        aExp = extractFloatx80Exp( a );
@@ -2582,18 +2582,18 @@ floatx80 floatx80_sglmul( floatx80 a, floatx80 b, float_status *status )
                        return propagateFloatx80NaN( a, b, status );
                }
                if ( ( bExp | bSig ) == 0 ) goto invalid;
-               return packFloatx80( zSign, 0x7FFF, floatx80_default_infinity_low );
+               if (inf_clear_intbit(status)) aSig = 0;
+               return packFloatx80(zSign, aExp, aSig);
        }
        if ( bExp == 0x7FFF ) {
                if ( (uint64_t) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b, status );
                if ( ( aExp | aSig ) == 0 ) {
                invalid:
                        float_raise( float_flag_invalid, status );
-                       z.low = floatx80_default_nan_low;
-                       z.high = floatx80_default_nan_high;
-                       return z;
+                       return floatx80_default_nan(status);
                }
-               return packFloatx80( zSign, 0x7FFF, floatx80_default_infinity_low );
+               if (inf_clear_intbit(status)) bSig = 0;
+               return packFloatx80(zSign, bExp, bSig);
        }
        if ( aExp == 0 ) {
                if ( aSig == 0 ) return packFloatx80( zSign, 0, 0 );
@@ -2651,8 +2651,9 @@ floatx80 floatx80_div(floatx80 a, floatx80 b, float_status *status)
             }
             goto invalid;
         }
-        return packFloatx80( zSign, 0x7FFF, floatx80_default_infinity_low );
-    }
+               if (inf_clear_intbit(status)) aSig = 0;
+               return packFloatx80(zSign, aExp, aSig);
+       }
     if ( bExp == 0x7FFF ) {
         if ((uint64_t)(bSig << 1)) {
             return propagateFloatx80NaN(a, b, status);
@@ -2709,7 +2710,6 @@ floatx80 floatx80_sgldiv( floatx80 a, floatx80 b, float_status *status )
        int32_t aExp, bExp, zExp;
        uint64_t aSig, bSig, zSig0, zSig1;
        uint64_t rem0, rem1, rem2, term0, term1, term2;
-       floatx80 z;
        
        aSig = extractFloatx80Frac( a );
        aExp = extractFloatx80Exp( a );
@@ -2724,7 +2724,8 @@ floatx80 floatx80_sgldiv( floatx80 a, floatx80 b, float_status *status )
                        if ( (uint64_t) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b, status );
                        goto invalid;
                }
-               return packFloatx80( zSign, 0x7FFF, floatx80_default_infinity_low );
+               if (inf_clear_intbit(status)) aSig = 0;
+               return packFloatx80(zSign, aExp, aSig);
        }
        if ( bExp == 0x7FFF ) {
                if ( (uint64_t) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b, status );
@@ -2735,9 +2736,7 @@ floatx80 floatx80_sgldiv( floatx80 a, floatx80 b, float_status *status )
                        if ( ( aExp | aSig ) == 0 ) {
                        invalid:
                                float_raise( float_flag_invalid, status );
-                               z.low = floatx80_default_nan_low;
-                               z.high = floatx80_default_nan_high;
-                       return z;
+                               return floatx80_default_nan(status);
                        }
                        float_raise( float_flag_divbyzero, status );
                        return packFloatx80( zSign, 0x7FFF, floatx80_default_infinity_low );
@@ -2884,7 +2883,6 @@ floatx80 floatx80_rem( floatx80 a, floatx80 b, uint64_t *q, flag *s, float_statu
     int32_t aExp, bExp, expDiff;
     uint64_t aSig0, aSig1, bSig;
     uint64_t qTemp, term0, term1, alternateASig0, alternateASig1;
-    floatx80 z;
     
     aSig0 = extractFloatx80Frac( a );
     aExp = extractFloatx80Exp( a );
@@ -2910,9 +2908,7 @@ floatx80 floatx80_rem( floatx80 a, floatx80 b, uint64_t *q, flag *s, float_statu
         if ( bSig == 0 ) {
         invalid:
             float_raise( float_flag_invalid, status );
-            z.low = floatx80_default_nan_low;
-            z.high = floatx80_default_nan_high;
-            return z;
+                       return floatx80_default_nan(status);
         }
         normalizeFloatx80Subnormal( bSig, &bExp, &bSig );
     }
@@ -2999,7 +2995,6 @@ floatx80 floatx80_mod( floatx80 a, floatx80 b, uint64_t *q, flag *s, float_statu
     int32_t aExp, bExp, expDiff;
     uint64_t aSig0, aSig1, bSig;
     uint64_t qTemp, term0, term1;
-    floatx80 z;
     
     aSig0 = extractFloatx80Frac( a );
     aExp = extractFloatx80Exp( a );
@@ -3025,10 +3020,8 @@ floatx80 floatx80_mod( floatx80 a, floatx80 b, uint64_t *q, flag *s, float_statu
         if ( bSig == 0 ) {
         invalid:
             float_raise( float_flag_invalid, status );
-            z.low = floatx80_default_nan_low;
-            z.high = floatx80_default_nan_high;
-            return z;
-        }
+                       return floatx80_default_nan(status);
+               }
         normalizeFloatx80Subnormal( bSig, &bExp, &bSig );
     }
     if ( aExp == 0 ) {
@@ -3105,10 +3098,9 @@ floatx80 floatx80_sqrt(floatx80 a, float_status *status)
     aExp = extractFloatx80Exp( a );
     aSign = extractFloatx80Sign( a );
     if ( aExp == 0x7FFF ) {
-        if ((uint64_t)(aSig0 << 1)) {
+        if ((uint64_t)(aSig0 << 1))
             return propagateFloatx80NaNOneArg(a, status);
-        }
-        if ( ! aSign ) return a;
+               if (!aSign) return inf_clear_intbit(status) ? packFloatx80(aSign, aExp, 0) : a;
         goto invalid;
     }
     if ( aSign ) {
@@ -3175,9 +3167,7 @@ floatx80 floatx80_getman( floatx80 a, float_status *status)
     if ( aExp == 0x7FFF ) {
         if ( (uint64_t) ( aSig<<1 ) ) return propagateFloatx80NaNOneArg( a, status );
         float_raise( float_flag_invalid, status );
-        a.low = floatx80_default_nan_low;
-        a.high = floatx80_default_nan_high;
-        return a;
+               return floatx80_default_nan(status);
     }
     
     if ( aExp == 0 ) {
@@ -3206,9 +3196,7 @@ floatx80 floatx80_getexp( floatx80 a, float_status *status)
     if ( aExp == 0x7FFF ) {
         if ( (uint64_t) ( aSig<<1 ) ) return propagateFloatx80NaNOneArg( a, status );
         float_raise( float_flag_invalid, status );
-        a.low = floatx80_default_nan_low;
-        a.high = floatx80_default_nan_high;
-        return a;
+               return floatx80_default_nan(status);
     }
     
     if ( aExp == 0 ) {
@@ -3246,13 +3234,11 @@ floatx80 floatx80_scale(floatx80 a, floatx80 b, float_status *status)
             return propagateFloatx80NaN( a, b, status );
         }
         float_raise( float_flag_invalid, status );
-        a.low = floatx80_default_nan_low;
-        a.high = floatx80_default_nan_high;
-        return a;
+               return floatx80_default_nan(status);
     }
     if ( aExp == 0x7FFF ) {
         if ( (uint64_t) ( aSig<<1 ) ) return propagateFloatx80NaN( a, b, status );
-        return packFloatx80( aSign, 0x7FFF, LIT64( 0x8000000000000000 ) );
+        return a;
     }
     if ( aExp == 0 ) {
         if ( aSig == 0 ) return packFloatx80( aSign, 0, 0);
@@ -3294,8 +3280,9 @@ floatx80 floatx80_abs(floatx80 a, float_status *status)
     if ( aExp == 0x7FFF ) {
         if ( (uint64_t) ( aSig<<1 ) )
             return propagateFloatx80NaNOneArg( a, status );
-        return packFloatx80( 0, 0x7FFF, floatx80_default_infinity_low );
-    }
+               if (inf_clear_intbit(status)) aSig = 0;
+               return packFloatx80(0, aExp, aSig);
+       }
     
     if ( aExp == 0 ) {
         if ( aSig == 0 ) return packFloatx80( 0, 0, 0 );
@@ -3326,8 +3313,9 @@ floatx80 floatx80_neg(floatx80 a, float_status *status)
     if ( aExp == 0x7FFF ) {
         if ( (uint64_t) ( aSig<<1 ) )
             return propagateFloatx80NaNOneArg( a, status );
-        return packFloatx80 ( !aSign, 0x7FFF, floatx80_default_infinity_low );
-    }
+               if (inf_clear_intbit(status)) aSig = 0;
+               return packFloatx80(!aSign, aExp, aSig);
+       }
     
        aSign = !aSign;
 
@@ -3363,9 +3351,8 @@ floatx80 floatx80_cmp( floatx80 a, floatx80 b, float_status *status )
     if ( ( aExp == 0x7FFF && (uint64_t) ( aSig<<1 ) ) ||
          ( bExp == 0x7FFF && (uint64_t) ( bSig<<1 ) ) ) {
                // 68040 FCMP -NaN return N flag set
-               if (status->fpu_model == 68040)
-               return propagateFloatx80NaN( packFloatx80( aSign, aExp, aSig ),
-                                     packFloatx80( bSign, bExp, bSig ), status );
+               if (fcmp_signed_nan(status))
+               return propagateFloatx80NaN(a, b, status );
                return propagateFloatx80NaN(packFloatx80(0, aExp, aSig),
                        packFloatx80(0, bExp, bSig), status);
        }
@@ -3413,8 +3400,8 @@ floatx80 floatx80_move( floatx80 a, float_status *status )
     aSign = extractFloatx80Sign( a );
     
     if ( aExp == 0x7FFF ) {
-        if ( (uint64_t) ( aSig<<1 ) ) return propagateFloatx80NaNOneArg( a, status );
-        return a;
+               if ((uint64_t)(aSig << 1)) return propagateFloatx80NaNOneArg(a, status);
+               return inf_clear_intbit(status) ? packFloatx80(aSign, aExp, 0) : a;
     }
     if ( aExp == 0 ) {
         if ( aSig == 0 ) return a;
index 061eca5d2d91048395832127fb784e9cd4d773a5..727ad88854f4a3ef864e2e81989e01513d5c139e 100644 (file)
@@ -221,7 +221,7 @@ typedef struct float_status {
     flag flush_inputs_to_zero;
     flag default_nan_mode;
     flag snan_bit_is_one;
-    uint32_t fpu_model;
+       flag floatx80_special_flags;
 } float_status;
 
 /*----------------------------------------------------------------------------
@@ -298,6 +298,30 @@ static inline flag get_default_nan_mode(float_status *status)
     return status->default_nan_mode;
 }
 
+/*----------------------------------------------------------------------------
+| Special flags for indicating some unique behavior is required.
+*----------------------------------------------------------------------------*/
+enum {
+       cmp_signed_nan = 0x01, addsub_swap_inf = 0x02, infinity_clear_intbit = 0x04
+};
+
+static inline void set_special_flags(uint8_t flags, float_status *status)
+{
+       status->floatx80_special_flags = flags;
+}
+static inline int8_t fcmp_signed_nan(float_status *status)
+{
+       return status->floatx80_special_flags & cmp_signed_nan;
+}
+static inline int8_t faddsub_swap_inf(float_status *status)
+{
+       return status->floatx80_special_flags & addsub_swap_inf;
+}
+static inline int8_t inf_clear_intbit(float_status *status)
+{
+       return status->floatx80_special_flags & infinity_clear_intbit;
+}
+
 /*----------------------------------------------------------------------------
 | Routine to raise any or all of the software IEC/IEEE floating-point
 | exception flags.
index 177b0f100edaf6e8ed50eb68e0ecf527ff875cdc..7753cf01dbf3d757dd2b085746f95e09c64c3f9e 100644 (file)
@@ -92,9 +92,7 @@ floatx80 floatx80_acos(floatx80 a, float_status *status)
                        }
                } else { // |X| > 1
                        float_raise(float_flag_invalid, status);
-                       a.low = floatx80_default_nan_low;
-                       a.high = floatx80_default_nan_high;
-                       return a;
+                       return floatx80_default_nan(status);
                }
        } // |X| < 1
        
@@ -152,9 +150,7 @@ floatx80 floatx80_asin(floatx80 a, float_status *status)
                        return floatx80_move(a, status);
                } else { // |X| > 1
                        float_raise(float_flag_invalid, status);
-                       a.low = floatx80_default_nan_low;
-                       a.high = floatx80_default_nan_high;
-                       return a;
+                       return floatx80_default_nan(status);
                }
 
        } // |X| < 1
@@ -369,9 +365,7 @@ floatx80 floatx80_atanh(floatx80 a, float_status *status)
                        return packFloatx80(aSign, 0x7FFF, floatx80_default_infinity_low);
                } else { // |X| > 1
                        float_raise(float_flag_invalid, status);
-                       a.low = floatx80_default_nan_low;
-                       a.high = floatx80_default_nan_high;
-                       return a;
+                       return floatx80_default_nan(status);
                }
        } // |X| < 1
        
@@ -417,9 +411,7 @@ floatx80 floatx80_cos(floatx80 a, float_status *status)
        if (aExp == 0x7FFF) {
                if ((uint64_t) (aSig<<1)) return propagateFloatx80NaNOneArg(a, status);
                float_raise(float_flag_invalid, status);
-               a.low = floatx80_default_nan_low;
-               a.high = floatx80_default_nan_high;
-               return a;
+               return floatx80_default_nan(status);
        }
        
        if (aExp == 0 && aSig == 0) {
@@ -619,7 +611,7 @@ floatx80 floatx80_cosh(floatx80 a, float_status *status)
        
        if (aExp == 0x7FFF) {
                if ((uint64_t) (aSig<<1)) return propagateFloatx80NaNOneArg(a, status);
-               return packFloatx80(0, 0x7FFF, floatx80_default_infinity_low);
+               return packFloatx80(0, aExp, aSig);
        }
        
        if (aExp == 0 && aSig == 0) {
@@ -687,7 +679,7 @@ floatx80 floatx80_etox(floatx80 a, float_status *status)
        if (aExp == 0x7FFF) {
                if ((uint64_t) (aSig<<1)) return propagateFloatx80NaNOneArg(a, status);
                if (aSign) return packFloatx80(0, 0, 0);
-               return packFloatx80(0, 0x7FFF, floatx80_default_infinity_low);
+               return a;
        }
        
        if (aExp == 0 && aSig == 0) {
@@ -822,7 +814,7 @@ floatx80 floatx80_etoxm1(floatx80 a, float_status *status)
        if (aExp == 0x7FFF) {
                if ((uint64_t) (aSig<<1)) return propagateFloatx80NaNOneArg(a, status);
                if (aSign) return packFloatx80(aSign, one_exp, one_sig);
-               return packFloatx80(0, 0x7FFF, floatx80_default_infinity_low);
+               return a;
        }
        
        if (aExp == 0 && aSig == 0) {
@@ -1005,7 +997,7 @@ floatx80 floatx80_log10(floatx80 a, float_status *status)
        if (aExp == 0x7FFF) {
                if ((uint64_t) (aSig<<1)) return propagateFloatx80NaNOneArg(a, status);
                if (aSign == 0)
-                       return packFloatx80(0, 0x7FFF, floatx80_default_infinity_low);
+                       return a;
        }
        
        if (aExp == 0 && aSig == 0) {
@@ -1015,9 +1007,7 @@ floatx80 floatx80_log10(floatx80 a, float_status *status)
        
        if (aSign) {
                float_raise(float_flag_invalid, status);
-               a.low = floatx80_default_nan_low;
-               a.high = floatx80_default_nan_high;
-               return a;
+               return floatx80_default_nan(status);
        }
        
        SET_PREC;
@@ -1053,7 +1043,7 @@ floatx80 floatx80_log2(floatx80 a, float_status *status)
        if (aExp == 0x7FFF) {
                if ((uint64_t) (aSig<<1)) return propagateFloatx80NaNOneArg(a, status);
                if (aSign == 0)
-                       return packFloatx80(0, 0x7FFF, floatx80_default_infinity_low);
+                       return a;
        }
        
        if (aExp == 0) {
@@ -1066,9 +1056,7 @@ floatx80 floatx80_log2(floatx80 a, float_status *status)
        
        if (aSign) {
                float_raise(float_flag_invalid, status);
-               a.low = floatx80_default_nan_low;
-               a.high = floatx80_default_nan_high;
-               return a;
+               return floatx80_default_nan(status);
        }
        
        SET_PREC;
@@ -1111,7 +1099,7 @@ floatx80 floatx80_logn(floatx80 a, float_status *status)
        if (aExp == 0x7FFF) {
                if ((uint64_t) (aSig<<1)) return propagateFloatx80NaNOneArg(a, status);
                if (aSign == 0)
-                       return packFloatx80(0, 0x7FFF, floatx80_default_infinity_low);
+                       return a;
        }
        
        adjk = 0;
@@ -1135,9 +1123,7 @@ floatx80 floatx80_logn(floatx80 a, float_status *status)
        
        if (aSign) {
                float_raise(float_flag_invalid, status);
-               a.low = floatx80_default_nan_low;
-               a.high = floatx80_default_nan_high;
-               return a;
+               return floatx80_default_nan(status);
        }
        
        SET_PREC;
@@ -1247,11 +1233,9 @@ floatx80 floatx80_lognp1(floatx80 a, float_status *status)
                if ((uint64_t) (aSig<<1)) return propagateFloatx80NaNOneArg(a, status);
                if (aSign) {
                        float_raise(float_flag_invalid, status);
-                       a.low = floatx80_default_nan_low;
-                       a.high = floatx80_default_nan_high;
-                       return a;
+                       return floatx80_default_nan(status);
                }
-               return packFloatx80(0, 0x7FFF, floatx80_default_infinity_low);
+               return a;
        }
        
        if (aExp == 0 && aSig == 0) {
@@ -1264,9 +1248,7 @@ floatx80 floatx80_lognp1(floatx80 a, float_status *status)
                        return packFloatx80(aSign, 0x7FFF, floatx80_default_infinity_low);
                }
                float_raise(float_flag_invalid, status);
-               a.low = floatx80_default_nan_low;
-               a.high = floatx80_default_nan_high;
-               return a;
+               return floatx80_default_nan(status);
        }
        
        if (aExp < 0x3f99 || (aExp == 0x3f99 && aSig == one_sig)) { // <= min threshold
@@ -1409,9 +1391,7 @@ floatx80 floatx80_sin(floatx80 a, float_status *status)
        if (aExp == 0x7FFF) {
                if ((uint64_t) (aSig<<1)) return propagateFloatx80NaNOneArg(a, status);
                float_raise(float_flag_invalid, status);
-               a.low = floatx80_default_nan_low;
-               a.high = floatx80_default_nan_high;
-               return a;
+               return floatx80_default_nan(status);
        }
        
        if (aExp == 0 && aSig == 0) {
@@ -1612,7 +1592,7 @@ floatx80 floatx80_sinh(floatx80 a, float_status *status)
        
        if (aExp == 0x7FFF) {
                if ((uint64_t) (aSig<<1)) return propagateFloatx80NaNOneArg(a, status);
-               return packFloatx80(aSign, 0x7FFF, floatx80_default_infinity_low);
+               return a;
        }
        
        if (aExp == 0 && aSig == 0) {
@@ -1687,9 +1667,7 @@ floatx80 floatx80_tan(floatx80 a, float_status *status)
        if (aExp == 0x7FFF) {
                if ((uint64_t) (aSig<<1)) return propagateFloatx80NaNOneArg(a, status);
                float_raise(float_flag_invalid, status);
-               a.low = floatx80_default_nan_low;
-               a.high = floatx80_default_nan_high;
-               return a;
+               return floatx80_default_nan(status);
        }
        
        if (aExp == 0 && aSig == 0) {
@@ -1962,7 +1940,7 @@ floatx80 floatx80_tentox(floatx80 a, float_status *status)
        if (aExp == 0x7FFF) {
                if ((uint64_t) (aSig<<1)) return propagateFloatx80NaNOneArg(a, status);
                if (aSign) return packFloatx80(0, 0, 0);
-               return packFloatx80(0, 0x7FFF, floatx80_default_infinity_low);
+               return a;
        }
        
        if (aExp == 0 && aSig == 0) {
@@ -2079,7 +2057,7 @@ floatx80 floatx80_twotox(floatx80 a, float_status *status)
        if (aExp == 0x7FFF) {
                if ((uint64_t) (aSig<<1)) return propagateFloatx80NaNOneArg(a, status);
                if (aSign) return packFloatx80(0, 0, 0);
-               return packFloatx80(0, 0x7FFF, floatx80_default_infinity_low);
+               return a;
        }
        
        if (aExp == 0 && aSig == 0) {