From 08c03a5de41d2348a60a466f87276c38658226e6 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Fri, 9 Mar 2018 01:25:32 -0500 Subject: [PATCH] target/m68k: add fmod/frem Using a local m68k floatx80_mod() [copied from previous: Written by Andreas Grabher for Previous, NeXT Computer Emulator.] The quotient byte of the FPSR is updated with the result of the operation. Backports commit 591596b77a1872d0652e666271ca055e57ea1e21 from qemu --- .../unicorn/m68k-softmmu/m68k-softmmu.vcxproj | 2 + .../m68k-softmmu/m68k-softmmu.vcxproj.filters | 6 + qemu/target/m68k/Makefile.objs | 1 + qemu/target/m68k/cpu.h | 1 + qemu/target/m68k/fpu_helper.c | 35 +++++- qemu/target/m68k/helper.h | 2 + qemu/target/m68k/softfloat.c | 105 ++++++++++++++++++ qemu/target/m68k/softfloat.h | 26 +++++ qemu/target/m68k/translate.c | 6 + 9 files changed, 183 insertions(+), 1 deletion(-) create mode 100644 qemu/target/m68k/softfloat.c create mode 100644 qemu/target/m68k/softfloat.h diff --git a/msvc/unicorn/m68k-softmmu/m68k-softmmu.vcxproj b/msvc/unicorn/m68k-softmmu/m68k-softmmu.vcxproj index 050c9414..ff0c4387 100644 --- a/msvc/unicorn/m68k-softmmu/m68k-softmmu.vcxproj +++ b/msvc/unicorn/m68k-softmmu/m68k-softmmu.vcxproj @@ -33,6 +33,7 @@ + @@ -69,6 +70,7 @@ + diff --git a/msvc/unicorn/m68k-softmmu/m68k-softmmu.vcxproj.filters b/msvc/unicorn/m68k-softmmu/m68k-softmmu.vcxproj.filters index 3234adc0..669200fb 100644 --- a/msvc/unicorn/m68k-softmmu/m68k-softmmu.vcxproj.filters +++ b/msvc/unicorn/m68k-softmmu/m68k-softmmu.vcxproj.filters @@ -63,6 +63,9 @@ target\m68k + + target\m68k + target\m68k @@ -119,6 +122,9 @@ target\m68k + + target\m68k + target\m68k diff --git a/qemu/target/m68k/Makefile.objs b/qemu/target/m68k/Makefile.objs index 92fd7685..17cc5b7c 100644 --- a/qemu/target/m68k/Makefile.objs +++ b/qemu/target/m68k/Makefile.objs @@ -1,2 +1,3 @@ obj-y += translate.o op_helper.o helper.o cpu.o fpu_helper.o +obj-y += softfloat.o obj-y += unicorn.o diff --git a/qemu/target/m68k/cpu.h b/qemu/target/m68k/cpu.h index dd8a99bb..59c6d00d 100644 --- a/qemu/target/m68k/cpu.h +++ b/qemu/target/m68k/cpu.h @@ -423,6 +423,7 @@ typedef enum { /* Quotient */ #define FPSR_QT_MASK 0x00ff0000 +#define FPSR_QT_SHIFT 16 /* Floating-Point Control Register */ /* Rounding mode */ diff --git a/qemu/target/m68k/fpu_helper.c b/qemu/target/m68k/fpu_helper.c index 4805ca39..afcf7dd9 100644 --- a/qemu/target/m68k/fpu_helper.c +++ b/qemu/target/m68k/fpu_helper.c @@ -23,7 +23,7 @@ #include "exec/helper-proto.h" #include "exec/exec-all.h" #include "exec/cpu_ldst.h" -#include "fpu/softfloat.h" +#include "softfloat.h" /* Undefined offsets may be different on various FPU. * On 68040 they return 0.0 (floatx80_zero) @@ -520,3 +520,36 @@ uint32_t HELPER(fmovemd_ld_postinc)(CPUM68KState *env, uint32_t addr, { return fmovem_postinc(env, addr, mask, cpu_ld_float64_ra); } + +static void make_quotient(CPUM68KState *env, floatx80 val) +{ + int32_t quotient; + int sign; + + if (floatx80_is_any_nan(val)) { + return; + } + + quotient = floatx80_to_int32(val, &env->fp_status); + sign = quotient < 0; + if (sign) { + quotient = -quotient; + } + + quotient = (sign << 7) | (quotient & 0x7f); + env->fpsr = (env->fpsr & ~FPSR_QT_MASK) | (quotient << FPSR_QT_SHIFT); +} + +void HELPER(fmod)(CPUM68KState *env, FPReg *res, FPReg *val0, FPReg *val1) +{ + res->d = floatx80_mod(val1->d, val0->d, &env->fp_status); + + make_quotient(env, res->d); +} + +void HELPER(frem)(CPUM68KState *env, FPReg *res, FPReg *val0, FPReg *val1) +{ + res->d = floatx80_rem(val1->d, val0->d, &env->fp_status); + + make_quotient(env, res->d); +} diff --git a/qemu/target/m68k/helper.h b/qemu/target/m68k/helper.h index 35b10bfc..3cf236ab 100644 --- a/qemu/target/m68k/helper.h +++ b/qemu/target/m68k/helper.h @@ -64,6 +64,8 @@ DEF_HELPER_3(fmovemx_ld_postinc, i32, env, i32, i32) DEF_HELPER_3(fmovemd_st_predec, i32, env, i32, i32) DEF_HELPER_3(fmovemd_st_postinc, i32, env, i32, i32) DEF_HELPER_3(fmovemd_ld_postinc, i32, env, i32, i32) +DEF_HELPER_4(fmod, void, env, fp, fp, fp) +DEF_HELPER_4(frem, void, env, fp, fp, fp) DEF_HELPER_3(mac_move, void, env, i32, i32) DEF_HELPER_3(macmulf, i64, env, i32, i32) diff --git a/qemu/target/m68k/softfloat.c b/qemu/target/m68k/softfloat.c new file mode 100644 index 00000000..8c77757b --- /dev/null +++ b/qemu/target/m68k/softfloat.c @@ -0,0 +1,105 @@ +/* + * Ported from a work by Andreas Grabher for Previous, NeXT Computer Emulator, + * derived from NetBSD M68040 FPSP functions, + * derived from release 2a of the SoftFloat IEC/IEEE Floating-point Arithmetic + * Package. Those parts of the code (and some later contributions) are + * provided under that license, as detailed below. + * It has subsequently been modified by contributors to the QEMU Project, + * so some portions are provided under: + * the SoftFloat-2a license + * the BSD license + * GPL-v2-or-later + * + * Any future contributions to this file will be taken to be licensed under + * the Softfloat-2a license unless specifically indicated otherwise. + */ + +/* Portions of this work are licensed under the terms of the GNU GPL, + * version 2 or later. See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "softfloat.h" +#include "fpu/softfloat-macros.h" + +/*---------------------------------------------------------------------------- + | Returns the modulo remainder of the extended double-precision floating-point + | value `a' with respect to the corresponding value `b'. + *----------------------------------------------------------------------------*/ + +floatx80 floatx80_mod(floatx80 a, floatx80 b, float_status *status) +{ + flag aSign, zSign; + int32_t aExp, bExp, expDiff; + uint64_t aSig0, aSig1, bSig; + uint64_t qTemp, term0, term1; + + aSig0 = extractFloatx80Frac(a); + aExp = extractFloatx80Exp(a); + aSign = extractFloatx80Sign(a); + bSig = extractFloatx80Frac(b); + bExp = extractFloatx80Exp(b); + + if (aExp == 0x7FFF) { + if ((uint64_t) (aSig0 << 1) + || ((bExp == 0x7FFF) && (uint64_t) (bSig << 1))) { + return propagateFloatx80NaN(a, b, status); + } + goto invalid; + } + if (bExp == 0x7FFF) { + if ((uint64_t) (bSig << 1)) { + return propagateFloatx80NaN(a, b, status); + } + return a; + } + if (bExp == 0) { + if (bSig == 0) { + invalid: + float_raise(float_flag_invalid, status); + return floatx80_default_nan(status); + } + normalizeFloatx80Subnormal(bSig, &bExp, &bSig); + } + if (aExp == 0) { + if ((uint64_t) (aSig0 << 1) == 0) { + return a; + } + normalizeFloatx80Subnormal(aSig0, &aExp, &aSig0); + } + bSig |= LIT64(0x8000000000000000); + zSign = aSign; + expDiff = aExp - bExp; + aSig1 = 0; + if (expDiff < 0) { + return a; + } + qTemp = (bSig <= aSig0); + if (qTemp) { + aSig0 -= bSig; + } + expDiff -= 64; + while (0 < expDiff) { + qTemp = estimateDiv128To64(aSig0, aSig1, bSig); + qTemp = (2 < qTemp) ? qTemp - 2 : 0; + mul64To128(bSig, qTemp, &term0, &term1); + sub128(aSig0, aSig1, term0, term1, &aSig0, &aSig1); + shortShift128Left(aSig0, aSig1, 62, &aSig0, &aSig1); + } + expDiff += 64; + if (0 < expDiff) { + qTemp = estimateDiv128To64(aSig0, aSig1, bSig); + qTemp = (2 < qTemp) ? qTemp - 2 : 0; + qTemp >>= 64 - expDiff; + mul64To128(bSig, qTemp << (64 - expDiff), &term0, &term1); + sub128(aSig0, aSig1, term0, term1, &aSig0, &aSig1); + shortShift128Left(0, bSig, 64 - expDiff, &term0, &term1); + while (le128(term0, term1, aSig0, aSig1)) { + ++qTemp; + sub128(aSig0, aSig1, term0, term1, &aSig0, &aSig1); + } + } + return + normalizeRoundAndPackFloatx80( + 80, zSign, bExp + expDiff, aSig0, aSig1, status); +} diff --git a/qemu/target/m68k/softfloat.h b/qemu/target/m68k/softfloat.h new file mode 100644 index 00000000..8d8ca0fc --- /dev/null +++ b/qemu/target/m68k/softfloat.h @@ -0,0 +1,26 @@ +/* + * Ported from a work by Andreas Grabher for Previous, NeXT Computer Emulator, + * derived from NetBSD M68040 FPSP functions, + * derived from release 2a of the SoftFloat IEC/IEEE Floating-point Arithmetic + * Package. Those parts of the code (and some later contributions) are + * provided under that license, as detailed below. + * It has subsequently been modified by contributors to the QEMU Project, + * so some portions are provided under: + * the SoftFloat-2a license + * the BSD license + * GPL-v2-or-later + * + * Any future contributions to this file will be taken to be licensed under + * the Softfloat-2a license unless specifically indicated otherwise. + */ + +/* Portions of this work are licensed under the terms of the GNU GPL, + * version 2 or later. See the COPYING file in the top-level directory. + */ + +#ifndef TARGET_M68K_SOFTFLOAT_H +#define TARGET_M68K_SOFTFLOAT_H +#include "fpu/softfloat.h" + +floatx80 floatx80_mod(floatx80 a, floatx80 b, float_status *status); +#endif diff --git a/qemu/target/m68k/translate.c b/qemu/target/m68k/translate.c index eef25fd6..b5e69d58 100644 --- a/qemu/target/m68k/translate.c +++ b/qemu/target/m68k/translate.c @@ -5280,6 +5280,9 @@ DISAS_INSN(fpu) case 0x64: /* fddiv */ gen_helper_fddiv(tcg_ctx, tcg_ctx->cpu_env, cpu_dest, cpu_src, cpu_dest); break; + case 0x21: /* fmod */ + gen_helper_fmod(tcg_ctx, tcg_ctx->cpu_env, cpu_dest, cpu_src, cpu_dest); + break; case 0x22: /* fadd */ gen_helper_fadd(tcg_ctx, tcg_ctx->cpu_env, cpu_dest, cpu_src, cpu_dest); break; @@ -5301,6 +5304,9 @@ DISAS_INSN(fpu) case 0x24: /* fsgldiv */ gen_helper_fsgldiv(tcg_ctx, tcg_ctx->cpu_env, cpu_dest, cpu_src, cpu_dest); break; + case 0x25: /* frem */ + gen_helper_frem(tcg_ctx, tcg_ctx->cpu_env, cpu_dest, cpu_src, cpu_dest); + break; case 0x27: /* fsglmul */ gen_helper_fsglmul(tcg_ctx, tcg_ctx->cpu_env, cpu_dest, cpu_src, cpu_dest); break;