qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH 0/4] target/m68k: implement 680x0 FPU (part 3)
@ 2017-07-03 16:23 Laurent Vivier
  2017-07-03 16:23 ` [Qemu-devel] [PATCH 1/4] softfloat: use floatx80_infinity in softfloat Laurent Vivier
                   ` (3 more replies)
  0 siblings, 4 replies; 13+ messages in thread
From: Laurent Vivier @ 2017-07-03 16:23 UTC (permalink / raw)
  To: qemu-devel; +Cc: Aurelien Jarno, Richard Henderson, Laurent Vivier

We start by defining the floatx80 value of infinity on m68k, as
it differs from the standard one (0x0000000000000000 instead of
0x8000000000000000). This patch superseds the patch I have
already sent that defines a "floatx80_default_inf" whereas
we have already a "floatx80_infinity": we should use
it instead.

Then we define the trigonometric function using the libm
functions. To do that, we need to introduce functions
to convert to and from floatx80 and "long double".
We use ldexpl()/frexpl() to extract exponent and
mantissa from the "long double" value. The function
to convert is also used in m68k_cpu_dump_state() to
display the value of FPU registers.

In the same way, we define fmod/frem using libm
fmodl() and remainderl().

And finally, we define fgetexp/fgetman/fscale.
For these three functions, I've tried to compare
the result with a real 68040 as most as possible.

Laurent Vivier (4):
  softfloat: use floatx80_infinity in softfloat
  target/m68k: add FPU trigonometric instructions
  target/m68k: add fmod/frem
  target-m68k: add fscale, fgetman and fgetexp

 fpu/softfloat-specialize.h |  14 ++
 fpu/softfloat.c            |  38 +++--
 include/fpu/softfloat.h    |   9 +-
 target/m68k/cpu.h          |   2 +
 target/m68k/fpu_helper.c   | 369 +++++++++++++++++++++++++++++++++++++++++++++
 target/m68k/helper.h       |  22 +++
 target/m68k/translate.c    |  88 +++++++++--
 7 files changed, 513 insertions(+), 29 deletions(-)

-- 
2.9.4

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [Qemu-devel] [PATCH 1/4] softfloat: use floatx80_infinity in softfloat
  2017-07-03 16:23 [Qemu-devel] [PATCH 0/4] target/m68k: implement 680x0 FPU (part 3) Laurent Vivier
@ 2017-07-03 16:23 ` Laurent Vivier
  2017-07-03 18:06   ` Richard Henderson
  2017-07-03 16:23 ` [Qemu-devel] [PATCH 2/4] target/m68k: add FPU trigonometric instructions Laurent Vivier
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 13+ messages in thread
From: Laurent Vivier @ 2017-07-03 16:23 UTC (permalink / raw)
  To: qemu-devel; +Cc: Aurelien Jarno, Richard Henderson, Laurent Vivier

Since f3218a8 ("softfloat: add floatx80 constants")
floatx80_infinity is defined but never used.

This patch updates floatx80 functions to use
this definition.

This allows to define a different default Infinity
value on m68k: the m68k FPU defines infinity with
all bits set to zero in the mantissa.

Signed-off-by: Laurent Vivier <laurent@vivier.eu>
---
 fpu/softfloat-specialize.h | 14 ++++++++++++++
 fpu/softfloat.c            | 38 ++++++++++++++++++++++++++------------
 include/fpu/softfloat.h    |  9 +++++++--
 3 files changed, 47 insertions(+), 14 deletions(-)

diff --git a/fpu/softfloat-specialize.h b/fpu/softfloat-specialize.h
index de2c5d5..1cb3502 100644
--- a/fpu/softfloat-specialize.h
+++ b/fpu/softfloat-specialize.h
@@ -178,6 +178,20 @@ floatx80 floatx80_default_nan(float_status *status)
 }
 
 /*----------------------------------------------------------------------------
+| The pattern for a default generated extended double-precision inf.
+*----------------------------------------------------------------------------*/
+
+#define floatx80_infinity_high 0x7FFF
+#if defined(TARGET_M68K)
+#define floatx80_infinity_low  LIT64(0x0000000000000000)
+#else
+#define floatx80_infinity_low  LIT64(0x8000000000000000)
+#endif
+
+const floatx80 floatx80_infinity
+    = make_floatx80_init(floatx80_infinity_high, floatx80_infinity_low);
+
+/*----------------------------------------------------------------------------
 | The pattern for a default generated quadruple-precision NaN.
 *----------------------------------------------------------------------------*/
 float128 float128_default_nan(float_status *status)
diff --git a/fpu/softfloat.c b/fpu/softfloat.c
index 433c5da..2355403 100644
--- a/fpu/softfloat.c
+++ b/fpu/softfloat.c
@@ -913,7 +913,9 @@ static floatx80 roundAndPackFloatx80(int8_t roundingPrecision, flag zSign,
                ) {
                 return packFloatx80( zSign, 0x7FFE, ~ roundMask );
             }
-            return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) );
+            return packFloatx80(zSign,
+                                floatx80_infinity_high,
+                                floatx80_infinity_low);
         }
         if ( zExp <= 0 ) {
             isTiny =
@@ -1885,7 +1887,9 @@ floatx80 float32_to_floatx80(float32 a, float_status *status)
         if (aSig) {
             return commonNaNToFloatx80(float32ToCommonNaN(a, status), status);
         }
-        return packFloatx80( aSign, 0x7FFF, LIT64( 0x8000000000000000 ) );
+        return packFloatx80(aSign,
+                            floatx80_infinity_high,
+                            floatx80_infinity_low);
     }
     if ( aExp == 0 ) {
         if ( aSig == 0 ) return packFloatx80( aSign, 0, 0 );
@@ -3666,7 +3670,9 @@ floatx80 float64_to_floatx80(float64 a, float_status *status)
         if (aSig) {
             return commonNaNToFloatx80(float64ToCommonNaN(a, status), status);
         }
-        return packFloatx80( aSign, 0x7FFF, LIT64( 0x8000000000000000 ) );
+        return packFloatx80(aSign,
+                            floatx80_infinity_high,
+                            floatx80_infinity_low);
     }
     if ( aExp == 0 ) {
         if ( aSig == 0 ) return packFloatx80( aSign, 0, 0 );
@@ -4927,8 +4933,8 @@ int64_t floatx80_to_int64(floatx80 a, float_status *status)
         if ( shiftCount ) {
             float_raise(float_flag_invalid, status);
             if (    ! aSign
-                 || (    ( aExp == 0x7FFF )
-                      && ( aSig != LIT64( 0x8000000000000000 ) ) )
+                 || ((aExp == floatx80_infinity_high)
+                     && (aSig != floatx80_infinity_low))
                ) {
                 return LIT64( 0x7FFFFFFFFFFFFFFF );
             }
@@ -5235,7 +5241,9 @@ static floatx80 addFloatx80Sigs(floatx80 a, floatx80 b, flag zSign,
             if ((uint64_t)(bSig << 1)) {
                 return propagateFloatx80NaN(a, b, status);
             }
-            return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) );
+            return packFloatx80(zSign,
+                                floatx80_infinity_high,
+                                floatx80_infinity_low);
         }
         if ( aExp == 0 ) ++expDiff;
         shift64ExtraRightJamming( aSig, 0, - expDiff, &aSig, &zSig1 );
@@ -5310,7 +5318,8 @@ static floatx80 subFloatx80Sigs(floatx80 a, floatx80 b, flag zSign,
         if ((uint64_t)(bSig << 1)) {
             return propagateFloatx80NaN(a, b, status);
         }
-        return packFloatx80( zSign ^ 1, 0x7FFF, LIT64( 0x8000000000000000 ) );
+        return packFloatx80(zSign ^ 1, floatx80_infinity_high,
+                            floatx80_infinity_low);
     }
     if ( aExp == 0 ) ++expDiff;
     shift128RightJamming( aSig, 0, - expDiff, &aSig, &zSig1 );
@@ -5415,7 +5424,8 @@ floatx80 floatx80_mul(floatx80 a, floatx80 b, float_status *status)
             return propagateFloatx80NaN(a, b, status);
         }
         if ( ( bExp | bSig ) == 0 ) goto invalid;
-        return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) );
+        return packFloatx80(zSign, floatx80_infinity_high,
+                                   floatx80_infinity_low);
     }
     if ( bExp == 0x7FFF ) {
         if ((uint64_t)(bSig << 1)) {
@@ -5426,7 +5436,8 @@ floatx80 floatx80_mul(floatx80 a, floatx80 b, float_status *status)
             float_raise(float_flag_invalid, status);
             return floatx80_default_nan(status);
         }
-        return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) );
+        return packFloatx80(zSign, floatx80_infinity_high,
+                                   floatx80_infinity_low);
     }
     if ( aExp == 0 ) {
         if ( aSig == 0 ) return packFloatx80( zSign, 0, 0 );
@@ -5480,7 +5491,8 @@ floatx80 floatx80_div(floatx80 a, floatx80 b, float_status *status)
             }
             goto invalid;
         }
-        return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) );
+        return packFloatx80(zSign, floatx80_infinity_high,
+                                   floatx80_infinity_low);
     }
     if ( bExp == 0x7FFF ) {
         if ((uint64_t)(bSig << 1)) {
@@ -5496,7 +5508,8 @@ floatx80 floatx80_div(floatx80 a, floatx80 b, float_status *status)
                 return floatx80_default_nan(status);
             }
             float_raise(float_flag_divbyzero, status);
-            return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) );
+            return packFloatx80(zSign, floatx80_infinity_high,
+                                       floatx80_infinity_low);
         }
         normalizeFloatx80Subnormal( bSig, &bExp, &bSig );
     }
@@ -6319,7 +6332,8 @@ floatx80 float128_to_floatx80(float128 a, float_status *status)
         if ( aSig0 | aSig1 ) {
             return commonNaNToFloatx80(float128ToCommonNaN(a, status), status);
         }
-        return packFloatx80( aSign, 0x7FFF, LIT64( 0x8000000000000000 ) );
+        return packFloatx80(aSign, floatx80_infinity_high,
+                                   floatx80_infinity_low);
     }
     if ( aExp == 0 ) {
         if ( ( aSig0 | aSig1 ) == 0 ) return packFloatx80( aSign, 0, 0 );
diff --git a/include/fpu/softfloat.h b/include/fpu/softfloat.h
index d9689ec..464a0f7 100644
--- a/include/fpu/softfloat.h
+++ b/include/fpu/softfloat.h
@@ -619,6 +619,11 @@ float64 floatx80_to_float64(floatx80, float_status *status);
 float128 floatx80_to_float128(floatx80, float_status *status);
 
 /*----------------------------------------------------------------------------
+| The pattern for an extended double-precision inf.
+*----------------------------------------------------------------------------*/
+extern const floatx80 floatx80_infinity;
+
+/*----------------------------------------------------------------------------
 | Software IEC/IEEE extended double-precision operations.
 *----------------------------------------------------------------------------*/
 floatx80 floatx80_round(floatx80 a, float_status *status);
@@ -658,7 +663,8 @@ static inline floatx80 floatx80_chs(floatx80 a)
 
 static inline int floatx80_is_infinity(floatx80 a)
 {
-    return (a.high & 0x7fff) == 0x7fff && a.low == 0x8000000000000000LL;
+    return (a.high & 0x7fff) == floatx80_infinity.high &&
+                       a.low == floatx80_infinity.low;
 }
 
 static inline int floatx80_is_neg(floatx80 a)
@@ -701,7 +707,6 @@ static inline bool floatx80_invalid_encoding(floatx80 a)
 #define floatx80_ln2 make_floatx80(0x3ffe, 0xb17217f7d1cf79acLL)
 #define floatx80_pi make_floatx80(0x4000, 0xc90fdaa22168c235LL)
 #define floatx80_half make_floatx80(0x3ffe, 0x8000000000000000LL)
-#define floatx80_infinity make_floatx80(0x7fff, 0x8000000000000000LL)
 
 /*----------------------------------------------------------------------------
 | The pattern for a default generated extended double-precision NaN.
-- 
2.9.4

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [Qemu-devel] [PATCH 2/4] target/m68k: add FPU trigonometric instructions
  2017-07-03 16:23 [Qemu-devel] [PATCH 0/4] target/m68k: implement 680x0 FPU (part 3) Laurent Vivier
  2017-07-03 16:23 ` [Qemu-devel] [PATCH 1/4] softfloat: use floatx80_infinity in softfloat Laurent Vivier
@ 2017-07-03 16:23 ` Laurent Vivier
  2017-07-03 19:11   ` Richard Henderson
  2017-07-03 16:23 ` [Qemu-devel] [PATCH 3/4] target/m68k: add fmod/frem Laurent Vivier
  2017-07-03 16:23 ` [Qemu-devel] [PATCH 4/4] target-m68k: add fscale, fgetman and fgetexp Laurent Vivier
  3 siblings, 1 reply; 13+ messages in thread
From: Laurent Vivier @ 2017-07-03 16:23 UTC (permalink / raw)
  To: qemu-devel; +Cc: Aurelien Jarno, Richard Henderson, Laurent Vivier

Add fsinh, flognp1, ftanh, fatan, fasin, fatanh,
fsin, ftan, fetox, ftwotox, ftentox, flogn, flog10, facos,
fcos, fsincos.

As softfloat library does not provide these functions,
we use the libm of the host.

Signed-off-by: Laurent Vivier <laurent@vivier.eu>
---
 target/m68k/cpu.h        |   1 +
 target/m68k/fpu_helper.c | 228 +++++++++++++++++++++++++++++++++++++++++++++++
 target/m68k/helper.h     |  17 ++++
 target/m68k/translate.c  |  73 +++++++++++----
 4 files changed, 304 insertions(+), 15 deletions(-)

diff --git a/target/m68k/cpu.h b/target/m68k/cpu.h
index 38a7e11..f8f4dd5 100644
--- a/target/m68k/cpu.h
+++ b/target/m68k/cpu.h
@@ -173,6 +173,7 @@ uint32_t cpu_m68k_get_ccr(CPUM68KState *env);
 void cpu_m68k_set_ccr(CPUM68KState *env, uint32_t);
 void cpu_m68k_set_fpcr(CPUM68KState *env, uint32_t val);
 
+long double floatx80_to_ldouble(floatx80 val);
 
 /* Instead of computing the condition codes after each m68k instruction,
  * QEMU just stores one operand (called CC_SRC), the result
diff --git a/target/m68k/fpu_helper.c b/target/m68k/fpu_helper.c
index bdfc537..2b07cb9 100644
--- a/target/m68k/fpu_helper.c
+++ b/target/m68k/fpu_helper.c
@@ -23,6 +23,7 @@
 #include "exec/helper-proto.h"
 #include "exec/exec-all.h"
 #include "exec/cpu_ldst.h"
+#include <math.h>
 
 /* Undefined offsets may be different on various FPU.
  * On 68040 they return 0.0 (floatx80_zero)
@@ -508,3 +509,230 @@ uint32_t HELPER(fmovemd_ld_postinc)(CPUM68KState *env, uint32_t addr,
 {
     return fmovem_postinc(env, addr, mask, cpu_ld_float64_ra);
 }
+
+long double floatx80_to_ldouble(floatx80 val)
+{
+    long double mantissa;
+    int32_t exp;
+    uint8_t sign;
+
+    if (floatx80_is_infinity(val)) {
+        if (floatx80_is_neg(val)) {
+            return -__builtin_infl();
+        }
+        return __builtin_infl();
+    }
+    if (floatx80_is_any_nan(val)) {
+        char low[20];
+        sprintf(low, "0x%016"PRIx64, val.low);
+        return nanl(low);
+    }
+
+    exp = (val.high & 0x7fff) - (0x3ffe + 64);
+    sign = val.high >> 15;
+    mantissa = (long double)val.low;
+    if (sign) {
+        mantissa = -mantissa;
+    }
+
+    return ldexpl(mantissa, exp);
+}
+
+static floatx80 ldouble_to_floatx80(long double val, float_status *status)
+{
+    floatx80 res;
+    long double mantissa;
+    int exp;
+
+    if (isinf(val)) {
+        res = floatx80_infinity;
+        if (isinf(val) < 0) {
+            res = floatx80_chs(res);
+        }
+        return res;
+    }
+    if (isnan(val)) {
+        res.high = floatx80_default_nan(NULL).high;
+        res.low = *(uint64_t *)&val; /* FIXME */
+        return res;
+    }
+
+    mantissa = frexpl(val, &exp);
+    res.high = exp + 0x3ffe;
+    if (mantissa < 0) {
+        res = floatx80_chs(res);
+        mantissa = -mantissa;
+    }
+    res.low = (uint64_t)ldexpl(mantissa, 64);
+
+    return floatx80_round(res, status);
+}
+
+void HELPER(fsinh)(CPUM68KState *env, FPReg *res, FPReg *val)
+{
+    long double d;
+
+    d = sinhl(floatx80_to_ldouble(val->d));
+    res->d = ldouble_to_floatx80(d, &env->fp_status);
+}
+
+void HELPER(flognp1)(CPUM68KState *env, FPReg *res, FPReg *val)
+{
+    long double d;
+
+    d = logl(floatx80_to_ldouble(val->d) + 1.0);
+
+    res->d = ldouble_to_floatx80(d, &env->fp_status);
+}
+
+void HELPER(fln)(CPUM68KState *env, FPReg *res, FPReg *val)
+{
+    long double d;
+
+    d = logl(floatx80_to_ldouble(val->d));
+
+    res->d = ldouble_to_floatx80(d, &env->fp_status);
+}
+
+void HELPER(flog10)(CPUM68KState *env, FPReg *res, FPReg *val)
+{
+    long double d;
+
+    d = log10l(floatx80_to_ldouble(val->d));
+
+    res->d = ldouble_to_floatx80(d, &env->fp_status);
+}
+
+void HELPER(fatan)(CPUM68KState *env, FPReg *res, FPReg *val)
+{
+    long double d;
+
+    d = atanl(floatx80_to_ldouble(val->d));
+    res->d = ldouble_to_floatx80(d, &env->fp_status);
+}
+
+void HELPER(fasin)(CPUM68KState *env, FPReg *res, FPReg *val)
+{
+    long double d;
+
+    d = floatx80_to_ldouble(val->d);
+    if (d < -1.0 || d > 1.0) {
+        res->d = floatx80_default_nan(NULL);
+        return;
+    }
+
+    res->d = ldouble_to_floatx80(asinl(d), &env->fp_status);
+}
+
+void HELPER(fatanh)(CPUM68KState *env, FPReg *res, FPReg *val)
+{
+    long double d;
+
+    d = floatx80_to_ldouble(val->d);
+    if (d < -1.0 || d > 1.0) {
+        res->d = floatx80_default_nan(NULL);
+        return;
+    }
+
+    d = atanhl(d);
+    res->d = ldouble_to_floatx80(d, &env->fp_status);
+}
+
+void HELPER(fsin)(CPUM68KState *env, FPReg *res, FPReg *val)
+{
+    long double d;
+
+    d = sinl(floatx80_to_ldouble(val->d));
+    res->d = ldouble_to_floatx80(d, &env->fp_status);
+}
+
+void HELPER(ftanh)(CPUM68KState *env, FPReg *res, FPReg *val)
+{
+    long double d;
+
+    d = tanhl(floatx80_to_ldouble(val->d));
+
+    res->d = ldouble_to_floatx80(d, &env->fp_status);
+}
+
+void HELPER(ftan)(CPUM68KState *env, FPReg *res, FPReg *val)
+{
+    long double d;
+
+    d = tanl(floatx80_to_ldouble(val->d));
+
+    res->d = ldouble_to_floatx80(d, &env->fp_status);
+}
+
+void HELPER(fexp)(CPUM68KState *env, FPReg *res, FPReg *val)
+{
+    long double d;
+
+    d = expl(floatx80_to_ldouble(val->d));
+
+    res->d = ldouble_to_floatx80(d, &env->fp_status);
+}
+
+void HELPER(fexp2)(CPUM68KState *env, FPReg *res, FPReg *val)
+{
+    long double d;
+
+    d = exp2l(floatx80_to_ldouble(val->d));
+
+    res->d = ldouble_to_floatx80(d, &env->fp_status);
+}
+
+void HELPER(fexp10)(CPUM68KState *env, FPReg *res, FPReg *val)
+{
+    long double d;
+
+    d = exp10l(floatx80_to_ldouble(val->d));
+
+    res->d = ldouble_to_floatx80(d, &env->fp_status);
+}
+
+void HELPER(fcosh)(CPUM68KState *env, FPReg *res, FPReg *val)
+{
+    long double d;
+
+    d = coshl(floatx80_to_ldouble(val->d));
+
+    res->d = ldouble_to_floatx80(d, &env->fp_status);
+}
+
+void HELPER(facos)(CPUM68KState *env, FPReg *res, FPReg *val)
+{
+    long double d;
+
+    d = floatx80_to_ldouble(val->d);
+    if (d < -1.0 || d > 1.0) {
+        res->d = floatx80_default_nan(NULL);
+        return;
+    }
+
+    d = acosl(d);
+    res->d = ldouble_to_floatx80(d, &env->fp_status);
+}
+
+void HELPER(fcos)(CPUM68KState *env, FPReg *res, FPReg *val)
+{
+    long double d;
+
+    d = cosl(floatx80_to_ldouble(val->d));
+
+    res->d = ldouble_to_floatx80(d, &env->fp_status);
+}
+
+void HELPER(fsincos)(CPUM68KState *env, FPReg *res0, FPReg *res1, FPReg *val)
+{
+    long double dsin, dcos;
+
+    sincosl(floatx80_to_ldouble(val->d), &dsin, &dcos);
+
+    /* If res0 and res1 specify the same floating-point data register,
+     * the sine result is stored in the register, and the cosine
+     * result is discarded.
+     */
+    res1->d = ldouble_to_floatx80(dcos, &env->fp_status);
+    res0->d = ldouble_to_floatx80(dsin, &env->fp_status);
+}
diff --git a/target/m68k/helper.h b/target/m68k/helper.h
index 475a1f2..302b6c0 100644
--- a/target/m68k/helper.h
+++ b/target/m68k/helper.h
@@ -60,6 +60,23 @@ DEF_HELPER_3(fmovemx_ld_postinc, i32, env, i32, i32)
 DEF_HELPER_3(fmovemd_st_predec, i32, env, i32, i32)
 DEF_HELPER_3(fmovemd_st_postinc, i32, env, i32, i32)
 DEF_HELPER_3(fmovemd_ld_postinc, i32, env, i32, i32)
+DEF_HELPER_3(fsinh, void, env, fp, fp)
+DEF_HELPER_3(flognp1, void, env, fp, fp)
+DEF_HELPER_3(fatan, void, env, fp, fp)
+DEF_HELPER_3(fasin, void, env, fp, fp)
+DEF_HELPER_3(fatanh, void, env, fp, fp)
+DEF_HELPER_3(fsin, void, env, fp, fp)
+DEF_HELPER_3(ftanh, void, env, fp, fp)
+DEF_HELPER_3(ftan, void, env, fp, fp)
+DEF_HELPER_3(fexp, void, env, fp, fp)
+DEF_HELPER_3(fexp2, void, env, fp, fp)
+DEF_HELPER_3(fexp10, void, env, fp, fp)
+DEF_HELPER_3(fln, void, env, fp, fp)
+DEF_HELPER_3(flog10, void, env, fp, fp)
+DEF_HELPER_3(fcosh, void, env, fp, fp)
+DEF_HELPER_3(facos, void, env, fp, fp)
+DEF_HELPER_3(fcos, void, env, fp, fp)
+DEF_HELPER_4(fsincos, void, env, fp, fp, fp)
 
 DEF_HELPER_3(mac_move, void, env, i32, i32)
 DEF_HELPER_3(macmulf, i64, env, i32, i32)
diff --git a/target/m68k/translate.c b/target/m68k/translate.c
index 3a519b7..8a712b3 100644
--- a/target/m68k/translate.c
+++ b/target/m68k/translate.c
@@ -4640,6 +4640,9 @@ DISAS_INSN(fpu)
     case 1: /* fint */
         gen_helper_firound(cpu_env, cpu_dest, cpu_src);
         break;
+    case 2: /* fsinh */
+        gen_helper_fsinh(cpu_env, cpu_dest, cpu_src);
+        break;
     case 3: /* fintrz */
         gen_helper_fitrunc(cpu_env, cpu_dest, cpu_src);
         break;
@@ -4652,6 +4655,42 @@ DISAS_INSN(fpu)
     case 0x45: /* fdsqrt */
         gen_helper_fdsqrt(cpu_env, cpu_dest, cpu_src);
         break;
+    case 0x06: /* flognp1 */
+        gen_helper_flognp1(cpu_env, cpu_dest, cpu_src);
+        break;
+    case 0x09: /* ftanh */
+        gen_helper_ftanh(cpu_env, cpu_dest, cpu_src);
+        break;
+    case 0x0a: /* fatan */
+        gen_helper_fatan(cpu_env, cpu_dest, cpu_src);
+        break;
+    case 0x0c: /* fasin */
+        gen_helper_fasin(cpu_env, cpu_dest, cpu_src);
+        break;
+    case 0x0d: /* fatanh */
+        gen_helper_fatanh(cpu_env, cpu_dest, cpu_src);
+        break;
+    case 0x0e: /* fsin */
+        gen_helper_fsin(cpu_env, cpu_dest, cpu_src);
+        break;
+    case 0x0f: /* ftan */
+        gen_helper_ftan(cpu_env, cpu_dest, cpu_src);
+        break;
+    case 0x10: /* fetox */
+        gen_helper_fexp(cpu_env, cpu_dest, cpu_src);
+        break;
+    case 0x11: /* ftwotox */
+        gen_helper_fexp2(cpu_env, cpu_dest, cpu_src);
+        break;
+    case 0x12: /* ftentox */
+        gen_helper_fexp10(cpu_env, cpu_dest, cpu_src);
+        break;
+    case 0x14: /* flogn */
+        gen_helper_fln(cpu_env, cpu_dest, cpu_src);
+        break;
+    case 0x15: /* flog10 */
+        gen_helper_flog10(cpu_env, cpu_dest, cpu_src);
+        break;
     case 0x18: /* fabs */
         gen_helper_fabs(cpu_env, cpu_dest, cpu_src);
         break;
@@ -4661,6 +4700,9 @@ DISAS_INSN(fpu)
     case 0x5c: /* fdabs */
         gen_helper_fdabs(cpu_env, cpu_dest, cpu_src);
         break;
+    case 0x19: /* fcosh */
+        gen_helper_fcosh(cpu_env, cpu_dest, cpu_src);
+        break;
     case 0x1a: /* fneg */
         gen_helper_fneg(cpu_env, cpu_dest, cpu_src);
         break;
@@ -4670,6 +4712,12 @@ DISAS_INSN(fpu)
     case 0x5e: /* fdneg */
         gen_helper_fdneg(cpu_env, cpu_dest, cpu_src);
         break;
+    case 0x1c: /* facos */
+        gen_helper_facos(cpu_env, cpu_dest, cpu_src);
+        break;
+    case 0x1d: /* fcos */
+        gen_helper_fcos(cpu_env, cpu_dest, cpu_src);
+        break;
     case 0x20: /* fdiv */
         gen_helper_fdiv(cpu_env, cpu_dest, cpu_src, cpu_dest);
         break;
@@ -4712,6 +4760,14 @@ DISAS_INSN(fpu)
     case 0x6c: /* fdsub */
         gen_helper_fdsub(cpu_env, cpu_dest, cpu_src, cpu_dest);
         break;
+    case 0x30: case 0x31: case 0x32:
+    case 0x33: case 0x34: case 0x35:
+    case 0x36: case 0x37: {
+            TCGv_ptr cpu_dest2 = gen_fp_ptr(REG(ext, 0));
+            gen_helper_fsincos(cpu_env, cpu_dest, cpu_dest2, cpu_src);
+            tcg_temp_free_ptr(cpu_dest2);
+        }
+        break;
     case 0x38: /* fcmp */
         gen_helper_fcmp(cpu_env, cpu_src, cpu_dest);
         return;
@@ -5626,18 +5682,6 @@ void gen_intermediate_code(CPUM68KState *env, TranslationBlock *tb)
     tb->icount = num_insns;
 }
 
-static double floatx80_to_double(CPUM68KState *env, uint16_t high, uint64_t low)
-{
-    floatx80 a = { .high = high, .low = low };
-    union {
-        float64 f64;
-        double d;
-    } u;
-
-    u.f64 = floatx80_to_float64(a, &env->fp_status);
-    return u.d;
-}
-
 void m68k_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf,
                          int flags)
 {
@@ -5647,11 +5691,10 @@ void m68k_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf,
     uint16_t sr;
     for (i = 0; i < 8; i++) {
         cpu_fprintf(f, "D%d = %08x   A%d = %08x   "
-                    "F%d = %04x %016"PRIx64"  (%12g)\n",
+                    "F%d = %04x %016"PRIx64"  (%12Lg)\n",
                     i, env->dregs[i], i, env->aregs[i],
                     i, env->fregs[i].l.upper, env->fregs[i].l.lower,
-                    floatx80_to_double(env, env->fregs[i].l.upper,
-                                       env->fregs[i].l.lower));
+                    floatx80_to_ldouble(env->fregs[i].d));
     }
     cpu_fprintf (f, "PC = %08x   ", env->pc);
     sr = env->sr | cpu_m68k_get_ccr(env);
-- 
2.9.4

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [Qemu-devel] [PATCH 3/4] target/m68k: add fmod/frem
  2017-07-03 16:23 [Qemu-devel] [PATCH 0/4] target/m68k: implement 680x0 FPU (part 3) Laurent Vivier
  2017-07-03 16:23 ` [Qemu-devel] [PATCH 1/4] softfloat: use floatx80_infinity in softfloat Laurent Vivier
  2017-07-03 16:23 ` [Qemu-devel] [PATCH 2/4] target/m68k: add FPU trigonometric instructions Laurent Vivier
@ 2017-07-03 16:23 ` Laurent Vivier
  2017-07-03 19:14   ` Richard Henderson
  2017-07-03 16:23 ` [Qemu-devel] [PATCH 4/4] target-m68k: add fscale, fgetman and fgetexp Laurent Vivier
  3 siblings, 1 reply; 13+ messages in thread
From: Laurent Vivier @ 2017-07-03 16:23 UTC (permalink / raw)
  To: qemu-devel; +Cc: Aurelien Jarno, Richard Henderson, Laurent Vivier

Use libm functions fmodl() and remainderl().
The quotient byte of the FPSR is updated with
the result of the operation.

Signed-off-by: Laurent Vivier <laurent@vivier.eu>
---
 target/m68k/cpu.h        |  1 +
 target/m68k/fpu_helper.c | 35 +++++++++++++++++++++++++++++++++++
 target/m68k/helper.h     |  2 ++
 target/m68k/translate.c  |  6 ++++++
 4 files changed, 44 insertions(+)

diff --git a/target/m68k/cpu.h b/target/m68k/cpu.h
index f8f4dd5..84794a9 100644
--- a/target/m68k/cpu.h
+++ b/target/m68k/cpu.h
@@ -236,6 +236,7 @@ typedef enum {
 /* Quotient */
 
 #define FPSR_QT_MASK  0x00ff0000
+#define FPSR_QT_SHIFT 16
 
 /* Floating-Point Control Register */
 /* Rounding mode */
diff --git a/target/m68k/fpu_helper.c b/target/m68k/fpu_helper.c
index 2b07cb9..715b9be 100644
--- a/target/m68k/fpu_helper.c
+++ b/target/m68k/fpu_helper.c
@@ -736,3 +736,38 @@ void HELPER(fsincos)(CPUM68KState *env, FPReg *res0, FPReg *res1, FPReg *val)
     res1->d = ldouble_to_floatx80(dcos, &env->fp_status);
     res0->d = ldouble_to_floatx80(dsin, &env->fp_status);
 }
+
+static void make_quotient(CPUM68KState *env, long double val, uint32_t sign)
+{
+    uint32_t quotient = (uint32_t)fabsl(val);
+    quotient = (sign << 7) | (quotient & 0x7f);
+    env->fpsr = (env->fpsr & ~FPSR_QT_MASK) | (quotient << FPSR_QT_SHIFT);
+}
+
+void HELPER(fmod)(CPUM68KState *env, FPReg *res, FPReg *val0, FPReg *val1)
+{
+    long double src, dst;
+    uint32_t sign = floatx80_is_neg(val0->d) ^  floatx80_is_neg(val1->d);
+
+    src = floatx80_to_ldouble(val0->d);
+    dst = floatx80_to_ldouble(val1->d);
+
+    dst = fmodl(dst, src);
+
+    make_quotient(env, dst, sign);
+    res->d = ldouble_to_floatx80(dst, &env->fp_status);
+}
+
+void HELPER(frem)(CPUM68KState *env, FPReg *res, FPReg *val0, FPReg *val1)
+{
+    long double src, dst;
+    uint32_t sign = floatx80_is_neg(val0->d) ^  floatx80_is_neg(val1->d);
+
+    src = floatx80_to_ldouble(val0->d);
+    dst = floatx80_to_ldouble(val1->d);
+
+    dst = remainderl(dst, src);
+
+    make_quotient(env, dst, sign);
+    res->d = ldouble_to_floatx80(dst, &env->fp_status);
+}
diff --git a/target/m68k/helper.h b/target/m68k/helper.h
index 302b6c0..889978e 100644
--- a/target/m68k/helper.h
+++ b/target/m68k/helper.h
@@ -77,6 +77,8 @@ DEF_HELPER_3(fcosh, void, env, fp, fp)
 DEF_HELPER_3(facos, void, env, fp, fp)
 DEF_HELPER_3(fcos, void, env, fp, fp)
 DEF_HELPER_4(fsincos, void, env, fp, fp, fp)
+DEF_HELPER_4(fmod, void, env, fp, fp, fp)
+DEF_HELPER_4(frem, void, env, fp, fp, fp)
 
 DEF_HELPER_3(mac_move, void, env, i32, i32)
 DEF_HELPER_3(macmulf, i64, env, i32, i32)
diff --git a/target/m68k/translate.c b/target/m68k/translate.c
index 8a712b3..fe9e0bf 100644
--- a/target/m68k/translate.c
+++ b/target/m68k/translate.c
@@ -4727,6 +4727,9 @@ DISAS_INSN(fpu)
     case 0x64: /* fddiv */
         gen_helper_fddiv(cpu_env, cpu_dest, cpu_src, cpu_dest);
         break;
+    case 0x21: /* fmod */
+        gen_helper_fmod(cpu_env, cpu_dest, cpu_src, cpu_dest);
+        break;
     case 0x22: /* fadd */
         gen_helper_fadd(cpu_env, cpu_dest, cpu_src, cpu_dest);
         break;
@@ -4748,6 +4751,9 @@ DISAS_INSN(fpu)
     case 0x24: /* fsgldiv */
         gen_helper_fsgldiv(cpu_env, cpu_dest, cpu_src, cpu_dest);
         break;
+    case 0x25: /* frem */
+        gen_helper_frem(cpu_env, cpu_dest, cpu_src, cpu_dest);
+        break;
     case 0x27: /* fsglmul */
         gen_helper_fsglmul(cpu_env, cpu_dest, cpu_src, cpu_dest);
         break;
-- 
2.9.4

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [Qemu-devel] [PATCH 4/4] target-m68k: add fscale, fgetman and fgetexp
  2017-07-03 16:23 [Qemu-devel] [PATCH 0/4] target/m68k: implement 680x0 FPU (part 3) Laurent Vivier
                   ` (2 preceding siblings ...)
  2017-07-03 16:23 ` [Qemu-devel] [PATCH 3/4] target/m68k: add fmod/frem Laurent Vivier
@ 2017-07-03 16:23 ` Laurent Vivier
  2017-07-03 19:26   ` Richard Henderson
  3 siblings, 1 reply; 13+ messages in thread
From: Laurent Vivier @ 2017-07-03 16:23 UTC (permalink / raw)
  To: qemu-devel; +Cc: Aurelien Jarno, Richard Henderson, Laurent Vivier

Signed-off-by: Laurent Vivier <laurent@vivier.eu>
---
 target/m68k/fpu_helper.c | 106 +++++++++++++++++++++++++++++++++++++++++++++++
 target/m68k/helper.h     |   3 ++
 target/m68k/translate.c  |   9 ++++
 3 files changed, 118 insertions(+)

diff --git a/target/m68k/fpu_helper.c b/target/m68k/fpu_helper.c
index 715b9be..88957fa 100644
--- a/target/m68k/fpu_helper.c
+++ b/target/m68k/fpu_helper.c
@@ -771,3 +771,109 @@ void HELPER(frem)(CPUM68KState *env, FPReg *res, FPReg *val0, FPReg *val1)
     make_quotient(env, dst, sign);
     res->d = ldouble_to_floatx80(dst, &env->fp_status);
 }
+
+void HELPER(fgetexp)(CPUM68KState *env, FPReg *res, FPReg *val)
+{
+    int32_t exp;
+
+    if (floatx80_is_infinity(val->d)) {
+        res->d = floatx80_default_nan(NULL);
+        /* FIXME: set the OPERR bit int he FPSR */
+        return;
+    }
+    if (floatx80_is_zero(val->d)) {
+        *res = *val;
+        return;
+    }
+    if (floatx80_is_zero_or_denormal(val->d)) {
+        res->d = int32_to_floatx80(-16384, &env->fp_status);
+        return;
+    }
+
+    if (floatx80_is_any_nan(val->d)) {
+        res->d = floatx80_default_nan(NULL);
+        return;
+    }
+
+    exp = (val->l.upper & 0x7fff) - 0x3fff;
+
+    res->d = int32_to_floatx80(exp, &env->fp_status);
+}
+
+void HELPER(fgetman)(CPUM68KState *env, FPReg *res, FPReg *val)
+{
+    if (floatx80_is_infinity(val->d)) {
+        res->d = floatx80_default_nan(NULL);
+        /* FIXME: set the OPERR bit int he FPSR */
+        return;
+    }
+    if (floatx80_is_zero(val->d) ||
+        floatx80_is_any_nan(val->d)) {
+        *res = *val;
+        return;
+    }
+
+    res->l.upper = (val->l.upper & 0x8000) | 0x3fff;
+    if (floatx80_is_zero_or_denormal(val->d)) {
+        res->l.lower = val->l.lower << 1;
+    } else {
+        res->l.lower = val->l.lower;
+    }
+}
+
+void HELPER(fscale)(CPUM68KState *env, FPReg *res, FPReg *val0, FPReg *val1)
+{
+    int rounding_mode;
+    int32_t scale;
+    int32_t exp;
+
+    if (floatx80_is_infinity(val0->d)) {
+        res->d = floatx80_default_nan(NULL);
+        /* FIXME: set the OPERR bit in the FPSR */
+        return;
+    }
+    if (floatx80_is_any_nan(val0->d)) {
+        res->d = floatx80_default_nan(NULL);
+        return;
+    }
+    if (floatx80_is_infinity(val1->d) ||
+        floatx80_is_zero_or_denormal(val1->d)) {
+        *res = *val1;
+        return;
+    }
+    if (floatx80_is_zero(val0->d)) {
+        res->d = floatx80_round(val1->d, &env->fp_status);
+        return;
+    }
+
+    rounding_mode = get_float_rounding_mode(&env->fp_status);
+    set_float_rounding_mode(float_round_to_zero, &env->fp_status);
+    scale = floatx80_to_int32(val0->d, &env->fp_status);
+    set_float_rounding_mode(rounding_mode, &env->fp_status);
+
+    if (scale >= 16384) {
+        if (floatx80_is_neg(val1->d)) {
+            res->d = floatx80_chs(floatx80_infinity);
+        } else {
+            res->d = floatx80_infinity;
+        }
+        /* FIXME: set OVFL in FPSR */
+        return;
+    }
+    if (scale <= -16384) {
+        if (floatx80_is_neg(val1->d)) {
+            res->d = floatx80_chs(floatx80_zero);
+        } else {
+            res->d = floatx80_zero;
+        }
+        /* FIXME: set UNFL in FPSR */
+        return;
+    }
+
+    exp = (val1->l.upper & 0x7fff) + scale;
+
+    res->l.upper = (val1->l.upper & 0x8000) | (exp & 0x7fff);
+    res->l.lower = val1->l.lower;
+
+    res->d = floatx80_round(res->d, &env->fp_status);
+}
diff --git a/target/m68k/helper.h b/target/m68k/helper.h
index 889978e..a6be815 100644
--- a/target/m68k/helper.h
+++ b/target/m68k/helper.h
@@ -79,6 +79,9 @@ DEF_HELPER_3(fcos, void, env, fp, fp)
 DEF_HELPER_4(fsincos, void, env, fp, fp, fp)
 DEF_HELPER_4(fmod, void, env, fp, fp, fp)
 DEF_HELPER_4(frem, void, env, fp, fp, fp)
+DEF_HELPER_3(fgetexp, void, env, fp, fp)
+DEF_HELPER_3(fgetman, void, env, fp, fp)
+DEF_HELPER_4(fscale, void, env, fp, fp, fp)
 
 DEF_HELPER_3(mac_move, void, env, i32, i32)
 DEF_HELPER_3(macmulf, i64, env, i32, i32)
diff --git a/target/m68k/translate.c b/target/m68k/translate.c
index fe9e0bf..348f4fb 100644
--- a/target/m68k/translate.c
+++ b/target/m68k/translate.c
@@ -4718,6 +4718,12 @@ DISAS_INSN(fpu)
     case 0x1d: /* fcos */
         gen_helper_fcos(cpu_env, cpu_dest, cpu_src);
         break;
+    case 0x1e: /* fgetexp */
+        gen_helper_fgetexp(cpu_env, cpu_dest, cpu_src);
+        break;
+    case 0x1f: /* fgetman */
+        gen_helper_fgetman(cpu_env, cpu_dest, cpu_src);
+        break;
     case 0x20: /* fdiv */
         gen_helper_fdiv(cpu_env, cpu_dest, cpu_src, cpu_dest);
         break;
@@ -4754,6 +4760,9 @@ DISAS_INSN(fpu)
     case 0x25: /* frem */
         gen_helper_frem(cpu_env, cpu_dest, cpu_src, cpu_dest);
         break;
+    case 0x26: /* fscale */
+        gen_helper_fscale(cpu_env, cpu_dest, cpu_src, cpu_dest);
+        break;
     case 0x27: /* fsglmul */
         gen_helper_fsglmul(cpu_env, cpu_dest, cpu_src, cpu_dest);
         break;
-- 
2.9.4

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [Qemu-devel] [PATCH 1/4] softfloat: use floatx80_infinity in softfloat
  2017-07-03 16:23 ` [Qemu-devel] [PATCH 1/4] softfloat: use floatx80_infinity in softfloat Laurent Vivier
@ 2017-07-03 18:06   ` Richard Henderson
  0 siblings, 0 replies; 13+ messages in thread
From: Richard Henderson @ 2017-07-03 18:06 UTC (permalink / raw)
  To: Laurent Vivier, qemu-devel; +Cc: Aurelien Jarno

On 07/03/2017 09:23 AM, Laurent Vivier wrote:
> Since f3218a8 ("softfloat: add floatx80 constants")
> floatx80_infinity is defined but never used.
> 
> This patch updates floatx80 functions to use
> this definition.
> 
> This allows to define a different default Infinity
> value on m68k: the m68k FPU defines infinity with
> all bits set to zero in the mantissa.
> 
> Signed-off-by: Laurent Vivier<laurent@vivier.eu>
> ---
>   fpu/softfloat-specialize.h | 14 ++++++++++++++
>   fpu/softfloat.c            | 38 ++++++++++++++++++++++++++------------
>   include/fpu/softfloat.h    |  9 +++++++--
>   3 files changed, 47 insertions(+), 14 deletions(-)

Reviewed-by: Richard Henderson <rth@twiddle.net>


r~

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [Qemu-devel] [PATCH 2/4] target/m68k: add FPU trigonometric instructions
  2017-07-03 16:23 ` [Qemu-devel] [PATCH 2/4] target/m68k: add FPU trigonometric instructions Laurent Vivier
@ 2017-07-03 19:11   ` Richard Henderson
  2017-07-03 19:17     ` Richard Henderson
  0 siblings, 1 reply; 13+ messages in thread
From: Richard Henderson @ 2017-07-03 19:11 UTC (permalink / raw)
  To: Laurent Vivier, qemu-devel; +Cc: Aurelien Jarno

On 07/03/2017 09:23 AM, Laurent Vivier wrote:
> +long double floatx80_to_ldouble(floatx80 val)
> +{
> +    long double mantissa;
> +    int32_t exp;
> +    uint8_t sign;
> +
> +    if (floatx80_is_infinity(val)) {
> +        if (floatx80_is_neg(val)) {
> +            return -__builtin_infl();
> +        }
> +        return __builtin_infl();

Better is the C99 INFINITY macro.

> +    }
> +    if (floatx80_is_any_nan(val)) {
> +        char low[20];
> +        sprintf(low, "0x%016"PRIx64, val.low);
> +        return nanl(low);

I think it would be better to avoid playing with nan payloads.

If you want to handle nans properly, I think you should provide a completely 
separate path through each user of floatx80_to_ldouble that avoids calling the 
libm function entirely.  And, more importantly, avoids the ldouble_to_floatx80 
call as well.

One possibly arrangement would be

	bool floatx80_to_ldouble(long double *out, floatx80 val)
	{
	  if (floatx80_is_any_nan(val)) {
	    *out = NAN;
	    return false;
	  }
           if (floatx80_is_infinity(val)) {
	    ...
	  } else {
	    ...
	  }
	  return true;
	}

   long double d;
   if (floatx80_to_ldouble(&d, val))) {
     d = sinl(d);
     val = ldouble_to_floatx80(d, status);
   } else {
     status->float_exception_flags |= float_flag_invalid;
     val = floatx80_default_nan(status);
   }

Failing that, just use the C99 NAN macro.

> +static floatx80 ldouble_to_floatx80(long double val, float_status *status)
> +{
> +    floatx80 res;
> +    long double mantissa;
> +    int exp;
> +
> +    if (isinf(val)) {
> +        res = floatx80_infinity;
> +        if (isinf(val) < 0) {

C99 isinf is merely boolean.  You want signbit for the second test.

> +    if (isnan(val)) {
> +        res.high = floatx80_default_nan(NULL).high;
> +        res.low = *(uint64_t *)&val; /* FIXME */
> +        return res;
> +    }

Likewise I'm uncomfortable with nan payloads.

You're not handling -0.0.  Perhaps

	switch (fpclassifyl(val)) {
	case FP_NAN:
	    res = floatx80_default_nan(status);
             break;
	case FP_INF:
	    res = floatx80_infinity;
	    break;
	case FP_ZERO:
	    res = floatx80_zero;
	    break;
	default:
	    // frexpl et al.
	}
	if (signbit(val)) {
	    res = floatx80_chs(res);
	}

is a better arrangement.

> +    mantissa = frexpl(val, &exp);
> +    res.high = exp + 0x3ffe;

Must be careful here: when long double = float128, this can either underflow or 
overflow.  Perhaps check for this and maybe even set the appropriate float_flag 
in status when it happens?

If you have gcc compile farm access, try gcc112 (power8 ppc64le host).

> +    res.low = (uint64_t)ldexpl(mantissa, 64);
> +
> +    return floatx80_round(res, status);

There may also be bits left over with float128, which means that rounding may 
be off.  But I think perhaps we don't really care *that* much about last-bit 
accuracy when it comes to these non-arithmetic insns.

> +    d = logl(floatx80_to_ldouble(val->d) + 1.0);

log1pl, which is important for actually computing values near 1.


r~

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [Qemu-devel] [PATCH 3/4] target/m68k: add fmod/frem
  2017-07-03 16:23 ` [Qemu-devel] [PATCH 3/4] target/m68k: add fmod/frem Laurent Vivier
@ 2017-07-03 19:14   ` Richard Henderson
  0 siblings, 0 replies; 13+ messages in thread
From: Richard Henderson @ 2017-07-03 19:14 UTC (permalink / raw)
  To: Laurent Vivier, qemu-devel; +Cc: Aurelien Jarno

On 07/03/2017 09:23 AM, Laurent Vivier wrote:
> Use libm functions fmodl() and remainderl().
> The quotient byte of the FPSR is updated with
> the result of the operation.
> 
> Signed-off-by: Laurent Vivier<laurent@vivier.eu>
> ---
>   target/m68k/cpu.h        |  1 +
>   target/m68k/fpu_helper.c | 35 +++++++++++++++++++++++++++++++++++
>   target/m68k/helper.h     |  2 ++
>   target/m68k/translate.c  |  6 ++++++
>   4 files changed, 44 insertions(+)

Reviewed-by: Richard Henderson <rth@twiddle.net>


r~

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [Qemu-devel] [PATCH 2/4] target/m68k: add FPU trigonometric instructions
  2017-07-03 19:11   ` Richard Henderson
@ 2017-07-03 19:17     ` Richard Henderson
  0 siblings, 0 replies; 13+ messages in thread
From: Richard Henderson @ 2017-07-03 19:17 UTC (permalink / raw)
  To: Laurent Vivier, qemu-devel; +Cc: Aurelien Jarno

On 07/03/2017 12:11 PM, Richard Henderson wrote:
>    if (floatx80_to_ldouble(&d, val))) {
>      d = sinl(d);
>      val = ldouble_to_floatx80(d, status);
>    } else {
>      status->float_exception_flags |= float_flag_invalid;
>      val = floatx80_default_nan(status);
>    }

Blah.  I didn't mean default_nan here, but use floatx80_maybe_silence_nan on 
the original input to the output.


r~

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [Qemu-devel] [PATCH 4/4] target-m68k: add fscale, fgetman and fgetexp
  2017-07-03 16:23 ` [Qemu-devel] [PATCH 4/4] target-m68k: add fscale, fgetman and fgetexp Laurent Vivier
@ 2017-07-03 19:26   ` Richard Henderson
  2017-07-03 19:50     ` Laurent Vivier
  0 siblings, 1 reply; 13+ messages in thread
From: Richard Henderson @ 2017-07-03 19:26 UTC (permalink / raw)
  To: Laurent Vivier, qemu-devel; +Cc: Aurelien Jarno

On 07/03/2017 09:23 AM, Laurent Vivier wrote:
> +void HELPER(fgetman)(CPUM68KState *env, FPReg *res, FPReg *val)
> +{
> +    if (floatx80_is_infinity(val->d)) {
> +        res->d = floatx80_default_nan(NULL);
> +        /* FIXME: set the OPERR bit int he FPSR */
> +        return;
> +    }
> +    if (floatx80_is_zero(val->d) ||
> +        floatx80_is_any_nan(val->d)) {
> +        *res = *val;
> +        return;
> +    }
> +
> +    res->l.upper = (val->l.upper & 0x8000) | 0x3fff;
> +    if (floatx80_is_zero_or_denormal(val->d)) {
> +        res->l.lower = val->l.lower << 1;

Surely you have to do more than this for denormals?  There may be more than one 
leading zero bit in the mant.  Do you actually need to re-normalize?  Or does 
real hardware produce a so-called "unnormal" in this situation?


r~

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [Qemu-devel] [PATCH 4/4] target-m68k: add fscale, fgetman and fgetexp
  2017-07-03 19:26   ` Richard Henderson
@ 2017-07-03 19:50     ` Laurent Vivier
  2017-07-03 20:31       ` Richard Henderson
  0 siblings, 1 reply; 13+ messages in thread
From: Laurent Vivier @ 2017-07-03 19:50 UTC (permalink / raw)
  To: Richard Henderson, qemu-devel; +Cc: Aurelien Jarno

Le 03/07/2017 à 21:26, Richard Henderson a écrit :
> On 07/03/2017 09:23 AM, Laurent Vivier wrote:
>> +void HELPER(fgetman)(CPUM68KState *env, FPReg *res, FPReg *val)
>> +{
>> +    if (floatx80_is_infinity(val->d)) {
>> +        res->d = floatx80_default_nan(NULL);
>> +        /* FIXME: set the OPERR bit int he FPSR */
>> +        return;
>> +    }
>> +    if (floatx80_is_zero(val->d) ||
>> +        floatx80_is_any_nan(val->d)) {
>> +        *res = *val;
>> +        return;
>> +    }
>> +
>> +    res->l.upper = (val->l.upper & 0x8000) | 0x3fff;
>> +    if (floatx80_is_zero_or_denormal(val->d)) {
>> +        res->l.lower = val->l.lower << 1;
> 
> Surely you have to do more than this for denormals?  There may be more
> than one leading zero bit in the mant.  Do you actually need to
> re-normalize?  Or does real hardware produce a so-called "unnormal" in
> this situation?

I don't know. Do you have test values I can try on real hardware to know?

I've tried:

		fmove.x #0x000056789ABCDEF12345,%fp0
		fgetman.x %fp0,%fp6

fp0            1.135643728339893804160017756766172e-4932	(raw
0x0000000056789abcdef12345)
fp6            1.3511111111108837373479679699883604	(raw
0x3fff0000acf13579bde2468a)

		fmove.x #0x000086789ABCDEF12345,%fp0
		fgetman.x %fp0,%fp6

fp0            1.7660380676734113365842698475140006e-4932	(raw
0x0000000086789abcdef12345)
fp6            1.0505555555554418686739839849941802	(raw
0x3fff000086789abcdef12345)

		fmove.x #0x000000000ABCDEF12345,%fp0
		fgetman.x %fp0,%fp6
fp0            2.1518178707571747286191852003521627e-4938	(raw
0x0000000000000abcdef12345)
fp6            1.342222103012886691431049257516861	(raw
0x3fff0000abcdef1234500000)

So I guess the mantissa must be shifted to left until we have a 1 in the
explicit integer part bit?

Thanks,
Laurent

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [Qemu-devel] [PATCH 4/4] target-m68k: add fscale, fgetman and fgetexp
  2017-07-03 19:50     ` Laurent Vivier
@ 2017-07-03 20:31       ` Richard Henderson
  2017-07-04  0:07         ` Laurent Vivier
  0 siblings, 1 reply; 13+ messages in thread
From: Richard Henderson @ 2017-07-03 20:31 UTC (permalink / raw)
  To: Laurent Vivier, qemu-devel; +Cc: Aurelien Jarno

On 07/03/2017 12:50 PM, Laurent Vivier wrote:
> 		fmove.x #0x000000000ABCDEF12345,%fp0
> 		fgetman.x %fp0,%fp6
> fp0            2.1518178707571747286191852003521627e-4938	(raw
> 0x0000000000000abcdef12345)
> fp6            1.342222103012886691431049257516861	(raw
> 0x3fff0000abcdef1234500000)

This one shows exactly what I was thinking about.

> So I guess the mantissa must be shifted to left until we have a 1 in the
> explicit integer part bit?

Yes.

Please try fgetexp on this same input.
I suspect the answer is -16384 - clz64(val->l.lower).
Otherwise the behaviour of fgetman above doesn't make sense.


r~

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [Qemu-devel] [PATCH 4/4] target-m68k: add fscale, fgetman and fgetexp
  2017-07-03 20:31       ` Richard Henderson
@ 2017-07-04  0:07         ` Laurent Vivier
  0 siblings, 0 replies; 13+ messages in thread
From: Laurent Vivier @ 2017-07-04  0:07 UTC (permalink / raw)
  To: Richard Henderson, qemu-devel; +Cc: Aurelien Jarno

Le 03/07/2017 à 22:31, Richard Henderson a écrit :
> On 07/03/2017 12:50 PM, Laurent Vivier wrote:
>>         fmove.x #0x000000000ABCDEF12345,%fp0
>>         fgetman.x %fp0,%fp6
>> fp0            2.1518178707571747286191852003521627e-4938    (raw
>> 0x0000000000000abcdef12345)
>> fp6            1.342222103012886691431049257516861    (raw
>> 0x3fff0000abcdef1234500000)
> 
> This one shows exactly what I was thinking about.
> 
>> So I guess the mantissa must be shifted to left until we have a 1 in the
>> explicit integer part bit?
> 
> Yes.
> 
> Please try fgetexp on this same input.

	        fmove.x #0x000000000ABCDEF12345,%fp0
	        fgetexp.x %fp0,%fp6
fp0            (raw 0x0000000000000abcdef12345)
fp6            -16403

> I suspect the answer is -16384 - clz64(val->l.lower).

It looks like -16383 - clz64(val->l.lower)

	        fmove.x #0x000056789ABCDEF12345,%fp0
	        fgetexp.x %fp0,%fp6
fp0            (raw 0x0000000056789abcdef12345)
fp6            -16384

	        fmove.x #0x000086789ABCDEF12345,%fp0
	        fgetexp.x %fp0,%fp6
fp0            (raw 0x0000000086789abcdef12345)
fp6            -16383

Thanks,
Laurent

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2017-07-04  0:07 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2017-07-03 16:23 [Qemu-devel] [PATCH 0/4] target/m68k: implement 680x0 FPU (part 3) Laurent Vivier
2017-07-03 16:23 ` [Qemu-devel] [PATCH 1/4] softfloat: use floatx80_infinity in softfloat Laurent Vivier
2017-07-03 18:06   ` Richard Henderson
2017-07-03 16:23 ` [Qemu-devel] [PATCH 2/4] target/m68k: add FPU trigonometric instructions Laurent Vivier
2017-07-03 19:11   ` Richard Henderson
2017-07-03 19:17     ` Richard Henderson
2017-07-03 16:23 ` [Qemu-devel] [PATCH 3/4] target/m68k: add fmod/frem Laurent Vivier
2017-07-03 19:14   ` Richard Henderson
2017-07-03 16:23 ` [Qemu-devel] [PATCH 4/4] target-m68k: add fscale, fgetman and fgetexp Laurent Vivier
2017-07-03 19:26   ` Richard Henderson
2017-07-03 19:50     ` Laurent Vivier
2017-07-03 20:31       ` Richard Henderson
2017-07-04  0:07         ` Laurent Vivier

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).