]> git.unchartedbackwaters.co.uk Git - francis/winuae.git/commitdiff
Packed decimal support.
authorToni Wilen <twilen@winuae.net>
Mon, 13 Mar 2017 17:44:53 +0000 (19:44 +0200)
committerToni Wilen <twilen@winuae.net>
Mon, 13 Mar 2017 17:44:53 +0000 (19:44 +0200)
fpp.cpp
fpp_softfloat.cpp
softfloat/softfloat.cpp
softfloat/softfloat.h
softfloat/softfloat_decimal.cpp [new file with mode: 0644]

diff --git a/fpp.cpp b/fpp.cpp
index 2daea2d5aef97271c45bd2531a3c651d6c5f6f5e..7e38ccfbeae5dc509dbc2e9eba5d1d22a0f35884 100644 (file)
--- a/fpp.cpp
+++ b/fpp.cpp
@@ -1183,6 +1183,17 @@ static void to_pack (fpdata *fpd, uae_u32 *wrd)
 
 #endif
 
+#if 1
+
+void from_pack_softfloat (fpdata *fp, uae_u32 *wrd, int kfactor);
+
+static void from_pack (fpdata *fpd, uae_u32 *wrd, int kfactor)
+{
+       from_pack_softfloat(fpd, wrd, kfactor);
+}
+
+#else
+
 static void from_pack (fpdata *src, uae_u32 *wrd, int kfactor)
 {
        int i, j, t;
@@ -1335,6 +1346,8 @@ static void from_pack (fpdata *src, uae_u32 *wrd, int kfactor)
        wrd[0] |= t << 16;
 }
 
+#endif
+
 // 68040/060 does not support denormals
 static bool normalize_or_fault_if_no_denormal_support(uae_u16 opcode, uae_u16 extra, uaecptr ea, uaecptr oldpc, fpdata *src)
 {
index a51c65bfe3e30703bca62bd1494f4950766176cd..c1cd413c9aed47c6a56c4a95fd483b74a4ab3fad 100644 (file)
@@ -88,6 +88,8 @@ static void fp_get_status(uae_u32 *status)
                *status |= FPSR_UNFL;
        if (fs.float_exception_flags & float_flag_inexact)
                *status |= FPSR_INEX2;
+       if (fs.float_exception_flags & float_flag_decimal)
+               *status |= FPSR_INEX1;
 }
 STATIC_INLINE void fp_clear_status(void)
 {
@@ -754,8 +756,6 @@ static void fp_normalize(fpdata *a)
        a->fpx = floatx80_normalize(a->fpx);
 }
 
-static float_status fsp;
-
 void to_pack_softfloat (fpdata *fp, uae_u32 *wrd)
 {
        uae_s32 exp = 0;
@@ -814,7 +814,8 @@ void to_pack_softfloat (fpdata *fp, uae_u32 *wrd)
                mant += (pack_frac >> (60 - i * 4)) & 0xF;
        }
 
-       
+#if 1
+
        if (pack_sm) {
                mant = -mant;
        }
@@ -874,20 +875,20 @@ void to_pack_softfloat (fpdata *fp, uae_u32 *wrd)
        
        while (exp) {
                if (exp & 1) {
-                       a = floatx80_mul(a, m, &fsp);
+                       a = floatx80_mul(a, m, &fs);
                }
-               m = floatx80_mul(m, m, &fsp);
+               m = floatx80_mul(m, m, &fs);
                exp >>= 1;
        }
 
        
        if (pack_se) {
-               z = floatx80_div(z, a, &fsp);
+               z = floatx80_div(z, a, &fs);
        } else {
-               z = floatx80_mul(z, a, &fsp);
+               z = floatx80_mul(z, a, &fs);
        }
 
-       
+#if 0  
        write_log(_T("z = %s\n"), fp_printx80(&z, 0));
        write_log(_T("m = %s\n"), fp_printx80(&m, 0));
        write_log(_T("a = %s\n"), fp_printx80(&a, 0));
@@ -895,15 +896,95 @@ void to_pack_softfloat (fpdata *fp, uae_u32 *wrd)
        
        write_log(_T("zerocount = %i\n"), zerocount);
        write_log(_T("multiplier = %llu\n"), multiplier);
+#endif
 
        fp->fpx = z;
+
+       /* TODO: set inex1 and restore rounding mode */
+       // if mul/div caused inex2 --> set inex1
+
+#else
+
+       floatx80 f;
+       f.high = exp & 0x3FFF;
+       f.high |= pack_se ? 0x4000 : 0;
+       f.high |= pack_sm ? 0x8000 : 0;
+       f.low = mant;
+       
+       fp->fpx = floatdecimal_to_floatx80(f, &fsp);
+
+#endif
+
        if (!currprefs.fpu_softfloat) {
                to_native(&fp->fp, fp);
        }
        
-       /* TODO: set inex1 and restore rounding mode */
-       // if mul/div caused inex2 --> set inex1
+}
 
+
+void from_pack_softfloat (fpdata *src, uae_u32 *wrd, int kfactor)
+{
+    floatx80 a;
+       fpdata fpd;
+
+       if (!currprefs.fpu_softfloat) {
+               from_native(src->fp, &fpd);
+       } else {
+               fpd.fpx = src->fpx;
+       }
+       a = fpd.fpx;
+   
+    floatx80 f = floatx80_to_floatdecimal(a, &kfactor, &fs);
+    
+    uae_u32 pack_exp = 0;   // packed exponent
+    uae_u32 pack_exp4 = 0;
+    uae_u32 pack_int = 0;   // packed integer part
+    uae_u64 pack_frac = 0;  // packed fraction
+    uae_u32 pack_se = 0;    // sign of packed exponent
+    uae_u32 pack_sm = 0;    // sign of packed significand
+    
+    uae_u32 exponent = f.high & 0x3FFF;
+    uae_u64 significand = f.low;
+
+    uae_s32 len = kfactor; // SoftFloat saved len to kfactor variable
+    
+    uae_u64 digit;
+    pack_frac = 0;
+    while (len > 0) {
+        len--;
+        digit = significand % 10;
+        significand /= 10;
+        if (len == 0) {
+            pack_int = digit;
+        } else {
+            pack_frac |= digit << (64 - len * 4);
+        }
+    }
+
+    digit = exponent / 1000;
+    exponent -= digit * 1000;
+    pack_exp4 = digit;
+    digit = exponent / 100;
+    exponent -= digit * 100;
+    pack_exp = digit << 8;
+    digit = exponent / 10;
+    exponent -= digit * 10;
+    pack_exp |= digit << 4;
+    pack_exp |= exponent;
+    
+    pack_se = f.high & 0x4000;
+    pack_sm = f.high & 0x8000;
+    
+    wrd[0] = pack_exp << 16;
+    wrd[0] |= pack_exp4 << 12;
+    wrd[0] |= pack_int;
+    wrd[0] |= pack_se ? 0x40000000 : 0;
+    wrd[0] |= pack_sm ? 0x80000000 : 0;
+    
+    wrd[1] = pack_frac >> 32;
+    wrd[2] = pack_frac & 0xffffffff;
+    
+    //printf("PACKED = %08x %08x %08x\n",wrd[0],wrd[1],wrd[2]);
 }
 
 void fp_init_softfloat(void)
@@ -911,8 +992,6 @@ void fp_init_softfloat(void)
        float_status fsx = { 0 };
        set_floatx80_rounding_precision(80, &fsx);
        set_float_rounding_mode(float_round_to_zero, &fsx);
-       set_floatx80_rounding_precision(80, &fsp);
-       set_float_rounding_mode(float_round_to_zero, &fsp);
 
        fpp_print = fp_print;
        fpp_is_snan = fp_is_snan;
index 90a3bbaa3ed5f426606b427496c2affd15f3318f..3c039e5fc8eab8e7780ae6c0cb5ec377343e665d 100644 (file)
@@ -3464,6 +3464,101 @@ floatx80 floatx80_move( floatx80 a, float_status *status )
 
 #endif // End of addition for Previous
 
+/*----------------------------------------------------------------------------
+| Returns 1 if the extended double-precision floating-point value `a' is
+| equal to the corresponding value `b', and 0 otherwise.  The comparison is
+| performed according to the IEC/IEEE Standard for Binary Floating-Point
+| Arithmetic.
+*----------------------------------------------------------------------------*/
+
+flag floatx80_eq( floatx80 a, floatx80 b, float_status *status )
+{
+       if (    (    ( extractFloatx80Exp( a ) == 0x7FFF )
+                               && (uint64_t) ( extractFloatx80Frac( a )<<1 ) )
+                       || (    ( extractFloatx80Exp( b ) == 0x7FFF )
+                               && (uint64_t) ( extractFloatx80Frac( b )<<1 ) )
+               ) {
+               if (    floatx80_is_signaling_nan( a )
+                               || floatx80_is_signaling_nan( b ) ) {
+                       float_raise( float_flag_invalid, status );
+               }
+               return 0;
+       }
+       return
+                       ( a.low == b.low )
+               && (    ( a.high == b.high )
+                               || (    ( a.low == 0 )
+                                       && ( (uint16_t) ( ( a.high | b.high )<<1 ) == 0 ) )
+                       );
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns 1 if the extended double-precision floating-point value `a' is
+| less than or equal to the corresponding value `b', and 0 otherwise.  The
+| comparison is performed according to the IEC/IEEE Standard for Binary
+| Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+flag floatx80_le( floatx80 a, floatx80 b, float_status *status )
+{
+       flag aSign, bSign;
+
+       if (    (    ( extractFloatx80Exp( a ) == 0x7FFF )
+                               && (uint64_t) ( extractFloatx80Frac( a )<<1 ) )
+                       || (    ( extractFloatx80Exp( b ) == 0x7FFF )
+                               && (uint64_t) ( extractFloatx80Frac( b )<<1 ) )
+               ) {
+               float_raise( float_flag_invalid, status );
+               return 0;
+       }
+       aSign = extractFloatx80Sign( a );
+       bSign = extractFloatx80Sign( b );
+       if ( aSign != bSign ) {
+               return
+                               aSign
+                       || (    ( ( (uint16_t) ( ( a.high | b.high )<<1 ) ) | a.low | b.low )
+                                       == 0 );
+       }
+       return
+                       aSign ? le128( b.high, b.low, a.high, a.low )
+               : le128( a.high, a.low, b.high, b.low );
+}
+
+/*----------------------------------------------------------------------------
+| Returns 1 if the extended double-precision floating-point value `a' is
+| less than the corresponding value `b', and 0 otherwise.  The comparison
+| is performed according to the IEC/IEEE Standard for Binary Floating-Point
+| Arithmetic.
+*----------------------------------------------------------------------------*/
+
+flag floatx80_lt( floatx80 a, floatx80 b, float_status *status )
+{
+       flag aSign, bSign;
+
+       if (    (    ( extractFloatx80Exp( a ) == 0x7FFF )
+                               && (uint64_t) ( extractFloatx80Frac( a )<<1 ) )
+                       || (    ( extractFloatx80Exp( b ) == 0x7FFF )
+                               && (uint64_t) ( extractFloatx80Frac( b )<<1 ) )
+               ) {
+               float_raise( float_flag_invalid, status );
+               return 0;
+       }
+       aSign = extractFloatx80Sign( a );
+       bSign = extractFloatx80Sign( b );
+       if ( aSign != bSign ) {
+               return
+                               aSign
+                       && (    ( ( (uint16_t) ( ( a.high | b.high )<<1 ) ) | a.low | b.low )
+                                       != 0 );
+       }
+       return
+                       aSign ? lt128( b.high, b.low, a.high, a.low )
+               : lt128( a.high, a.low, b.high, b.low );
+
+}
+
+
 /*----------------------------------------------------------------------------
 | Returns the result of converting the 64-bit two's complement integer `a'
 | to the extended double-precision floating-point format.  The conversion
index 17bc9377e27f02445589adeca1d1fad55e503b52..5ae05c60961e8a7dd35cf3065b839f5e8e09d8af 100644 (file)
@@ -188,15 +188,14 @@ enum {
 | Software IEC/IEEE floating-point exception flags.
 *----------------------------------------------------------------------------*/
 enum {
-    float_flag_invalid   =  1,
-       float_flag_denormal = 2,
-    float_flag_divbyzero =  4,
-    float_flag_overflow  =  8,
-    float_flag_underflow = 16,
-    float_flag_inexact   = 32,
-       float_flag_signaling = 64
-//    float_flag_input_denormal = 64,
-//    float_flag_output_denormal = 128
+    float_flag_invalid   = 0x01,
+       float_flag_denormal  = 0x02,
+    float_flag_divbyzero = 0x04,
+    float_flag_overflow  = 0x08,
+    float_flag_underflow = 0x10,
+    float_flag_inexact   = 0x20,
+       float_flag_signaling = 0x40,
+       float_flag_decimal =   0x80
 };
 
 /*----------------------------------------------------------------------------
@@ -383,11 +382,12 @@ int8_t floatx80_to_int8(floatx80, float_status *status);
 #endif
 int32_t floatx80_to_int32_round_to_zero(floatx80, float_status *status);
 int64_t floatx80_to_int64(floatx80, float_status *status);
-int64_t floatx80_to_int64_round_to_zero(floatx80, float_status *status);
 float32 floatx80_to_float32(floatx80, float_status *status);
 float64 floatx80_to_float64(floatx80, float_status *status);
 #ifdef SOFTFLOAT_68K
 floatx80 floatx80_to_floatx80( floatx80, float_status *status);
+floatx80 floatdecimal_to_floatx80(floatx80, float_status *status);
+floatx80 floatx80_to_floatdecimal(floatx80, int32_t*, float_status *status);
 #endif
 
 uint64_t extractFloatx80Frac( floatx80 a );
@@ -400,6 +400,10 @@ floatx80 floatx80_round_to_float64( floatx80, float_status *status );
 floatx80 floatx80_round32( floatx80, float_status *status);
 floatx80 floatx80_round64( floatx80, float_status *status);
 
+flag floatx80_eq( floatx80, floatx80, float_status *status);
+flag floatx80_le( floatx80, floatx80, float_status *status);
+flag floatx80_lt( floatx80, floatx80, float_status *status);
+
 #ifdef SOFTFLOAT_68K
 flag floatx80_is_zero( floatx80 );
 flag floatx80_is_infinity( floatx80 );
diff --git a/softfloat/softfloat_decimal.cpp b/softfloat/softfloat_decimal.cpp
new file mode 100644 (file)
index 0000000..0de1f95
--- /dev/null
@@ -0,0 +1,429 @@
+/*============================================================================
+
+This C source file is an extension to the SoftFloat IEC/IEEE Floating-point 
+Arithmetic Package, Release 2a.
+
+=============================================================================*/
+
+#include <stdint.h>
+
+#include "softfloat.h"
+#include "softfloat-macros.h"
+#include "softfloat/softfloat-specialize.h"
+
+/*----------------------------------------------------------------------------
+| Methods for converting decimal floats to binary extended precision floats.
+*----------------------------------------------------------------------------*/
+
+void mul128by128(int32_t *aExp, uint64_t *aSig0, uint64_t *aSig1, int32_t bExp, uint64_t bSig0, uint64_t bSig1)
+{
+    int32_t zExp;
+    uint64_t zSig0, zSig1, zSig2, zSig3;
+    
+    zExp = *aExp;
+    zSig0 = *aSig0;
+    zSig1 = *aSig1;
+
+    zExp += bExp - 0x3FFE;
+    mul128To256(zSig0, zSig1, bSig0, bSig1, &zSig0, &zSig1, &zSig2, &zSig3);
+    zSig1 |= (zSig2 | zSig3) != 0;
+    if ( 0 < (int64_t) zSig0 ) {
+        shortShift128Left( zSig0, zSig1, 1, &zSig0, &zSig1 );
+        --zExp;
+    }
+    *aExp = zExp;
+    *aSig0 = zSig0;
+    *aSig1 = zSig1;
+}
+
+void div128by128(int32_t *aExp, uint64_t *aSig0, uint64_t *aSig1, int32_t bExp, uint64_t bSig0, uint64_t bSig1)
+{
+    int32_t zExp;
+    uint64_t zSig0, zSig1;
+    uint64_t rem0, rem1, rem2, rem3, term0, term1, term2, term3;
+    
+    zExp = *aExp;
+    zSig0 = *aSig0;
+    zSig1 = *aSig1;
+    
+    zExp -= bExp - 0x3FFE;
+    rem1 = 0;
+    if ( le128( bSig0, bSig1, zSig0, zSig1 ) ) {
+        shift128Right( zSig0, zSig1, 1, &zSig0, &zSig1 );
+        ++zExp;
+    }
+    zSig0 = estimateDiv128To64( zSig0, zSig1, bSig0 );
+    mul128By64To192( bSig0, bSig1, zSig0, &term0, &term1, &term2 );
+    sub192( zSig0, zSig1, 0, term0, term1, term2, &rem0, &rem1, &rem2 );
+    while ( (int64_t) rem0 < 0 ) {
+        --zSig0;
+        add192( rem0, rem1, rem2, 0, bSig0, bSig1, &rem0, &rem1, &rem2 );
+    }
+    zSig1 = estimateDiv128To64( rem1, rem2, bSig0 );
+    if ( ( zSig1 & 0x3FFF ) <= 4 ) {
+        mul128By64To192( bSig0, bSig1, zSig1, &term1, &term2, &term3 );
+        sub192( rem1, rem2, 0, term1, term2, term3, &rem1, &rem2, &rem3 );
+        while ( (int64_t) rem1 < 0 ) {
+            --zSig1;
+            add192( rem1, rem2, rem3, 0, bSig0, bSig1, &rem1, &rem2, &rem3 );
+        }
+        zSig1 |= ( ( rem1 | rem2 | rem3 ) != 0 );
+    }
+
+    *aExp = zExp;
+    *aSig0 = zSig0;
+    *aSig1 = zSig1;
+}
+
+/*----------------------------------------------------------------------------
+| Decimal to binary
+*----------------------------------------------------------------------------*/
+
+floatx80 floatdecimal_to_floatx80(floatx80 a, float_status *status)
+{
+    flag decSign, zSign, decExpSign, increment;
+    int32_t decExp, zExp, mExp, xExp, shiftCount;
+    uint64_t decSig, zSig0, zSig1, mSig0, mSig1, xSig0, xSig1;
+    
+    decSign = extractFloatx80Sign(a);
+    decExp = extractFloatx80Exp(a);
+    decSig = extractFloatx80Frac(a);
+    
+    if (decExp == 0x7FFF) return a;
+    
+    if (decExp == 0 && decSig == 0) return a;
+    
+    decExpSign = (decExp >> 14) & 1;
+    decExp &= 0x3FFF;
+    
+    shiftCount = countLeadingZeros64( decSig );
+    zExp = 0x403E - shiftCount;
+    zSig0 = decSig << shiftCount;
+    zSig1 = 0;
+    zSign = decSign;
+    
+    mExp = 0x4002;
+    mSig0 = LIT64(0xA000000000000000);
+       mSig1 = 0;
+    xExp = 0x3FFF;
+    xSig0 = LIT64(0x8000000000000000);
+    
+    while (decExp) {
+        if (decExp & 1) {
+            mul128by128(&xExp, &xSig0, &xSig1, mExp, mSig0, mSig1);
+        }
+        mul128by128(&mExp, &mSig0, &mSig1, mExp, mSig0, mSig1);
+        decExp >>= 1;
+    }
+    
+    if (decExpSign) {
+        div128by128(&zExp, &zSig0, &zSig1, xExp, xSig0, xSig1);
+    } else {
+        mul128by128(&zExp, &zSig0, &zSig1, xExp, xSig0, xSig1);
+    }
+    
+    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 (zSig1) float_raise(float_flag_decimal, status);
+    
+    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 );
+    
+}
+
+/*----------------------------------------------------------------------------
+ | Binary to decimal
+ *----------------------------------------------------------------------------*/
+
+floatx80 floatx80_to_floatdecimal(floatx80 a, int32_t *k, float_status *status)
+{
+    flag aSign;
+    int32_t aExp;
+    uint64_t aSig;
+    
+    flag decSign;
+    int32_t decExp, zExp, mExp, xExp;
+    uint64_t decSig, zSig0, zSig1, mSig0, mSig1, xSig0, xSig1;
+    
+    aSign = extractFloatx80Sign(a);
+    aExp = extractFloatx80Exp(a);
+    aSig = extractFloatx80Frac(a);
+    
+    if (aExp == 0x7FFF) {
+        if ((uint64_t) (aSig<<1)) return propagateFloatx80NaNOneArg(a, status);
+        return a;
+    }
+    
+    if (aExp == 0) {
+        if (aSig == 0) return packFloatx80(aSign, 0, 0);
+        normalizeFloatx80Subnormal(aSig, &aExp, &aSig);
+    }
+
+    int32_t kfactor = *k;
+    
+    int32_t ilog, len;
+    
+    flag bSign;
+    
+
+    
+    floatx80 b;
+    floatx80 c;
+    floatx80 one = int32_to_floatx80(1);
+    floatx80 log2 = packFloatx80(0, 0x3FFD, LIT64(0x9A209A84FBCFF798));
+    floatx80 log2up1 = packFloatx80(0, 0x3FFD, LIT64(0x9A209A84FBCFF799));
+    
+    
+    if (aExp < 0) {
+        ilog = -4933;
+    } else {
+        b = packFloatx80(0, 0x3FFF, aSig);
+        c = int32_to_floatx80(aExp - 0x3FFF);
+        b = floatx80_add(b, c, status);
+        b = floatx80_sub(b, one, status);
+        bSign = extractFloatx80Sign(b);
+        if (bSign) {
+            b = floatx80_mul(b, log2up1, status);
+        } else {
+            b = floatx80_mul(b, log2, status);
+        }
+        ilog = floatx80_to_int32(b, status);
+    }
+    
+    bool ictr = false;
+    
+try_again:
+    //printf("ILOG = %i\n",ilog);
+    
+    if (kfactor > 0) {
+        if (kfactor > 17) {
+            kfactor = 17;
+            float_raise(float_flag_invalid, status);
+        }
+        len = kfactor;
+    } else {
+        len = ilog + 1 - kfactor;
+        if (len > 17) {
+            len = 17;
+        }
+        if (len < 1) {
+            len = 1;
+        }
+    }
+    
+    //printf("LEN = %i\n",len);
+    
+    if (kfactor <= 0 && kfactor > ilog) {
+        ilog = kfactor;
+        //printf("ILOG is kfactor = %i\n",ilog);
+    }
+    
+    flag lambda = 0;
+    int iscale = ilog + 1 - len;
+    
+    if (iscale < 0) {
+        lambda = 1;
+#if 0
+        if (iscale <= -4908) { // do we need this?
+            iscale += 24;
+            temp_for_a9 = 24;
+        }
+#endif
+        iscale = -iscale;
+    }
+    
+    //printf("ISCALE = %i, LAMDA = %i\n",iscale,lambda);
+    
+    mExp = 0x4002;
+    mSig0 = LIT64(0xA000000000000000);
+    mSig1 = 0;
+    xExp = 0x3FFF;
+    xSig0 = LIT64(0x8000000000000000);
+    xSig1 = 0;
+    
+    while (iscale) {
+        if (iscale & 1) {
+            mul128by128(&xExp, &xSig0, &xSig1, mExp, mSig0, mSig1);
+        }
+        mul128by128(&mExp, &mSig0, &mSig1, mExp, mSig0, mSig1);
+        iscale >>= 1;
+    }
+    
+    zExp = aExp;
+    zSig0 = aSig;
+    zSig1 = 0;
+    
+    if (lambda) {
+        mul128by128(&zExp, &zSig0, &zSig1, xExp, xSig0, xSig1);
+    } else {
+        div128by128(&zExp, &zSig0, &zSig1, xExp, xSig0, xSig1);
+    }
+    if (zSig1) zSig0 |= 1;
+    
+    floatx80 z = packFloatx80(aSign, zExp, zSig0);
+    z = floatx80_round_to_int(z, status);
+    zSig0 = extractFloatx80Frac(z);
+    zExp = extractFloatx80Exp(z);
+    zSig1 = 0;
+    
+    if (ictr == false) {
+        int lentemp = len - 1;
+        
+        mExp = 0x4002;
+        mSig0 = LIT64(0xA000000000000000);
+        mSig1 = 0;
+        xExp = 0x3FFF;
+        xSig0 = LIT64(0x8000000000000000);
+        xSig1 = 0;
+        
+        while (lentemp) {
+            if (lentemp & 1) {
+                mul128by128(&xExp, &xSig0, &xSig1, mExp, mSig0, mSig1);
+            }
+            mul128by128(&mExp, &mSig0, &mSig1, mExp, mSig0, mSig1);
+            lentemp >>= 1;
+        }
+        
+        zSig0 = extractFloatx80Frac(z);
+        zExp = extractFloatx80Exp(z);
+        
+        if (zExp < xExp || ((zExp == xExp) && lt128(zSig0, 0, xSig0, xSig1))) { // z < x
+            ilog -= 1;
+            ictr = true;
+            mul128by128(&xExp, &xSig0, &xSig1, 0x4002, LIT64(0xA000000000000000), 0);
+            goto try_again;
+        }
+        
+        mul128by128(&xExp, &xSig0, &xSig1, 0x4002, LIT64(0xA000000000000000), 0);
+        
+        if (zExp > xExp || ((zExp == xExp) && lt128(xSig0, xSig1, zSig0, 0))) { // z > x
+            ilog += 1;
+            ictr = true;
+            goto try_again;
+        }
+    } else {
+        int lentemp = len;
+
+        mExp = 0x4002;
+        mSig0 = LIT64(0xA000000000000000);
+        mSig1 = 0;
+        xExp = 0x3FFF;
+        xSig0 = LIT64(0x8000000000000000);
+        xSig1 = 0;
+        
+        while (lentemp) {
+            if (lentemp & 1) {
+                mul128by128(&xExp, &xSig0, &xSig1, mExp, mSig0, mSig1);
+            }
+            mul128by128(&mExp, &mSig0, &mSig1, mExp, mSig0, mSig1);
+            lentemp >>= 1;
+        }
+
+        if (eq128(zSig0, 0, xSig0, xSig1)) {
+            div128by128(&zExp, &zSig0, &zSig1, 0x4002, LIT64(0xA000000000000000), 0);
+            ilog += 1;
+            len += 1;
+            mul128by128(&xExp, &xSig0, &xSig1, 0x4002, LIT64(0xA000000000000000), 0);
+        }
+    }
+    
+    if (zSig1) zSig0 |= 1;
+    
+    z = packFloatx80(0, zExp, zSig0);
+    
+    decSign = aSign;
+    decSig = floatx80_to_int64(z, status);
+    decExp = (ilog < 0) ? -ilog : ilog;
+    if (decExp > 999) {
+        float_raise(float_flag_invalid, status);
+    }
+    if (ilog < 0) decExp |= 0x4000;
+    
+    *k = len;
+    
+    return packFloatx80(decSign, decExp, decSig);
+#if 0
+    printf("abs(Yint) = %s\n",fp_print(&zint));
+    
+    uae_u64 significand = floatx80_to_int64(zint);
+    
+    printf("Mantissa = %lli\n",significand);
+    
+    printf("Exponent = %i\n",ilog);
+    
+    uae_s32 exp = ilog;
+    
+    uae_u32 pack_exp = 0;   // packed exponent
+    uae_u32 pack_exp4 = 0;
+    uae_u32 pack_int = 0;   // packed integer part
+    uae_u64 pack_frac = 0;  // packed fraction
+    uae_u32 pack_se = 0;    // sign of packed exponent
+    uae_u32 pack_sm = 0;    // sign of packed significand
+    
+    if (exp < 0) {
+        exp = -exp;
+        pack_se = 1;
+    }
+    
+    uae_u64 digit;
+    pack_frac = 0;
+    while (len > 0) {
+        len--;
+        digit = significand % 10;
+        significand /= 10;
+        if (len == 0) {
+            pack_int = digit;
+        } else {
+            pack_frac |= digit << (64 - len * 4);
+        }
+    }
+    printf("PACKED FRACTION = %02x.%16llx\n",pack_int, pack_frac);
+    
+    if (exp > 999) {
+        digit = exp / 1000;
+        exp -= digit * 1000;
+        pack_exp4 = digit;
+        // OPERR
+    }
+    digit = exp / 100;
+    exp -= digit * 100;
+    pack_exp = digit << 8;
+    digit = exp / 10;
+    exp -= digit * 10;
+    pack_exp |= digit << 4;
+    pack_exp |= exp;
+    
+    pack_sm = aSign;
+    
+    wrd[0] = pack_exp << 16;
+    wrd[0] |= pack_exp4 << 12;
+    wrd[0] |= pack_int;
+    wrd[0] |= pack_se ? 0x40000000 : 0;
+    wrd[0] |= pack_sm ? 0x80000000 : 0;
+    
+    wrd[1] = pack_frac >> 32;
+    wrd[2] = pack_frac & 0xffffffff;
+    
+    printf("PACKED = %08x %08x %08x\n",wrd[0],wrd[1],wrd[2]);
+#endif
+}