aboutsummaryrefslogtreecommitdiff
path: root/target
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2018-03-05 13:29:31 +0000
committerPeter Maydell <peter.maydell@linaro.org>2018-03-05 13:29:31 +0000
commit4a22592e32868db846898831c27fbee8e73e24e3 (patch)
treec535db857a8bdc290b1e5ef9e9806a9e2e28665e /target
parent7fceeb190ac6fbbbec0bf904f743190708301e31 (diff)
parent0d379c1709aa6b2d09dd3b493bfdf3a5fe6debcd (diff)
Merge remote-tracking branch 'remotes/vivier/tags/m68k-for-2.12-pull-request' into staging
# gpg: Signature made Sun 04 Mar 2018 17:32:25 GMT # gpg: using RSA key F30C38BD3F2FBE3C # gpg: Good signature from "Laurent Vivier <lvivier@redhat.com>" # gpg: aka "Laurent Vivier <laurent@vivier.eu>" # gpg: aka "Laurent Vivier (Red Hat) <lvivier@redhat.com>" # Primary key fingerprint: CD2F 75DD C8E3 A4DC 2E4F 5173 F30C 38BD 3F2F BE3C * remotes/vivier/tags/m68k-for-2.12-pull-request: target/m68k: add fscale, fgetman and fgetexp softfloat: use floatx80_infinity in softfloat target/m68k: add fmod/frem softfloat: export some functions target/m68k: TCGv returned by gen_load() must be freed Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'target')
-rw-r--r--target/m68k/Makefile.objs3
-rw-r--r--target/m68k/cpu.h1
-rw-r--r--target/m68k/fpu_helper.c50
-rw-r--r--target/m68k/helper.h5
-rw-r--r--target/m68k/softfloat.c249
-rw-r--r--target/m68k/softfloat.h29
-rw-r--r--target/m68k/translate.c26
7 files changed, 361 insertions, 2 deletions
diff --git a/target/m68k/Makefile.objs b/target/m68k/Makefile.objs
index d143f20270..ac61948676 100644
--- a/target/m68k/Makefile.objs
+++ b/target/m68k/Makefile.objs
@@ -1,4 +1,5 @@
obj-y += m68k-semi.o
-obj-y += translate.o op_helper.o helper.o cpu.o fpu_helper.o
+obj-y += translate.o op_helper.o helper.o cpu.o
+obj-y += fpu_helper.o softfloat.o
obj-y += gdbstub.o
obj-$(CONFIG_SOFTMMU) += monitor.o
diff --git a/target/m68k/cpu.h b/target/m68k/cpu.h
index 65f4fb95cb..2259bf22dc 100644
--- a/target/m68k/cpu.h
+++ b/target/m68k/cpu.h
@@ -427,6 +427,7 @@ typedef enum {
/* Quotient */
#define FPSR_QT_MASK 0x00ff0000
+#define FPSR_QT_SHIFT 16
/* Floating-Point Control Register */
/* Rounding mode */
diff --git a/target/m68k/fpu_helper.c b/target/m68k/fpu_helper.c
index 3c5a82aaa0..cdb9b50462 100644
--- a/target/m68k/fpu_helper.c
+++ b/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)
@@ -509,3 +509,51 @@ 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);
+}
+
+void HELPER(fgetexp)(CPUM68KState *env, FPReg *res, FPReg *val)
+{
+ res->d = floatx80_getexp(val->d, &env->fp_status);
+}
+
+void HELPER(fgetman)(CPUM68KState *env, FPReg *res, FPReg *val)
+{
+ res->d = floatx80_getman(val->d, &env->fp_status);
+}
+
+void HELPER(fscale)(CPUM68KState *env, FPReg *res, FPReg *val0, FPReg *val1)
+{
+ res->d = floatx80_scale(val1->d, val0->d, &env->fp_status);
+}
diff --git a/target/m68k/helper.h b/target/m68k/helper.h
index 7f400f0def..c348dced3a 100644
--- a/target/m68k/helper.h
+++ b/target/m68k/helper.h
@@ -63,6 +63,11 @@ 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(fgetexp, void, env, fp, fp)
+DEF_HELPER_3(fgetman, void, env, fp, fp)
+DEF_HELPER_4(fscale, void, env, fp, fp, fp)
DEF_HELPER_3(mac_move, void, env, i32, i32)
DEF_HELPER_3(macmulf, i64, env, i32, i32)
diff --git a/target/m68k/softfloat.c b/target/m68k/softfloat.c
new file mode 100644
index 0000000000..9cb141900c
--- /dev/null
+++ b/target/m68k/softfloat.c
@@ -0,0 +1,249 @@
+/*
+ * 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"
+
+static floatx80 propagateFloatx80NaNOneArg(floatx80 a, float_status *status)
+{
+ if (floatx80_is_signaling_nan(a, status)) {
+ float_raise(float_flag_invalid, status);
+ }
+
+ if (status->default_nan_mode) {
+ return floatx80_default_nan(status);
+ }
+
+ return floatx80_maybe_silence_nan(a, status);
+}
+
+/*----------------------------------------------------------------------------
+ | 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);
+}
+
+/*----------------------------------------------------------------------------
+ | Returns the mantissa of the extended double-precision floating-point
+ | value `a'.
+ *----------------------------------------------------------------------------*/
+
+floatx80 floatx80_getman(floatx80 a, float_status *status)
+{
+ flag aSign;
+ int32_t aExp;
+ uint64_t aSig;
+
+ 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) {
+ if (aSig == 0) {
+ return packFloatx80(aSign, 0, 0);
+ }
+ normalizeFloatx80Subnormal(aSig, &aExp, &aSig);
+ }
+
+ return roundAndPackFloatx80(status->floatx80_rounding_precision, aSign,
+ 0x3FFF, aSig, 0, status);
+}
+
+/*----------------------------------------------------------------------------
+ | Returns the exponent of the extended double-precision floating-point
+ | value `a' as an extended double-precision value.
+ *----------------------------------------------------------------------------*/
+
+floatx80 floatx80_getexp(floatx80 a, float_status *status)
+{
+ flag aSign;
+ int32_t aExp;
+ uint64_t aSig;
+
+ 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) {
+ if (aSig == 0) {
+ return packFloatx80(aSign, 0, 0);
+ }
+ normalizeFloatx80Subnormal(aSig, &aExp, &aSig);
+ }
+
+ return int32_to_floatx80(aExp - 0x3FFF, status);
+}
+
+/*----------------------------------------------------------------------------
+ | Scales extended double-precision floating-point value in operand `a' by
+ | value `b'. The function truncates the value in the second operand 'b' to
+ | an integral value and adds that value to the exponent of the operand 'a'.
+ | The operation performed according to the IEC/IEEE Standard for Binary
+ | Floating-Point Arithmetic.
+ *----------------------------------------------------------------------------*/
+
+floatx80 floatx80_scale(floatx80 a, floatx80 b, float_status *status)
+{
+ flag aSign, bSign;
+ int32_t aExp, bExp, shiftCount;
+ uint64_t aSig, bSig;
+
+ aSig = extractFloatx80Frac(a);
+ aExp = extractFloatx80Exp(a);
+ aSign = extractFloatx80Sign(a);
+ bSig = extractFloatx80Frac(b);
+ bExp = extractFloatx80Exp(b);
+ bSign = extractFloatx80Sign(b);
+
+ if (bExp == 0x7FFF) {
+ if ((uint64_t) (bSig << 1) ||
+ ((aExp == 0x7FFF) && (uint64_t) (aSig << 1))) {
+ return propagateFloatx80NaN(a, b, status);
+ }
+ float_raise(float_flag_invalid , status);
+ return floatx80_default_nan(status);
+ }
+ if (aExp == 0x7FFF) {
+ if ((uint64_t) (aSig << 1)) {
+ return propagateFloatx80NaN(a, b, status);
+ }
+ return packFloatx80(aSign, floatx80_infinity.high,
+ floatx80_infinity.low);
+ }
+ if (aExp == 0) {
+ if (aSig == 0) {
+ return packFloatx80(aSign, 0, 0);
+ }
+ if (bExp < 0x3FFF) {
+ return a;
+ }
+ normalizeFloatx80Subnormal(aSig, &aExp, &aSig);
+ }
+
+ if (bExp < 0x3FFF) {
+ return a;
+ }
+
+ if (0x400F < bExp) {
+ aExp = bSign ? -0x6001 : 0xE000;
+ return roundAndPackFloatx80(status->floatx80_rounding_precision,
+ aSign, aExp, aSig, 0, status);
+ }
+
+ shiftCount = 0x403E - bExp;
+ bSig >>= shiftCount;
+ aExp = bSign ? (aExp - bSig) : (aExp + bSig);
+
+ return roundAndPackFloatx80(status->floatx80_rounding_precision,
+ aSign, aExp, aSig, 0, status);
+}
diff --git a/target/m68k/softfloat.h b/target/m68k/softfloat.h
new file mode 100644
index 0000000000..78fbc0cd0c
--- /dev/null
+++ b/target/m68k/softfloat.h
@@ -0,0 +1,29 @@
+/*
+ * 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);
+floatx80 floatx80_getman(floatx80 a, float_status *status);
+floatx80 floatx80_getexp(floatx80 a, float_status *status);
+floatx80 floatx80_scale(floatx80 a, floatx80 b, float_status *status);
+#endif
diff --git a/target/m68k/translate.c b/target/m68k/translate.c
index 93cd38950e..dbb24f8d84 100644
--- a/target/m68k/translate.c
+++ b/target/m68k/translate.c
@@ -2871,6 +2871,7 @@ DISAS_INSN(unlk)
tcg_gen_mov_i32(reg, tmp);
tcg_gen_addi_i32(QREG_SP, src, 4);
tcg_temp_free(src);
+ tcg_temp_free(tmp);
}
#if defined(CONFIG_SOFTMMU)
@@ -3148,6 +3149,9 @@ DISAS_INSN(subx_mem)
gen_subx(s, src, dest, opsize);
gen_store(s, opsize, addr_dest, QREG_CC_N, IS_USER(s));
+
+ tcg_temp_free(dest);
+ tcg_temp_free(src);
}
DISAS_INSN(mov3q)
@@ -3354,6 +3358,9 @@ DISAS_INSN(addx_mem)
gen_addx(s, src, dest, opsize);
gen_store(s, opsize, addr_dest, QREG_CC_N, IS_USER(s));
+
+ tcg_temp_free(dest);
+ tcg_temp_free(src);
}
static inline void shift_im(DisasContext *s, uint16_t insn, int opsize)
@@ -4398,6 +4405,8 @@ DISAS_INSN(chk2)
gen_flush_flags(s);
gen_helper_chk2(cpu_env, reg, bound1, bound2);
tcg_temp_free(reg);
+ tcg_temp_free(bound1);
+ tcg_temp_free(bound2);
}
static void m68k_copy_line(TCGv dst, TCGv src, int index)
@@ -4547,6 +4556,7 @@ DISAS_INSN(moves)
} else {
gen_partset_reg(opsize, reg, tmp);
}
+ tcg_temp_free(tmp);
}
switch (extract32(insn, 3, 3)) {
case 3: /* Indirect postincrement. */
@@ -5062,6 +5072,12 @@ DISAS_INSN(fpu)
case 0x5e: /* fdneg */
gen_helper_fdneg(cpu_env, cpu_dest, cpu_src);
break;
+ case 0x1e: /* fgetexp */
+ gen_helper_fgetexp(cpu_env, cpu_dest, cpu_src);
+ break;
+ case 0x1f: /* fgetman */
+ gen_helper_fgetman(cpu_env, cpu_dest, cpu_src);
+ break;
case 0x20: /* fdiv */
gen_helper_fdiv(cpu_env, cpu_dest, cpu_src, cpu_dest);
break;
@@ -5071,6 +5087,9 @@ DISAS_INSN(fpu)
case 0x64: /* fddiv */
gen_helper_fddiv(cpu_env, cpu_dest, cpu_src, cpu_dest);
break;
+ case 0x21: /* fmod */
+ gen_helper_fmod(cpu_env, cpu_dest, cpu_src, cpu_dest);
+ break;
case 0x22: /* fadd */
gen_helper_fadd(cpu_env, cpu_dest, cpu_src, cpu_dest);
break;
@@ -5092,6 +5111,12 @@ DISAS_INSN(fpu)
case 0x24: /* fsgldiv */
gen_helper_fsgldiv(cpu_env, cpu_dest, cpu_src, cpu_dest);
break;
+ case 0x25: /* frem */
+ gen_helper_frem(cpu_env, cpu_dest, cpu_src, cpu_dest);
+ break;
+ case 0x26: /* fscale */
+ gen_helper_fscale(cpu_env, cpu_dest, cpu_src, cpu_dest);
+ break;
case 0x27: /* fsglmul */
gen_helper_fsglmul(cpu_env, cpu_dest, cpu_src, cpu_dest);
break;
@@ -5537,6 +5562,7 @@ DISAS_INSN(mac)
case 4: /* Pre-decrement. */
tcg_gen_mov_i32(AREG(insn, 0), addr);
}
+ tcg_temp_free(loadval);
}
}