]> git.unchartedbackwaters.co.uk Git - francis/winuae.git/commitdiff
FPU packed decimal updates, should be 100% accurate now.
authorToni Wilen <twilen@winuae.net>
Sun, 19 Mar 2017 17:06:38 +0000 (19:06 +0200)
committerToni Wilen <twilen@winuae.net>
Sun, 19 Mar 2017 17:06:38 +0000 (19:06 +0200)
fpp.cpp
softfloat/SOFTFLOAT-MACROS.H
softfloat/softfloat_decimal.cpp

diff --git a/fpp.cpp b/fpp.cpp
index 8444eedbae7e4a71f9627b573d1dd93356a22073..afe15f78b75191c82b0cc0885f59ceb0d4936b57 100644 (file)
--- a/fpp.cpp
+++ b/fpp.cpp
@@ -10,6 +10,8 @@
 
 #define __USE_ISOC9X  /* We might be able to pick up a NaN */
 
+#define FPU_TEST 0
+
 #include <math.h>
 #include <float.h>
 #include <fenv.h>
@@ -2918,6 +2920,22 @@ void fpu_modechange(void)
        }
 }
 
+#if FPU_TEST
+
+static void fpu_test(void)
+{
+       fpdata testp;
+       uae_u32 packed[3];
+
+       fpp_set_fpcr(0x30);
+       fpp_to_exten_fmovem(&testp, 0xB4000000, 0x80000000, 0x000003fc);
+    write_log(_T("INPUT: %s (%04x %16llx)\n"), fpp_print(&testp, -1), testp.fpx.high, testp.fpx.low);
+    fpp_from_pack(&testp, packed, 17);
+    fpp_to_pack(&testp, packed, 0);
+}
+
+#endif
+
 void fpu_reset (void)
 {
        if (currprefs.fpu_softfloat) {
@@ -2938,6 +2956,11 @@ void fpu_reset (void)
        // reset precision
        fpp_set_mode(0x00000080 | 0x00000010);
        fpp_set_mode(0x00000000);
+
+#if FPU_TEST
+       fpu_test();
+#endif
+
 }
 
 uae_u8 *restore_fpu (uae_u8 *src)
@@ -3035,6 +3058,4 @@ uae_u8 *save_fpu (int *len, uae_u8 *dstptr)
        return dstbak;
 }
 
-#ifdef _MSC_VER
-#pragma fenv_access(off)
-#endif
+
index a84956e614c7b0f33e5be93912325f29e1b78a88..55937eb89f8b95b0426eb969c20f756389d7e789 100644 (file)
@@ -484,7 +484,7 @@ static inline void
  )
 {
     uint64_t z0, z1, z2;
-    int8_t borrow0, borrow1;
+    uint8_t borrow0, borrow1;
 
     z2 = a2 - b2;
     borrow1 = ( a2 < b2 );
index 9e1d3977261d410050c6bcf0af804699f8bdfd44..86956d0386c0f817efd1da44fc846f11673140c7 100644 (file)
@@ -55,7 +55,7 @@ void round128to64(flag aSign, int32_t *aExp, uint64_t *aSig0, uint64_t *aSig1, f
                        ++zExp;
                        zSig0 = LIT64(0x8000000000000000);
                } else {
-                       zSig0 &= ~ (((int64_t) (zSig1<<1) == 0) & (status->float_rounding_mode == float_round_nearest_even));
+                       zSig0 &= ~ (((uint64_t) (zSig1<<1) == 0) & (status->float_rounding_mode == float_round_nearest_even));
                }
        } else {
                if ( zSig0 == 0 ) zExp = 0;
@@ -66,7 +66,7 @@ void round128to64(flag aSign, int32_t *aExp, uint64_t *aSig0, uint64_t *aSig1, f
        *aSig1 = 0;
 }
 
-void mul128by128round(flag aSign, int32_t *aExp, uint64_t *aSig0, uint64_t *aSig1, int32_t bExp, uint64_t bSig0, uint64_t bSig1, float_status *status)
+void mul128by128round(int32_t *aExp, uint64_t *aSig0, uint64_t *aSig1, int32_t bExp, uint64_t bSig0, uint64_t bSig1, float_status *status)
 {
        int32_t zExp;
        uint64_t zSig0, zSig1, zSig2, zSig3;
@@ -75,7 +75,7 @@ void mul128by128round(flag aSign, int32_t *aExp, uint64_t *aSig0, uint64_t *aSig
        zSig0 = *aSig0;
        zSig1 = *aSig1;
        
-       round128to64(aSign, &bExp, &bSig0, &bSig1, status);
+       round128to64(0, &bExp, &bSig0, &bSig1, status);
        
        zExp += bExp - 0x3FFE;
        mul128To256(zSig0, zSig1, bSig0, bSig1, &zSig0, &zSig1, &zSig2, &zSig3);
@@ -88,7 +88,7 @@ void mul128by128round(flag aSign, int32_t *aExp, uint64_t *aSig0, uint64_t *aSig
        *aSig0 = zSig0;
        *aSig1 = zSig1;
        
-       round128to64(aSign, aExp, aSig0, aSig1, status);
+       round128to64(0, aExp, aSig0, aSig1, status);
 }
 
 void mul128by128(int32_t *aExp, uint64_t *aSig0, uint64_t *aSig1, int32_t bExp, uint64_t bSig0, uint64_t bSig1)
@@ -150,11 +150,65 @@ void div128by128(int32_t *paExp, uint64_t *paSig0, uint64_t *paSig1, int32_t bEx
        *paSig1 = zSig1;
 }
 
-void tentoint128(flag aSign, int32_t *aExp, uint64_t *aSig0, uint64_t *aSig1, int32_t scale, float_status *status)
+#if 0
+
+void tentoint128(flag mSign, flag eSign, int32_t *aExp, uint64_t *aSig0, uint64_t *aSig1, int32_t scale, float_status *status)
 {
-       int32_t mExp;
-       uint64_t mSig0, mSig1;
-       
+    int32_t mExp;
+    uint64_t mSig0, mSig1;
+
+    
+    *aExp = 0x3FFF;
+    *aSig0 = LIT64(0x8000000000000000);
+    *aSig1 = 0;
+
+    mExp = 0x4002;
+    mSig0 = LIT64(0xA000000000000000);
+    mSig1 = 0;
+
+    
+    while (scale) {
+        if (scale & 1) {
+            mul128by128round(aExp, aSig0, aSig1, mExp, mSig0, mSig1, status);
+        }
+        mul128by128(&mExp, &mSig0, &mSig1, mExp, mSig0, mSig1);
+        scale >>= 1;
+    }
+}
+
+#else
+
+void tentoint128(flag mSign, flag eSign, int32_t *aExp, uint64_t *aSig0, uint64_t *aSig1, int32_t scale, float_status *status)
+ {
+    int8_t save_rounding_mode;
+    int32_t mExp;
+    uint64_t mSig0, mSig1;
+     
+    save_rounding_mode = status->float_rounding_mode;
+    switch (status->float_rounding_mode) {
+        case float_round_nearest_even:
+            break;
+        case float_round_down:
+            if (mSign != eSign) {
+                set_float_rounding_mode(float_round_up, status);
+            }
+            break;
+        case float_round_up:
+            if (mSign != eSign) {
+                set_float_rounding_mode(float_round_down, status);
+            }
+            break;
+        case float_round_to_zero:
+            if (eSign == 0) {
+                set_float_rounding_mode(float_round_down, status);
+            } else {
+                set_float_rounding_mode(float_round_up, status);
+            }
+            break;
+        default:
+            break;
+    }  
+
        *aExp = 0x3FFF;
        *aSig0 = LIT64(0x8000000000000000);
        *aSig1 = 0;
@@ -165,13 +219,17 @@ void tentoint128(flag aSign, int32_t *aExp, uint64_t *aSig0, uint64_t *aSig1, in
        
        while (scale) {
                if (scale & 1) {
-                       mul128by128round(aSign, aExp, aSig0, aSig1, mExp, mSig0, mSig1, status);
+                       mul128by128round(aExp, aSig0, aSig1, mExp, mSig0, mSig1, status);
                }
                mul128by128(&mExp, &mSig0, &mSig1, mExp, mSig0, mSig1);
                scale >>= 1;
        }
+
+       set_float_rounding_mode(save_rounding_mode, status);
 }
 
+#endif
+
 int64_t tentointdec(int32_t scale)
 {
        uint64_t decM, decX;
@@ -299,7 +357,7 @@ floatx80 floatdecimal_to_floatx80(floatx80 a, float_status *status)
        zSig1 = 0;
        zSign = decSign;
        
-       tentoint128(zSign, &xExp, &xSig0, &xSig1, decExp, status);
+       tentoint128(decSign, decExpSign, &xExp, &xSig0, &xSig1, decExp, status);
 
        if (decExpSign) {
                div128by128(&zExp, &zSig0, &zSig1, xExp, xSig0, xSig1);
@@ -403,7 +461,9 @@ try_again:
        
        decimal_log(_T("ISCALE = %i, LAMBDA = %i\n"),iscale, lambda);
        
-       tentoint128(0, &xExp, &xSig0, &xSig1, iscale, status);
+       tentoint128(lambda, 0, &xExp, &xSig0, &xSig1, iscale, status);
+
+       decimal_log(_T("AFTER tentoint128: zExp = %04x, zSig0 = %16llx, zSig1 = %16llx\n"), xExp, xSig0, xSig1);
 
        zExp = aExp;
        zSig0 = aSig;