]> git.unchartedbackwaters.co.uk Git - francis/winuae.git/commitdiff
FPU update.
authorToni Wilen <twilen@winuae.net>
Mon, 6 Mar 2017 16:02:40 +0000 (18:02 +0200)
committerToni Wilen <twilen@winuae.net>
Mon, 6 Mar 2017 16:02:40 +0000 (18:02 +0200)
fpp.cpp
fpp_native.cpp
fpp_softfloat.cpp
include/fpp.h
newcpu.cpp
softfloat/softfloat.cpp
softfloat/softfloat.h

diff --git a/fpp.cpp b/fpp.cpp
index 0c7a05bfa09e7d44da73f773599f0d64f5dd2b50..46623643014d1efb125fa95fbf98bf38e7a8801c 100644 (file)
--- a/fpp.cpp
+++ b/fpp.cpp
@@ -75,7 +75,7 @@ FPP_A fpp_round64;
 FPP_AB fpp_int;
 FPP_AB fpp_sinh;
 FPP_AB fpp_intrz;
-FPP_AB fpp_sqrt;
+FPP_ABP fpp_sqrt;
 FPP_AB fpp_lognp1;
 FPP_AB fpp_etoxm1;
 FPP_AB fpp_tanh;
@@ -90,28 +90,28 @@ FPP_AB fpp_tentox;
 FPP_AB fpp_logn;
 FPP_AB fpp_log10;
 FPP_AB fpp_log2;
-FPP_AB fpp_abs;
+FPP_ABP fpp_abs;
 FPP_AB fpp_cosh;
-FPP_AB fpp_neg;
+FPP_ABP fpp_neg;
 FPP_AB fpp_acos;
 FPP_AB fpp_cos;
 FPP_AB fpp_getexp;
 FPP_AB fpp_getman;
-FPP_AB fpp_div;
+FPP_ABP fpp_div;
 FPP_ABQS fpp_mod;
-FPP_AB fpp_add;
-FPP_AB fpp_mul;
+FPP_ABP fpp_add;
+FPP_ABP fpp_mul;
 FPP_ABQS fpp_rem;
 FPP_AB fpp_scale;
-FPP_AB fpp_sub;
+FPP_ABP fpp_sub;
 FPP_AB fpp_sgldiv;
 FPP_AB fpp_sglmul;
 FPP_AB fpp_cmp;
 FPP_AB fpp_tst;
-FPP_AB fpp_move;
+FPP_ABP fpp_move;
 
 #define DEBUG_FPP 0
-#define EXCEPTION_FPP 1
+#define EXCEPTION_FPP 0
 
 STATIC_INLINE int isinrom (void)
 {
@@ -427,17 +427,9 @@ static void fpsr_check_arithmetic_exception(uae_u32 mask, fpdata *src, uae_u32 o
                                }
                        } else if (regs.fp_exp_pend == 53) { // OVFL
                                fpp_get_internal_overflow(&eo);
-                               if (((regs.fpcr >> 6) & 3) == 1)
-                                       fpp_round32(&eo);
-                               if (((regs.fpcr >> 6) & 3) >= 2)
-                                       fpp_round64(&eo);
                                fpp_from_exten_fmovem(&eo, &fsave_data.eo[0], &fsave_data.eo[1], &fsave_data.eo[2]);
                        } else if (regs.fp_exp_pend == 51) { // UNFL
                                fpp_get_internal_underflow(&eo);
-                               if (((regs.fpcr >> 6) & 3) == 1)
-                                       fpp_round32(&eo);
-                               if (((regs.fpcr >> 6) & 3) >= 2)
-                                       fpp_round64(&eo);
                                fpp_from_exten_fmovem(&eo, &fsave_data.eo[0], &fsave_data.eo[1], &fsave_data.eo[2]);
                        } // else INEX1, INEX2: do nothing
 
@@ -558,12 +550,17 @@ static int fpsr_set_bsun(void)
     return 0;
 }
 
-void fpsr_set_quotient(uae_u64 quot, uae_s8 sign)
+static void fpsr_set_quotient(uae_u64 quot, uae_u8 sign)
 {
        regs.fpsr &= 0x0f00fff8;
        regs.fpsr |= (quot << 16) & FPSR_QUOT_LSB;
        regs.fpsr |= sign ? FPSR_QUOT_SIGN : 0;
 }
+static void fpsr_get_quotient(uae_u64 *quot, uae_u8 *sign)
+{
+       *quot = (regs.fpsr & FPSR_QUOT_LSB) >> 16;
+       *sign = (regs.fpsr & FPSR_QUOT_SIGN) ? 1 : 0;
+}
 
 uae_u32 fpp_get_fpsr (void)
 {
@@ -2618,7 +2615,7 @@ static uaecptr fmovem2fpp (uaecptr ad, uae_u32 list, int incr, int regdir)
        return ad;
 }
 
-static bool arithmetic(fpdata *src, fpdata *dst, int extra)
+static bool fp_arithmetic(fpdata *src, fpdata *dst, int extra)
 {
        uae_u64 q = 0;
        uae_u8 s = 0;
@@ -2626,122 +2623,145 @@ static bool arithmetic(fpdata *src, fpdata *dst, int extra)
        switch (extra & 0x7f)
        {
                case 0x00: /* FMOVE */
-               case 0x40:
-               case 0x44:
-                       fpp_move(src, dst);
+                       fpp_move(dst, src, 0);
+                       break;
+               case 0x40: /* FSMOVE */
+                       fpp_move(dst, src, 32);
+                       break;
+               case 0x44: /* FDMOVE */
+                       fpp_move(dst, src, 64);
                        break;
                case 0x01: /* FINT */
-                       fpp_int(src, dst);
+                       fpp_int(dst, src);
                        break;
                case 0x02: /* FSINH */
-                       fpp_sinh(src, dst);
+                       fpp_sinh(dst, src);
                        break;
                case 0x03: /* FINTRZ */
-                       fpp_intrz(src, dst);
+                       fpp_intrz(dst, src);
                        break;
                case 0x04: /* FSQRT */
+                       fpp_sqrt(dst, src, 0);
+                       break;
                case 0x41: /* FSSQRT */
+                       fpp_sqrt(dst, src,  32);
+                       break;
                case 0x45: /* FDSQRT */
-                       fpp_sqrt(src, dst);
+                       fpp_sqrt(dst, src, 64);
                        break;
                case 0x06: /* FLOGNP1 */
-                       fpp_lognp1(src, dst);
+                       fpp_lognp1(dst, src);
                        break;
                case 0x08: /* FETOXM1 */
-                       fpp_etoxm1(src, dst);
+                       fpp_etoxm1(dst, src);
                        break;
                case 0x09: /* FTANH */
-                       fpp_tanh(src, dst);
+                       fpp_tanh(dst, src);
                        break;
                case 0x0a: /* FATAN */
-                       fpp_atan(src, dst);
+                       fpp_atan(dst, src);
                        break;
                case 0x0c: /* FASIN */
-                       fpp_asin(src, dst);
+                       fpp_asin(dst, src);
                        break;
                case 0x0d: /* FATANH */
-                       fpp_atanh(src, dst);
+                       fpp_atanh(dst, src);
                        break;
                case 0x0e: /* FSIN */
-                       fpp_sin(src, dst);
+                       fpp_sin(dst, src);
                        break;
                case 0x0f: /* FTAN */
-                       fpp_tan(src, dst);
+                       fpp_tan(dst, src);
                        break;
                case 0x10: /* FETOX */
-                       fpp_etox(src, dst);
+                       fpp_etox(dst, src);
                        break;
                case 0x11: /* FTWOTOX */
-                       fpp_twotox(src, dst);
+                       fpp_twotox(dst, src);
                        break;
                case 0x12: /* FTENTOX */
-                       fpp_tentox(src, dst);
+                       fpp_tentox(dst, src);
                        break;
                case 0x14: /* FLOGN */
-                       fpp_logn(src, dst);
+                       fpp_logn(dst, src);
                        break;
                case 0x15: /* FLOG10 */
-                       fpp_log10(src, dst);
+                       fpp_log10(dst, src);
                        break;
                case 0x16: /* FLOG2 */
-                       fpp_log2(src, dst);
+                       fpp_log2(dst, src);
                        break;
                case 0x18: /* FABS */
+                       fpp_abs(dst, src, 0);
+                       break;
                case 0x58: /* FSABS */
+                       fpp_abs(dst, src, 32);
+                       break;
                case 0x5c: /* FDABS */
-                       fpp_abs(src, dst);
+                       fpp_abs(dst, src, 64);
                        break;
                case 0x19: /* FCOSH */
-                       fpp_cosh(src, dst);
+                       fpp_cosh(dst, src);
                        break;
                case 0x1a: /* FNEG */
+                       fpp_neg(dst, src, 0);
+                       break;
                case 0x5a: /* FSNEG */
+                       fpp_neg(dst, src, 32);
+                       break;
                case 0x5e: /* FDNEG */
-                       fpp_neg(src, dst);
+                       fpp_neg(dst, src, 64);
                        break;
                case 0x1c: /* FACOS */
-                       fpp_acos(src, dst);
+                       fpp_acos(dst, src);
                        break;
                case 0x1d: /* FCOS */
-                       fpp_cos(src, dst);
+                       fpp_cos(dst, src);
                        break;
                case 0x1e: /* FGETEXP */
-                       fpp_getexp(src, dst);
+                       fpp_getexp(dst, src);
                        break;
                case 0x1f: /* FGETMAN */
-                       fpp_getman(src, dst);
+                       fpp_getman(dst, src);
                        break;
                case 0x20: /* FDIV */
+                       fpp_div(dst, src, 0);
+                       break;
                case 0x60: /* FSDIV */
+                       fpp_div(dst, src, 32);
+                       break;
                case 0x64: /* FDDIV */
-                       fpp_div(dst, src);
+                       fpp_div(dst, src, 64);
                        break;
                case 0x21: /* FMOD */
+                       fpsr_get_quotient(&q, &s);
                        fpp_mod(dst, src, &q, &s);
-                       if (fpsr_make_status())
-                               return false;
                        fpsr_set_quotient(q, s);
                        break;
                case 0x22: /* FADD */
+                       fpp_add(dst, src, 0);
+                       break;
                case 0x62: /* FSADD */
+                       fpp_add(dst, src, 32);
+                       break;
                case 0x66: /* FDADD */
-                       fpp_add(dst, src);
+                       fpp_add(dst, src, 64);
                        break;
                case 0x23: /* FMUL */
+                       fpp_mul(dst, src, 0);
+                       break;
                case 0x63: /* FSMUL */
+                       fpp_mul(dst, src, 32);
+                       break;
                case 0x67: /* FDMUL */
-                       fpp_mul(dst, src);
+                       fpp_mul(dst, src, 64);
                        break;
                case 0x24: /* FSGLDIV */
                        fpp_sgldiv(dst, src);
-                       fpsr_set_result(dst);
-                       if (fpsr_make_status())
-                               return false;
-                       return true;
+                       break;
                case 0x25: /* FREM */
+                       fpsr_get_quotient(&q, &s);
                        fpp_rem(dst, src, &q, &s);
-                       if (fpsr_make_status())
-                               return false;
                        fpsr_set_quotient(q, s);
                        break;
                case 0x26: /* FSCALE */
@@ -2749,14 +2769,15 @@ static bool arithmetic(fpdata *src, fpdata *dst, int extra)
                        break;
                case 0x27: /* FSGLMUL */
                        fpp_sglmul(dst, src);
-                       fpsr_set_result(dst);
-                       if (fpsr_make_status())
-                               return false;
-                       return true;
+                       break;
                case 0x28: /* FSUB */
+                       fpp_sub(dst, src, 0);
+                       break;
                case 0x68: /* FSSUB */
+                       fpp_sub(dst, src, 32);
+                       break;
                case 0x6c: /* FDSUB */
-                       fpp_sub(dst, src);
+                       fpp_sub(dst, src, 64);
                        break;
                case 0x30: /* FSINCOS */
                case 0x31: /* FSINCOS */
@@ -2766,28 +2787,22 @@ static bool arithmetic(fpdata *src, fpdata *dst, int extra)
                case 0x35: /* FSINCOS */
                case 0x36: /* FSINCOS */
                case 0x37: /* FSINCOS */
-                       fpp_cos(src, dst);
-            if (((regs.fpcr >> 6) & 3) == 1)
-                               fpp_round_single(dst);
-            else if (((regs.fpcr >> 6) & 3) == 2)
-                               fpp_round_double(dst);
+                       fpp_cos(dst, src);
                        regs.fp[extra & 7] = *dst;
-                       fpp_sin(src, dst);
+                       fpp_sin(dst, src);
                        break;
                case 0x38: /* FCMP */
                {
                        fpp_cmp(dst, src);
+                       fpsr_make_status();
                        fpsr_set_result(dst);
-                       if (fpsr_make_status())
-                               return false;
                        return false;
                }
                case 0x3a: /* FTST */
                {
                        fpp_tst(dst, src);
+                       fpsr_make_status();
                        fpsr_set_result(dst);
-                       if (fpsr_make_status())
-                               return false;
                        return false;
                }
                default:
@@ -2795,17 +2810,6 @@ static bool arithmetic(fpdata *src, fpdata *dst, int extra)
                        return false;
        }
 
-       // must check instruction rounding overrides first
-       if ((extra & 0x44) == 0x40) {
-        fpp_round_single(dst);
-       } else if ((extra & 0x44) == 0x44) {
-        fpp_round_double(dst);
-       } else if (((regs.fpcr >> 6) & 3) == 1) {
-        fpp_round_single(dst);
-       } else if (((regs.fpcr >> 6) & 3) == 2) {
-        fpp_round_double(dst);
-       }
-
        fpsr_set_result(dst);
 
        if (fpsr_make_status())
@@ -3083,11 +3087,13 @@ static void fpuop_arithmetic2 (uae_u32 opcode, uae_u16 extra)
                        if (regs.fp_unimp_pend)
                                return;
 
-                       v = arithmetic(&src, &dst, extra);
+                       v = fp_arithmetic(&src, &dst, extra);
+
+                       fpsr_check_arithmetic_exception(0, &src, opcode, extra, ad);
+
                        if (v)
                                regs.fp[reg] = dst;
 
-                       fpsr_check_arithmetic_exception(0, &src, opcode, extra, ad);
                        return;
                default:
                break;
@@ -3145,6 +3151,9 @@ void fpu_reset (void)
     fpp_set_fpcr (0);
     fpp_set_fpsr (0);
        fpux_restore (NULL);
+       // reset precision
+       fpp_set_mode(0x00000080 | 0x00000010);
+       fpp_set_mode(0x00000000);
 }
 
 uae_u8 *restore_fpu (uae_u8 *src)
index 8df7b92ee80d15ed6a97d96eaf2d3166b920f73a..19cdcb0238a9d5622ab96d8a8006c57391eeaa84 100644 (file)
@@ -122,6 +122,9 @@ static const double twoto32 = 4294967296.0;
 #define FPCR_PRECISION_EXTENDED        0x00000000
 
 static struct float_status fs;
+static uae_u32 fpu_mode_control = 0;
+static int fpu_prec;
+static int temp_prec;
 
 #if defined(CPU_i386) || defined(CPU_x86_64)
 
@@ -212,32 +215,44 @@ static void native_set_fpucw(uae_u32 m68k_cw)
 /* Functions for setting host/library modes and getting status */
 static void fp_set_mode(uae_u32 mode_control)
 {
+       if (mode_control == fpu_mode_control)
+               return;
     switch(mode_control & FPCR_ROUNDING_PRECISION) {
         case FPCR_PRECISION_EXTENDED: // X
+#ifdef USE_LONG_DOUBLE
+                       fpu_prec = 80;
+#else
+                       fpu_prec = 64;
+#endif
             break;
         case FPCR_PRECISION_SINGLE:   // S
+                       fpu_prec = 32;
             break;
         case FPCR_PRECISION_DOUBLE:   // D
         default:                      // undefined
+                       fpu_prec = 64;
             break;
     }
 #ifdef USE_HOST_ROUNDING
-    switch(mode_control & FPCR_ROUNDING_MODE) {
-        case FPCR_ROUND_NEAR: // to neareset
-            fesetround(FE_TONEAREST);
-            break;
-        case FPCR_ROUND_ZERO: // to zero
-            fesetround(FE_TOWARDZERO);
-            break;
-        case FPCR_ROUND_MINF: // to minus
-            fesetround(FE_DOWNWARD);
-            break;
-        case FPCR_ROUND_PINF: // to plus
-            fesetround(FE_UPWARD);
-            break;
-    }
+       if ((mode_control & FPCR_ROUNDING_MODE) != (fpu_mode_control & FPCR_ROUNDING_MODE)) {
+               switch(mode_control & FPCR_ROUNDING_MODE) {
+                       case FPCR_ROUND_NEAR: // to neareset
+                               fesetround(FE_TONEAREST);
+                               break;
+                       case FPCR_ROUND_ZERO: // to zero
+                               fesetround(FE_TOWARDZERO);
+                               break;
+                       case FPCR_ROUND_MINF: // to minus
+                               fesetround(FE_DOWNWARD);
+                               break;
+                       case FPCR_ROUND_PINF: // to plus
+                               fesetround(FE_UPWARD);
+                               break;
+               }
+       }
        native_set_fpucw(mode_control);
 #endif
+       fpu_mode_control = mode_control;
 }
 
 
@@ -264,30 +279,6 @@ static void fp_clear_status(void)
     feclearexcept (FE_ALL_EXCEPT);
 }
 
-static const TCHAR *fp_print(fpdata *fpd)
-{
-       static TCHAR fs[32];
-       bool n, d;
-
-       n = signbit(fpd->fp) ? 1 : 0;
-       d = isnormal(fpd->fp) ? 0 : 1;
-
-       if(isinf(fpd->fp)) {
-               _stprintf(fs, _T("%c%s"), n ? '-' : '+', _T("inf"));
-       } else if(isnan(fpd->fp)) {
-               _stprintf(fs, _T("%c%s"), n ? '-' : '+', _T("nan"));
-       } else {
-               if(n)
-                       fpd->fp *= -1.0;
-#if USE_LONG_DOUBLE
-               _stprintf(fs, _T("#%Le"), fpd->fp);
-#else
-               _stprintf(fs, _T("#%e"), fpd->fp);
-#endif
-       }
-       return fs;
-}
-
 /* Functions for detecting float type */
 static bool fp_is_snan(fpdata *fpd)
 {
@@ -602,19 +593,95 @@ static void fp_round_double(fpdata *fpd)
 #endif
 }
 
+static const TCHAR *fp_print(fpdata *fpd, int mode)
+{
+       static TCHAR fsout[32];
+       bool n, d;
+
+       if (mode < 0) {
+               uae_u32 w1, w2, w3;
+               fp_from_exten(fpd, &w1, &w2, &w3);
+               _stprintf(fsout, _T("%04X-%08X-%08X"), w1 >> 16, w2, w3);
+               return fsout;
+       }
+
+       n = signbit(fpd->fp) ? 1 : 0;
+       d = isnormal(fpd->fp) ? 0 : 1;
+
+       if(isinf(fpd->fp)) {
+               _stprintf(fsout, _T("%c%s"), n ? '-' : '+', _T("inf"));
+       } else if(isnan(fpd->fp)) {
+               _stprintf(fsout, _T("%c%s"), n ? '-' : '+', _T("nan"));
+       } else {
+               if(n)
+                       fpd->fp *= -1.0;
+#if USE_LONG_DOUBLE
+               _stprintf(fsout, _T("#%Le"), fpd->fp);
+#else
+               _stprintf(fsout, _T("#%e"), fpd->fp);
+#endif
+       }
+       if (mode == 0 || mode > _tcslen(fsout))
+               return fsout;
+       fsout[mode] = 0;
+       return fsout;
+}
+
+static void fp_set_prec(int prec)
+{
+#if 0
+       temp_fpu_mode_control = fpu_mode_control;
+       if (prec && fpu_prec > prec) {
+               fpu_mode_control &= ~FPCR_ROUNDING_PRECISION;
+               switch (prec)
+               {
+                       case 80:
+                       fpu_mode_control |= FPCR_PRECISION_EXTENDED;
+                       break;
+                       case 64:
+                       default:
+                       fpu_mode_control |= FPCR_PRECISION_DOUBLE;
+                       break;
+                       case 32:
+                       fpu_mode_control |= FPCR_PRECISION_SINGLE;
+                       break;
+               }
+               fp_set_mode(fpu_mode_control);
+       }
+#endif
+       temp_prec = prec;
+}
+static void fp_reset_prec(fpdata *fpd)
+{
+#if 0
+       fp_set_mode(temp_fpu_mode_control);
+#else
+       int prec = temp_prec;
+       if (temp_prec == 0)
+               prec = fpu_prec;
+       if (prec == 64) {
+               fp_round_double(fpd);
+       } else if (prec == 32) {
+               fp_round_single(fpd);
+       }
+#endif
+}
+
 /* Arithmetic functions */
 
-static void fp_move(fpdata *src, fpdata *dst)
+static void fp_move(fpdata *a, fpdata *b, int prec)
 {
-       dst->fp = src->fp;
+       fp_set_prec(prec);
+       a->fp = b->fp;
+       fp_reset_prec(a);
 }
 
 #ifdef USE_LONG_DOUBLE
 
-STATIC_INLINE fptype fp_int(fpdata *a, fpdata *dst)
+STATIC_INLINE fptype fp_int(fpdata *a, fpdata *b)
 {
 #ifdef USE_HOST_ROUNDING
-    dst->fp = rintl(a->dst);
+    a->fp = rintl(b->dst);
 #else
     switch (regs.fpcr & FPCR_ROUNDING_MODE)
     {
@@ -668,42 +735,44 @@ STATIC_INLINE fptype fp_rem(fptype a, fptype b, uae_u64 *q, uae_s8 *s)
 
 #else // if !USE_LONG_DOUBLE
 
-static void fp_int(fpdata *fpd, fpdata *dst)
+static void fp_int(fpdata *a, fpdata *b)
 {
-       fptype a = fpd->fp;
+       fptype bb = b->fp;
 #ifdef USE_HOST_ROUNDING
-       dst->fp = rintl(a);
+       a->fp = rintl(bb);
 #else
     switch (regs.fpcr & FPCR_ROUNDING_MODE)
     {
         case FPCR_ROUND_NEAR:
-            dst->fp = fp_round_to_nearest(a);
+            a->fp = fp_round_to_nearest(bb);
         case FPCR_ROUND_ZERO:
-            dst->fp = fp_round_to_zero(a);
+            a->fp = fp_round_to_zero(bb);
         case FPCR_ROUND_MINF:
-            dst->fp = fp_round_to_minus_infinity(a);
+            a->fp = fp_round_to_minus_infinity(bb);
         case FPCR_ROUND_PINF:
-            dst->fp = fp_round_to_plus_infinity(a);
+            a->fp = fp_round_to_plus_infinity(bb);
         default: /* never reached */
                break;
     }
 #endif
 }
 
-static void fp_getexp(fpdata *a, fpdata *dst)
+static void fp_getexp(fpdata *a, fpdata *b)
 {
     int expon;
-    frexpl(a->fp, &expon);
-    dst->fp = (double) (expon - 1);
+    frexpl(b->fp, &expon);
+    a->fp = (double) (expon - 1);
 }
-static void fp_getman(fpdata *a, fpdata *dst)
+static void fp_getman(fpdata *a, fpdata *b)
 {
     int expon;
-    dst->fp = frexpl(a->fp, &expon) * 2.0;
+    a->fp = frexpl(b->fp, &expon) * 2.0;
 }
-static void fp_div(fpdata *a, fpdata *b)
+static void fp_div(fpdata *a, fpdata *b, int prec)
 {
+       fp_set_prec(prec);
        a->fp = a->fp / b->fp;
+       fp_reset_prec(b);
 }
 static void fp_mod(fpdata *a, fpdata *b, uae_u64 *q, uae_u8 *s)
 {
@@ -747,113 +816,124 @@ static void fp_scale(fpdata *a, fpdata *b)
 
 #endif // !USE_LONG_DOUBLE
 
-static void fp_sinh(fpdata *a, fpdata *dst)
+static void fp_sinh(fpdata *a, fpdata *b)
 {
-       dst->fp = sinhl(a->fp);
+       a->fp = sinhl(b->fp);
 }
-static void fp_intrz(fpdata *fpd, fpdata *dst)
+static void fp_intrz(fpdata *a, fpdata *b)
 {
 #ifdef USE_HOST_ROUNDING
-    dst->fp = truncl(fpd->fp);
+    a->fp = truncl(b->fp);
 #else
-    dst->fp = fp_round_to_zero (fpd->fp);
+    a->fp = fp_round_to_zero (b->fp);
 #endif
 }
-static void fp_sqrt(fpdata *a, fpdata *dst)
+static void fp_sqrt(fpdata *a, fpdata *b, int prec)
 {
-       dst->fp = sqrtl(a->fp);
+       fp_set_prec(prec);
+       a->fp = sqrtl(b->fp);
+       fp_reset_prec(b);
 }
-static void fp_lognp1(fpdata *a, fpdata *dst)
+static void fp_lognp1(fpdata *a, fpdata *b)
 {
-       dst->fp = log1pl(a->fp);
+       a->fp = log1pl(b->fp);
 }
-static void fp_etoxm1(fpdata *a, fpdata *dst)
+static void fp_etoxm1(fpdata *a, fpdata *b)
 {
-       dst->fp = expm1l(a->fp);
+       a->fp = expm1l(b->fp);
 }
-static void fp_tanh(fpdata *a, fpdata *dst)
+static void fp_tanh(fpdata *a, fpdata *b)
 {
-       dst->fp = tanhl(a->fp);
+       a->fp = tanhl(b->fp);
 }
-static void fp_atan(fpdata *a, fpdata *dst)
+static void fp_atan(fpdata *a, fpdata *b)
 {
-       dst->fp = atanl(a->fp);
+       a->fp = atanl(b->fp);
 }
-static void fp_atanh(fpdata *a, fpdata *dst)
+static void fp_atanh(fpdata *a, fpdata *b)
 {
-       dst->fp = atanhl(a->fp);
+       a->fp = atanhl(b->fp);
 }
-static void fp_sin(fpdata *a, fpdata *dst)
+static void fp_sin(fpdata *a, fpdata *b)
 {
-       dst->fp = sinl(a->fp);
+       a->fp = sinl(b->fp);
 }
-static void fp_asin(fpdata *a, fpdata *dst)
+static void fp_asin(fpdata *a, fpdata *b)
 {
-       dst->fp = asinl(a->fp);
+       a->fp = asinl(b->fp);
 }
-static void fp_tan(fpdata *a, fpdata *dst)
+static void fp_tan(fpdata *a, fpdata *b)
 {
-       dst->fp = tanl(a->fp);
+       a->fp = tanl(b->fp);
 }
-static void fp_etox(fpdata *a, fpdata *dst)
+static void fp_etox(fpdata *a, fpdata *b)
 {
-       dst->fp = expl(a->fp);
+       a->fp = expl(b->fp);
 }
-static void fp_twotox(fpdata *a, fpdata *dst)
+static void fp_twotox(fpdata *a, fpdata *b)
 {
-       dst->fp = powl(2.0, a->fp);
+       a->fp = powl(2.0, b->fp);
 }
-static void fp_tentox(fpdata *a, fpdata *dst)
+static void fp_tentox(fpdata *a, fpdata *b)
 {
-       dst->fp = powl(10.0, a->fp);
+       a->fp = powl(10.0, b->fp);
 }
-static void fp_logn(fpdata *a, fpdata *dst)
+static void fp_logn(fpdata *a, fpdata *b)
 {
-       dst->fp = logl(a->fp);
+       a->fp = logl(b->fp);
 }
-static void fp_log10(fpdata *a, fpdata *dst)
+static void fp_log10(fpdata *a, fpdata *b)
 {
-       dst->fp = log10l(a->fp);
+       a->fp = log10l(b->fp);
 }
-static void fp_log2(fpdata *a, fpdata *dst)
+static void fp_log2(fpdata *a, fpdata *b)
 {
-       dst->fp = log2l(a->fp);
+       a->fp = log2l(b->fp);
 }
-static void fp_abs(fpdata *a, fpdata *dst)
+static void fp_abs(fpdata *a, fpdata *b, int prec)
 {
-       dst->fp = a->fp < 0.0 ? -a->fp : a->fp;
+       fp_set_prec(prec);
+       a->fp = b->fp < 0.0 ? -b->fp : b->fp;
+       fp_reset_prec(a);
 }
-static void fp_cosh(fpdata *a, fpdata *dst)
+static void fp_cosh(fpdata *a, fpdata *b)
 {
-       dst->fp = coshl(a->fp);
+       a->fp = coshl(b->fp);
 }
-static void fp_neg(fpdata *a, fpdata *dst)
+static void fp_neg(fpdata *a, fpdata *b, int prec)
 {
-       dst->fp = -a->fp;
+       fp_set_prec(prec);
+       a->fp = -b->fp;
+       fp_reset_prec(a);
 }
-static void fp_acos(fpdata *a, fpdata *dst)
+static void fp_acos(fpdata *a, fpdata *b)
 {
-       dst->fp = acosl(a->fp);
+       a->fp = acosl(b->fp);
 }
-static void fp_cos(fpdata *a, fpdata *dst)
+static void fp_cos(fpdata *a, fpdata *b)
 {
-       dst->fp = cosl(a->fp);
+       a->fp = cosl(b->fp);
 }
-static void fp_sub(fpdata *a, fpdata *b)
+static void fp_sub(fpdata *a, fpdata *b, int prec)
 {
+       fp_set_prec(prec);
        a->fp = a->fp - b->fp;
+       fp_reset_prec(a);
 }
-static void fp_add(fpdata *a, fpdata *b)
+static void fp_add(fpdata *a, fpdata *b, int prec)
 {
+       fp_set_prec(prec);
        a->fp = a->fp + b->fp;
+       fp_reset_prec(a);
 }
-static void fp_mul(fpdata *a, fpdata *b)
+static void fp_mul(fpdata *a, fpdata *b, int prec)
 {
+       fp_set_prec(prec);
        a->fp = a->fp * b->fp;
+       fp_reset_prec(a);
 }
 static void fp_sglmul(fpdata *a, fpdata *b)
 {
-       // not exact
        a->fp = a->fp * b->fp;
        fpp_round32(a);
 }
@@ -910,8 +990,7 @@ static void fp_cmp(fpdata *a, fpdata *b)
                if (!b_neg)
                        v = -1.0;
        } else {
-               fpp_sub(a, b);
-               v = a->fp;
+               v = a->fp - b->fp;
                fp_clear_status();
        }
        a->fp = v;
index be98f6173d91759c64eaf048ee6cbd0cbe525261..862c35e999ae3e8925737ac72603a5256a2da070 100644 (file)
@@ -43,9 +43,22 @@ static struct float_status fs;
 /* Functions for setting host/library modes and getting status */
 static void fp_set_mode(uae_u32 mode_control)
 {
-       set_floatx80_rounding_precision(80, &fs);
        set_float_detect_tininess(float_tininess_before_rounding, &fs);
-    switch(mode_control & FPCR_ROUNDING_MODE) {
+
+       switch(mode_control & FPCR_ROUNDING_PRECISION) {
+               case FPCR_PRECISION_SINGLE: // single
+                       set_floatx80_rounding_precision(32, &fs);
+                       break;
+               default: // double
+               case FPCR_PRECISION_DOUBLE: // double
+                       set_floatx80_rounding_precision(64, &fs);
+                       break;
+               case FPCR_PRECISION_EXTENDED: // extended
+                       set_floatx80_rounding_precision(80, &fs);
+                       break;
+       }
+       
+       switch(mode_control & FPCR_ROUNDING_MODE) {
         case FPCR_ROUND_NEAR: // to neareset
             set_float_rounding_mode(float_round_nearest_even, &fs);
             break;
@@ -59,7 +72,6 @@ static void fp_set_mode(uae_u32 mode_control)
             set_float_rounding_mode(float_round_up, &fs);
             break;
     }
-    return;
 }
 
 static void fp_get_status(uae_u32 *status)
@@ -83,7 +95,7 @@ STATIC_INLINE void fp_clear_status(void)
 }
 
 
-static const TCHAR *fp_print(fpdata *fpd)
+static const TCHAR *fp_print(fpdata *fpd, int mode)
 {
        static TCHAR fsout[32];
        flag n, u, d;
@@ -91,6 +103,11 @@ static const TCHAR *fp_print(fpdata *fpd)
        int i;
        floatx80 *fx = &fpd->fpx;
 
+       if (mode < 0) {
+               _stprintf(fsout, _T("%04X-%08X-%08X"), fx->high, (uae_u32)(fx->low >> 32), (uae_u32)fx->low);
+               return fsout;
+       }
+
        n = floatx80_is_negative(*fx);
        u = floatx80_is_unnormal(*fx);
        d = floatx80_is_denormal(*fx);
@@ -121,6 +138,9 @@ static const TCHAR *fp_print(fpdata *fpd)
                _stprintf(fsout, _T("%c%#.17e%s%s"), n?'-':'+', result, u ? _T("U") : _T(""), d ? _T("D") : _T(""));
 #endif
        }
+       if (mode == 0 || mode > _tcslen(fsout))
+               return fsout;
+       fsout[mode] = 0;
        return fsout;
 }
 
@@ -334,7 +354,8 @@ static void fp_get_internal_overflow(fpdata *fpd)
        }
        
        fpd->fpx.high = ((uint16_t)floatx80_internal_exp) & 0x7fff;
-       fpd->fpx.low = floatx80_internal_sig0;  
+       fpd->fpx.high |= ((uint16_t)floatx80_internal_sign) << 15;
+       fpd->fpx.low = floatx80_internal_sig;   
  }
 
 static void fp_get_internal_underflow(fpdata *fpd)
@@ -346,7 +367,8 @@ static void fp_get_internal_underflow(fpdata *fpd)
        }
     
     fpd->fpx.high = ((uint16_t)floatx80_internal_exp) & 0x7fff;
-    fpd->fpx.low = floatx80_internal_sig0;
+       fpd->fpx.high |= ((uint16_t)floatx80_internal_sign) << 15;
+    fpd->fpx.low = floatx80_internal_sig;
 }
 
 static void fp_get_exceptional_operand_grs(uae_u32 *wrd1, uae_u32 *wrd2, uae_u32 *wrd3, uae_u32 *grs)
@@ -359,6 +381,26 @@ static void fp_get_exceptional_operand_grs(uae_u32 *wrd1, uae_u32 *wrd2, uae_u32
        *grs |= (floatx80_internal_sig1 & 0x3fffffffffffffffULL) ? 1 : 0;
 }
 
+static void fp_get_internal_unmodified(uae_u32 *grs, fpdata *fpd)
+{
+    uint64_t roundbits;
+
+    fpd->fpx.high = ((uint16_t)floatx80_internal_exp) & 0x7fff;
+    fpd->fpx.high |= ((uint16_t)floatx80_internal_sign) << 15;
+    fpd->fpx.low = floatx80_internal_sig0;
+    
+    shift64RightJamming(floatx80_internal_sig1, 61, &roundbits);
+    *grs = (uae_u32)roundbits;
+}
+
+static void fp_get_internal(fpdata *fpd)
+{
+
+       fpd->fpx.high = ((int16_t)floatx80_internal_exp) & 0x7fff;
+       fpd->fpx.high |= ((int16_t)floatx80_internal_sign) << 15;
+       fpd->fpx.low = floatx80_internal_sig;
+}
+
 /* Functions for rounding */
 
 static floatx80 fp_to_sgl(floatx80 a)
@@ -395,134 +437,105 @@ static void fp_round_double(fpdata *fpd)
 
 /* Arithmetic functions */
 
-static void fp_move(fpdata *src, fpdata *dst)
-{
-    dst->fpx = floatx80_move(src->fpx, &fs);
-}
-
-static void fp_int(fpdata *a, fpdata *dst)
+static void fp_int(fpdata *a, fpdata *b)
 {
-    dst->fpx = floatx80_round_to_int(a->fpx, &fs);
+    a->fpx = floatx80_round_to_int(b->fpx, &fs);
 }
 
-static void fp_intrz(fpdata *a, fpdata *dst)
+static void fp_intrz(fpdata *a, fpdata *b)
 {
-    dst->fpx = floatx80_round_to_int_toward_zero(a->fpx, &fs);
+    a->fpx = floatx80_round_to_int_toward_zero(b->fpx, &fs);
 }
-static void fp_sqrt(fpdata *a, fpdata *dst)
-{
-    dst->fpx = floatx80_sqrt(a->fpx, &fs);
-}
-static void fp_lognp1(fpdata *a, fpdata *dst)
+static void fp_lognp1(fpdata *a, fpdata *b)
 {
     fptype fpa;
        flag e = 0;
-       dst->fpx = floatx80_lognp1_check(a->fpx, &e, &fs);
+       a->fpx = floatx80_lognp1_check(b->fpx, &e, &fs);
        if (e)
                return;
-    to_native(&fpa, a);
+    to_native(&fpa, b);
     fpa = log(a->fp + 1.0);
-    from_native(fpa, dst);
+    from_native(fpa, a);
 }
-static void fp_sin(fpdata *a, fpdata *dst)
+static void fp_sin(fpdata *a, fpdata *b)
 {
     fptype fpa;
        flag e = 0;
-       dst->fpx = floatx80_sin_check(a->fpx, &e, &fs);
+       a->fpx = floatx80_sin_check(b->fpx, &e, &fs);
        if (e)
                return;
-    to_native(&fpa, a);
+    to_native(&fpa, b);
     fpa = sin(fpa);
-    from_native(fpa, dst);
+    from_native(fpa, a);
 }
-static void fp_tan(fpdata *a, fpdata *dst)
+static void fp_tan(fpdata *a, fpdata *b)
 {
     fptype fpa;
        flag e = 0;
-       dst->fpx = floatx80_tan_check(a->fpx, &e, &fs);
+       a->fpx = floatx80_tan_check(b->fpx, &e, &fs);
        if (e)
                return;
-    to_native(&fpa, a);
+    to_native(&fpa, b);
     fpa = tan(fpa);
-    from_native(fpa, dst);
+    from_native(fpa, a);
 }
-static void fp_logn(fpdata *a, fpdata *dst)
+static void fp_logn(fpdata *a, fpdata *b)
 {
     fptype fpa;
        flag e = 0;
-       dst->fpx = floatx80_logn_check(a->fpx, &e, &fs);
+       a->fpx = floatx80_logn_check(b->fpx, &e, &fs);
        if (e)
                return;
-    to_native(&fpa, a);
+    to_native(&fpa, b);
     fpa = log(fpa);
-    from_native(fpa, dst);
+    from_native(fpa, a);
 }
-static void fp_log10(fpdata *a, fpdata *dst)
+static void fp_log10(fpdata *a, fpdata *b)
 {
     fptype fpa;
        flag e = 0;
-       dst->fpx = floatx80_log10_check(a->fpx, &e, &fs);
+       a->fpx = floatx80_log10_check(b->fpx, &e, &fs);
        if (e)
                return;
-    to_native(&fpa, a);
+    to_native(&fpa, b);
     fpa = log10(fpa);
-    from_native(fpa, dst);
+    from_native(fpa, a);
 }
-static void fp_log2(fpdata *a, fpdata *dst)
+static void fp_log2(fpdata *a, fpdata *b)
 {
     fptype fpa;
        flag e = 0;
-       dst->fpx = floatx80_log2_check(a->fpx, &e, &fs);
+       a->fpx = floatx80_log2_check(b->fpx, &e, &fs);
        if (e)
                return;
-    to_native(&fpa, a);
+    to_native(&fpa, b);
     fpa = log2(fpa);
-    from_native(fpa, dst);
+    from_native(fpa, a);
 }
 
-static void fp_abs(fpdata *a, fpdata *dst)
-{
-       dst->fpx = floatx80_abs(a->fpx, &fs);
-}
-static void fp_neg(fpdata *a, fpdata *dst)
-{
-       dst->fpx = floatx80_neg(a->fpx, &fs);
-}
-static void fp_cos(fpdata *a, fpdata *dst)
+static void fp_cos(fpdata *a, fpdata *b)
 {
     fptype fpa;
        flag e = 0;
-       dst->fpx = floatx80_sin_check(a->fpx, &e, &fs);
+       a->fpx = floatx80_sin_check(b->fpx, &e, &fs);
        if (e)
                return;
-    to_native(&fpa, a);
+    to_native(&fpa, b);
     fpa = cos(fpa);
-    from_native(fpa, dst);
-}
-static void fp_getexp(fpdata *a, fpdata *dst)
-{
-    dst->fpx = floatx80_getexp(a->fpx, &fs);
+    from_native(fpa, a);
 }
-static void fp_getman(fpdata *a, fpdata *dst)
+static void fp_getexp(fpdata *a, fpdata *b)
 {
-    dst->fpx = floatx80_getman(a->fpx, &fs);
+    a->fpx = floatx80_getexp(b->fpx, &fs);
 }
-static void fp_div(fpdata *a, fpdata *b)
+static void fp_getman(fpdata *a, fpdata *b)
 {
-    a->fpx = floatx80_div(a->fpx, b->fpx, &fs);
+    a->fpx = floatx80_getman(b->fpx, &fs);
 }
 static void fp_mod(fpdata *a, fpdata *b, uae_u64 *q, uae_u8 *s)
 {
     a->fpx = floatx80_mod(a->fpx, b->fpx, q, s, &fs);
 }
-static void fp_add(fpdata *a, fpdata *b)
-{
-    a->fpx = floatx80_add(a->fpx, b->fpx, &fs);
-}
-static void fp_mul(fpdata *a, fpdata *b)
-{
-    a->fpx = floatx80_mul(a->fpx, b->fpx, &fs);
-}
 static void fp_sgldiv(fpdata *a, fpdata *b)
 {
     a->fpx = floatx80_sgldiv(a->fpx, b->fpx, &fs);
@@ -539,10 +552,6 @@ static void fp_scale(fpdata *a, fpdata *b)
 {
     a->fpx = floatx80_scale(a->fpx, b->fpx, &fs);
 }
-static void fp_sub(fpdata *a, fpdata *b)
-{
-    a->fpx = floatx80_sub(a->fpx, b->fpx, &fs);
-}
 static void fp_cmp(fpdata *a, fpdata *b)
 {
     a->fpx = floatx80_cmp(a->fpx, b->fpx, &fs);
@@ -552,128 +561,189 @@ static void fp_tst(fpdata *a, fpdata *b)
        a->fpx = floatx80_tst(b->fpx, &fs);
 }
 
+#define SETPREC \
+    uint8_t oldprec = fs.floatx80_rounding_precision; \
+       if (prec > 0) \
+           set_floatx80_rounding_precision(prec, &fs);
+
+#define RESETPREC \
+       if (prec > 0) \
+               set_floatx80_rounding_precision(oldprec, &fs);
+
+
+/* Functions with fixed precision */
+static void fp_move(fpdata *a, fpdata *b, int prec)
+{
+       SETPREC
+    a->fpx = floatx80_move(b->fpx, &fs);
+       RESETPREC
+}
+static void fp_abs(fpdata *a, fpdata *b, int prec)
+{
+       SETPREC
+    a->fpx = floatx80_abs(b->fpx, &fs);
+       RESETPREC
+}
+static void fp_neg(fpdata *a, fpdata *b, int prec)
+{
+       SETPREC
+    a->fpx = floatx80_neg(b->fpx, &fs);
+       RESETPREC
+}
+static void fp_add(fpdata *a, fpdata *b, int prec)
+{
+       SETPREC
+    a->fpx = floatx80_add(a->fpx, b->fpx, &fs);
+       RESETPREC
+}
+static void fp_sub(fpdata *a, fpdata *b, int prec)
+{
+       SETPREC
+    a->fpx = floatx80_sub(a->fpx, b->fpx, &fs);
+       RESETPREC
+}
+static void fp_mul(fpdata *a, fpdata *b, int prec)
+{
+       SETPREC
+    a->fpx = floatx80_mul(a->fpx, b->fpx, &fs);
+       RESETPREC
+}
+static void fp_div(fpdata *a, fpdata *b, int prec)
+{
+       SETPREC
+    a->fpx = floatx80_div(a->fpx, b->fpx, &fs);
+       RESETPREC
+}
+static void fp_sqrt(fpdata *a, fpdata *b, int prec)
+{
+       SETPREC
+    a->fpx = floatx80_sqrt(b->fpx, &fs);
+       RESETPREC
+}
+
+
 /* FIXME: create softfloat functions for following arithmetics */
 
-static void fp_sinh(fpdata *a, fpdata *dst)
+static void fp_sinh(fpdata *a, fpdata *b)
 {
     fptype fpa;
        flag e = 0;
-       dst->fpx = floatx80_sinh_check(a->fpx, &e, &fs);
+       a->fpx = floatx80_sinh_check(b->fpx, &e, &fs);
        if (e)
                return;
-    to_native(&fpa, a);
+    to_native(&fpa, b);
     fpa = sinhl(fpa);
-    from_native(fpa, dst);
+    from_native(fpa, a);
 }
-static void fp_etoxm1(fpdata *a, fpdata *dst)
+static void fp_etoxm1(fpdata *a, fpdata *b)
 {
     fptype fpa;
        flag e = 0;
-       dst->fpx = floatx80_etoxm1_check(a->fpx, &e, &fs);
+       a->fpx = floatx80_etoxm1_check(b->fpx, &e, &fs);
        if (e)
                return;
-    to_native(&fpa, a);
+    to_native(&fpa, b);
     fpa = expl(fpa) - 1.0;
-    from_native(fpa, dst);
+    from_native(fpa, a);
 }
-static void fp_tanh(fpdata *a, fpdata *dst)
+static void fp_tanh(fpdata *a, fpdata *b)
 {
     fptype fpa;
        flag e = 0;
-       dst->fpx = floatx80_tanh_check(a->fpx, &e, &fs);
+       a->fpx = floatx80_tanh_check(b->fpx, &e, &fs);
        if (e)
                return;
-    to_native(&fpa, a);
+    to_native(&fpa, b);
     fpa = tanhl(fpa);
-    from_native(fpa, dst);
+    from_native(fpa, a);
 }
-static void fp_atan(fpdata *a, fpdata *dst)
+static void fp_atan(fpdata *a, fpdata *b)
 {
     fptype fpa;
        flag e = 0;
-       dst->fpx = floatx80_atan_check(a->fpx, &e, &fs);
+       a->fpx = floatx80_atan_check(b->fpx, &e, &fs);
        if (e)
                return;
-    to_native(&fpa, a);
+    to_native(&fpa, b);
     fpa = atanl(fpa);
-    from_native(fpa, dst);
+    from_native(fpa, a);
 }
-static void fp_asin(fpdata *a, fpdata *dst)
+static void fp_asin(fpdata *a, fpdata *b)
 {
     fptype fpa;
        flag e = 0;
-       dst->fpx = floatx80_asin_check(a->fpx, &e, &fs);
+       a->fpx = floatx80_asin_check(b->fpx, &e, &fs);
        if (e)
                return;
-    to_native(&fpa, a);
+    to_native(&fpa, b);
     fpa = asinl(fpa);
-    from_native(fpa, dst);
+    from_native(fpa, a);
 }
-static void fp_atanh(fpdata *a, fpdata *dst)
+static void fp_atanh(fpdata *a, fpdata *b)
 {
     fptype fpa;
        flag e = 0;
-       dst->fpx = floatx80_atanh_check(a->fpx, &e, &fs);
+       a->fpx = floatx80_atanh_check(b->fpx, &e, &fs);
        if (e)
                return;
-    to_native(&fpa, a);
+    to_native(&fpa, b);
     fpa = atanhl(fpa);
-    from_native(fpa, dst);
+    from_native(fpa, a);
 }
-static void fp_etox(fpdata *a, fpdata *dst)
+static void fp_etox(fpdata *a, fpdata *b)
 {
     fptype fpa;
        flag e = 0;
-       dst->fpx = floatx80_etox_check(a->fpx, &e, &fs);
+       a->fpx = floatx80_etox_check(b->fpx, &e, &fs);
        if (e)
                return;
-    to_native(&fpa, a);
+    to_native(&fpa, b);
     fpa = expl(fpa);
-    from_native(fpa, dst);
+    from_native(fpa, a);
 }
-static void fp_twotox(fpdata *a, fpdata *dst)
+static void fp_twotox(fpdata *a, fpdata *b)
 {
     fptype fpa;
        flag e = 0;
-       dst->fpx = floatx80_twotox_check(a->fpx, &e, &fs);
+       a->fpx = floatx80_twotox_check(b->fpx, &e, &fs);
        if (e)
                return;
-    to_native(&fpa, a);
+    to_native(&fpa, b);
     fpa = powl(2.0, fpa);
-    from_native(fpa, dst);
+    from_native(fpa, a);
 }
-static void fp_tentox(fpdata *a, fpdata *dst)
+static void fp_tentox(fpdata *a, fpdata *b)
 {
     fptype fpa;
        flag e = 0;
-       dst->fpx = floatx80_tentox_check(a->fpx, &e, &fs);
+       a->fpx = floatx80_tentox_check(b->fpx, &e, &fs);
        if (e)
                return;
-    to_native(&fpa, a);
+    to_native(&fpa, b);
     fpa = powl(10.0, fpa);
-    from_native(fpa, dst);
+    from_native(fpa, a);
 }
-static void fp_cosh(fpdata *a, fpdata *dst)
+static void fp_cosh(fpdata *a, fpdata *b)
 {
     fptype fpa;
        flag e = 0;
-       dst->fpx = floatx80_cosh_check(a->fpx, &e, &fs);
+       a->fpx = floatx80_cosh_check(b->fpx, &e, &fs);
        if (e)
                return;
-    to_native(&fpa, a);
+    to_native(&fpa, b);
     fpa = coshl(fpa);
-    from_native(fpa, dst);
+    from_native(fpa, a);
 }
-static void fp_acos(fpdata *a, fpdata *dst)
+static void fp_acos(fpdata *a, fpdata *b)
 {
     fptype fpa;
        flag e = 0;
-       dst->fpx = floatx80_acos_check(a->fpx, &e, &fs);
+       a->fpx = floatx80_acos_check(b->fpx, &e, &fs);
        if (e)
                return;
-    to_native(&fpa, a);
+    to_native(&fpa, b);
     fpa = acosl(fpa);
-    from_native(fpa, dst);
+    from_native(fpa, a);
 }
 
 static void fp_normalize(fpdata *a)
index 4f2f883566eb469fcbb2a578b30c652e5786a4d3..81d62e431fe042445a73f0dfc413b8e90f505bc8 100644 (file)
@@ -19,6 +19,7 @@ extern void init_fpucw_x87(void);
 
 typedef void (*FPP_ABQS)(fpdata*, fpdata*, uae_u64*, uae_u8*);
 typedef void (*FPP_AB)(fpdata*, fpdata*);
+typedef void (*FPP_ABP)(fpdata*, fpdata*, int);
 typedef void (*FPP_A)(fpdata*);
 
 typedef bool (*FPP_IS)(fpdata*);
@@ -44,7 +45,7 @@ typedef void (*FPP_FROM_EXTEN)(fpdata*, uae_u32*, uae_u32*, uae_u32*);
 typedef void (*FPP_PACK)(uae_u32*, uae_u32*, uae_u32*);
 typedef void (*FPP_PACKG)(uae_u32*, uae_u32*, uae_u32*, uae_u32*);
 
-typedef const TCHAR* (*FPP_PRINT)(fpdata*);
+typedef const TCHAR* (*FPP_PRINT)(fpdata*,int);
 
 extern FPP_PRINT fpp_print;
 
@@ -89,7 +90,7 @@ extern FPP_PACKG fpp_get_exceptional_operand_grs;
 extern FPP_AB fpp_int;
 extern FPP_AB fpp_sinh;
 extern FPP_AB fpp_intrz;
-extern FPP_AB fpp_sqrt;
+extern FPP_ABP fpp_sqrt;
 extern FPP_AB fpp_lognp1;
 extern FPP_AB fpp_etoxm1;
 extern FPP_AB fpp_tanh;
@@ -104,22 +105,22 @@ extern FPP_AB fpp_tentox;
 extern FPP_AB fpp_logn;
 extern FPP_AB fpp_log10;
 extern FPP_AB fpp_log2;
-extern FPP_AB fpp_abs;
+extern FPP_ABP fpp_abs;
 extern FPP_AB fpp_cosh;
-extern FPP_AB fpp_neg;
+extern FPP_ABP fpp_neg;
 extern FPP_AB fpp_acos;
 extern FPP_AB fpp_cos;
 extern FPP_AB fpp_getexp;
 extern FPP_AB fpp_getman;
-extern FPP_AB fpp_div;
+extern FPP_ABP fpp_div;
 extern FPP_ABQS fpp_mod;
-extern FPP_AB fpp_add;
-extern FPP_AB fpp_mul;
+extern FPP_ABP fpp_add;
+extern FPP_ABP fpp_mul;
 extern FPP_ABQS fpp_rem;
 extern FPP_AB fpp_scale;
-extern FPP_AB fpp_sub;
+extern FPP_ABP fpp_sub;
 extern FPP_AB fpp_sgldiv;
 extern FPP_AB fpp_sglmul;
 extern FPP_AB fpp_cmp;
 extern FPP_AB fpp_tst;
-extern FPP_AB fpp_move;
+extern FPP_ABP fpp_move;
index 8efec75de18b3a984420555845cff797591d2f23..b5e26d37ecfbc60d937f80dd49c0cc10b6ba8b5e 100644 (file)
@@ -1790,7 +1790,7 @@ static uaecptr ShowEA (void *f, uaecptr pc, uae_u16 opcode, int reg, amodes mode
                        {
                                fpdata fp;
                                fpp_to_single(&fp, get_ilong_debug(pc));
-                               _stprintf(buffer, _T("#%s"), fpp_print(&fp));
+                               _stprintf(buffer, _T("#%s"), fpp_print(&fp, 0));
                                pc += 4;
                        }
                        break;
@@ -1798,7 +1798,7 @@ static uaecptr ShowEA (void *f, uaecptr pc, uae_u16 opcode, int reg, amodes mode
                        {
                                fpdata fp;
                                fpp_to_double(&fp, get_ilong_debug(pc), get_ilong_debug(pc + 4));
-                               _stprintf(buffer, _T("#%s"), fpp_print(&fp));
+                               _stprintf(buffer, _T("#%s"), fpp_print(&fp, 0));
                                pc += 8;
                        }
                        break;
@@ -1806,7 +1806,7 @@ static uaecptr ShowEA (void *f, uaecptr pc, uae_u16 opcode, int reg, amodes mode
                {
                        fpdata fp;
                        fpp_to_exten(&fp, get_ilong_debug(pc), get_ilong_debug(pc + 4), get_ilong_debug(pc + 8));
-                       _stprintf(buffer, _T("#%s"), fpp_print(&fp));
+                       _stprintf(buffer, _T("#%s"), fpp_print(&fp, 0));
                        pc += 12;
                        break;
                }
@@ -2570,13 +2570,13 @@ static void Exception_build_stack_frame_common (uae_u32 oldpc, uae_u32 currpc, u
                Exception_build_stack_frame(oldpc, regs.instruction_pc, regs.mmu_ssw, nr, 0x0);
        } else if (nr >= 48 && nr <= 55) {
                if (regs.fpu_exp_pre) {
-                       if (currprefs.cpu_model == 68060 && nr == 55 && (regs.fp_unimp_pend & 2)) { // packed decimal real
+                       if (currprefs.cpu_model == 68060 && nr == 55 && regs.fp_unimp_pend == 2) { // packed decimal real
                                Exception_build_stack_frame(regs.fp_ea, regs.instruction_pc, 0, nr, 0x2);
                        } else {
                                Exception_build_stack_frame(oldpc, regs.instruction_pc, 0, nr, 0x0);
                        }
                } else { /* post-instruction */
-                       if (currprefs.cpu_model == 68060 && nr == 55 && (regs.fp_unimp_pend & 2)) { // packed decimal real
+                       if (currprefs.cpu_model == 68060 && nr == 55 && regs.fp_unimp_pend == 2) { // packed decimal real
                                Exception_build_stack_frame(regs.fp_ea, currpc, 0, nr, 0x2);
                        } else {
                                Exception_build_stack_frame(oldpc, currpc, 0, nr, 0x3);
@@ -6336,13 +6336,16 @@ void m68k_dumpstate (uaecptr pc, uaecptr *nextpc)
 #ifdef FPUEMU
        if (currprefs.fpu_model) {
                uae_u32 fpsr;
-               for (i = 0; i < 8; i++){
-                       console_out_f (_T("FP%d: %g "), i, regs.fp[i].fp);
-                       if ((i & 3) == 3)
+               for (i = 0; i < 8; i++) {
+                       if (!(i & 1))
+                               console_out_f(_T("%d: "), i);
+                       console_out_f (_T("%s "), fpp_print(&regs.fp[i], -1));
+                       console_out_f (_T("%s "), fpp_print(&regs.fp[i], 0));
+                       if (i & 1)
                                console_out_f (_T("\n"));
                }
                fpsr = fpp_get_fpsr ();
-               console_out_f (_T("FPSR: %04X FPCR: %08x FPIAR: %08x N=%d Z=%d I=%d NAN=%d\n"),
+               console_out_f (_T("FPSR: %08X FPCR: %08x FPIAR: %08x N=%d Z=%d I=%d NAN=%d\n"),
                        fpsr, regs.fpcr, regs.fpiar,
                        (fpsr & 0x8000000) != 0,
                        (fpsr & 0x4000000) != 0,
index 410a9436de3bf3ebc6bb71c9a589e33d3f4c2be4..2b093df1f49b73194abe66ca1a1cc07799aec7c3 100644 (file)
@@ -101,7 +101,9 @@ this code that are retained.
  | double-precision floating-point value for external use.
  *----------------------------------------------------------------------------*/
 flag floatx80_internal_sign = 0;
-uint32_t floatx80_internal_exp = 0;
+int32_t floatx80_internal_exp = 0;
+uint64_t floatx80_internal_sig = 0;
+int32_t floatx80_internal_exp0 = 0;
 uint64_t floatx80_internal_sig0 = 0;
 uint64_t floatx80_internal_sig1 = 0;
 
@@ -109,32 +111,126 @@ uint64_t floatx80_internal_sig1 = 0;
  | Function for storing sign, exponent and significand of extended
  | double-precision floating-point intermediate result for external use.
  *----------------------------------------------------------------------------*/
-static void saveFloatx80Internal( flag zSign, uint32_t zExp, uint64_t zSig0, uint64_t zSig1 )
+floatx80 roundSaveFloatx80Internal( int8_t roundingPrecision, flag zSign, int32_t zExp, uint64_t zSig0, uint64_t zSig1, float_status *status )
 {
+    int64_t roundIncrement, roundMask, roundBits;
+    flag increment;
+    
+    if ( roundingPrecision == 80 ) {
+        goto precision80;
+    } else if ( roundingPrecision == 64 ) {
+        roundIncrement = LIT64( 0x0000000000000400 );
+        roundMask = LIT64( 0x00000000000007FF );
+    } else if ( roundingPrecision == 32 ) {
+        roundIncrement = LIT64( 0x0000008000000000 );
+        roundMask = LIT64( 0x000000FFFFFFFFFF );
+    } else {
+        goto precision80;
+    }
+    
+    zSig0 |= ( zSig1 != 0 );
+    if ( status->float_rounding_mode != float_round_nearest_even ) {
+        if ( status->float_rounding_mode == float_round_to_zero ) {
+            roundIncrement = 0;
+        } else {
+            roundIncrement = roundMask;
+            if ( zSign ) {
+                if ( status->float_rounding_mode == float_round_up ) roundIncrement = 0;
+            } else {
+                if ( status->float_rounding_mode == float_round_down ) roundIncrement = 0;
+            }
+        }
+    }
+    
+    roundBits = zSig0 & roundMask;
+    
+    zSig0 += roundIncrement;
+    if ( zSig0 < roundIncrement ) {
+        ++zExp;
+        zSig0 = LIT64( 0x8000000000000000 );
+    }
+    roundIncrement = roundMask + 1;
+    if ( status->float_rounding_mode == float_round_nearest_even && ( roundBits<<1 == roundIncrement ) ) {
+        roundMask |= roundIncrement;
+    }
+    zSig0 &= ~ roundMask;
+    if ( zSig0 == 0 ) zExp = 0;
+    return packFloatx80( zSign, zExp, zSig0 );
+
+precision80:
+    increment = ( (int64_t) zSig1 < 0 );
+    if ( status->float_rounding_mode != float_round_nearest_even ) {
+        if ( status->float_rounding_mode == float_round_to_zero ) {
+            increment = 0;
+        } else {
+            if ( zSign ) {
+                increment = ( status->float_rounding_mode == float_round_down ) && zSig1;
+            } else {
+                increment = ( status->float_rounding_mode == float_round_up ) && zSig1;
+            }
+        }
+    }
+    if ( increment ) {
+        ++zSig0;
+        if ( zSig0 == 0 ) {
+            ++zExp;
+            zSig0 = LIT64( 0x8000000000000000 );
+        } else {
+            zSig0 &= ~ ( ( (uint64_t) ( zSig1<<1 ) == 0 ) & ( status->float_rounding_mode == float_round_nearest_even ) );
+        }
+    } else {
+        if ( zSig0 == 0 ) zExp = 0;
+    }
+    return packFloatx80( zSign, zExp, zSig0 );
+}
+
+static void saveFloatx80Internal( flag zSign, int32_t zExp, uint64_t zSig0, uint64_t zSig1, float_status *status )
+{
+    floatx80 z = roundSaveFloatx80Internal( status->floatx80_rounding_precision, zSign, zExp, zSig0, zSig1, status );
+    floatx80 z0 = roundSaveFloatx80Internal( 80, zSign, zExp, zSig0, zSig1, status );
+
+       floatx80_internal_sign = zSign;
+    floatx80_internal_exp = extractFloatx80Exp( z );
+    floatx80_internal_sig = extractFloatx80Frac( z );
+    floatx80_internal_exp0 = extractFloatx80Exp( z0 );
+    floatx80_internal_sig0 = extractFloatx80Frac( z0 );
+       floatx80_internal_sig1 = zSig1;
+}
+
+static void saveFloat64Internal( flag zSign, int16_t zExp, uint64_t zSig, float_status *status )
+{
+       floatx80 z = roundSaveFloatx80Internal( 64, zSign, zExp + 0x3C01, zSig<<1, 0, status );
+
     floatx80_internal_sign = zSign;
-    floatx80_internal_exp = zExp;
-    floatx80_internal_sig0 = zSig0;
-    floatx80_internal_sig1 = zSig1;
+    floatx80_internal_exp = extractFloatx80Exp( z );
+    floatx80_internal_sig = extractFloatx80Frac( z );
+    floatx80_internal_exp0 = zExp + 0x3C01;
+    floatx80_internal_sig0 = zSig<<1;
+    floatx80_internal_sig1 = 0;
 }
 
-static void saveFloat64Internal( flag zSign, uint16_t zExp, uint64_t zSig, float_status *status )
+static void saveFloat32Internal( flag zSign, int16_t zExp, uint32_t zSig, float_status *status )
 {
-    floatx80 z = roundAndPackFloatx80( 64, zSign, 0x3FFF, zSig<<1, 0, status );
+       floatx80 z = roundSaveFloatx80Internal( 32, zSign, zExp + 0x3F81, ( (uint64_t) zSig )<<33, 0, status );
 
     floatx80_internal_sign = zSign;
-    floatx80_internal_exp = zExp + 0x3C01;
-    floatx80_internal_sig0 = extractFloatx80Frac( z );
+    floatx80_internal_exp = extractFloatx80Exp( z );
+    floatx80_internal_sig = extractFloatx80Frac( z );
+    floatx80_internal_exp0 = zExp + 0x3F81;
+    floatx80_internal_sig0 = ( (uint64_t) zSig )<<33;
     floatx80_internal_sig1 = 0;
 }
 
-static void saveFloat32Internal( flag zSign, uint16_t zExp, uint32_t zSig, float_status *status )
+void saveFloatx80InternalSgl( flag zSign, int32_t zExp, uint64_t zSig0, uint64_t zSig1, float_status *status )
 {
-    floatx80 z = roundAndPackFloatx80( 32, zSign, 0x3FFF, ( (uint64_t) zSig )<<33, 0, status );
+    floatx80 z = roundSaveFloatx80Internal( 32, zSign, zExp, zSig0, zSig1, status );
     
     floatx80_internal_sign = zSign;
-    floatx80_internal_exp = zExp + 0x3F81;
-    floatx80_internal_sig0 = extractFloatx80Frac( z );
-    floatx80_internal_sig1 = 0;
+    floatx80_internal_exp = extractFloatx80Exp( z );
+    floatx80_internal_sig = extractFloatx80Frac( z );
+    floatx80_internal_exp0 = zExp;
+    floatx80_internal_sig0 = zSig0;
+    floatx80_internal_sig1 = zSig1;
 }
 
 /*----------------------------------------------------------------------------
@@ -831,6 +927,7 @@ floatx80 packFloatx80( flag zSign, int32_t zExp, uint64_t zSig )
 | Floating-Point Arithmetic.
 *----------------------------------------------------------------------------*/
 
+#ifndef SOFTFLOAT_68K
 floatx80 roundAndPackFloatx80(int8_t roundingPrecision, flag zSign,
                                      int32_t zExp, uint64_t zSig0, uint64_t zSig1,
                                      float_status *status)
@@ -902,7 +999,7 @@ floatx80 roundAndPackFloatx80(int8_t roundingPrecision, flag zSign,
 #ifdef SOFTFLOAT_68K
                        if ( isTiny ) {
                                float_raise( float_flag_underflow, status );
-                               saveFloatx80Internal( zSign, zExp, zSig0, zSig1 );
+                               saveFloatx80Internal( zSign, zExp, zSig0, zSig1, status );
                        }
                        shift64RightJamming( zSig0, -zExp, &zSig0 );
 #else
@@ -982,7 +1079,7 @@ if (roundBits) {
             float_raise(float_flag_overflow | float_flag_inexact, status);
 #else
             float_raise( float_flag_overflow, status );
-                       saveFloatx80Internal( zSign, zExp, zSig0, zSig1 );
+                       saveFloatx80Internal( zSign, zExp, zSig0, zSig1, status );
             if ( ( zSig0 & roundMask ) || zSig1 ) float_raise( float_flag_inexact, status );
 #endif
                        if (    ( roundingMode == float_round_to_zero )
@@ -1011,7 +1108,7 @@ if (roundBits) {
 #ifdef SOFTFLOAT_68K
                        if ( isTiny ) {
                                float_raise( float_flag_underflow, status );
-                               saveFloatx80Internal( zSign, zExp, zSig0, zSig1 );
+                               saveFloatx80Internal( zSign, zExp, zSig0, zSig1, status );
                        }
                        shift64ExtraRightJamming( zSig0, zSig1, -zExp, &zSig0, &zSig1 );
 #else
@@ -1070,6 +1167,160 @@ if (roundBits) {
 
 }
 
+#else // SOFTFLOAT_68K
+
+floatx80 roundAndPackFloatx80( int8_t roundingPrecision, flag zSign, int32_t zExp, uint64_t zSig0, uint64_t zSig1, float_status *status )
+{
+    int8_t roundingMode;
+    flag roundNearestEven, increment;
+    int64_t roundIncrement, roundMask, roundBits;
+    int32_t expOffset;
+    
+    roundingMode = status->float_rounding_mode;
+    roundNearestEven = ( roundingMode == float_round_nearest_even );
+    if ( roundingPrecision == 80 ) goto precision80;
+    if ( roundingPrecision == 64 ) {
+        roundIncrement = LIT64( 0x0000000000000400 );
+        roundMask = LIT64( 0x00000000000007FF );
+        expOffset = 0x3C00;
+    } else if ( roundingPrecision == 32 ) {
+        roundIncrement = LIT64( 0x0000008000000000 );
+        roundMask = LIT64( 0x000000FFFFFFFFFF );
+        expOffset = 0x3F80;
+    } else {
+        goto precision80;
+    }
+    zSig0 |= ( zSig1 != 0 );
+    if ( ! roundNearestEven ) {
+        if ( roundingMode == float_round_to_zero ) {
+            roundIncrement = 0;
+        } else {
+            roundIncrement = roundMask;
+            if ( zSign ) {
+                if ( roundingMode == float_round_up ) roundIncrement = 0;
+            } else {
+                if ( roundingMode == float_round_down ) roundIncrement = 0;
+            }
+        }
+    }
+    roundBits = zSig0 & roundMask;
+    if ( ( ( 0x7FFE - expOffset ) < zExp ) ||
+        ( ( zExp == ( 0x7FFE - expOffset ) ) && ( zSig0 + roundIncrement < zSig0 ) ) ) {
+        float_raise( float_flag_overflow, status );
+        saveFloatx80Internal( zSign, zExp, zSig0, zSig1, status );
+        if ( zSig0 & roundMask ) float_raise( float_flag_inexact, status );
+        if (    ( roundingMode == float_round_to_zero )
+            || ( zSign && ( roundingMode == float_round_up ) )
+            || ( ! zSign && ( roundingMode == float_round_down ) )
+            ) {
+            return packFloatx80( zSign, 0x7FFE - expOffset, ~ roundMask );
+        }
+        return packFloatx80( zSign, 0x7FFF, floatx80_default_infinity_low );
+    }
+    if ( zExp < ( expOffset + 1 ) ) {
+        float_raise( float_flag_underflow, status );
+        saveFloatx80Internal( zSign, zExp, zSig0, zSig1, status );
+        shift64RightJamming( zSig0, -( zExp - ( expOffset + 1 ) ), &zSig0 );
+        zExp = expOffset + 1;
+        roundBits = zSig0 & roundMask;
+        if ( roundBits ) float_raise( float_flag_inexact, status );
+        zSig0 += roundIncrement;
+        roundIncrement = roundMask + 1;
+        if ( roundNearestEven && ( roundBits<<1 == roundIncrement ) ) {
+            roundMask |= roundIncrement;
+        }
+        zSig0 &= ~ roundMask;
+        return packFloatx80( zSign, zExp, zSig0 );
+    }
+    if ( roundBits ) {
+        float_raise( float_flag_inexact, status );
+        saveFloatx80Internal( zSign, zExp, zSig0, zSig1, status );
+    }
+    zSig0 += roundIncrement;
+    if ( zSig0 < roundIncrement ) {
+        ++zExp;
+        zSig0 = LIT64( 0x8000000000000000 );
+    }
+    roundIncrement = roundMask + 1;
+    if ( roundNearestEven && ( roundBits<<1 == roundIncrement ) ) {
+        roundMask |= roundIncrement;
+    }
+    zSig0 &= ~ roundMask;
+    if ( zSig0 == 0 ) zExp = 0;
+    return packFloatx80( zSign, zExp, zSig0 );
+precision80:
+    increment = ( (int64_t) zSig1 < 0 );
+    if ( ! roundNearestEven ) {
+        if ( roundingMode == float_round_to_zero ) {
+            increment = 0;
+        } else {
+            if ( zSign ) {
+                increment = ( roundingMode == float_round_down ) && zSig1;
+            } else {
+                increment = ( roundingMode == float_round_up ) && zSig1;
+            }
+        }
+    }
+    if ( 0x7FFE <= (uint32_t) zExp ) {
+        if ( ( 0x7FFE < zExp ) ||
+            ( ( zExp == 0x7FFE ) && ( zSig0 == LIT64( 0xFFFFFFFFFFFFFFFF ) ) && increment )
+            ) {
+            roundMask = 0;
+            float_raise( float_flag_overflow, status );
+            saveFloatx80Internal( zSign, zExp, zSig0, zSig1, status );
+            if ( ( zSig0 & roundMask ) || zSig1 ) float_raise( float_flag_inexact, status );
+            if (    ( roundingMode == float_round_to_zero )
+                || ( zSign && ( roundingMode == float_round_up ) )
+                || ( ! zSign && ( roundingMode == float_round_down ) )
+                ) {
+                return packFloatx80( zSign, 0x7FFE, ~ roundMask );
+            }
+            return packFloatx80( zSign, 0x7FFF, floatx80_default_infinity_low );
+        }
+        if ( zExp < 0 ) {
+            float_raise( float_flag_underflow, status );
+            saveFloatx80Internal( zSign, zExp, zSig0, zSig1, status );
+            shift64ExtraRightJamming( zSig0, zSig1, -zExp, &zSig0, &zSig1 );
+            zExp = 0;
+            if ( zSig1 ) float_raise( float_flag_inexact, status );
+            if ( roundNearestEven ) {
+                increment = ( (int64_t) zSig1 < 0 );
+            } else {
+                if ( zSign ) {
+                    increment = ( roundingMode == float_round_down ) && zSig1;
+                } else {
+                    increment = ( roundingMode == float_round_up ) && zSig1;
+                }
+            }
+            if ( increment ) {
+                ++zSig0;
+                zSig0 &=
+                ~ ( ( (uint64_t) ( zSig1<<1 ) == 0 ) & roundNearestEven );
+            }
+            return packFloatx80( zSign, zExp, zSig0 );
+        }
+    }
+    if ( zSig1 ) {
+        float_raise( float_flag_inexact, status );
+        saveFloatx80Internal( zSign, zExp, zSig0, zSig1, status );
+    }
+    if ( increment ) {
+        ++zSig0;
+        if ( zSig0 == 0 ) {
+            ++zExp;
+            zSig0 = LIT64( 0x8000000000000000 );
+        } else {
+            zSig0 &= ~ ( ( (uint64_t) ( zSig1<<1 ) == 0 ) & roundNearestEven );
+        }
+    } else {
+        if ( zSig0 == 0 ) zExp = 0;
+    }
+    return packFloatx80( zSign, zExp, zSig0 );
+    
+}
+
+#endif
+
 #ifdef SOFTFLOAT_68K // 21-01-2017: Added for Previous
 floatx80 roundAndPackFloatx80Sgl( flag zSign, int32_t zExp, uint64_t zSig0, uint64_t zSig1, float_status *status )
 {
@@ -1103,7 +1354,7 @@ floatx80 roundAndPackFloatx80Sgl( flag zSign, int32_t zExp, uint64_t zSig0, uint
             || ( ( zExp == 0x7FFE ) && ( zSig0 + roundIncrement < zSig0 ) )
             ) {
             float_raise( float_flag_overflow, status );
-                       saveFloatx80Internal( zSign, zExp, zSig0, zSig1 );
+                       saveFloatx80InternalSgl( zSign, zExp, zSig0, zSig1, status );
                        if ( zSig0 & roundMask ) float_raise( float_flag_inexact, status );
             if (    ( roundingMode == float_round_to_zero )
                 || ( zSign && ( roundingMode == float_round_up ) )
@@ -1121,12 +1372,12 @@ floatx80 roundAndPackFloatx80Sgl( flag zSign, int32_t zExp, uint64_t zSig0, uint
             || ( zSig0 <= zSig0 + roundIncrement );
                        if ( isTiny ) {
                                float_raise( float_flag_underflow, status );
-                               saveFloatx80Internal( zSign, zExp, zSig0, zSig1 );
+                               saveFloatx80InternalSgl( zSign, zExp, zSig0, zSig1, status );
                        }
             shift64RightJamming( zSig0, -zExp, &zSig0 );
             zExp = 0;
             roundBits = zSig0 & roundMask;
-            if ( roundBits ) status->float_exception_flags |= float_flag_inexact;
+            if ( roundBits ) float_raise ( float_flag_inexact, status );
             zSig0 += roundIncrement;
             if ( roundNearestEven && ( roundBits == roundIncrement ) ) {
                 roundMask |= roundIncrement<<1;
@@ -1135,7 +1386,10 @@ floatx80 roundAndPackFloatx80Sgl( flag zSign, int32_t zExp, uint64_t zSig0, uint
             return packFloatx80( zSign, zExp, zSig0 );
         }
     }
-    if ( roundBits ) status->float_exception_flags |= float_flag_inexact;
+    if ( roundBits ) {
+        float_raise( float_flag_inexact, status );
+        saveFloatx80InternalSgl( zSign, zExp, zSig0, zSig1, status );
+    }
     zSig0 += roundIncrement;
     if ( zSig0 < roundIncrement ) {
         ++zExp;
@@ -2475,9 +2729,8 @@ floatx80 floatx80_rem( floatx80 a, floatx80 b, uint64_t *q, flag *s, float_statu
     bSig = extractFloatx80Frac( b );
     bExp = extractFloatx80Exp( b );
     bSign = extractFloatx80Sign( b );
-    *q = 0;
-    *s = 0;
-    if ( aExp == 0x7FFF ) {
+
+       if ( aExp == 0x7FFF ) {
         if (    (uint64_t) ( aSig0<<1 )
             || ( ( bExp == 0x7FFF ) && (uint64_t) ( bSig<<1 ) ) ) {
             return propagateFloatx80NaN( a, b, status );
@@ -2486,6 +2739,8 @@ floatx80 floatx80_rem( floatx80 a, floatx80 b, uint64_t *q, flag *s, float_statu
     }
     if ( bExp == 0x7FFF ) {
         if ( (uint64_t) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b, status );
+        *s = (aSign != bSign);
+        *q = 0;
         return a;
     }
     if ( bExp == 0 ) {
@@ -2500,7 +2755,11 @@ floatx80 floatx80_rem( floatx80 a, floatx80 b, uint64_t *q, flag *s, float_statu
     }
     if ( aExp == 0 ) {
 #ifdef SOFTFLOAT_68K
-        if ( aSig0 == 0 ) return a;
+        if ( aSig0 == 0 ) {
+            *s = (aSign != bSign);
+            *q = 0;
+            return a;
+        }
 #else
         if ( (uint64_t) ( aSig0<<1 ) == 0 ) return a;
 #endif
@@ -2585,9 +2844,8 @@ floatx80 floatx80_mod( floatx80 a, floatx80 b, uint64_t *q, flag *s, float_statu
     bSig = extractFloatx80Frac( b );
     bExp = extractFloatx80Exp( b );
     bSign = extractFloatx80Sign( b );
-    *q = 0;
-    *s = 0;
-    if ( aExp == 0x7FFF ) {
+
+       if ( aExp == 0x7FFF ) {
         if (    (uint64_t) ( aSig0<<1 )
             || ( ( bExp == 0x7FFF ) && (uint64_t) ( bSig<<1 ) ) ) {
             return propagateFloatx80NaN( a, b, status );
@@ -2596,6 +2854,8 @@ floatx80 floatx80_mod( floatx80 a, floatx80 b, uint64_t *q, flag *s, float_statu
     }
     if ( bExp == 0x7FFF ) {
         if ( (uint64_t) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b, status );
+        *s = (aSign != bSign);
+        *q = 0;
         return a;
     }
     if ( bExp == 0 ) {
@@ -2610,7 +2870,11 @@ floatx80 floatx80_mod( floatx80 a, floatx80 b, uint64_t *q, flag *s, float_statu
     }
     if ( aExp == 0 ) {
 #ifdef SOFTFLOAT_68K
-        if ( aSig0 == 0 ) return a;
+        if ( aSig0 == 0 ) {
+            *s = (aSign != bSign);
+            *q = 0;
+            return a;
+        }
 #else
         if ( (uint64_t) ( aSig0<<1 ) == 0 ) return a;
 #endif
@@ -2835,8 +3099,8 @@ floatx80 floatx80_scale(floatx80 a, floatx80 b, float_status *status)
     
     if ( bExp < 0x3FFF ) return a;
     
-    if ( 0x400E < bExp ) {
-        aExp = bSign ? -0x4000 : 0x7FFF;
+    if ( 0x400F < bExp ) {
+        aExp = bSign ? -0x6001 : 0xE000;
         return roundAndPackFloatx80(
                     status->floatx80_rounding_precision, aSign, aExp, aSig, 0, status );
     }
@@ -2985,7 +3249,7 @@ floatx80 floatx80_move( floatx80 a, float_status *status )
         if ( aSig == 0 ) return a;
         normalizeRoundAndPackFloatx80( status->floatx80_rounding_precision, aSign, aExp, aSig, 0, status );
     }
-    return a;
+    return roundAndPackFloatx80( status->floatx80_rounding_precision, aSign, aExp, aSig, 0, status );
 }
 
 #endif // End of addition for Previous
index 6fe6c44c0732de27018839bb605e510e633caee9..707f3d566a7897a39f872e57b83cf1b2d234465b 100644 (file)
@@ -207,16 +207,12 @@ enum {
  *----------------------------------------------------------------------------*/
 
 extern flag floatx80_internal_sign;
-extern uint32_t floatx80_internal_exp;
+extern int32_t floatx80_internal_exp;
+extern uint64_t floatx80_internal_sig;
+extern int32_t floatx80_internal_exp0;
 extern uint64_t floatx80_internal_sig0;
 extern uint64_t floatx80_internal_sig1;
 
-/*----------------------------------------------------------------------------
- | Function for storing sign, exponent and significand of extended 
- | double-precision floating-point intermediate result for external use.
- *----------------------------------------------------------------------------*/
-void saveFloatx80Internal( flag zSign, uint32_t zExp, uint64_t zSig0, uint64_t zSig1 );
-
 typedef struct float_status {
     signed char float_detect_tininess;
     signed char float_rounding_mode;
@@ -230,6 +226,12 @@ typedef struct float_status {
     flag snan_bit_is_one;
 } float_status;
 
+/*----------------------------------------------------------------------------
+ | Function for storing sign, exponent and significand of extended 
+ | double-precision floating-point intermediate result for external use.
+ *----------------------------------------------------------------------------*/
+void saveFloatx80Internal( flag zSign, int32_t zExp, uint64_t zSig0, uint64_t zSig1, float_status *status );
+
 static inline void set_float_detect_tininess(int val, float_status *status)
 {
     status->float_detect_tininess = val;