• Subject: [Qemu-devel] [PATCH 00/11] implement 680x0 FPU (part 5)
  • Author: Laurent Vivier
  • Date: March 12, 2018, 8:27 p.m.
  • Patches: 11 / 11
Changeset
target/m68k/fpu_helper.c            |   61 ++
target/m68k/helper.h                |   11 +
target/m68k/softfloat.c             | 1637 +++++++++++++++++++++++++++++++++++
target/m68k/softfloat.h             |   11 +
target/m68k/softfloat_fpsp_tables.h |  267 ++++++
target/m68k/translate.c             |   38 +
6 files changed, 2025 insertions(+)
Git apply log
Switched to a new branch '20180312202728.23790-1-laurent@vivier.eu'
Applying: target/m68k: implement ftan
Using index info to reconstruct a base tree...
M	target/m68k/fpu_helper.c
M	target/m68k/helper.h
M	target/m68k/softfloat.c
M	target/m68k/softfloat.h
M	target/m68k/softfloat_fpsp_tables.h
M	target/m68k/translate.c
Falling back to patching base and 3-way merge...
Auto-merging target/m68k/translate.c
CONFLICT (content): Merge conflict in target/m68k/translate.c
Auto-merging target/m68k/softfloat_fpsp_tables.h
CONFLICT (content): Merge conflict in target/m68k/softfloat_fpsp_tables.h
Auto-merging target/m68k/softfloat.h
CONFLICT (content): Merge conflict in target/m68k/softfloat.h
Auto-merging target/m68k/softfloat.c
CONFLICT (content): Merge conflict in target/m68k/softfloat.c
Auto-merging target/m68k/helper.h
CONFLICT (content): Merge conflict in target/m68k/helper.h
Auto-merging target/m68k/fpu_helper.c
CONFLICT (content): Merge conflict in target/m68k/fpu_helper.c
error: Failed to merge in the changes.
Patch failed at 0001 target/m68k: implement ftan
The copy of the patch that failed is found in: .git/rebase-apply/patch
When you have resolved this problem, run "git am --continue".
If you prefer to skip this patch, run "git am --skip" instead.
To restore the original branch and stop patching, run "git am --abort".
Failed to apply patch:
[Qemu-devel] [PATCH 01/11] target/m68k: implement ftan
Test passed: checkpatch

loading

Test passed: docker-mingw@fedora

loading

Test passed: s390x

loading

Test passed: docker-quick@centos6

loading

Test passed: docker-build@min-glib

loading

[Qemu-devel] [PATCH 00/11] implement 680x0 FPU (part 5)
Posted by Laurent Vivier, 14 weeks ago
Implement fcosh, fsinh, ftanh, fatanh, facos, fasin,
fatan, fsincos, fcos, fsin, ftan.

This is the last series to implement FPU instructions for 680x0...

As previously, all the floatx80 functions are copied from "Previous",
the NeXT Computer Emulator, and written by Andreas Grabher.

I did not improve or clean up the code, it's a simple port of
Andreas' work from "Previous".

I think this series will need some improvemants in the future:
for intance sin and cos functions can be merged in sincos
function (and we have unmodified "adjn" variable in floatx80_cos()
and floatx80_sin() that can be removed otherwise).

"Previous" code I have ported to QEMU can be found in (r844):

  http://svn.code.sf.net/p/previous/code/trunk/src/softfloat/

"Previous" code is a C implementation of m68040 assembly language functions
found in ($NetBSD: copyright.s,v 1.2 1994/10/26 07:48:57 cgd Exp)

  https://ftp.netbsd.org/pub/NetBSD/NetBSD-current/src/sys/arch/m68k/fpsp/

All the original work is under SoftFloat-2a license, and additional work
under BSD license or GPL-v2-or-later license.

All softfloat new functions are added in target/m68k as they are derived
from m68k code.

I have compared results of these instructions from a real m68040 and from
QEMU, and they match (sincos differs [1] because in QEMU we compute it as
sin and cos, and on m68040 sin and cos results differ also with
sincos results. It looks like a rounding problem, perhaps a bug in m68040
FPU? or in my test program?)

I know this will need more work, but for the moment I only would
like to provide these new instructions to the maintream of QEMU.

[1] Example:

sincos -6.125952 -> (0.156586, 0.987664)

QEMU:

  sincos c0010000c407cd1182c2bb27 -> 3ffc0000a05812beea449a4d
                                     3ffe0000fcd791d65887d19a
  sin c0010000c407cd1182c2bb27    -> 3ffc0000a05812beea449a4d
  cos c0010000c407cd1182c2bb27    -> 3ffe0000fcd791d65887d19a

m68040:

  sincos c0010000c407cd1182c2bb27 -> 3ffc0000a05812beea449a4d
                                     3ffe0000fcd791d65887d199 <<--
  sin c0010000c407cd1182c2bb27    -> 3ffc0000a05812beea449a4d
  cos c0010000c407cd1182c2bb27    -> 3ffe0000fcd791d65887d19a

test program is basically:

    register long double a, sin, cos, pi;
    long double step;

    asm("fmovecr #0, %0" : "=f" (pi));
    step = pi / 1024;
    for (a = -2*pi; a <= 2*pi; a+= step) {
        asm("fsincos.x %2, %0, %1" : "=f" (cos), "=f" (sin) : "f" (a));
        print_result(a, sin, cos);
        asm("fsin.x %1, %0" : "=f" (sin) : "f" (a));
        asm("fcos.x %1, %0" : "=f" (cos) : "f" (a));
        print_result(a, sin, cos);
    }

Laurent Vivier (11):
  target/m68k: implement ftan
  target/m68k: implement fsin
  target/m68k: implement fcos
  target/m68k: implement fsincos
  target/m68k: implement fatan
  target/m68k: implement fasin
  target/m68k: implement facos
  target/m68k: implement fatanh
  target/m68k: implement ftanh
  target/m68k: implement fsinh
  target/m68k: implement fcosh

 target/m68k/fpu_helper.c            |   61 ++
 target/m68k/helper.h                |   11 +
 target/m68k/softfloat.c             | 1637 +++++++++++++++++++++++++++++++++++
 target/m68k/softfloat.h             |   11 +
 target/m68k/softfloat_fpsp_tables.h |  267 ++++++
 target/m68k/translate.c             |   38 +
 6 files changed, 2025 insertions(+)

-- 
2.14.3


Re: [Qemu-devel] [PATCH 00/11] implement 680x0 FPU (part 5)
Posted by Richard Henderson, 14 weeks ago
On 03/13/2018 04:27 AM, Laurent Vivier wrote:
> I have compared results of these instructions from a real m68040 and from
> QEMU, and they match (sincos differs [1] because in QEMU we compute it as
> sin and cos, and on m68040 sin and cos results differ also with
> sincos results. It looks like a rounding problem, perhaps a bug in m68040
> FPU? or in my test program?)
> 
> I know this will need more work, but for the moment I only would
> like to provide these new instructions to the maintream of QEMU.
> 
> [1] Example:
> 
> sincos -6.125952 -> (0.156586, 0.987664)
> 
> QEMU:
> 
>   sincos c0010000c407cd1182c2bb27 -> 3ffc0000a05812beea449a4d
>                                      3ffe0000fcd791d65887d19a
>   sin c0010000c407cd1182c2bb27    -> 3ffc0000a05812beea449a4d
>   cos c0010000c407cd1182c2bb27    -> 3ffe0000fcd791d65887d19a
> 
> m68040:
> 
>   sincos c0010000c407cd1182c2bb27 -> 3ffc0000a05812beea449a4d
>                                      3ffe0000fcd791d65887d199 <<--
>   sin c0010000c407cd1182c2bb27    -> 3ffc0000a05812beea449a4d
>   cos c0010000c407cd1182c2bb27    -> 3ffe0000fcd791d65887d19a

Wow, this does seem like a processor bug.

Anyway, I've looked through the patch set and nothing stands out,

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>


r~

[Qemu-devel] [PATCH 01/11] target/m68k: implement ftan
Posted by Laurent Vivier, 14 weeks ago
Using a local m68k floatx80_tan()
[copied from previous:
Written by Andreas Grabher for Previous, NeXT Computer Emulator.]

Signed-off-by: Laurent Vivier <laurent@vivier.eu>
---
 target/m68k/fpu_helper.c            |   5 +
 target/m68k/helper.h                |   1 +
 target/m68k/softfloat.c             | 210 ++++++++++++++++++++++++++++++++++++
 target/m68k/softfloat.h             |   1 +
 target/m68k/softfloat_fpsp_tables.h | 136 +++++++++++++++++++++++
 target/m68k/translate.c             |   3 +
 6 files changed, 356 insertions(+)

diff --git a/target/m68k/fpu_helper.c b/target/m68k/fpu_helper.c
index 62cbb0dff1..c41115ea05 100644
--- a/target/m68k/fpu_helper.c
+++ b/target/m68k/fpu_helper.c
@@ -592,3 +592,8 @@ void HELPER(ftentox)(CPUM68KState *env, FPReg *res, FPReg *val)
 {
     res->d = floatx80_tentox(val->d, &env->fp_status);
 }
+
+void HELPER(ftan)(CPUM68KState *env, FPReg *res, FPReg *val)
+{
+    res->d = floatx80_tan(val->d, &env->fp_status);
+}
diff --git a/target/m68k/helper.h b/target/m68k/helper.h
index 9a9734c196..af9480fe49 100644
--- a/target/m68k/helper.h
+++ b/target/m68k/helper.h
@@ -75,6 +75,7 @@ DEF_HELPER_3(flog2, void, env, fp, fp)
 DEF_HELPER_3(fetox, void, env, fp, fp)
 DEF_HELPER_3(ftwotox, void, env, fp, fp)
 DEF_HELPER_3(ftentox, void, env, fp, fp)
+DEF_HELPER_3(ftan, void, env, fp, fp)
 
 DEF_HELPER_3(mac_move, void, env, i32, i32)
 DEF_HELPER_3(macmulf, i64, env, i32, i32)
diff --git a/target/m68k/softfloat.c b/target/m68k/softfloat.c
index 4bd5b9e6b7..488dbc522b 100644
--- a/target/m68k/softfloat.c
+++ b/target/m68k/softfloat.c
@@ -1266,3 +1266,213 @@ floatx80 floatx80_tentox(floatx80 a, float_status *status)
         return a;
     }
 }
+
+/*----------------------------------------------------------------------------
+ | Tangent
+ *----------------------------------------------------------------------------*/
+
+floatx80 floatx80_tan(floatx80 a, float_status *status)
+{
+    flag aSign, xSign;
+    int32_t aExp, xExp;
+    uint64_t aSig, xSig;
+
+    int8_t user_rnd_mode, user_rnd_prec;
+
+    int32_t compact, l, n, j;
+    floatx80 fp0, fp1, fp2, fp3, fp4, fp5, invtwopi, twopi1, twopi2;
+    float32 twoto63;
+    flag endflag;
+
+    aSig = extractFloatx80Frac(a);
+    aExp = extractFloatx80Exp(a);
+    aSign = extractFloatx80Sign(a);
+
+    if (aExp == 0x7FFF) {
+        if ((uint64_t) (aSig << 1)) {
+            return propagateFloatx80NaNOneArg(a, status);
+        }
+        float_raise(float_flag_invalid, status);
+        return floatx80_default_nan(status);
+    }
+
+    if (aExp == 0 && aSig == 0) {
+        return packFloatx80(aSign, 0, 0);
+    }
+
+    user_rnd_mode = status->float_rounding_mode;
+    user_rnd_prec = status->floatx80_rounding_precision;
+    status->float_rounding_mode = float_round_nearest_even;
+    status->floatx80_rounding_precision = 80;
+
+    compact = floatx80_make_compact(aExp, aSig);
+
+    fp0 = a;
+
+    if (compact < 0x3FD78000 || compact > 0x4004BC7E) {
+        /* 2^(-40) > |X| > 15 PI */
+        if (compact > 0x3FFF8000) { /* |X| >= 15 PI */
+            /* REDUCEX */
+            fp1 = packFloatx80(0, 0, 0);
+            if (compact == 0x7FFEFFFF) {
+                twopi1 = packFloatx80(aSign ^ 1, 0x7FFE,
+                                      LIT64(0xC90FDAA200000000));
+                twopi2 = packFloatx80(aSign ^ 1, 0x7FDC,
+                                      LIT64(0x85A308D300000000));
+                fp0 = floatx80_add(fp0, twopi1, status);
+                fp1 = fp0;
+                fp0 = floatx80_add(fp0, twopi2, status);
+                fp1 = floatx80_sub(fp1, fp0, status);
+                fp1 = floatx80_add(fp1, twopi2, status);
+            }
+        loop:
+            xSign = extractFloatx80Sign(fp0);
+            xExp = extractFloatx80Exp(fp0);
+            xExp -= 0x3FFF;
+            if (xExp <= 28) {
+                l = 0;
+                endflag = 1;
+            } else {
+                l = xExp - 27;
+                endflag = 0;
+            }
+            invtwopi = packFloatx80(0, 0x3FFE - l,
+                                    LIT64(0xA2F9836E4E44152A)); /* INVTWOPI */
+            twopi1 = packFloatx80(0, 0x3FFF + l, LIT64(0xC90FDAA200000000));
+            twopi2 = packFloatx80(0, 0x3FDD + l, LIT64(0x85A308D300000000));
+
+            /* SIGN(INARG)*2^63 IN SGL */
+            twoto63 = packFloat32(xSign, 0xBE, 0);
+
+            fp2 = floatx80_mul(fp0, invtwopi, status);
+            fp2 = floatx80_add(fp2, float32_to_floatx80(twoto63, status),
+                               status); /* THE FRACT PART OF FP2 IS ROUNDED */
+            fp2 = floatx80_sub(fp2, float32_to_floatx80(twoto63, status),
+                               status); /* FP2 is N */
+            fp4 = floatx80_mul(twopi1, fp2, status); /* W = N*P1 */
+            fp5 = floatx80_mul(twopi2, fp2, status); /* w = N*P2 */
+            fp3 = floatx80_add(fp4, fp5, status); /* FP3 is P */
+            fp4 = floatx80_sub(fp4, fp3, status); /* W-P */
+            fp0 = floatx80_sub(fp0, fp3, status); /* FP0 is A := R - P */
+            fp4 = floatx80_add(fp4, fp5, status); /* FP4 is p = (W-P)+w */
+            fp3 = fp0; /* FP3 is A */
+            fp1 = floatx80_sub(fp1, fp4, status); /* FP1 is a := r - p */
+            fp0 = floatx80_add(fp0, fp1, status); /* FP0 is R := A+a */
+
+            if (endflag > 0) {
+                n = floatx80_to_int32(fp2, status);
+                goto tancont;
+            }
+            fp3 = floatx80_sub(fp3, fp0, status); /* A-R */
+            fp1 = floatx80_add(fp1, fp3, status); /* FP1 is r := (A-R)+a */
+            goto loop;
+        } else {
+            status->float_rounding_mode = user_rnd_mode;
+            status->floatx80_rounding_precision = user_rnd_prec;
+
+            a = floatx80_move(a, status);
+
+            float_raise(float_flag_inexact, status);
+
+            return a;
+        }
+    } else {
+        fp1 = floatx80_mul(fp0, float64_to_floatx80(
+                           make_float64(0x3FE45F306DC9C883), status),
+                           status); /* X*2/PI */
+
+        n = floatx80_to_int32(fp1, status);
+        j = 32 + n;
+
+        fp0 = floatx80_sub(fp0, pi_tbl[j], status); /* X-Y1 */
+        fp0 = floatx80_sub(fp0, float32_to_floatx80(pi_tbl2[j], status),
+                           status); /* FP0 IS R = (X-Y1)-Y2 */
+
+    tancont:
+        if (n & 1) {
+            /* NODD */
+            fp1 = fp0; /* R */
+            fp0 = floatx80_mul(fp0, fp0, status); /* S = R*R */
+            fp3 = float64_to_floatx80(make_float64(0x3EA0B759F50F8688),
+                                      status); /* Q4 */
+            fp2 = float64_to_floatx80(make_float64(0xBEF2BAA5A8924F04),
+                                      status); /* P3 */
+            fp3 = floatx80_mul(fp3, fp0, status); /* SQ4 */
+            fp2 = floatx80_mul(fp2, fp0, status); /* SP3 */
+            fp3 = floatx80_add(fp3, float64_to_floatx80(
+                               make_float64(0xBF346F59B39BA65F), status),
+                               status); /* Q3+SQ4 */
+            fp4 = packFloatx80(0, 0x3FF6, LIT64(0xE073D3FC199C4A00));
+            fp2 = floatx80_add(fp2, fp4, status); /* P2+SP3 */
+            fp3 = floatx80_mul(fp3, fp0, status); /* S(Q3+SQ4) */
+            fp2 = floatx80_mul(fp2, fp0, status); /* S(P2+SP3) */
+            fp4 = packFloatx80(0, 0x3FF9, LIT64(0xD23CD68415D95FA1));
+            fp3 = floatx80_add(fp3, fp4, status); /* Q2+S(Q3+SQ4) */
+            fp4 = packFloatx80(1, 0x3FFC, LIT64(0x8895A6C5FB423BCA));
+            fp2 = floatx80_add(fp2, fp4, status); /* P1+S(P2+SP3) */
+            fp3 = floatx80_mul(fp3, fp0, status); /* S(Q2+S(Q3+SQ4)) */
+            fp2 = floatx80_mul(fp2, fp0, status); /* S(P1+S(P2+SP3)) */
+            fp4 = packFloatx80(1, 0x3FFD, LIT64(0xEEF57E0DA84BC8CE));
+            fp3 = floatx80_add(fp3, fp4, status); /* Q1+S(Q2+S(Q3+SQ4)) */
+            fp2 = floatx80_mul(fp2, fp1, status); /* RS(P1+S(P2+SP3)) */
+            fp0 = floatx80_mul(fp0, fp3, status); /* S(Q1+S(Q2+S(Q3+SQ4))) */
+            fp1 = floatx80_add(fp1, fp2, status); /* R+RS(P1+S(P2+SP3)) */
+            fp0 = floatx80_add(fp0, float32_to_floatx80(
+                               make_float32(0x3F800000), status),
+                               status); /* 1+S(Q1+S(Q2+S(Q3+SQ4))) */
+
+            xSign = extractFloatx80Sign(fp1);
+            xExp = extractFloatx80Exp(fp1);
+            xSig = extractFloatx80Frac(fp1);
+            xSign ^= 1;
+            fp1 = packFloatx80(xSign, xExp, xSig);
+
+            status->float_rounding_mode = user_rnd_mode;
+            status->floatx80_rounding_precision = user_rnd_prec;
+
+            a = floatx80_div(fp0, fp1, status);
+
+            float_raise(float_flag_inexact, status);
+
+            return a;
+        } else {
+            fp1 = floatx80_mul(fp0, fp0, status); /* S = R*R */
+            fp3 = float64_to_floatx80(make_float64(0x3EA0B759F50F8688),
+                                      status); /* Q4 */
+            fp2 = float64_to_floatx80(make_float64(0xBEF2BAA5A8924F04),
+                                      status); /* P3 */
+            fp3 = floatx80_mul(fp3, fp1, status); /* SQ4 */
+            fp2 = floatx80_mul(fp2, fp1, status); /* SP3 */
+            fp3 = floatx80_add(fp3, float64_to_floatx80(
+                               make_float64(0xBF346F59B39BA65F), status),
+                               status); /* Q3+SQ4 */
+            fp4 = packFloatx80(0, 0x3FF6, LIT64(0xE073D3FC199C4A00));
+            fp2 = floatx80_add(fp2, fp4, status); /* P2+SP3 */
+            fp3 = floatx80_mul(fp3, fp1, status); /* S(Q3+SQ4) */
+            fp2 = floatx80_mul(fp2, fp1, status); /* S(P2+SP3) */
+            fp4 = packFloatx80(0, 0x3FF9, LIT64(0xD23CD68415D95FA1));
+            fp3 = floatx80_add(fp3, fp4, status); /* Q2+S(Q3+SQ4) */
+            fp4 = packFloatx80(1, 0x3FFC, LIT64(0x8895A6C5FB423BCA));
+            fp2 = floatx80_add(fp2, fp4, status); /* P1+S(P2+SP3) */
+            fp3 = floatx80_mul(fp3, fp1, status); /* S(Q2+S(Q3+SQ4)) */
+            fp2 = floatx80_mul(fp2, fp1, status); /* S(P1+S(P2+SP3)) */
+            fp4 = packFloatx80(1, 0x3FFD, LIT64(0xEEF57E0DA84BC8CE));
+            fp3 = floatx80_add(fp3, fp4, status); /* Q1+S(Q2+S(Q3+SQ4)) */
+            fp2 = floatx80_mul(fp2, fp0, status); /* RS(P1+S(P2+SP3)) */
+            fp1 = floatx80_mul(fp1, fp3, status); /* S(Q1+S(Q2+S(Q3+SQ4))) */
+            fp0 = floatx80_add(fp0, fp2, status); /* R+RS(P1+S(P2+SP3)) */
+            fp1 = floatx80_add(fp1, float32_to_floatx80(
+                               make_float32(0x3F800000), status),
+                               status); /* 1+S(Q1+S(Q2+S(Q3+SQ4))) */
+
+            status->float_rounding_mode = user_rnd_mode;
+            status->floatx80_rounding_precision = user_rnd_prec;
+
+            a = floatx80_div(fp0, fp1, status);
+
+            float_raise(float_flag_inexact, status);
+
+            return a;
+        }
+    }
+}
diff --git a/target/m68k/softfloat.h b/target/m68k/softfloat.h
index d28e49fe9f..c5ac54d87b 100644
--- a/target/m68k/softfloat.h
+++ b/target/m68k/softfloat.h
@@ -34,4 +34,5 @@ floatx80 floatx80_log2(floatx80 a, float_status *status);
 floatx80 floatx80_etox(floatx80 a, float_status *status);
 floatx80 floatx80_twotox(floatx80 a, float_status *status);
 floatx80 floatx80_tentox(floatx80 a, float_status *status);
+floatx80 floatx80_tan(floatx80 a, float_status *status);
 #endif
diff --git a/target/m68k/softfloat_fpsp_tables.h b/target/m68k/softfloat_fpsp_tables.h
index dd76dc0373..a9c86a5af2 100644
--- a/target/m68k/softfloat_fpsp_tables.h
+++ b/target/m68k/softfloat_fpsp_tables.h
@@ -371,4 +371,140 @@ static const uint32_t exp2_tbl2[64] = {
     0xBFBDBF4A, 0x3FBEC01A, 0x3FBE8CAC, 0xBFBCBB3F,
     0x3FBEF73A, 0xBFB8B795, 0x3FBEF84B, 0xBFBEF581
 };
+
+static const floatx80 pi_tbl[65] = {
+    make_floatx80_init(0xC004, 0xC90FDAA22168C235),
+    make_floatx80_init(0xC004, 0xC2C75BCD105D7C23),
+    make_floatx80_init(0xC004, 0xBC7EDCF7FF523611),
+    make_floatx80_init(0xC004, 0xB6365E22EE46F000),
+    make_floatx80_init(0xC004, 0xAFEDDF4DDD3BA9EE),
+    make_floatx80_init(0xC004, 0xA9A56078CC3063DD),
+    make_floatx80_init(0xC004, 0xA35CE1A3BB251DCB),
+    make_floatx80_init(0xC004, 0x9D1462CEAA19D7B9),
+    make_floatx80_init(0xC004, 0x96CBE3F9990E91A8),
+    make_floatx80_init(0xC004, 0x9083652488034B96),
+    make_floatx80_init(0xC004, 0x8A3AE64F76F80584),
+    make_floatx80_init(0xC004, 0x83F2677A65ECBF73),
+    make_floatx80_init(0xC003, 0xFB53D14AA9C2F2C2),
+    make_floatx80_init(0xC003, 0xEEC2D3A087AC669F),
+    make_floatx80_init(0xC003, 0xE231D5F66595DA7B),
+    make_floatx80_init(0xC003, 0xD5A0D84C437F4E58),
+    make_floatx80_init(0xC003, 0xC90FDAA22168C235),
+    make_floatx80_init(0xC003, 0xBC7EDCF7FF523611),
+    make_floatx80_init(0xC003, 0xAFEDDF4DDD3BA9EE),
+    make_floatx80_init(0xC003, 0xA35CE1A3BB251DCB),
+    make_floatx80_init(0xC003, 0x96CBE3F9990E91A8),
+    make_floatx80_init(0xC003, 0x8A3AE64F76F80584),
+    make_floatx80_init(0xC002, 0xFB53D14AA9C2F2C2),
+    make_floatx80_init(0xC002, 0xE231D5F66595DA7B),
+    make_floatx80_init(0xC002, 0xC90FDAA22168C235),
+    make_floatx80_init(0xC002, 0xAFEDDF4DDD3BA9EE),
+    make_floatx80_init(0xC002, 0x96CBE3F9990E91A8),
+    make_floatx80_init(0xC001, 0xFB53D14AA9C2F2C2),
+    make_floatx80_init(0xC001, 0xC90FDAA22168C235),
+    make_floatx80_init(0xC001, 0x96CBE3F9990E91A8),
+    make_floatx80_init(0xC000, 0xC90FDAA22168C235),
+    make_floatx80_init(0xBFFF, 0xC90FDAA22168C235),
+    make_floatx80_init(0x0000, 0x0000000000000000),
+    make_floatx80_init(0x3FFF, 0xC90FDAA22168C235),
+    make_floatx80_init(0x4000, 0xC90FDAA22168C235),
+    make_floatx80_init(0x4001, 0x96CBE3F9990E91A8),
+    make_floatx80_init(0x4001, 0xC90FDAA22168C235),
+    make_floatx80_init(0x4001, 0xFB53D14AA9C2F2C2),
+    make_floatx80_init(0x4002, 0x96CBE3F9990E91A8),
+    make_floatx80_init(0x4002, 0xAFEDDF4DDD3BA9EE),
+    make_floatx80_init(0x4002, 0xC90FDAA22168C235),
+    make_floatx80_init(0x4002, 0xE231D5F66595DA7B),
+    make_floatx80_init(0x4002, 0xFB53D14AA9C2F2C2),
+    make_floatx80_init(0x4003, 0x8A3AE64F76F80584),
+    make_floatx80_init(0x4003, 0x96CBE3F9990E91A8),
+    make_floatx80_init(0x4003, 0xA35CE1A3BB251DCB),
+    make_floatx80_init(0x4003, 0xAFEDDF4DDD3BA9EE),
+    make_floatx80_init(0x4003, 0xBC7EDCF7FF523611),
+    make_floatx80_init(0x4003, 0xC90FDAA22168C235),
+    make_floatx80_init(0x4003, 0xD5A0D84C437F4E58),
+    make_floatx80_init(0x4003, 0xE231D5F66595DA7B),
+    make_floatx80_init(0x4003, 0xEEC2D3A087AC669F),
+    make_floatx80_init(0x4003, 0xFB53D14AA9C2F2C2),
+    make_floatx80_init(0x4004, 0x83F2677A65ECBF73),
+    make_floatx80_init(0x4004, 0x8A3AE64F76F80584),
+    make_floatx80_init(0x4004, 0x9083652488034B96),
+    make_floatx80_init(0x4004, 0x96CBE3F9990E91A8),
+    make_floatx80_init(0x4004, 0x9D1462CEAA19D7B9),
+    make_floatx80_init(0x4004, 0xA35CE1A3BB251DCB),
+    make_floatx80_init(0x4004, 0xA9A56078CC3063DD),
+    make_floatx80_init(0x4004, 0xAFEDDF4DDD3BA9EE),
+    make_floatx80_init(0x4004, 0xB6365E22EE46F000),
+    make_floatx80_init(0x4004, 0xBC7EDCF7FF523611),
+    make_floatx80_init(0x4004, 0xC2C75BCD105D7C23),
+    make_floatx80_init(0x4004, 0xC90FDAA22168C235)
+};
+
+static const float32 pi_tbl2[65] = {
+    const_float32(0x21800000),
+    const_float32(0xA0D00000),
+    const_float32(0xA1E80000),
+    const_float32(0x21480000),
+    const_float32(0xA1200000),
+    const_float32(0x21FC0000),
+    const_float32(0x21100000),
+    const_float32(0xA1580000),
+    const_float32(0x21E00000),
+    const_float32(0x20B00000),
+    const_float32(0xA1880000),
+    const_float32(0x21C40000),
+    const_float32(0x20000000),
+    const_float32(0x21380000),
+    const_float32(0xA1300000),
+    const_float32(0x9FC00000),
+    const_float32(0x21000000),
+    const_float32(0xA1680000),
+    const_float32(0xA0A00000),
+    const_float32(0x20900000),
+    const_float32(0x21600000),
+    const_float32(0xA1080000),
+    const_float32(0x1F800000),
+    const_float32(0xA0B00000),
+    const_float32(0x20800000),
+    const_float32(0xA0200000),
+    const_float32(0x20E00000),
+    const_float32(0x1F000000),
+    const_float32(0x20000000),
+    const_float32(0x20600000),
+    const_float32(0x1F800000),
+    const_float32(0x1F000000),
+    const_float32(0x00000000),
+    const_float32(0x9F000000),
+    const_float32(0x9F800000),
+    const_float32(0xA0600000),
+    const_float32(0xA0000000),
+    const_float32(0x9F000000),
+    const_float32(0xA0E00000),
+    const_float32(0x20200000),
+    const_float32(0xA0800000),
+    const_float32(0x20B00000),
+    const_float32(0x9F800000),
+    const_float32(0x21080000),
+    const_float32(0xA1600000),
+    const_float32(0xA0900000),
+    const_float32(0x20A00000),
+    const_float32(0x21680000),
+    const_float32(0xA1000000),
+    const_float32(0x1FC00000),
+    const_float32(0x21300000),
+    const_float32(0xA1380000),
+    const_float32(0xA0000000),
+    const_float32(0xA1C40000),
+    const_float32(0x21880000),
+    const_float32(0xA0B00000),
+    const_float32(0xA1E00000),
+    const_float32(0x21580000),
+    const_float32(0xA1100000),
+    const_float32(0xA1FC0000),
+    const_float32(0x21200000),
+    const_float32(0xA1480000),
+    const_float32(0x21E80000),
+    const_float32(0x20D00000),
+    const_float32(0xA1800000),
+};
 #endif
diff --git a/target/m68k/translate.c b/target/m68k/translate.c
index 6d5bde0777..af8cdc2580 100644
--- a/target/m68k/translate.c
+++ b/target/m68k/translate.c
@@ -5057,6 +5057,9 @@ DISAS_INSN(fpu)
     case 0x06: /* flognp1 */
         gen_helper_flognp1(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_fetox(cpu_env, cpu_dest, cpu_src);
         break;
-- 
2.14.3


[Qemu-devel] [PATCH 02/11] target/m68k: implement fsin
Posted by Laurent Vivier, 14 weeks ago
Using a local m68k floatx80_sin()
[copied from previous:
Written by Andreas Grabher for Previous, NeXT Computer Emulator.]

Signed-off-by: Laurent Vivier <laurent@vivier.eu>
---
 target/m68k/fpu_helper.c |   5 +
 target/m68k/helper.h     |   1 +
 target/m68k/softfloat.c  | 247 +++++++++++++++++++++++++++++++++++++++++++++++
 target/m68k/softfloat.h  |   1 +
 target/m68k/translate.c  |   3 +
 5 files changed, 257 insertions(+)

diff --git a/target/m68k/fpu_helper.c b/target/m68k/fpu_helper.c
index c41115ea05..a6cfb4db1a 100644
--- a/target/m68k/fpu_helper.c
+++ b/target/m68k/fpu_helper.c
@@ -597,3 +597,8 @@ void HELPER(ftan)(CPUM68KState *env, FPReg *res, FPReg *val)
 {
     res->d = floatx80_tan(val->d, &env->fp_status);
 }
+
+void HELPER(fsin)(CPUM68KState *env, FPReg *res, FPReg *val)
+{
+    res->d = floatx80_sin(val->d, &env->fp_status);
+}
diff --git a/target/m68k/helper.h b/target/m68k/helper.h
index af9480fe49..6d8bfaab64 100644
--- a/target/m68k/helper.h
+++ b/target/m68k/helper.h
@@ -76,6 +76,7 @@ DEF_HELPER_3(fetox, void, env, fp, fp)
 DEF_HELPER_3(ftwotox, void, env, fp, fp)
 DEF_HELPER_3(ftentox, void, env, fp, fp)
 DEF_HELPER_3(ftan, void, env, fp, fp)
+DEF_HELPER_3(fsin, void, env, fp, fp)
 
 DEF_HELPER_3(mac_move, void, env, i32, i32)
 DEF_HELPER_3(macmulf, i64, env, i32, i32)
diff --git a/target/m68k/softfloat.c b/target/m68k/softfloat.c
index 488dbc522b..6fb9665336 100644
--- a/target/m68k/softfloat.c
+++ b/target/m68k/softfloat.c
@@ -1476,3 +1476,250 @@ floatx80 floatx80_tan(floatx80 a, float_status *status)
         }
     }
 }
+
+/*----------------------------------------------------------------------------
+ | Sine
+ *----------------------------------------------------------------------------*/
+
+floatx80 floatx80_sin(floatx80 a, float_status *status)
+{
+    flag aSign, xSign;
+    int32_t aExp, xExp;
+    uint64_t aSig, xSig;
+
+    int8_t user_rnd_mode, user_rnd_prec;
+
+    int32_t compact, l, n, j;
+    floatx80 fp0, fp1, fp2, fp3, fp4, fp5, x, invtwopi, twopi1, twopi2;
+    float32 posneg1, twoto63;
+    flag adjn, endflag;
+
+    aSig = extractFloatx80Frac(a);
+    aExp = extractFloatx80Exp(a);
+    aSign = extractFloatx80Sign(a);
+
+    if (aExp == 0x7FFF) {
+        if ((uint64_t) (aSig << 1)) {
+            return propagateFloatx80NaNOneArg(a, status);
+        }
+        float_raise(float_flag_invalid, status);
+        return floatx80_default_nan(status);
+    }
+
+    if (aExp == 0 && aSig == 0) {
+        return packFloatx80(aSign, 0, 0);
+    }
+
+    adjn = 0;
+
+    user_rnd_mode = status->float_rounding_mode;
+    user_rnd_prec = status->floatx80_rounding_precision;
+    status->float_rounding_mode = float_round_nearest_even;
+    status->floatx80_rounding_precision = 80;
+
+    compact = floatx80_make_compact(aExp, aSig);
+
+    fp0 = a;
+
+    if (compact < 0x3FD78000 || compact > 0x4004BC7E) {
+        /* 2^(-40) > |X| > 15 PI */
+        if (compact > 0x3FFF8000) { /* |X| >= 15 PI */
+            /* REDUCEX */
+            fp1 = packFloatx80(0, 0, 0);
+            if (compact == 0x7FFEFFFF) {
+                twopi1 = packFloatx80(aSign ^ 1, 0x7FFE,
+                                      LIT64(0xC90FDAA200000000));
+                twopi2 = packFloatx80(aSign ^ 1, 0x7FDC,
+                                      LIT64(0x85A308D300000000));
+                fp0 = floatx80_add(fp0, twopi1, status);
+                fp1 = fp0;
+                fp0 = floatx80_add(fp0, twopi2, status);
+                fp1 = floatx80_sub(fp1, fp0, status);
+                fp1 = floatx80_add(fp1, twopi2, status);
+            }
+        loop:
+            xSign = extractFloatx80Sign(fp0);
+            xExp = extractFloatx80Exp(fp0);
+            xExp -= 0x3FFF;
+            if (xExp <= 28) {
+                l = 0;
+                endflag = 1;
+            } else {
+                l = xExp - 27;
+                endflag = 0;
+            }
+            invtwopi = packFloatx80(0, 0x3FFE - l,
+                                    LIT64(0xA2F9836E4E44152A)); /* INVTWOPI */
+            twopi1 = packFloatx80(0, 0x3FFF + l, LIT64(0xC90FDAA200000000));
+            twopi2 = packFloatx80(0, 0x3FDD + l, LIT64(0x85A308D300000000));
+
+            /* SIGN(INARG)*2^63 IN SGL */
+            twoto63 = packFloat32(xSign, 0xBE, 0);
+
+            fp2 = floatx80_mul(fp0, invtwopi, status);
+            fp2 = floatx80_add(fp2, float32_to_floatx80(twoto63, status),
+                               status); /* THE FRACT PART OF FP2 IS ROUNDED */
+            fp2 = floatx80_sub(fp2, float32_to_floatx80(twoto63, status),
+                               status); /* FP2 is N */
+            fp4 = floatx80_mul(twopi1, fp2, status); /* W = N*P1 */
+            fp5 = floatx80_mul(twopi2, fp2, status); /* w = N*P2 */
+            fp3 = floatx80_add(fp4, fp5, status); /* FP3 is P */
+            fp4 = floatx80_sub(fp4, fp3, status); /* W-P */
+            fp0 = floatx80_sub(fp0, fp3, status); /* FP0 is A := R - P */
+            fp4 = floatx80_add(fp4, fp5, status); /* FP4 is p = (W-P)+w */
+            fp3 = fp0; /* FP3 is A */
+            fp1 = floatx80_sub(fp1, fp4, status); /* FP1 is a := r - p */
+            fp0 = floatx80_add(fp0, fp1, status); /* FP0 is R := A+a */
+
+            if (endflag > 0) {
+                n = floatx80_to_int32(fp2, status);
+                goto sincont;
+            }
+            fp3 = floatx80_sub(fp3, fp0, status); /* A-R */
+            fp1 = floatx80_add(fp1, fp3, status); /* FP1 is r := (A-R)+a */
+            goto loop;
+        } else {
+            /* SINSM */
+            fp0 = float32_to_floatx80(make_float32(0x3F800000),
+                                      status); /* 1 */
+
+            status->float_rounding_mode = user_rnd_mode;
+            status->floatx80_rounding_precision = user_rnd_prec;
+
+            if (adjn) {
+                /* COSTINY */
+                a = floatx80_sub(fp0, float32_to_floatx80(
+                                 make_float32(0x00800000), status), status);
+            } else {
+                /* SINTINY */
+                a = floatx80_move(a, status);
+            }
+            float_raise(float_flag_inexact, status);
+
+            return a;
+        }
+    } else {
+        fp1 = floatx80_mul(fp0, float64_to_floatx80(
+                           make_float64(0x3FE45F306DC9C883), status),
+                           status); /* X*2/PI */
+
+        n = floatx80_to_int32(fp1, status);
+        j = 32 + n;
+
+        fp0 = floatx80_sub(fp0, pi_tbl[j], status); /* X-Y1 */
+        fp0 = floatx80_sub(fp0, float32_to_floatx80(pi_tbl2[j], status),
+                           status); /* FP0 IS R = (X-Y1)-Y2 */
+
+    sincont:
+        if ((n + adjn) & 1) {
+            /* COSPOLY */
+            fp0 = floatx80_mul(fp0, fp0, status); /* FP0 IS S */
+            fp1 = floatx80_mul(fp0, fp0, status); /* FP1 IS T */
+            fp2 = float64_to_floatx80(make_float64(0x3D2AC4D0D6011EE3),
+                                      status); /* B8 */
+            fp3 = float64_to_floatx80(make_float64(0xBDA9396F9F45AC19),
+                                      status); /* B7 */
+
+            xSign = extractFloatx80Sign(fp0); /* X IS S */
+            xExp = extractFloatx80Exp(fp0);
+            xSig = extractFloatx80Frac(fp0);
+
+            if (((n + adjn) >> 1) & 1) {
+                xSign ^= 1;
+                posneg1 = make_float32(0xBF800000); /* -1 */
+            } else {
+                xSign ^= 0;
+                posneg1 = make_float32(0x3F800000); /* 1 */
+            } /* X IS NOW R'= SGN*R */
+
+            fp2 = floatx80_mul(fp2, fp1, status); /* TB8 */
+            fp3 = floatx80_mul(fp3, fp1, status); /* TB7 */
+            fp2 = floatx80_add(fp2, float64_to_floatx80(
+                               make_float64(0x3E21EED90612C972), status),
+                               status); /* B6+TB8 */
+            fp3 = floatx80_add(fp3, float64_to_floatx80(
+                               make_float64(0xBE927E4FB79D9FCF), status),
+                               status); /* B5+TB7 */
+            fp2 = floatx80_mul(fp2, fp1, status); /* T(B6+TB8) */
+            fp3 = floatx80_mul(fp3, fp1, status); /* T(B5+TB7) */
+            fp2 = floatx80_add(fp2, float64_to_floatx80(
+                               make_float64(0x3EFA01A01A01D423), status),
+                               status); /* B4+T(B6+TB8) */
+            fp4 = packFloatx80(1, 0x3FF5, LIT64(0xB60B60B60B61D438));
+            fp3 = floatx80_add(fp3, fp4, status); /* B3+T(B5+TB7) */
+            fp2 = floatx80_mul(fp2, fp1, status); /* T(B4+T(B6+TB8)) */
+            fp1 = floatx80_mul(fp1, fp3, status); /* T(B3+T(B5+TB7)) */
+            fp4 = packFloatx80(0, 0x3FFA, LIT64(0xAAAAAAAAAAAAAB5E));
+            fp2 = floatx80_add(fp2, fp4, status); /* B2+T(B4+T(B6+TB8)) */
+            fp1 = floatx80_add(fp1, float32_to_floatx80(
+                               make_float32(0xBF000000), status),
+                               status); /* B1+T(B3+T(B5+TB7)) */
+            fp0 = floatx80_mul(fp0, fp2, status); /* S(B2+T(B4+T(B6+TB8))) */
+            fp0 = floatx80_add(fp0, fp1, status); /* [B1+T(B3+T(B5+TB7))]+
+                                                   * [S(B2+T(B4+T(B6+TB8)))]
+                                                   */
+
+            x = packFloatx80(xSign, xExp, xSig);
+            fp0 = floatx80_mul(fp0, x, status);
+
+            status->float_rounding_mode = user_rnd_mode;
+            status->floatx80_rounding_precision = user_rnd_prec;
+
+            a = floatx80_add(fp0, float32_to_floatx80(posneg1, status), status);
+
+            float_raise(float_flag_inexact, status);
+
+            return a;
+        } else {
+            /* SINPOLY */
+            xSign = extractFloatx80Sign(fp0); /* X IS R */
+            xExp = extractFloatx80Exp(fp0);
+            xSig = extractFloatx80Frac(fp0);
+
+            xSign ^= ((n + adjn) >> 1) & 1; /* X IS NOW R'= SGN*R */
+
+            fp0 = floatx80_mul(fp0, fp0, status); /* FP0 IS S */
+            fp1 = floatx80_mul(fp0, fp0, status); /* FP1 IS T */
+            fp3 = float64_to_floatx80(make_float64(0xBD6AAA77CCC994F5),
+                                      status); /* A7 */
+            fp2 = float64_to_floatx80(make_float64(0x3DE612097AAE8DA1),
+                                      status); /* A6 */
+            fp3 = floatx80_mul(fp3, fp1, status); /* T*A7 */
+            fp2 = floatx80_mul(fp2, fp1, status); /* T*A6 */
+            fp3 = floatx80_add(fp3, float64_to_floatx80(
+                               make_float64(0xBE5AE6452A118AE4), status),
+                               status); /* A5+T*A7 */
+            fp2 = floatx80_add(fp2, float64_to_floatx80(
+                               make_float64(0x3EC71DE3A5341531), status),
+                               status); /* A4+T*A6 */
+            fp3 = floatx80_mul(fp3, fp1, status); /* T(A5+TA7) */
+            fp2 = floatx80_mul(fp2, fp1, status); /* T(A4+TA6) */
+            fp3 = floatx80_add(fp3, float64_to_floatx80(
+                               make_float64(0xBF2A01A01A018B59), status),
+                               status); /* A3+T(A5+TA7) */
+            fp4 = packFloatx80(0, 0x3FF8, LIT64(0x88888888888859AF));
+            fp2 = floatx80_add(fp2, fp4, status); /* A2+T(A4+TA6) */
+            fp1 = floatx80_mul(fp1, fp3, status); /* T(A3+T(A5+TA7)) */
+            fp2 = floatx80_mul(fp2, fp0, status); /* S(A2+T(A4+TA6)) */
+            fp4 = packFloatx80(1, 0x3FFC, LIT64(0xAAAAAAAAAAAAAA99));
+            fp1 = floatx80_add(fp1, fp4, status); /* A1+T(A3+T(A5+TA7)) */
+            fp1 = floatx80_add(fp1, fp2,
+                               status); /* [A1+T(A3+T(A5+TA7))]+
+                                         * [S(A2+T(A4+TA6))]
+                                         */
+
+            x = packFloatx80(xSign, xExp, xSig);
+            fp0 = floatx80_mul(fp0, x, status); /* R'*S */
+            fp0 = floatx80_mul(fp0, fp1, status); /* SIN(R')-R' */
+
+            status->float_rounding_mode = user_rnd_mode;
+            status->floatx80_rounding_precision = user_rnd_prec;
+
+            a = floatx80_add(fp0, x, status);
+
+            float_raise(float_flag_inexact, status);
+
+            return a;
+        }
+    }
+}
diff --git a/target/m68k/softfloat.h b/target/m68k/softfloat.h
index c5ac54d87b..e8ccf69ba8 100644
--- a/target/m68k/softfloat.h
+++ b/target/m68k/softfloat.h
@@ -35,4 +35,5 @@ floatx80 floatx80_etox(floatx80 a, float_status *status);
 floatx80 floatx80_twotox(floatx80 a, float_status *status);
 floatx80 floatx80_tentox(floatx80 a, float_status *status);
 floatx80 floatx80_tan(floatx80 a, float_status *status);
+floatx80 floatx80_sin(floatx80 a, float_status *status);
 #endif
diff --git a/target/m68k/translate.c b/target/m68k/translate.c
index af8cdc2580..05ab75e43f 100644
--- a/target/m68k/translate.c
+++ b/target/m68k/translate.c
@@ -5057,6 +5057,9 @@ DISAS_INSN(fpu)
     case 0x06: /* flognp1 */
         gen_helper_flognp1(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;
-- 
2.14.3


[Qemu-devel] [PATCH 03/11] target/m68k: implement fcos
Posted by Laurent Vivier, 14 weeks ago
Using a local m68k floatx80_cos()
[copied from previous:
Written by Andreas Grabher for Previous, NeXT Computer Emulator.]

Signed-off-by: Laurent Vivier <laurent@vivier.eu>
---
 target/m68k/fpu_helper.c |   5 +
 target/m68k/helper.h     |   1 +
 target/m68k/softfloat.c  | 244 +++++++++++++++++++++++++++++++++++++++++++++++
 target/m68k/softfloat.h  |   1 +
 target/m68k/translate.c  |   3 +
 5 files changed, 254 insertions(+)

diff --git a/target/m68k/fpu_helper.c b/target/m68k/fpu_helper.c
index a6cfb4db1a..71df19c685 100644
--- a/target/m68k/fpu_helper.c
+++ b/target/m68k/fpu_helper.c
@@ -602,3 +602,8 @@ void HELPER(fsin)(CPUM68KState *env, FPReg *res, FPReg *val)
 {
     res->d = floatx80_sin(val->d, &env->fp_status);
 }
+
+void HELPER(fcos)(CPUM68KState *env, FPReg *res, FPReg *val)
+{
+    res->d = floatx80_cos(val->d, &env->fp_status);
+}
diff --git a/target/m68k/helper.h b/target/m68k/helper.h
index 6d8bfaab64..767baf75a3 100644
--- a/target/m68k/helper.h
+++ b/target/m68k/helper.h
@@ -77,6 +77,7 @@ DEF_HELPER_3(ftwotox, void, env, fp, fp)
 DEF_HELPER_3(ftentox, void, env, fp, fp)
 DEF_HELPER_3(ftan, void, env, fp, fp)
 DEF_HELPER_3(fsin, void, env, fp, fp)
+DEF_HELPER_3(fcos, void, env, fp, fp)
 
 DEF_HELPER_3(mac_move, void, env, i32, i32)
 DEF_HELPER_3(macmulf, i64, env, i32, i32)
diff --git a/target/m68k/softfloat.c b/target/m68k/softfloat.c
index 6fb9665336..a3a12a0bcb 100644
--- a/target/m68k/softfloat.c
+++ b/target/m68k/softfloat.c
@@ -1723,3 +1723,247 @@ floatx80 floatx80_sin(floatx80 a, float_status *status)
         }
     }
 }
+
+/*----------------------------------------------------------------------------
+ | Cosine
+ *----------------------------------------------------------------------------*/
+
+floatx80 floatx80_cos(floatx80 a, float_status *status)
+{
+    flag aSign, xSign;
+    int32_t aExp, xExp;
+    uint64_t aSig, xSig;
+
+    int8_t user_rnd_mode, user_rnd_prec;
+
+    int32_t compact, l, n, j;
+    floatx80 fp0, fp1, fp2, fp3, fp4, fp5, x, invtwopi, twopi1, twopi2;
+    float32 posneg1, twoto63;
+    flag adjn, endflag;
+
+    aSig = extractFloatx80Frac(a);
+    aExp = extractFloatx80Exp(a);
+    aSign = extractFloatx80Sign(a);
+
+    if (aExp == 0x7FFF) {
+        if ((uint64_t) (aSig << 1)) {
+            return propagateFloatx80NaNOneArg(a, status);
+        }
+        float_raise(float_flag_invalid, status);
+        return floatx80_default_nan(status);
+    }
+
+    if (aExp == 0 && aSig == 0) {
+        return packFloatx80(0, one_exp, one_sig);
+    }
+
+    adjn = 1;
+
+    user_rnd_mode = status->float_rounding_mode;
+    user_rnd_prec = status->floatx80_rounding_precision;
+    status->float_rounding_mode = float_round_nearest_even;
+    status->floatx80_rounding_precision = 80;
+
+    compact = floatx80_make_compact(aExp, aSig);
+
+    fp0 = a;
+
+    if (compact < 0x3FD78000 || compact > 0x4004BC7E) {
+        /* 2^(-40) > |X| > 15 PI */
+        if (compact > 0x3FFF8000) { /* |X| >= 15 PI */
+            /* REDUCEX */
+            fp1 = packFloatx80(0, 0, 0);
+            if (compact == 0x7FFEFFFF) {
+                twopi1 = packFloatx80(aSign ^ 1, 0x7FFE,
+                                      LIT64(0xC90FDAA200000000));
+                twopi2 = packFloatx80(aSign ^ 1, 0x7FDC,
+                                      LIT64(0x85A308D300000000));
+                fp0 = floatx80_add(fp0, twopi1, status);
+                fp1 = fp0;
+                fp0 = floatx80_add(fp0, twopi2, status);
+                fp1 = floatx80_sub(fp1, fp0, status);
+                fp1 = floatx80_add(fp1, twopi2, status);
+            }
+        loop:
+            xSign = extractFloatx80Sign(fp0);
+            xExp = extractFloatx80Exp(fp0);
+            xExp -= 0x3FFF;
+            if (xExp <= 28) {
+                l = 0;
+                endflag = 1;
+            } else {
+                l = xExp - 27;
+                endflag = 0;
+            }
+            invtwopi = packFloatx80(0, 0x3FFE - l,
+                                    LIT64(0xA2F9836E4E44152A)); /* INVTWOPI */
+            twopi1 = packFloatx80(0, 0x3FFF + l, LIT64(0xC90FDAA200000000));
+            twopi2 = packFloatx80(0, 0x3FDD + l, LIT64(0x85A308D300000000));
+
+            /* SIGN(INARG)*2^63 IN SGL */
+            twoto63 = packFloat32(xSign, 0xBE, 0);
+
+            fp2 = floatx80_mul(fp0, invtwopi, status);
+            fp2 = floatx80_add(fp2, float32_to_floatx80(twoto63, status),
+                               status); /* THE FRACT PART OF FP2 IS ROUNDED */
+            fp2 = floatx80_sub(fp2, float32_to_floatx80(twoto63, status),
+                               status); /* FP2 is N */
+            fp4 = floatx80_mul(twopi1, fp2, status); /* W = N*P1 */
+            fp5 = floatx80_mul(twopi2, fp2, status); /* w = N*P2 */
+            fp3 = floatx80_add(fp4, fp5, status); /* FP3 is P */
+            fp4 = floatx80_sub(fp4, fp3, status); /* W-P */
+            fp0 = floatx80_sub(fp0, fp3, status); /* FP0 is A := R - P */
+            fp4 = floatx80_add(fp4, fp5, status); /* FP4 is p = (W-P)+w */
+            fp3 = fp0; /* FP3 is A */
+            fp1 = floatx80_sub(fp1, fp4, status); /* FP1 is a := r - p */
+            fp0 = floatx80_add(fp0, fp1, status); /* FP0 is R := A+a */
+
+            if (endflag > 0) {
+                n = floatx80_to_int32(fp2, status);
+                goto sincont;
+            }
+            fp3 = floatx80_sub(fp3, fp0, status); /* A-R */
+            fp1 = floatx80_add(fp1, fp3, status); /* FP1 is r := (A-R)+a */
+            goto loop;
+        } else {
+            /* SINSM */
+            fp0 = float32_to_floatx80(make_float32(0x3F800000), status); /* 1 */
+
+            status->float_rounding_mode = user_rnd_mode;
+            status->floatx80_rounding_precision = user_rnd_prec;
+
+            if (adjn) {
+                /* COSTINY */
+                a = floatx80_sub(fp0, float32_to_floatx80(
+                                 make_float32(0x00800000), status),
+                                 status);
+            } else {
+                /* SINTINY */
+                a = floatx80_move(a, status);
+            }
+            float_raise(float_flag_inexact, status);
+
+            return a;
+        }
+    } else {
+        fp1 = floatx80_mul(fp0, float64_to_floatx80(
+                           make_float64(0x3FE45F306DC9C883), status),
+                           status); /* X*2/PI */
+
+        n = floatx80_to_int32(fp1, status);
+        j = 32 + n;
+
+        fp0 = floatx80_sub(fp0, pi_tbl[j], status); /* X-Y1 */
+        fp0 = floatx80_sub(fp0, float32_to_floatx80(pi_tbl2[j], status),
+                           status); /* FP0 IS R = (X-Y1)-Y2 */
+
+    sincont:
+        if ((n + adjn) & 1) {
+            /* COSPOLY */
+            fp0 = floatx80_mul(fp0, fp0, status); /* FP0 IS S */
+            fp1 = floatx80_mul(fp0, fp0, status); /* FP1 IS T */
+            fp2 = float64_to_floatx80(make_float64(0x3D2AC4D0D6011EE3),
+                                      status); /* B8 */
+            fp3 = float64_to_floatx80(make_float64(0xBDA9396F9F45AC19),
+                                      status); /* B7 */
+
+            xSign = extractFloatx80Sign(fp0); /* X IS S */
+            xExp = extractFloatx80Exp(fp0);
+            xSig = extractFloatx80Frac(fp0);
+
+            if (((n + adjn) >> 1) & 1) {
+                xSign ^= 1;
+                posneg1 = make_float32(0xBF800000); /* -1 */
+            } else {
+                xSign ^= 0;
+                posneg1 = make_float32(0x3F800000); /* 1 */
+            } /* X IS NOW R'= SGN*R */
+
+            fp2 = floatx80_mul(fp2, fp1, status); /* TB8 */
+            fp3 = floatx80_mul(fp3, fp1, status); /* TB7 */
+            fp2 = floatx80_add(fp2, float64_to_floatx80(
+                               make_float64(0x3E21EED90612C972), status),
+                               status); /* B6+TB8 */
+            fp3 = floatx80_add(fp3, float64_to_floatx80(
+                               make_float64(0xBE927E4FB79D9FCF), status),
+                               status); /* B5+TB7 */
+            fp2 = floatx80_mul(fp2, fp1, status); /* T(B6+TB8) */
+            fp3 = floatx80_mul(fp3, fp1, status); /* T(B5+TB7) */
+            fp2 = floatx80_add(fp2, float64_to_floatx80(
+                               make_float64(0x3EFA01A01A01D423), status),
+                               status); /* B4+T(B6+TB8) */
+            fp4 = packFloatx80(1, 0x3FF5, LIT64(0xB60B60B60B61D438));
+            fp3 = floatx80_add(fp3, fp4, status); /* B3+T(B5+TB7) */
+            fp2 = floatx80_mul(fp2, fp1, status); /* T(B4+T(B6+TB8)) */
+            fp1 = floatx80_mul(fp1, fp3, status); /* T(B3+T(B5+TB7)) */
+            fp4 = packFloatx80(0, 0x3FFA, LIT64(0xAAAAAAAAAAAAAB5E));
+            fp2 = floatx80_add(fp2, fp4, status); /* B2+T(B4+T(B6+TB8)) */
+            fp1 = floatx80_add(fp1, float32_to_floatx80(
+                               make_float32(0xBF000000), status),
+                               status); /* B1+T(B3+T(B5+TB7)) */
+            fp0 = floatx80_mul(fp0, fp2, status); /* S(B2+T(B4+T(B6+TB8))) */
+            fp0 = floatx80_add(fp0, fp1, status);
+                              /* [B1+T(B3+T(B5+TB7))]+[S(B2+T(B4+T(B6+TB8)))] */
+
+            x = packFloatx80(xSign, xExp, xSig);
+            fp0 = floatx80_mul(fp0, x, status);
+
+            status->float_rounding_mode = user_rnd_mode;
+            status->floatx80_rounding_precision = user_rnd_prec;
+
+            a = floatx80_add(fp0, float32_to_floatx80(posneg1, status), status);
+
+            float_raise(float_flag_inexact, status);
+
+            return a;
+        } else {
+            /* SINPOLY */
+            xSign = extractFloatx80Sign(fp0); /* X IS R */
+            xExp = extractFloatx80Exp(fp0);
+            xSig = extractFloatx80Frac(fp0);
+
+            xSign ^= ((n + adjn) >> 1) & 1; /* X IS NOW R'= SGN*R */
+
+            fp0 = floatx80_mul(fp0, fp0, status); /* FP0 IS S */
+            fp1 = floatx80_mul(fp0, fp0, status); /* FP1 IS T */
+            fp3 = float64_to_floatx80(make_float64(0xBD6AAA77CCC994F5),
+                                      status); /* A7 */
+            fp2 = float64_to_floatx80(make_float64(0x3DE612097AAE8DA1),
+                                      status); /* A6 */
+            fp3 = floatx80_mul(fp3, fp1, status); /* T*A7 */
+            fp2 = floatx80_mul(fp2, fp1, status); /* T*A6 */
+            fp3 = floatx80_add(fp3, float64_to_floatx80(
+                               make_float64(0xBE5AE6452A118AE4), status),
+                               status); /* A5+T*A7 */
+            fp2 = floatx80_add(fp2, float64_to_floatx80(
+                               make_float64(0x3EC71DE3A5341531), status),
+                               status); /* A4+T*A6 */
+            fp3 = floatx80_mul(fp3, fp1, status); /* T(A5+TA7) */
+            fp2 = floatx80_mul(fp2, fp1, status); /* T(A4+TA6) */
+            fp3 = floatx80_add(fp3, float64_to_floatx80(
+                               make_float64(0xBF2A01A01A018B59), status),
+                               status); /* A3+T(A5+TA7) */
+            fp4 = packFloatx80(0, 0x3FF8, LIT64(0x88888888888859AF));
+            fp2 = floatx80_add(fp2, fp4, status); /* A2+T(A4+TA6) */
+            fp1 = floatx80_mul(fp1, fp3, status); /* T(A3+T(A5+TA7)) */
+            fp2 = floatx80_mul(fp2, fp0, status); /* S(A2+T(A4+TA6)) */
+            fp4 = packFloatx80(1, 0x3FFC, LIT64(0xAAAAAAAAAAAAAA99));
+            fp1 = floatx80_add(fp1, fp4, status); /* A1+T(A3+T(A5+TA7)) */
+            fp1 = floatx80_add(fp1, fp2, status);
+                                    /* [A1+T(A3+T(A5+TA7))]+[S(A2+T(A4+TA6))] */
+
+            x = packFloatx80(xSign, xExp, xSig);
+            fp0 = floatx80_mul(fp0, x, status); /* R'*S */
+            fp0 = floatx80_mul(fp0, fp1, status); /* SIN(R')-R' */
+
+            status->float_rounding_mode = user_rnd_mode;
+            status->floatx80_rounding_precision = user_rnd_prec;
+
+            a = floatx80_add(fp0, x, status);
+
+            float_raise(float_flag_inexact, status);
+
+            return a;
+        }
+    }
+}
diff --git a/target/m68k/softfloat.h b/target/m68k/softfloat.h
index e8ccf69ba8..4fd5b2c609 100644
--- a/target/m68k/softfloat.h
+++ b/target/m68k/softfloat.h
@@ -36,4 +36,5 @@ floatx80 floatx80_twotox(floatx80 a, float_status *status);
 floatx80 floatx80_tentox(floatx80 a, float_status *status);
 floatx80 floatx80_tan(floatx80 a, float_status *status);
 floatx80 floatx80_sin(floatx80 a, float_status *status);
+floatx80 floatx80_cos(floatx80 a, float_status *status);
 #endif
diff --git a/target/m68k/translate.c b/target/m68k/translate.c
index 05ab75e43f..f47388da4b 100644
--- a/target/m68k/translate.c
+++ b/target/m68k/translate.c
@@ -5099,6 +5099,9 @@ DISAS_INSN(fpu)
     case 0x5e: /* fdneg */
         gen_helper_fdneg(cpu_env, cpu_dest, cpu_src);
         break;
+    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;
-- 
2.14.3


[Qemu-devel] [PATCH 04/11] target/m68k: implement fsincos
Posted by Laurent Vivier, 14 weeks ago
using floatx80_sin() and floatx80_cos()

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

diff --git a/target/m68k/fpu_helper.c b/target/m68k/fpu_helper.c
index 71df19c685..36e34d42a8 100644
--- a/target/m68k/fpu_helper.c
+++ b/target/m68k/fpu_helper.c
@@ -607,3 +607,14 @@ void HELPER(fcos)(CPUM68KState *env, FPReg *res, FPReg *val)
 {
     res->d = floatx80_cos(val->d, &env->fp_status);
 }
+
+void HELPER(fsincos)(CPUM68KState *env, FPReg *res0, FPReg *res1, FPReg *val)
+{
+    floatx80 a = val->d;
+    /* 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 = floatx80_cos(a, &env->fp_status);
+    res0->d = floatx80_sin(a, &env->fp_status);
+}
diff --git a/target/m68k/helper.h b/target/m68k/helper.h
index 767baf75a3..a168ffbaea 100644
--- a/target/m68k/helper.h
+++ b/target/m68k/helper.h
@@ -78,6 +78,7 @@ DEF_HELPER_3(ftentox, void, env, fp, fp)
 DEF_HELPER_3(ftan, void, env, fp, fp)
 DEF_HELPER_3(fsin, 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 f47388da4b..a78edd8825 100644
--- a/target/m68k/translate.c
+++ b/target/m68k/translate.c
@@ -5159,6 +5159,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;
-- 
2.14.3


[Qemu-devel] [PATCH 05/11] target/m68k: implement fatan
Posted by Laurent Vivier, 14 weeks ago
Using a local m68k floatx80_atan()
[copied from previous:
Written by Andreas Grabher for Previous, NeXT Computer Emulator.]

Signed-off-by: Laurent Vivier <laurent@vivier.eu>
---
 target/m68k/fpu_helper.c            |   5 +
 target/m68k/helper.h                |   1 +
 target/m68k/softfloat.c             | 200 ++++++++++++++++++++++++++++++++++++
 target/m68k/softfloat.h             |   1 +
 target/m68k/softfloat_fpsp_tables.h | 131 +++++++++++++++++++++++
 target/m68k/translate.c             |   3 +
 6 files changed, 341 insertions(+)

diff --git a/target/m68k/fpu_helper.c b/target/m68k/fpu_helper.c
index 36e34d42a8..47328490ee 100644
--- a/target/m68k/fpu_helper.c
+++ b/target/m68k/fpu_helper.c
@@ -618,3 +618,8 @@ void HELPER(fsincos)(CPUM68KState *env, FPReg *res0, FPReg *res1, FPReg *val)
     res1->d = floatx80_cos(a, &env->fp_status);
     res0->d = floatx80_sin(a, &env->fp_status);
 }
+
+void HELPER(fatan)(CPUM68KState *env, FPReg *res, FPReg *val)
+{
+    res->d = floatx80_atan(val->d, &env->fp_status);
+}
diff --git a/target/m68k/helper.h b/target/m68k/helper.h
index a168ffbaea..304569e997 100644
--- a/target/m68k/helper.h
+++ b/target/m68k/helper.h
@@ -79,6 +79,7 @@ DEF_HELPER_3(ftan, void, env, fp, fp)
 DEF_HELPER_3(fsin, void, env, fp, fp)
 DEF_HELPER_3(fcos, void, env, fp, fp)
 DEF_HELPER_4(fsincos, void, env, fp, fp, fp)
+DEF_HELPER_3(fatan, void, env, fp, fp)
 
 DEF_HELPER_3(mac_move, void, env, i32, i32)
 DEF_HELPER_3(macmulf, i64, env, i32, i32)
diff --git a/target/m68k/softfloat.c b/target/m68k/softfloat.c
index a3a12a0bcb..00ac9a1e0a 100644
--- a/target/m68k/softfloat.c
+++ b/target/m68k/softfloat.c
@@ -23,6 +23,9 @@
 #include "fpu/softfloat-macros.h"
 #include "softfloat_fpsp_tables.h"
 
+#define piby2_exp   0x3FFF
+#define pi_sig      LIT64(0xc90fdaa22168c235)
+
 static floatx80 propagateFloatx80NaNOneArg(floatx80 a, float_status *status)
 {
     if (floatx80_is_signaling_nan(a, status)) {
@@ -1967,3 +1970,200 @@ floatx80 floatx80_cos(floatx80 a, float_status *status)
         }
     }
 }
+
+/*----------------------------------------------------------------------------
+ | Arc tangent
+ *----------------------------------------------------------------------------*/
+
+floatx80 floatx80_atan(floatx80 a, float_status *status)
+{
+    flag aSign;
+    int32_t aExp;
+    uint64_t aSig;
+
+    int8_t user_rnd_mode, user_rnd_prec;
+
+    int32_t compact, tbl_index;
+    floatx80 fp0, fp1, fp2, fp3, xsave;
+
+    aSig = extractFloatx80Frac(a);
+    aExp = extractFloatx80Exp(a);
+    aSign = extractFloatx80Sign(a);
+
+    if (aExp == 0x7FFF) {
+        if ((uint64_t) (aSig << 1)) {
+            return propagateFloatx80NaNOneArg(a, status);
+        }
+        a = packFloatx80(aSign, piby2_exp, pi_sig);
+        float_raise(float_flag_inexact, status);
+        return floatx80_move(a, status);
+    }
+
+    if (aExp == 0 && aSig == 0) {
+        return packFloatx80(aSign, 0, 0);
+    }
+
+    compact = floatx80_make_compact(aExp, aSig);
+
+    user_rnd_mode = status->float_rounding_mode;
+    user_rnd_prec = status->floatx80_rounding_precision;
+    status->float_rounding_mode = float_round_nearest_even;
+    status->floatx80_rounding_precision = 80;
+
+    if (compact < 0x3FFB8000 || compact > 0x4002FFFF) {
+        /* |X| >= 16 or |X| < 1/16 */
+        if (compact > 0x3FFF8000) { /* |X| >= 16 */
+            if (compact > 0x40638000) { /* |X| > 2^(100) */
+                fp0 = packFloatx80(aSign, piby2_exp, pi_sig);
+                fp1 = packFloatx80(aSign, 0x0001, one_sig);
+
+                status->float_rounding_mode = user_rnd_mode;
+                status->floatx80_rounding_precision = user_rnd_prec;
+
+                a = floatx80_sub(fp0, fp1, status);
+
+                float_raise(float_flag_inexact, status);
+
+                return a;
+            } else {
+                fp0 = a;
+                fp1 = packFloatx80(1, one_exp, one_sig); /* -1 */
+                fp1 = floatx80_div(fp1, fp0, status); /* X' = -1/X */
+                xsave = fp1;
+                fp0 = floatx80_mul(fp1, fp1, status); /* Y = X'*X' */
+                fp1 = floatx80_mul(fp0, fp0, status); /* Z = Y*Y */
+                fp3 = float64_to_floatx80(make_float64(0xBFB70BF398539E6A),
+                                          status); /* C5 */
+                fp2 = float64_to_floatx80(make_float64(0x3FBC7187962D1D7D),
+                                          status); /* C4 */
+                fp3 = floatx80_mul(fp3, fp1, status); /* Z*C5 */
+                fp2 = floatx80_mul(fp2, fp1, status); /* Z*C4 */
+                fp3 = floatx80_add(fp3, float64_to_floatx80(
+                                   make_float64(0xBFC24924827107B8), status),
+                                   status); /* C3+Z*C5 */
+                fp2 = floatx80_add(fp2, float64_to_floatx80(
+                                   make_float64(0x3FC999999996263E), status),
+                                   status); /* C2+Z*C4 */
+                fp1 = floatx80_mul(fp1, fp3, status); /* Z*(C3+Z*C5) */
+                fp2 = floatx80_mul(fp2, fp0, status); /* Y*(C2+Z*C4) */
+                fp1 = floatx80_add(fp1, float64_to_floatx80(
+                                   make_float64(0xBFD5555555555536), status),
+                                   status); /* C1+Z*(C3+Z*C5) */
+                fp0 = floatx80_mul(fp0, xsave, status); /* X'*Y */
+                /* [Y*(C2+Z*C4)]+[C1+Z*(C3+Z*C5)] */
+                fp1 = floatx80_add(fp1, fp2, status);
+                /* X'*Y*([B1+Z*(B3+Z*B5)]+[Y*(B2+Z*(B4+Z*B6))]) ?? */
+                fp0 = floatx80_mul(fp0, fp1, status);
+                fp0 = floatx80_add(fp0, xsave, status);
+                fp1 = packFloatx80(aSign, piby2_exp, pi_sig);
+
+                status->float_rounding_mode = user_rnd_mode;
+                status->floatx80_rounding_precision = user_rnd_prec;
+
+                a = floatx80_add(fp0, fp1, status);
+
+                float_raise(float_flag_inexact, status);
+
+                return a;
+            }
+        } else { /* |X| < 1/16 */
+            if (compact < 0x3FD78000) { /* |X| < 2^(-40) */
+                status->float_rounding_mode = user_rnd_mode;
+                status->floatx80_rounding_precision = user_rnd_prec;
+
+                a = floatx80_move(a, status);
+
+                float_raise(float_flag_inexact, status);
+
+                return a;
+            } else {
+                fp0 = a;
+                xsave = a;
+                fp0 = floatx80_mul(fp0, fp0, status); /* Y = X*X */
+                fp1 = floatx80_mul(fp0, fp0, status); /* Z = Y*Y */
+                fp2 = float64_to_floatx80(make_float64(0x3FB344447F876989),
+                                          status); /* B6 */
+                fp3 = float64_to_floatx80(make_float64(0xBFB744EE7FAF45DB),
+                                          status); /* B5 */
+                fp2 = floatx80_mul(fp2, fp1, status); /* Z*B6 */
+                fp3 = floatx80_mul(fp3, fp1, status); /* Z*B5 */
+                fp2 = floatx80_add(fp2, float64_to_floatx80(
+                                   make_float64(0x3FBC71C646940220), status),
+                                   status); /* B4+Z*B6 */
+                fp3 = floatx80_add(fp3, float64_to_floatx80(
+                                   make_float64(0xBFC24924921872F9),
+                                   status), status); /* B3+Z*B5 */
+                fp2 = floatx80_mul(fp2, fp1, status); /* Z*(B4+Z*B6) */
+                fp1 = floatx80_mul(fp1, fp3, status); /* Z*(B3+Z*B5) */
+                fp2 = floatx80_add(fp2, float64_to_floatx80(
+                                   make_float64(0x3FC9999999998FA9), status),
+                                   status); /* B2+Z*(B4+Z*B6) */
+                fp1 = floatx80_add(fp1, float64_to_floatx80(
+                                   make_float64(0xBFD5555555555555), status),
+                                   status); /* B1+Z*(B3+Z*B5) */
+                fp2 = floatx80_mul(fp2, fp0, status); /* Y*(B2+Z*(B4+Z*B6)) */
+                fp0 = floatx80_mul(fp0, xsave, status); /* X*Y */
+                /* [B1+Z*(B3+Z*B5)]+[Y*(B2+Z*(B4+Z*B6))] */
+                fp1 = floatx80_add(fp1, fp2, status);
+                /* X*Y*([B1+Z*(B3+Z*B5)]+[Y*(B2+Z*(B4+Z*B6))]) */
+                fp0 = floatx80_mul(fp0, fp1, status);
+
+                status->float_rounding_mode = user_rnd_mode;
+                status->floatx80_rounding_precision = user_rnd_prec;
+
+                a = floatx80_add(fp0, xsave, status);
+
+                float_raise(float_flag_inexact, status);
+
+                return a;
+            }
+        }
+    } else {
+        aSig &= LIT64(0xF800000000000000);
+        aSig |= LIT64(0x0400000000000000);
+        xsave = packFloatx80(aSign, aExp, aSig); /* F */
+        fp0 = a;
+        fp1 = a; /* X */
+        fp2 = packFloatx80(0, one_exp, one_sig); /* 1 */
+        fp1 = floatx80_mul(fp1, xsave, status); /* X*F */
+        fp0 = floatx80_sub(fp0, xsave, status); /* X-F */
+        fp1 = floatx80_add(fp1, fp2, status); /* 1 + X*F */
+        fp0 = floatx80_div(fp0, fp1, status); /* U = (X-F)/(1+X*F) */
+
+        tbl_index = compact;
+
+        tbl_index &= 0x7FFF0000;
+        tbl_index -= 0x3FFB0000;
+        tbl_index >>= 1;
+        tbl_index += compact & 0x00007800;
+        tbl_index >>= 11;
+
+        fp3 = atan_tbl[tbl_index];
+
+        fp3.high |= aSign ? 0x8000 : 0; /* ATAN(F) */
+
+        fp1 = floatx80_mul(fp0, fp0, status); /* V = U*U */
+        fp2 = float64_to_floatx80(make_float64(0xBFF6687E314987D8),
+                                  status); /* A3 */
+        fp2 = floatx80_add(fp2, fp1, status); /* A3+V */
+        fp2 = floatx80_mul(fp2, fp1, status); /* V*(A3+V) */
+        fp1 = floatx80_mul(fp1, fp0, status); /* U*V */
+        fp2 = floatx80_add(fp2, float64_to_floatx80(
+                           make_float64(0x4002AC6934A26DB3), status),
+                           status); /* A2+V*(A3+V) */
+        fp1 = floatx80_mul(fp1, float64_to_floatx80(
+                           make_float64(0xBFC2476F4E1DA28E), status),
+                           status); /* A1+U*V */
+        fp1 = floatx80_mul(fp1, fp2, status); /* A1*U*V*(A2+V*(A3+V)) */
+        fp0 = floatx80_add(fp0, fp1, status); /* ATAN(U) */
+
+        status->float_rounding_mode = user_rnd_mode;
+        status->floatx80_rounding_precision = user_rnd_prec;
+
+        a = floatx80_add(fp0, fp3, status); /* ATAN(X) */
+
+        float_raise(float_flag_inexact, status);
+
+        return a;
+    }
+}
diff --git a/target/m68k/softfloat.h b/target/m68k/softfloat.h
index 4fd5b2c609..eec45f3ffe 100644
--- a/target/m68k/softfloat.h
+++ b/target/m68k/softfloat.h
@@ -37,4 +37,5 @@ floatx80 floatx80_tentox(floatx80 a, float_status *status);
 floatx80 floatx80_tan(floatx80 a, float_status *status);
 floatx80 floatx80_sin(floatx80 a, float_status *status);
 floatx80 floatx80_cos(floatx80 a, float_status *status);
+floatx80 floatx80_atan(floatx80 a, float_status *status);
 #endif
diff --git a/target/m68k/softfloat_fpsp_tables.h b/target/m68k/softfloat_fpsp_tables.h
index a9c86a5af2..3f1419ee6e 100644
--- a/target/m68k/softfloat_fpsp_tables.h
+++ b/target/m68k/softfloat_fpsp_tables.h
@@ -507,4 +507,135 @@ static const float32 pi_tbl2[65] = {
     const_float32(0x20D00000),
     const_float32(0xA1800000),
 };
+
+static const floatx80 atan_tbl[128] = {
+    make_floatx80_init(0x3FFB, 0x83D152C5060B7A51),
+    make_floatx80_init(0x3FFB, 0x8BC8544565498B8B),
+    make_floatx80_init(0x3FFB, 0x93BE406017626B0D),
+    make_floatx80_init(0x3FFB, 0x9BB3078D35AEC202),
+    make_floatx80_init(0x3FFB, 0xA3A69A525DDCE7DE),
+    make_floatx80_init(0x3FFB, 0xAB98E94362765619),
+    make_floatx80_init(0x3FFB, 0xB389E502F9C59862),
+    make_floatx80_init(0x3FFB, 0xBB797E436B09E6FB),
+    make_floatx80_init(0x3FFB, 0xC367A5C739E5F446),
+    make_floatx80_init(0x3FFB, 0xCB544C61CFF7D5C6),
+    make_floatx80_init(0x3FFB, 0xD33F62F82488533E),
+    make_floatx80_init(0x3FFB, 0xDB28DA8162404C77),
+    make_floatx80_init(0x3FFB, 0xE310A4078AD34F18),
+    make_floatx80_init(0x3FFB, 0xEAF6B0A8188EE1EB),
+    make_floatx80_init(0x3FFB, 0xF2DAF1949DBE79D5),
+    make_floatx80_init(0x3FFB, 0xFABD581361D47E3E),
+    make_floatx80_init(0x3FFC, 0x8346AC210959ECC4),
+    make_floatx80_init(0x3FFC, 0x8B232A08304282D8),
+    make_floatx80_init(0x3FFC, 0x92FB70B8D29AE2F9),
+    make_floatx80_init(0x3FFC, 0x9ACF476F5CCD1CB4),
+    make_floatx80_init(0x3FFC, 0xA29E76304954F23F),
+    make_floatx80_init(0x3FFC, 0xAA68C5D08AB85230),
+    make_floatx80_init(0x3FFC, 0xB22DFFFD9D539F83),
+    make_floatx80_init(0x3FFC, 0xB9EDEF453E900EA5),
+    make_floatx80_init(0x3FFC, 0xC1A85F1CC75E3EA5),
+    make_floatx80_init(0x3FFC, 0xC95D1BE828138DE6),
+    make_floatx80_init(0x3FFC, 0xD10BF300840D2DE4),
+    make_floatx80_init(0x3FFC, 0xD8B4B2BA6BC05E7A),
+    make_floatx80_init(0x3FFC, 0xE0572A6BB42335F6),
+    make_floatx80_init(0x3FFC, 0xE7F32A70EA9CAA8F),
+    make_floatx80_init(0x3FFC, 0xEF88843264ECEFAA),
+    make_floatx80_init(0x3FFC, 0xF7170A28ECC06666),
+    make_floatx80_init(0x3FFD, 0x812FD288332DAD32),
+    make_floatx80_init(0x3FFD, 0x88A8D1B1218E4D64),
+    make_floatx80_init(0x3FFD, 0x9012AB3F23E4AEE8),
+    make_floatx80_init(0x3FFD, 0x976CC3D411E7F1B9),
+    make_floatx80_init(0x3FFD, 0x9EB689493889A227),
+    make_floatx80_init(0x3FFD, 0xA5EF72C34487361B),
+    make_floatx80_init(0x3FFD, 0xAD1700BAF07A7227),
+    make_floatx80_init(0x3FFD, 0xB42CBCFAFD37EFB7),
+    make_floatx80_init(0x3FFD, 0xBB303A940BA80F89),
+    make_floatx80_init(0x3FFD, 0xC22115C6FCAEBBAF),
+    make_floatx80_init(0x3FFD, 0xC8FEF3E686331221),
+    make_floatx80_init(0x3FFD, 0xCFC98330B4000C70),
+    make_floatx80_init(0x3FFD, 0xD6807AA1102C5BF9),
+    make_floatx80_init(0x3FFD, 0xDD2399BC31252AA3),
+    make_floatx80_init(0x3FFD, 0xE3B2A8556B8FC517),
+    make_floatx80_init(0x3FFD, 0xEA2D764F64315989),
+    make_floatx80_init(0x3FFD, 0xF3BF5BF8BAD1A21D),
+    make_floatx80_init(0x3FFE, 0x801CE39E0D205C9A),
+    make_floatx80_init(0x3FFE, 0x8630A2DADA1ED066),
+    make_floatx80_init(0x3FFE, 0x8C1AD445F3E09B8C),
+    make_floatx80_init(0x3FFE, 0x91DB8F1664F350E2),
+    make_floatx80_init(0x3FFE, 0x97731420365E538C),
+    make_floatx80_init(0x3FFE, 0x9CE1C8E6A0B8CDBA),
+    make_floatx80_init(0x3FFE, 0xA22832DBCADAAE09),
+    make_floatx80_init(0x3FFE, 0xA746F2DDB7602294),
+    make_floatx80_init(0x3FFE, 0xAC3EC0FB997DD6A2),
+    make_floatx80_init(0x3FFE, 0xB110688AEBDC6F6A),
+    make_floatx80_init(0x3FFE, 0xB5BCC49059ECC4B0),
+    make_floatx80_init(0x3FFE, 0xBA44BC7DD470782F),
+    make_floatx80_init(0x3FFE, 0xBEA94144FD049AAC),
+    make_floatx80_init(0x3FFE, 0xC2EB4ABB661628B6),
+    make_floatx80_init(0x3FFE, 0xC70BD54CE602EE14),
+    make_floatx80_init(0x3FFE, 0xCD000549ADEC7159),
+    make_floatx80_init(0x3FFE, 0xD48457D2D8EA4EA3),
+    make_floatx80_init(0x3FFE, 0xDB948DA712DECE3B),
+    make_floatx80_init(0x3FFE, 0xE23855F969E8096A),
+    make_floatx80_init(0x3FFE, 0xE8771129C4353259),
+    make_floatx80_init(0x3FFE, 0xEE57C16E0D379C0D),
+    make_floatx80_init(0x3FFE, 0xF3E10211A87C3779),
+    make_floatx80_init(0x3FFE, 0xF919039D758B8D41),
+    make_floatx80_init(0x3FFE, 0xFE058B8F64935FB3),
+    make_floatx80_init(0x3FFF, 0x8155FB497B685D04),
+    make_floatx80_init(0x3FFF, 0x83889E3549D108E1),
+    make_floatx80_init(0x3FFF, 0x859CFA76511D724B),
+    make_floatx80_init(0x3FFF, 0x87952ECFFF8131E7),
+    make_floatx80_init(0x3FFF, 0x89732FD19557641B),
+    make_floatx80_init(0x3FFF, 0x8B38CAD101932A35),
+    make_floatx80_init(0x3FFF, 0x8CE7A8D8301EE6B5),
+    make_floatx80_init(0x3FFF, 0x8F46A39E2EAE5281),
+    make_floatx80_init(0x3FFF, 0x922DA7D791888487),
+    make_floatx80_init(0x3FFF, 0x94D19FCBDEDF5241),
+    make_floatx80_init(0x3FFF, 0x973AB94419D2A08B),
+    make_floatx80_init(0x3FFF, 0x996FF00E08E10B96),
+    make_floatx80_init(0x3FFF, 0x9B773F9512321DA7),
+    make_floatx80_init(0x3FFF, 0x9D55CC320F935624),
+    make_floatx80_init(0x3FFF, 0x9F100575006CC571),
+    make_floatx80_init(0x3FFF, 0xA0A9C290D97CC06C),
+    make_floatx80_init(0x3FFF, 0xA22659EBEBC0630A),
+    make_floatx80_init(0x3FFF, 0xA388B4AFF6EF0EC9),
+    make_floatx80_init(0x3FFF, 0xA4D35F1061D292C4),
+    make_floatx80_init(0x3FFF, 0xA60895DCFBE3187E),
+    make_floatx80_init(0x3FFF, 0xA72A51DC7367BEAC),
+    make_floatx80_init(0x3FFF, 0xA83A51530956168F),
+    make_floatx80_init(0x3FFF, 0xA93A20077539546E),
+    make_floatx80_init(0x3FFF, 0xAA9E7245023B2605),
+    make_floatx80_init(0x3FFF, 0xAC4C84BA6FE4D58F),
+    make_floatx80_init(0x3FFF, 0xADCE4A4A606B9712),
+    make_floatx80_init(0x3FFF, 0xAF2A2DCD8D263C9C),
+    make_floatx80_init(0x3FFF, 0xB0656F81F22265C7),
+    make_floatx80_init(0x3FFF, 0xB18465150F71496A),
+    make_floatx80_init(0x3FFF, 0xB28AAA156F9ADA35),
+    make_floatx80_init(0x3FFF, 0xB37B44FF3766B895),
+    make_floatx80_init(0x3FFF, 0xB458C3DCE9630433),
+    make_floatx80_init(0x3FFF, 0xB525529D562246BD),
+    make_floatx80_init(0x3FFF, 0xB5E2CCA95F9D88CC),
+    make_floatx80_init(0x3FFF, 0xB692CADA7ACA1ADA),
+    make_floatx80_init(0x3FFF, 0xB736AEA7A6925838),
+    make_floatx80_init(0x3FFF, 0xB7CFAB287E9F7B36),
+    make_floatx80_init(0x3FFF, 0xB85ECC66CB219835),
+    make_floatx80_init(0x3FFF, 0xB8E4FD5A20A593DA),
+    make_floatx80_init(0x3FFF, 0xB99F41F64AFF9BB5),
+    make_floatx80_init(0x3FFF, 0xBA7F1E17842BBE7B),
+    make_floatx80_init(0x3FFF, 0xBB4712857637E17D),
+    make_floatx80_init(0x3FFF, 0xBBFABE8A4788DF6F),
+    make_floatx80_init(0x3FFF, 0xBC9D0FAD2B689D79),
+    make_floatx80_init(0x3FFF, 0xBD306A39471ECD86),
+    make_floatx80_init(0x3FFF, 0xBDB6C731856AF18A),
+    make_floatx80_init(0x3FFF, 0xBE31CAC502E80D70),
+    make_floatx80_init(0x3FFF, 0xBEA2D55CE33194E2),
+    make_floatx80_init(0x3FFF, 0xBF0B10B7C03128F0),
+    make_floatx80_init(0x3FFF, 0xBF6B7A18DACB778D),
+    make_floatx80_init(0x3FFF, 0xBFC4EA4663FA18F6),
+    make_floatx80_init(0x3FFF, 0xC0181BDE8B89A454),
+    make_floatx80_init(0x3FFF, 0xC065B066CFBF6439),
+    make_floatx80_init(0x3FFF, 0xC0AE345F56340AE6),
+    make_floatx80_init(0x3FFF, 0xC0F222919CB9E6A7)
+};
 #endif
diff --git a/target/m68k/translate.c b/target/m68k/translate.c
index a78edd8825..88015e7ed8 100644
--- a/target/m68k/translate.c
+++ b/target/m68k/translate.c
@@ -5057,6 +5057,9 @@ DISAS_INSN(fpu)
     case 0x06: /* flognp1 */
         gen_helper_flognp1(cpu_env, cpu_dest, cpu_src);
         break;
+    case 0x0a: /* fatan */
+        gen_helper_fatan(cpu_env, cpu_dest, cpu_src);
+        break;
     case 0x0e: /* fsin */
         gen_helper_fsin(cpu_env, cpu_dest, cpu_src);
         break;
-- 
2.14.3


[Qemu-devel] [PATCH 06/11] target/m68k: implement fasin
Posted by Laurent Vivier, 14 weeks ago
Using a local m68k floatx80_asin()
[copied from previous:
Written by Andreas Grabher for Previous, NeXT Computer Emulator.]

Signed-off-by: Laurent Vivier <laurent@vivier.eu>
---
 target/m68k/fpu_helper.c |  5 ++++
 target/m68k/helper.h     |  1 +
 target/m68k/softfloat.c  | 65 ++++++++++++++++++++++++++++++++++++++++++++++++
 target/m68k/softfloat.h  |  1 +
 target/m68k/translate.c  |  3 +++
 5 files changed, 75 insertions(+)

diff --git a/target/m68k/fpu_helper.c b/target/m68k/fpu_helper.c
index 47328490ee..972cc97d96 100644
--- a/target/m68k/fpu_helper.c
+++ b/target/m68k/fpu_helper.c
@@ -623,3 +623,8 @@ void HELPER(fatan)(CPUM68KState *env, FPReg *res, FPReg *val)
 {
     res->d = floatx80_atan(val->d, &env->fp_status);
 }
+
+void HELPER(fasin)(CPUM68KState *env, FPReg *res, FPReg *val)
+{
+    res->d = floatx80_asin(val->d, &env->fp_status);
+}
diff --git a/target/m68k/helper.h b/target/m68k/helper.h
index 304569e997..e1aca375e0 100644
--- a/target/m68k/helper.h
+++ b/target/m68k/helper.h
@@ -80,6 +80,7 @@ DEF_HELPER_3(fsin, void, env, fp, fp)
 DEF_HELPER_3(fcos, void, env, fp, fp)
 DEF_HELPER_4(fsincos, void, env, fp, fp, fp)
 DEF_HELPER_3(fatan, void, env, fp, fp)
+DEF_HELPER_3(fasin, void, env, fp, fp)
 
 DEF_HELPER_3(mac_move, void, env, i32, i32)
 DEF_HELPER_3(macmulf, i64, env, i32, i32)
diff --git a/target/m68k/softfloat.c b/target/m68k/softfloat.c
index 00ac9a1e0a..91f0435ac3 100644
--- a/target/m68k/softfloat.c
+++ b/target/m68k/softfloat.c
@@ -2167,3 +2167,68 @@ floatx80 floatx80_atan(floatx80 a, float_status *status)
         return a;
     }
 }
+
+/*----------------------------------------------------------------------------
+ | Arc sine
+ *----------------------------------------------------------------------------*/
+
+floatx80 floatx80_asin(floatx80 a, float_status *status)
+{
+    flag aSign;
+    int32_t aExp;
+    uint64_t aSig;
+
+    int8_t user_rnd_mode, user_rnd_prec;
+
+    int32_t compact;
+    floatx80 fp0, fp1, fp2, one;
+
+    aSig = extractFloatx80Frac(a);
+    aExp = extractFloatx80Exp(a);
+    aSign = extractFloatx80Sign(a);
+
+    if (aExp == 0x7FFF && (uint64_t) (aSig << 1)) {
+        return propagateFloatx80NaNOneArg(a, status);
+    }
+
+    if (aExp == 0 && aSig == 0) {
+        return packFloatx80(aSign, 0, 0);
+    }
+
+    compact = floatx80_make_compact(aExp, aSig);
+
+    if (compact >= 0x3FFF8000) { /* |X| >= 1 */
+        if (aExp == one_exp && aSig == one_sig) { /* |X| == 1 */
+            float_raise(float_flag_inexact, status);
+            a = packFloatx80(aSign, piby2_exp, pi_sig);
+            return floatx80_move(a, status);
+        } else { /* |X| > 1 */
+            float_raise(float_flag_invalid, status);
+            return floatx80_default_nan(status);
+        }
+
+    } /* |X| < 1 */
+
+    user_rnd_mode = status->float_rounding_mode;
+    user_rnd_prec = status->floatx80_rounding_precision;
+    status->float_rounding_mode = float_round_nearest_even;
+    status->floatx80_rounding_precision = 80;
+
+    one = packFloatx80(0, one_exp, one_sig);
+    fp0 = a;
+
+    fp1 = floatx80_sub(one, fp0, status);   /* 1 - X */
+    fp2 = floatx80_add(one, fp0, status);   /* 1 + X */
+    fp1 = floatx80_mul(fp2, fp1, status);   /* (1+X)*(1-X) */
+    fp1 = floatx80_sqrt(fp1, status);       /* SQRT((1+X)*(1-X)) */
+    fp0 = floatx80_div(fp0, fp1, status);   /* X/SQRT((1+X)*(1-X)) */
+
+    status->float_rounding_mode = user_rnd_mode;
+    status->floatx80_rounding_precision = user_rnd_prec;
+
+    a = floatx80_atan(fp0, status);         /* ATAN(X/SQRT((1+X)*(1-X))) */
+
+    float_raise(float_flag_inexact, status);
+
+    return a;
+}
diff --git a/target/m68k/softfloat.h b/target/m68k/softfloat.h
index eec45f3ffe..ca0eb674aa 100644
--- a/target/m68k/softfloat.h
+++ b/target/m68k/softfloat.h
@@ -38,4 +38,5 @@ floatx80 floatx80_tan(floatx80 a, float_status *status);
 floatx80 floatx80_sin(floatx80 a, float_status *status);
 floatx80 floatx80_cos(floatx80 a, float_status *status);
 floatx80 floatx80_atan(floatx80 a, float_status *status);
+floatx80 floatx80_asin(floatx80 a, float_status *status);
 #endif
diff --git a/target/m68k/translate.c b/target/m68k/translate.c
index 88015e7ed8..d4169c4533 100644
--- a/target/m68k/translate.c
+++ b/target/m68k/translate.c
@@ -5060,6 +5060,9 @@ DISAS_INSN(fpu)
     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 0x0e: /* fsin */
         gen_helper_fsin(cpu_env, cpu_dest, cpu_src);
         break;
-- 
2.14.3


[Qemu-devel] [PATCH 07/11] target/m68k: implement facos
Posted by Laurent Vivier, 14 weeks ago
Using a local m68k floatx80_acos()
[copied from previous:
Written by Andreas Grabher for Previous, NeXT Computer Emulator.]

Signed-off-by: Laurent Vivier <laurent@vivier.eu>
---
 target/m68k/fpu_helper.c |  5 ++++
 target/m68k/helper.h     |  1 +
 target/m68k/softfloat.c  | 70 ++++++++++++++++++++++++++++++++++++++++++++++++
 target/m68k/softfloat.h  |  1 +
 target/m68k/translate.c  |  3 +++
 5 files changed, 80 insertions(+)

diff --git a/target/m68k/fpu_helper.c b/target/m68k/fpu_helper.c
index 972cc97d96..18ad6999cb 100644
--- a/target/m68k/fpu_helper.c
+++ b/target/m68k/fpu_helper.c
@@ -628,3 +628,8 @@ void HELPER(fasin)(CPUM68KState *env, FPReg *res, FPReg *val)
 {
     res->d = floatx80_asin(val->d, &env->fp_status);
 }
+
+void HELPER(facos)(CPUM68KState *env, FPReg *res, FPReg *val)
+{
+    res->d = floatx80_acos(val->d, &env->fp_status);
+}
diff --git a/target/m68k/helper.h b/target/m68k/helper.h
index e1aca375e0..83247a8143 100644
--- a/target/m68k/helper.h
+++ b/target/m68k/helper.h
@@ -81,6 +81,7 @@ DEF_HELPER_3(fcos, void, env, fp, fp)
 DEF_HELPER_4(fsincos, void, env, fp, fp, fp)
 DEF_HELPER_3(fatan, void, env, fp, fp)
 DEF_HELPER_3(fasin, void, env, fp, fp)
+DEF_HELPER_3(facos, void, env, fp, fp)
 
 DEF_HELPER_3(mac_move, void, env, i32, i32)
 DEF_HELPER_3(macmulf, i64, env, i32, i32)
diff --git a/target/m68k/softfloat.c b/target/m68k/softfloat.c
index 91f0435ac3..3d66f6946f 100644
--- a/target/m68k/softfloat.c
+++ b/target/m68k/softfloat.c
@@ -23,6 +23,7 @@
 #include "fpu/softfloat-macros.h"
 #include "softfloat_fpsp_tables.h"
 
+#define pi_exp      0x4000
 #define piby2_exp   0x3FFF
 #define pi_sig      LIT64(0xc90fdaa22168c235)
 
@@ -2232,3 +2233,72 @@ floatx80 floatx80_asin(floatx80 a, float_status *status)
 
     return a;
 }
+
+/*----------------------------------------------------------------------------
+ | Arc cosine
+ *----------------------------------------------------------------------------*/
+
+floatx80 floatx80_acos(floatx80 a, float_status *status)
+{
+    flag aSign;
+    int32_t aExp;
+    uint64_t aSig;
+
+    int8_t user_rnd_mode, user_rnd_prec;
+
+    int32_t compact;
+    floatx80 fp0, fp1, one;
+
+    aSig = extractFloatx80Frac(a);
+    aExp = extractFloatx80Exp(a);
+    aSign = extractFloatx80Sign(a);
+
+    if (aExp == 0x7FFF && (uint64_t) (aSig << 1)) {
+        return propagateFloatx80NaNOneArg(a, status);
+    }
+    if (aExp == 0 && aSig == 0) {
+        float_raise(float_flag_inexact, status);
+        return roundAndPackFloatx80(status->floatx80_rounding_precision, 0,
+                                    piby2_exp, pi_sig, 0, status);
+    }
+
+    compact = floatx80_make_compact(aExp, aSig);
+
+    if (compact >= 0x3FFF8000) { /* |X| >= 1 */
+        if (aExp == one_exp && aSig == one_sig) { /* |X| == 1 */
+            if (aSign) { /* X == -1 */
+                a = packFloatx80(0, pi_exp, pi_sig);
+                float_raise(float_flag_inexact, status);
+                return floatx80_move(a, status);
+            } else { /* X == +1 */
+                return packFloatx80(0, 0, 0);
+            }
+        } else { /* |X| > 1 */
+            float_raise(float_flag_invalid, status);
+            return floatx80_default_nan(status);
+        }
+    } /* |X| < 1 */
+
+    user_rnd_mode = status->float_rounding_mode;
+    user_rnd_prec = status->floatx80_rounding_precision;
+    status->float_rounding_mode = float_round_nearest_even;
+    status->floatx80_rounding_precision = 80;
+
+    one = packFloatx80(0, one_exp, one_sig);
+    fp0 = a;
+
+    fp1 = floatx80_add(one, fp0, status);   /* 1 + X */
+    fp0 = floatx80_sub(one, fp0, status);   /* 1 - X */
+    fp0 = floatx80_div(fp0, fp1, status);   /* (1-X)/(1+X) */
+    fp0 = floatx80_sqrt(fp0, status);       /* SQRT((1-X)/(1+X)) */
+    fp0 = floatx80_atan(fp0, status);       /* ATAN(SQRT((1-X)/(1+X))) */
+
+    status->float_rounding_mode = user_rnd_mode;
+    status->floatx80_rounding_precision = user_rnd_prec;
+
+    a = floatx80_add(fp0, fp0, status);     /* 2 * ATAN(SQRT((1-X)/(1+X))) */
+
+    float_raise(float_flag_inexact, status);
+
+    return a;
+}
diff --git a/target/m68k/softfloat.h b/target/m68k/softfloat.h
index ca0eb674aa..1140491c81 100644
--- a/target/m68k/softfloat.h
+++ b/target/m68k/softfloat.h
@@ -39,4 +39,5 @@ floatx80 floatx80_sin(floatx80 a, float_status *status);
 floatx80 floatx80_cos(floatx80 a, float_status *status);
 floatx80 floatx80_atan(floatx80 a, float_status *status);
 floatx80 floatx80_asin(floatx80 a, float_status *status);
+floatx80 floatx80_acos(floatx80 a, float_status *status);
 #endif
diff --git a/target/m68k/translate.c b/target/m68k/translate.c
index d4169c4533..5fad76c785 100644
--- a/target/m68k/translate.c
+++ b/target/m68k/translate.c
@@ -5105,6 +5105,9 @@ 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;
-- 
2.14.3


[Qemu-devel] [PATCH 08/11] target/m68k: implement fatanh
Posted by Laurent Vivier, 14 weeks ago
Using a local m68k floatx80_atanh()
[copied from previous:
Written by Andreas Grabher for Previous, NeXT Computer Emulator.]

Signed-off-by: Laurent Vivier <laurent@vivier.eu>
---
 target/m68k/fpu_helper.c |  5 ++++
 target/m68k/helper.h     |  1 +
 target/m68k/softfloat.c  | 65 ++++++++++++++++++++++++++++++++++++++++++++++++
 target/m68k/softfloat.h  |  1 +
 target/m68k/translate.c  |  3 +++
 5 files changed, 75 insertions(+)

diff --git a/target/m68k/fpu_helper.c b/target/m68k/fpu_helper.c
index 18ad6999cb..38b663e1d2 100644
--- a/target/m68k/fpu_helper.c
+++ b/target/m68k/fpu_helper.c
@@ -633,3 +633,8 @@ void HELPER(facos)(CPUM68KState *env, FPReg *res, FPReg *val)
 {
     res->d = floatx80_acos(val->d, &env->fp_status);
 }
+
+void HELPER(fatanh)(CPUM68KState *env, FPReg *res, FPReg *val)
+{
+    res->d = floatx80_atanh(val->d, &env->fp_status);
+}
diff --git a/target/m68k/helper.h b/target/m68k/helper.h
index 83247a8143..092baec3d5 100644
--- a/target/m68k/helper.h
+++ b/target/m68k/helper.h
@@ -82,6 +82,7 @@ DEF_HELPER_4(fsincos, void, env, fp, fp, fp)
 DEF_HELPER_3(fatan, void, env, fp, fp)
 DEF_HELPER_3(fasin, void, env, fp, fp)
 DEF_HELPER_3(facos, void, env, fp, fp)
+DEF_HELPER_3(fatanh, void, env, fp, fp)
 
 DEF_HELPER_3(mac_move, void, env, i32, i32)
 DEF_HELPER_3(macmulf, i64, env, i32, i32)
diff --git a/target/m68k/softfloat.c b/target/m68k/softfloat.c
index 3d66f6946f..5ce8413e96 100644
--- a/target/m68k/softfloat.c
+++ b/target/m68k/softfloat.c
@@ -2302,3 +2302,68 @@ floatx80 floatx80_acos(floatx80 a, float_status *status)
 
     return a;
 }
+
+/*----------------------------------------------------------------------------
+ | Hyperbolic arc tangent
+ *----------------------------------------------------------------------------*/
+
+floatx80 floatx80_atanh(floatx80 a, float_status *status)
+{
+    flag aSign;
+    int32_t aExp;
+    uint64_t aSig;
+
+    int8_t user_rnd_mode, user_rnd_prec;
+
+    int32_t compact;
+    floatx80 fp0, fp1, fp2, one;
+
+    aSig = extractFloatx80Frac(a);
+    aExp = extractFloatx80Exp(a);
+    aSign = extractFloatx80Sign(a);
+
+    if (aExp == 0x7FFF && (uint64_t) (aSig << 1)) {
+        return propagateFloatx80NaNOneArg(a, status);
+    }
+
+    if (aExp == 0 && aSig == 0) {
+        return packFloatx80(aSign, 0, 0);
+    }
+
+    compact = floatx80_make_compact(aExp, aSig);
+
+    if (compact >= 0x3FFF8000) { /* |X| >= 1 */
+        if (aExp == one_exp && aSig == one_sig) { /* |X| == 1 */
+            float_raise(float_flag_divbyzero, status);
+            return packFloatx80(aSign, floatx80_infinity.high,
+                                floatx80_infinity.low);
+        } else { /* |X| > 1 */
+            float_raise(float_flag_invalid, status);
+            return floatx80_default_nan(status);
+        }
+    } /* |X| < 1 */
+
+    user_rnd_mode = status->float_rounding_mode;
+    user_rnd_prec = status->floatx80_rounding_precision;
+    status->float_rounding_mode = float_round_nearest_even;
+    status->floatx80_rounding_precision = 80;
+
+    one = packFloatx80(0, one_exp, one_sig);
+    fp2 = packFloatx80(aSign, 0x3FFE, one_sig); /* SIGN(X) * (1/2) */
+    fp0 = packFloatx80(0, aExp, aSig); /* Y = |X| */
+    fp1 = packFloatx80(1, aExp, aSig); /* -Y */
+    fp0 = floatx80_add(fp0, fp0, status); /* 2Y */
+    fp1 = floatx80_add(fp1, one, status); /* 1-Y */
+    fp0 = floatx80_div(fp0, fp1, status); /* Z = 2Y/(1-Y) */
+    fp0 = floatx80_lognp1(fp0, status); /* LOG1P(Z) */
+
+    status->float_rounding_mode = user_rnd_mode;
+    status->floatx80_rounding_precision = user_rnd_prec;
+
+    a = floatx80_mul(fp0, fp2,
+                     status); /* ATANH(X) = SIGN(X) * (1/2) * LOG1P(Z) */
+
+    float_raise(float_flag_inexact, status);
+
+    return a;
+}
diff --git a/target/m68k/softfloat.h b/target/m68k/softfloat.h
index 1140491c81..e9943aed20 100644
--- a/target/m68k/softfloat.h
+++ b/target/m68k/softfloat.h
@@ -40,4 +40,5 @@ floatx80 floatx80_cos(floatx80 a, float_status *status);
 floatx80 floatx80_atan(floatx80 a, float_status *status);
 floatx80 floatx80_asin(floatx80 a, float_status *status);
 floatx80 floatx80_acos(floatx80 a, float_status *status);
+floatx80 floatx80_atanh(floatx80 a, float_status *status);
 #endif
diff --git a/target/m68k/translate.c b/target/m68k/translate.c
index 5fad76c785..2f7caa0ca0 100644
--- a/target/m68k/translate.c
+++ b/target/m68k/translate.c
@@ -5063,6 +5063,9 @@ DISAS_INSN(fpu)
     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;
-- 
2.14.3


[Qemu-devel] [PATCH 09/11] target/m68k: implement ftanh
Posted by Laurent Vivier, 14 weeks ago
Using local m68k floatx80_tanh() and floatx80_etoxm1()
[copied from previous:
Written by Andreas Grabher for Previous, NeXT Computer Emulator.]

Signed-off-by: Laurent Vivier <laurent@vivier.eu>
---
 target/m68k/fpu_helper.c |   5 +
 target/m68k/helper.h     |   1 +
 target/m68k/softfloat.c  | 366 +++++++++++++++++++++++++++++++++++++++++++++++
 target/m68k/softfloat.h  |   2 +
 target/m68k/translate.c  |   3 +
 5 files changed, 377 insertions(+)

diff --git a/target/m68k/fpu_helper.c b/target/m68k/fpu_helper.c
index 38b663e1d2..7d68879f34 100644
--- a/target/m68k/fpu_helper.c
+++ b/target/m68k/fpu_helper.c
@@ -638,3 +638,8 @@ void HELPER(fatanh)(CPUM68KState *env, FPReg *res, FPReg *val)
 {
     res->d = floatx80_atanh(val->d, &env->fp_status);
 }
+
+void HELPER(ftanh)(CPUM68KState *env, FPReg *res, FPReg *val)
+{
+    res->d = floatx80_tanh(val->d, &env->fp_status);
+}
diff --git a/target/m68k/helper.h b/target/m68k/helper.h
index 092baec3d5..f100141367 100644
--- a/target/m68k/helper.h
+++ b/target/m68k/helper.h
@@ -83,6 +83,7 @@ DEF_HELPER_3(fatan, void, env, fp, fp)
 DEF_HELPER_3(fasin, void, env, fp, fp)
 DEF_HELPER_3(facos, void, env, fp, fp)
 DEF_HELPER_3(fatanh, void, env, fp, fp)
+DEF_HELPER_3(ftanh, void, env, fp, fp)
 
 DEF_HELPER_3(mac_move, void, env, i32, i32)
 DEF_HELPER_3(macmulf, i64, env, i32, i32)
diff --git a/target/m68k/softfloat.c b/target/m68k/softfloat.c
index 5ce8413e96..4ce5783f03 100644
--- a/target/m68k/softfloat.c
+++ b/target/m68k/softfloat.c
@@ -2367,3 +2367,369 @@ floatx80 floatx80_atanh(floatx80 a, float_status *status)
 
     return a;
 }
+
+/*----------------------------------------------------------------------------
+ | e to x minus 1
+ *----------------------------------------------------------------------------*/
+
+floatx80 floatx80_etoxm1(floatx80 a, float_status *status)
+{
+    flag aSign;
+    int32_t aExp;
+    uint64_t aSig;
+
+    int8_t user_rnd_mode, user_rnd_prec;
+
+    int32_t compact, n, j, m, m1;
+    floatx80 fp0, fp1, fp2, fp3, l2, sc, onebysc;
+
+    aSig = extractFloatx80Frac(a);
+    aExp = extractFloatx80Exp(a);
+    aSign = extractFloatx80Sign(a);
+
+    if (aExp == 0x7FFF) {
+        if ((uint64_t) (aSig << 1)) {
+            return propagateFloatx80NaNOneArg(a, status);
+        }
+        if (aSign) {
+            return packFloatx80(aSign, one_exp, one_sig);
+        }
+        return packFloatx80(0, floatx80_infinity.high,
+                            floatx80_infinity.low);
+    }
+
+    if (aExp == 0 && aSig == 0) {
+        return packFloatx80(aSign, 0, 0);
+    }
+
+    user_rnd_mode = status->float_rounding_mode;
+    user_rnd_prec = status->floatx80_rounding_precision;
+    status->float_rounding_mode = float_round_nearest_even;
+    status->floatx80_rounding_precision = 80;
+
+    if (aExp >= 0x3FFD) { /* |X| >= 1/4 */
+        compact = floatx80_make_compact(aExp, aSig);
+
+        if (compact <= 0x4004C215) { /* |X| <= 70 log2 */
+            fp0 = a;
+            fp1 = a;
+            fp0 = floatx80_mul(fp0, float32_to_floatx80(
+                               make_float32(0x42B8AA3B), status),
+                               status); /* 64/log2 * X */
+            n = floatx80_to_int32(fp0, status); /* int(64/log2*X) */
+            fp0 = int32_to_floatx80(n, status);
+
+            j = n & 0x3F; /* J = N mod 64 */
+            m = n / 64; /* NOTE: this is really arithmetic right shift by 6 */
+            if (n < 0 && j) {
+                /* arithmetic right shift is division and
+                 * round towards minus infinity
+                 */
+                m--;
+            }
+            m1 = -m;
+            /*m += 0x3FFF; // biased exponent of 2^(M) */
+            /*m1 += 0x3FFF; // biased exponent of -2^(-M) */
+
+            fp2 = fp0; /* N */
+            fp0 = floatx80_mul(fp0, float32_to_floatx80(
+                               make_float32(0xBC317218), status),
+                               status); /* N * L1, L1 = lead(-log2/64) */
+            l2 = packFloatx80(0, 0x3FDC, LIT64(0x82E308654361C4C6));
+            fp2 = floatx80_mul(fp2, l2, status); /* N * L2, L1+L2 = -log2/64 */
+            fp0 = floatx80_add(fp0, fp1, status); /* X + N*L1 */
+            fp0 = floatx80_add(fp0, fp2, status); /* R */
+
+            fp1 = floatx80_mul(fp0, fp0, status); /* S = R*R */
+            fp2 = float32_to_floatx80(make_float32(0x3950097B),
+                                      status); /* A6 */
+            fp2 = floatx80_mul(fp2, fp1, status); /* fp2 is S*A6 */
+            fp3 = floatx80_mul(float32_to_floatx80(make_float32(0x3AB60B6A),
+                               status), fp1, status); /* fp3 is S*A5 */
+            fp2 = floatx80_add(fp2, float64_to_floatx80(
+                               make_float64(0x3F81111111174385), status),
+                               status); /* fp2 IS A4+S*A6 */
+            fp3 = floatx80_add(fp3, float64_to_floatx80(
+                               make_float64(0x3FA5555555554F5A), status),
+                               status); /* fp3 is A3+S*A5 */
+            fp2 = floatx80_mul(fp2, fp1, status); /* fp2 IS S*(A4+S*A6) */
+            fp3 = floatx80_mul(fp3, fp1, status); /* fp3 IS S*(A3+S*A5) */
+            fp2 = floatx80_add(fp2, float64_to_floatx80(
+                               make_float64(0x3FC5555555555555), status),
+                               status); /* fp2 IS A2+S*(A4+S*A6) */
+            fp3 = floatx80_add(fp3, float32_to_floatx80(
+                               make_float32(0x3F000000), status),
+                               status); /* fp3 IS A1+S*(A3+S*A5) */
+            fp2 = floatx80_mul(fp2, fp1,
+                               status); /* fp2 IS S*(A2+S*(A4+S*A6)) */
+            fp1 = floatx80_mul(fp1, fp3,
+                               status); /* fp1 IS S*(A1+S*(A3+S*A5)) */
+            fp2 = floatx80_mul(fp2, fp0,
+                               status); /* fp2 IS R*S*(A2+S*(A4+S*A6)) */
+            fp0 = floatx80_add(fp0, fp1,
+                               status); /* fp0 IS R+S*(A1+S*(A3+S*A5)) */
+            fp0 = floatx80_add(fp0, fp2, status); /* fp0 IS EXP(R) - 1 */
+
+            fp0 = floatx80_mul(fp0, exp_tbl[j],
+                               status); /* 2^(J/64)*(Exp(R)-1) */
+
+            if (m >= 64) {
+                fp1 = float32_to_floatx80(exp_tbl2[j], status);
+                onebysc = packFloatx80(1, m1 + 0x3FFF, one_sig); /* -2^(-M) */
+                fp1 = floatx80_add(fp1, onebysc, status);
+                fp0 = floatx80_add(fp0, fp1, status);
+                fp0 = floatx80_add(fp0, exp_tbl[j], status);
+            } else if (m < -3) {
+                fp0 = floatx80_add(fp0, float32_to_floatx80(exp_tbl2[j],
+                                   status), status);
+                fp0 = floatx80_add(fp0, exp_tbl[j], status);
+                onebysc = packFloatx80(1, m1 + 0x3FFF, one_sig); /* -2^(-M) */
+                fp0 = floatx80_add(fp0, onebysc, status);
+            } else { /* -3 <= m <= 63 */
+                fp1 = exp_tbl[j];
+                fp0 = floatx80_add(fp0, float32_to_floatx80(exp_tbl2[j],
+                                   status), status);
+                onebysc = packFloatx80(1, m1 + 0x3FFF, one_sig); /* -2^(-M) */
+                fp1 = floatx80_add(fp1, onebysc, status);
+                fp0 = floatx80_add(fp0, fp1, status);
+            }
+
+            sc = packFloatx80(0, m + 0x3FFF, one_sig);
+
+            status->float_rounding_mode = user_rnd_mode;
+            status->floatx80_rounding_precision = user_rnd_prec;
+
+            a = floatx80_mul(fp0, sc, status);
+
+            float_raise(float_flag_inexact, status);
+
+            return a;
+        } else { /* |X| > 70 log2 */
+            if (aSign) {
+                fp0 = float32_to_floatx80(make_float32(0xBF800000),
+                      status); /* -1 */
+
+                status->float_rounding_mode = user_rnd_mode;
+                status->floatx80_rounding_precision = user_rnd_prec;
+
+                a = floatx80_add(fp0, float32_to_floatx80(
+                                 make_float32(0x00800000), status),
+                                 status); /* -1 + 2^(-126) */
+
+                float_raise(float_flag_inexact, status);
+
+                return a;
+            } else {
+                status->float_rounding_mode = user_rnd_mode;
+                status->floatx80_rounding_precision = user_rnd_prec;
+
+                return floatx80_etox(a, status);
+            }
+        }
+    } else { /* |X| < 1/4 */
+        if (aExp >= 0x3FBE) {
+            fp0 = a;
+            fp0 = floatx80_mul(fp0, fp0, status); /* S = X*X */
+            fp1 = float32_to_floatx80(make_float32(0x2F30CAA8),
+                                      status); /* B12 */
+            fp1 = floatx80_mul(fp1, fp0, status); /* S * B12 */
+            fp2 = float32_to_floatx80(make_float32(0x310F8290),
+                                      status); /* B11 */
+            fp1 = floatx80_add(fp1, float32_to_floatx80(
+                               make_float32(0x32D73220), status),
+                               status); /* B10 */
+            fp2 = floatx80_mul(fp2, fp0, status);
+            fp1 = floatx80_mul(fp1, fp0, status);
+            fp2 = floatx80_add(fp2, float32_to_floatx80(
+                               make_float32(0x3493F281), status),
+                               status); /* B9 */
+            fp1 = floatx80_add(fp1, float64_to_floatx80(
+                               make_float64(0x3EC71DE3A5774682), status),
+                               status); /* B8 */
+            fp2 = floatx80_mul(fp2, fp0, status);
+            fp1 = floatx80_mul(fp1, fp0, status);
+            fp2 = floatx80_add(fp2, float64_to_floatx80(
+                               make_float64(0x3EFA01A019D7CB68), status),
+                               status); /* B7 */
+            fp1 = floatx80_add(fp1, float64_to_floatx80(
+                               make_float64(0x3F2A01A01A019DF3), status),
+                               status); /* B6 */
+            fp2 = floatx80_mul(fp2, fp0, status);
+            fp1 = floatx80_mul(fp1, fp0, status);
+            fp2 = floatx80_add(fp2, float64_to_floatx80(
+                               make_float64(0x3F56C16C16C170E2), status),
+                               status); /* B5 */
+            fp1 = floatx80_add(fp1, float64_to_floatx80(
+                               make_float64(0x3F81111111111111), status),
+                               status); /* B4 */
+            fp2 = floatx80_mul(fp2, fp0, status);
+            fp1 = floatx80_mul(fp1, fp0, status);
+            fp2 = floatx80_add(fp2, float64_to_floatx80(
+                               make_float64(0x3FA5555555555555), status),
+                               status); /* B3 */
+            fp3 = packFloatx80(0, 0x3FFC, LIT64(0xAAAAAAAAAAAAAAAB));
+            fp1 = floatx80_add(fp1, fp3, status); /* B2 */
+            fp2 = floatx80_mul(fp2, fp0, status);
+            fp1 = floatx80_mul(fp1, fp0, status);
+
+            fp2 = floatx80_mul(fp2, fp0, status);
+            fp1 = floatx80_mul(fp1, a, status);
+
+            fp0 = floatx80_mul(fp0, float32_to_floatx80(
+                               make_float32(0x3F000000), status),
+                               status); /* S*B1 */
+            fp1 = floatx80_add(fp1, fp2, status); /* Q */
+            fp0 = floatx80_add(fp0, fp1, status); /* S*B1+Q */
+
+            status->float_rounding_mode = user_rnd_mode;
+            status->floatx80_rounding_precision = user_rnd_prec;
+
+            a = floatx80_add(fp0, a, status);
+
+            float_raise(float_flag_inexact, status);
+
+            return a;
+        } else { /* |X| < 2^(-65) */
+            sc = packFloatx80(1, 1, one_sig);
+            fp0 = a;
+
+            if (aExp < 0x0033) { /* |X| < 2^(-16382) */
+                fp0 = floatx80_mul(fp0, float64_to_floatx80(
+                                   make_float64(0x48B0000000000000), status),
+                                   status);
+                fp0 = floatx80_add(fp0, sc, status);
+
+                status->float_rounding_mode = user_rnd_mode;
+                status->floatx80_rounding_precision = user_rnd_prec;
+
+                a = floatx80_mul(fp0, float64_to_floatx80(
+                                 make_float64(0x3730000000000000), status),
+                                 status);
+            } else {
+                status->float_rounding_mode = user_rnd_mode;
+                status->floatx80_rounding_precision = user_rnd_prec;
+
+                a = floatx80_add(fp0, sc, status);
+            }
+
+            float_raise(float_flag_inexact, status);
+
+            return a;
+        }
+    }
+}
+
+/*----------------------------------------------------------------------------
+ | Hyperbolic tangent
+ *----------------------------------------------------------------------------*/
+
+floatx80 floatx80_tanh(floatx80 a, float_status *status)
+{
+    flag aSign, vSign;
+    int32_t aExp, vExp;
+    uint64_t aSig, vSig;
+
+    int8_t user_rnd_mode, user_rnd_prec;
+
+    int32_t compact;
+    floatx80 fp0, fp1;
+    uint32_t sign;
+
+    aSig = extractFloatx80Frac(a);
+    aExp = extractFloatx80Exp(a);
+    aSign = extractFloatx80Sign(a);
+
+    if (aExp == 0x7FFF) {
+        if ((uint64_t) (aSig << 1)) {
+            return propagateFloatx80NaNOneArg(a, status);
+        }
+        return packFloatx80(aSign, one_exp, one_sig);
+    }
+
+    if (aExp == 0 && aSig == 0) {
+        return packFloatx80(aSign, 0, 0);
+    }
+
+    user_rnd_mode = status->float_rounding_mode;
+    user_rnd_prec = status->floatx80_rounding_precision;
+    status->float_rounding_mode = float_round_nearest_even;
+    status->floatx80_rounding_precision = 80;
+
+    compact = floatx80_make_compact(aExp, aSig);
+
+    if (compact < 0x3FD78000 || compact > 0x3FFFDDCE) {
+        /* TANHBORS */
+        if (compact < 0x3FFF8000) {
+            /* TANHSM */
+            status->float_rounding_mode = user_rnd_mode;
+            status->floatx80_rounding_precision = user_rnd_prec;
+
+            a = floatx80_move(a, status);
+
+            float_raise(float_flag_inexact, status);
+
+            return a;
+        } else {
+            if (compact > 0x40048AA1) {
+                /* TANHHUGE */
+                sign = 0x3F800000;
+                sign |= aSign ? 0x80000000 : 0x00000000;
+                fp0 = float32_to_floatx80(make_float32(sign), status);
+                sign &= 0x80000000;
+                sign ^= 0x80800000; /* -SIGN(X)*EPS */
+
+                status->float_rounding_mode = user_rnd_mode;
+                status->floatx80_rounding_precision = user_rnd_prec;
+
+                a = floatx80_add(fp0, float32_to_floatx80(make_float32(sign),
+                                 status), status);
+
+                float_raise(float_flag_inexact, status);
+
+                return a;
+            } else {
+                fp0 = packFloatx80(0, aExp + 1, aSig); /* Y = 2|X| */
+                fp0 = floatx80_etox(fp0, status); /* FP0 IS EXP(Y) */
+                fp0 = floatx80_add(fp0, float32_to_floatx80(
+                                   make_float32(0x3F800000),
+                                   status), status); /* EXP(Y)+1 */
+                sign = aSign ? 0x80000000 : 0x00000000;
+                fp1 = floatx80_div(float32_to_floatx80(make_float32(
+                                   sign ^ 0xC0000000), status), fp0,
+                                   status); /* -SIGN(X)*2 / [EXP(Y)+1] */
+                fp0 = float32_to_floatx80(make_float32(sign | 0x3F800000),
+                                          status); /* SIGN */
+
+                status->float_rounding_mode = user_rnd_mode;
+                status->floatx80_rounding_precision = user_rnd_prec;
+
+                a = floatx80_add(fp1, fp0, status);
+
+                float_raise(float_flag_inexact, status);
+
+                return a;
+            }
+        }
+    } else { /* 2**(-40) < |X| < (5/2)LOG2 */
+        fp0 = packFloatx80(0, aExp + 1, aSig); /* Y = 2|X| */
+        fp0 = floatx80_etoxm1(fp0, status); /* FP0 IS Z = EXPM1(Y) */
+        fp1 = floatx80_add(fp0, float32_to_floatx80(make_float32(0x40000000),
+                           status),
+                           status); /* Z+2 */
+
+        vSign = extractFloatx80Sign(fp1);
+        vExp = extractFloatx80Exp(fp1);
+        vSig = extractFloatx80Frac(fp1);
+
+        fp1 = packFloatx80(vSign ^ aSign, vExp, vSig);
+
+        status->float_rounding_mode = user_rnd_mode;
+        status->floatx80_rounding_precision = user_rnd_prec;
+
+        a = floatx80_div(fp0, fp1, status);
+
+        float_raise(float_flag_inexact, status);
+
+        return a;
+    }
+}
diff --git a/target/m68k/softfloat.h b/target/m68k/softfloat.h
index e9943aed20..4cdb5a49ca 100644
--- a/target/m68k/softfloat.h
+++ b/target/m68k/softfloat.h
@@ -41,4 +41,6 @@ floatx80 floatx80_atan(floatx80 a, float_status *status);
 floatx80 floatx80_asin(floatx80 a, float_status *status);
 floatx80 floatx80_acos(floatx80 a, float_status *status);
 floatx80 floatx80_atanh(floatx80 a, float_status *status);
+floatx80 floatx80_etoxm1(floatx80 a, float_status *status);
+floatx80 floatx80_tanh(floatx80 a, float_status *status);
 #endif
diff --git a/target/m68k/translate.c b/target/m68k/translate.c
index 2f7caa0ca0..0caae904b5 100644
--- a/target/m68k/translate.c
+++ b/target/m68k/translate.c
@@ -5057,6 +5057,9 @@ DISAS_INSN(fpu)
     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;
-- 
2.14.3


[Qemu-devel] [PATCH 10/11] target/m68k: implement fsinh
Posted by Laurent Vivier, 14 weeks ago
Using a local m68k floatx80_sinh()
[copied from previous:
Written by Andreas Grabher for Previous, NeXT Computer Emulator.]

Signed-off-by: Laurent Vivier <laurent@vivier.eu>
---
 target/m68k/fpu_helper.c |  5 +++
 target/m68k/helper.h     |  1 +
 target/m68k/softfloat.c  | 89 ++++++++++++++++++++++++++++++++++++++++++++++++
 target/m68k/softfloat.h  |  1 +
 target/m68k/translate.c  |  3 ++
 5 files changed, 99 insertions(+)

diff --git a/target/m68k/fpu_helper.c b/target/m68k/fpu_helper.c
index 7d68879f34..4c969dfe00 100644
--- a/target/m68k/fpu_helper.c
+++ b/target/m68k/fpu_helper.c
@@ -643,3 +643,8 @@ void HELPER(ftanh)(CPUM68KState *env, FPReg *res, FPReg *val)
 {
     res->d = floatx80_tanh(val->d, &env->fp_status);
 }
+
+void HELPER(fsinh)(CPUM68KState *env, FPReg *res, FPReg *val)
+{
+    res->d = floatx80_sinh(val->d, &env->fp_status);
+}
diff --git a/target/m68k/helper.h b/target/m68k/helper.h
index f100141367..acdca1af03 100644
--- a/target/m68k/helper.h
+++ b/target/m68k/helper.h
@@ -84,6 +84,7 @@ DEF_HELPER_3(fasin, void, env, fp, fp)
 DEF_HELPER_3(facos, void, env, fp, fp)
 DEF_HELPER_3(fatanh, void, env, fp, fp)
 DEF_HELPER_3(ftanh, void, env, fp, fp)
+DEF_HELPER_3(fsinh, void, env, fp, fp)
 
 DEF_HELPER_3(mac_move, void, env, i32, i32)
 DEF_HELPER_3(macmulf, i64, env, i32, i32)
diff --git a/target/m68k/softfloat.c b/target/m68k/softfloat.c
index 4ce5783f03..1528bfd147 100644
--- a/target/m68k/softfloat.c
+++ b/target/m68k/softfloat.c
@@ -2733,3 +2733,92 @@ floatx80 floatx80_tanh(floatx80 a, float_status *status)
         return a;
     }
 }
+
+/*----------------------------------------------------------------------------
+ | Hyperbolic sine
+ *----------------------------------------------------------------------------*/
+
+floatx80 floatx80_sinh(floatx80 a, float_status *status)
+{
+    flag aSign;
+    int32_t aExp;
+    uint64_t aSig;
+
+    int8_t user_rnd_mode, user_rnd_prec;
+
+    int32_t compact;
+    floatx80 fp0, fp1, fp2;
+    float32 fact;
+
+    aSig = extractFloatx80Frac(a);
+    aExp = extractFloatx80Exp(a);
+    aSign = extractFloatx80Sign(a);
+
+    if (aExp == 0x7FFF) {
+        if ((uint64_t) (aSig << 1)) {
+            return propagateFloatx80NaNOneArg(a, status);
+        }
+        return packFloatx80(aSign, floatx80_infinity.high,
+                            floatx80_infinity.low);
+    }
+
+    if (aExp == 0 && aSig == 0) {
+        return packFloatx80(aSign, 0, 0);
+    }
+
+    user_rnd_mode = status->float_rounding_mode;
+    user_rnd_prec = status->floatx80_rounding_precision;
+    status->float_rounding_mode = float_round_nearest_even;
+    status->floatx80_rounding_precision = 80;
+
+    compact = floatx80_make_compact(aExp, aSig);
+
+    if (compact > 0x400CB167) {
+        /* SINHBIG */
+        if (compact > 0x400CB2B3) {
+            status->float_rounding_mode = user_rnd_mode;
+            status->floatx80_rounding_precision = user_rnd_prec;
+
+            return roundAndPackFloatx80(status->floatx80_rounding_precision,
+                                        aSign, 0x8000, aSig, 0, status);
+        } else {
+            fp0 = floatx80_abs(a); /* Y = |X| */
+            fp0 = floatx80_sub(fp0, float64_to_floatx80(
+                               make_float64(0x40C62D38D3D64634), status),
+                               status); /* (|X|-16381LOG2_LEAD) */
+            fp0 = floatx80_sub(fp0, float64_to_floatx80(
+                               make_float64(0x3D6F90AEB1E75CC7), status),
+                               status); /* |X| - 16381 LOG2, ACCURATE */
+            fp0 = floatx80_etox(fp0, status);
+            fp2 = packFloatx80(aSign, 0x7FFB, one_sig);
+
+            status->float_rounding_mode = user_rnd_mode;
+            status->floatx80_rounding_precision = user_rnd_prec;
+
+            a = floatx80_mul(fp0, fp2, status);
+
+            float_raise(float_flag_inexact, status);
+
+            return a;
+        }
+    } else { /* |X| < 16380 LOG2 */
+        fp0 = floatx80_abs(a); /* Y = |X| */
+        fp0 = floatx80_etoxm1(fp0, status); /* FP0 IS Z = EXPM1(Y) */
+        fp1 = floatx80_add(fp0, float32_to_floatx80(make_float32(0x3F800000),
+                           status), status); /* 1+Z */
+        fp2 = fp0;
+        fp0 = floatx80_div(fp0, fp1, status); /* Z/(1+Z) */
+        fp0 = floatx80_add(fp0, fp2, status);
+
+        fact = packFloat32(aSign, 0x7E, 0);
+
+        status->float_rounding_mode = user_rnd_mode;
+        status->floatx80_rounding_precision = user_rnd_prec;
+
+        a = floatx80_mul(fp0, float32_to_floatx80(fact, status), status);
+
+        float_raise(float_flag_inexact, status);
+
+        return a;
+    }
+}
diff --git a/target/m68k/softfloat.h b/target/m68k/softfloat.h
index 4cdb5a49ca..f033abf9ea 100644
--- a/target/m68k/softfloat.h
+++ b/target/m68k/softfloat.h
@@ -43,4 +43,5 @@ floatx80 floatx80_acos(floatx80 a, float_status *status);
 floatx80 floatx80_atanh(floatx80 a, float_status *status);
 floatx80 floatx80_etoxm1(floatx80 a, float_status *status);
 floatx80 floatx80_tanh(floatx80 a, float_status *status);
+floatx80 floatx80_sinh(floatx80 a, float_status *status);
 #endif
diff --git a/target/m68k/translate.c b/target/m68k/translate.c
index 0caae904b5..7d83aaf91d 100644
--- a/target/m68k/translate.c
+++ b/target/m68k/translate.c
@@ -5042,6 +5042,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;
-- 
2.14.3


[Qemu-devel] [PATCH 11/11] target/m68k: implement fcosh
Posted by Laurent Vivier, 14 weeks ago
Using a local m68k  floatx80_cosh()
[copied from previous:
Written by Andreas Grabher for Previous, NeXT Computer Emulator.]

Signed-off-by: Laurent Vivier <laurent@vivier.eu>
---
 target/m68k/fpu_helper.c |  5 +++
 target/m68k/helper.h     |  1 +
 target/m68k/softfloat.c  | 81 ++++++++++++++++++++++++++++++++++++++++++++++++
 target/m68k/softfloat.h  |  1 +
 target/m68k/translate.c  |  3 ++
 5 files changed, 91 insertions(+)

diff --git a/target/m68k/fpu_helper.c b/target/m68k/fpu_helper.c
index 4c969dfe00..6eeffdf9bb 100644
--- a/target/m68k/fpu_helper.c
+++ b/target/m68k/fpu_helper.c
@@ -648,3 +648,8 @@ void HELPER(fsinh)(CPUM68KState *env, FPReg *res, FPReg *val)
 {
     res->d = floatx80_sinh(val->d, &env->fp_status);
 }
+
+void HELPER(fcosh)(CPUM68KState *env, FPReg *res, FPReg *val)
+{
+    res->d = floatx80_cosh(val->d, &env->fp_status);
+}
diff --git a/target/m68k/helper.h b/target/m68k/helper.h
index acdca1af03..feee7be626 100644
--- a/target/m68k/helper.h
+++ b/target/m68k/helper.h
@@ -85,6 +85,7 @@ DEF_HELPER_3(facos, void, env, fp, fp)
 DEF_HELPER_3(fatanh, void, env, fp, fp)
 DEF_HELPER_3(ftanh, void, env, fp, fp)
 DEF_HELPER_3(fsinh, void, env, fp, fp)
+DEF_HELPER_3(fcosh, void, env, fp, fp)
 
 DEF_HELPER_3(mac_move, void, env, i32, i32)
 DEF_HELPER_3(macmulf, i64, env, i32, i32)
diff --git a/target/m68k/softfloat.c b/target/m68k/softfloat.c
index 1528bfd147..dffb371c71 100644
--- a/target/m68k/softfloat.c
+++ b/target/m68k/softfloat.c
@@ -2822,3 +2822,84 @@ floatx80 floatx80_sinh(floatx80 a, float_status *status)
         return a;
     }
 }
+
+/*----------------------------------------------------------------------------
+ | Hyperbolic cosine
+ *----------------------------------------------------------------------------*/
+
+floatx80 floatx80_cosh(floatx80 a, float_status *status)
+{
+    int32_t aExp;
+    uint64_t aSig;
+
+    int8_t user_rnd_mode, user_rnd_prec;
+
+    int32_t compact;
+    floatx80 fp0, fp1;
+
+    aSig = extractFloatx80Frac(a);
+    aExp = extractFloatx80Exp(a);
+
+    if (aExp == 0x7FFF) {
+        if ((uint64_t) (aSig << 1)) {
+            return propagateFloatx80NaNOneArg(a, status);
+        }
+        return packFloatx80(0, floatx80_infinity.high,
+                            floatx80_infinity.low);
+    }
+
+    if (aExp == 0 && aSig == 0) {
+        return packFloatx80(0, one_exp, one_sig);
+    }
+
+    user_rnd_mode = status->float_rounding_mode;
+    user_rnd_prec = status->floatx80_rounding_precision;
+    status->float_rounding_mode = float_round_nearest_even;
+    status->floatx80_rounding_precision = 80;
+
+    compact = floatx80_make_compact(aExp, aSig);
+
+    if (compact > 0x400CB167) {
+        if (compact > 0x400CB2B3) {
+            status->float_rounding_mode = user_rnd_mode;
+            status->floatx80_rounding_precision = user_rnd_prec;
+            return roundAndPackFloatx80(status->floatx80_rounding_precision, 0,
+                                        0x8000, one_sig, 0, status);
+        } else {
+            fp0 = packFloatx80(0, aExp, aSig);
+            fp0 = floatx80_sub(fp0, float64_to_floatx80(
+                               make_float64(0x40C62D38D3D64634), status),
+                               status);
+            fp0 = floatx80_sub(fp0, float64_to_floatx80(
+                               make_float64(0x3D6F90AEB1E75CC7), status),
+                               status);
+            fp0 = floatx80_etox(fp0, status);
+            fp1 = packFloatx80(0, 0x7FFB, one_sig);
+
+            status->float_rounding_mode = user_rnd_mode;
+            status->floatx80_rounding_precision = user_rnd_prec;
+
+            a = floatx80_mul(fp0, fp1, status);
+
+            float_raise(float_flag_inexact, status);
+
+            return a;
+        }
+    }
+
+    fp0 = packFloatx80(0, aExp, aSig); /* |X| */
+    fp0 = floatx80_etox(fp0, status); /* EXP(|X|) */
+    fp0 = floatx80_mul(fp0, float32_to_floatx80(make_float32(0x3F000000),
+                       status), status); /* (1/2)*EXP(|X|) */
+    fp1 = float32_to_floatx80(make_float32(0x3E800000), status); /* 1/4 */
+    fp1 = floatx80_div(fp1, fp0, status); /* 1/(2*EXP(|X|)) */
+
+    status->float_rounding_mode = user_rnd_mode;
+    status->floatx80_rounding_precision = user_rnd_prec;
+
+    a = floatx80_add(fp0, fp1, status);
+
+    float_raise(float_flag_inexact, status);
+
+    return a;
+}
diff --git a/target/m68k/softfloat.h b/target/m68k/softfloat.h
index f033abf9ea..602661d5a8 100644
--- a/target/m68k/softfloat.h
+++ b/target/m68k/softfloat.h
@@ -44,4 +44,5 @@ floatx80 floatx80_atanh(floatx80 a, float_status *status);
 floatx80 floatx80_etoxm1(floatx80 a, float_status *status);
 floatx80 floatx80_tanh(floatx80 a, float_status *status);
 floatx80 floatx80_sinh(floatx80 a, float_status *status);
+floatx80 floatx80_cosh(floatx80 a, float_status *status);
 #endif
diff --git a/target/m68k/translate.c b/target/m68k/translate.c
index 7d83aaf91d..cef6f663ad 100644
--- a/target/m68k/translate.c
+++ b/target/m68k/translate.c
@@ -5105,6 +5105,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;
-- 
2.14.3