From 3ec21437b1470cff373c002c1ebb4f70f666f0c3 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Sat, 14 Jan 2023 23:29:56 +0000 Subject: [PATCH 1/4] target/m68k: pass quotient directly into make_quotient() Signed-off-by: Mark Cave-Ayland Reviewed-by: Laurent Vivier Reviewed-by: Richard Henderson Message-Id: <20230114232959.118224-2-mark.cave-ayland@ilande.co.uk> Signed-off-by: Laurent Vivier --- target/m68k/fpu_helper.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/target/m68k/fpu_helper.c b/target/m68k/fpu_helper.c index fdc4937e29..0932c464fd 100644 --- a/target/m68k/fpu_helper.c +++ b/target/m68k/fpu_helper.c @@ -515,16 +515,10 @@ 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) +static void make_quotient(CPUM68KState *env, int32_t quotient) { - 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; @@ -538,14 +532,22 @@ 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); + if (floatx80_is_any_nan(res->d)) { + return; + } + + make_quotient(env, floatx80_to_int32(res->d, &env->fp_status)); } 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); + if (floatx80_is_any_nan(res->d)) { + return; + } + + make_quotient(env, floatx80_to_int32(res->d, &env->fp_status)); } void HELPER(fgetexp)(CPUM68KState *env, FPReg *res, FPReg *val) From 60b598df6e3e3d76dae6967e03d4418f6aac6064 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Sat, 14 Jan 2023 23:29:57 +0000 Subject: [PATCH 2/4] target/m68k: pass sign directly into make_quotient() This enables the quotient parameter to be changed from int32_t to uint32_t and also allows the extra sign logic in make_quotient() to be removed. Signed-off-by: Mark Cave-Ayland Reviewed-by: Richard Henderson Reviewed-by: Laurent Vivier Message-Id: <20230114232959.118224-3-mark.cave-ayland@ilande.co.uk> Signed-off-by: Laurent Vivier --- target/m68k/fpu_helper.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/target/m68k/fpu_helper.c b/target/m68k/fpu_helper.c index 0932c464fd..76b34b8988 100644 --- a/target/m68k/fpu_helper.c +++ b/target/m68k/fpu_helper.c @@ -515,39 +515,42 @@ 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, int32_t quotient) +static void make_quotient(CPUM68KState *env, int sign, uint32_t quotient) { - int sign; - - 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) { + uint32_t quotient; + int sign; + res->d = floatx80_mod(val1->d, val0->d, &env->fp_status); if (floatx80_is_any_nan(res->d)) { return; } - make_quotient(env, floatx80_to_int32(res->d, &env->fp_status)); + sign = extractFloatx80Sign(res->d); + quotient = floatx80_to_int32(floatx80_abs(res->d), &env->fp_status); + make_quotient(env, sign, quotient); } void HELPER(frem)(CPUM68KState *env, FPReg *res, FPReg *val0, FPReg *val1) { + uint32_t quotient; + int sign; + res->d = floatx80_rem(val1->d, val0->d, &env->fp_status); if (floatx80_is_any_nan(res->d)) { return; } - make_quotient(env, floatx80_to_int32(res->d, &env->fp_status)); + sign = extractFloatx80Sign(res->d); + quotient = floatx80_to_int32(floatx80_abs(res->d), &env->fp_status); + make_quotient(env, sign, quotient); } void HELPER(fgetexp)(CPUM68KState *env, FPReg *res, FPReg *val) From ad6dae3b3369433ab43a1b190bb3a8aacabb1bbf Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Sat, 14 Jan 2023 23:29:58 +0000 Subject: [PATCH 3/4] target/m68k: fix FPSR quotient byte for fmod instruction The FPSR quotient byte should be set to the value of the quotient and not the result. Switch from using floatx80_mod() to floatx80_modrem() which returns the quotient as a uint64_t which can be used for the quotient byte. Signed-off-by: Mark Cave-Ayland Reviewed-by: Laurent Vivier Reviewed-by: Richard Henderson Message-Id: <20230114232959.118224-4-mark.cave-ayland@ilande.co.uk> Signed-off-by: Laurent Vivier --- target/m68k/fpu_helper.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/target/m68k/fpu_helper.c b/target/m68k/fpu_helper.c index 76b34b8988..5fd094a33c 100644 --- a/target/m68k/fpu_helper.c +++ b/target/m68k/fpu_helper.c @@ -523,17 +523,16 @@ static void make_quotient(CPUM68KState *env, int sign, uint32_t quotient) void HELPER(fmod)(CPUM68KState *env, FPReg *res, FPReg *val0, FPReg *val1) { - uint32_t quotient; - int sign; + uint64_t quotient; + int sign = extractFloatx80Sign(val1->d) ^ extractFloatx80Sign(val0->d); - res->d = floatx80_mod(val1->d, val0->d, &env->fp_status); + res->d = floatx80_modrem(val1->d, val0->d, true, "ient, + &env->fp_status); if (floatx80_is_any_nan(res->d)) { return; } - sign = extractFloatx80Sign(res->d); - quotient = floatx80_to_int32(floatx80_abs(res->d), &env->fp_status); make_quotient(env, sign, quotient); } From 1a282f60a971aa86e3cdd1b7ca000790e43bb310 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Sat, 14 Jan 2023 23:29:59 +0000 Subject: [PATCH 4/4] target/m68k: fix FPSR quotient byte for frem instruction The FPSR quotient byte should be set to the value of the quotient and not the result. Manually calculate the quotient in the frem helper in round to nearest even mode (note this is different from the quotient calculated internally for fmod), and use it to set the quotient byte accordingly. Signed-off-by: Mark Cave-Ayland Fixes: https://gitlab.com/qemu-project/qemu/-/issues/1314 Reviewed-by: Richard Henderson Message-Id: <20230114232959.118224-5-mark.cave-ayland@ilande.co.uk> Signed-off-by: Laurent Vivier --- target/m68k/fpu_helper.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/target/m68k/fpu_helper.c b/target/m68k/fpu_helper.c index 5fd094a33c..3a37d8f584 100644 --- a/target/m68k/fpu_helper.c +++ b/target/m68k/fpu_helper.c @@ -538,18 +538,27 @@ void HELPER(fmod)(CPUM68KState *env, FPReg *res, FPReg *val0, FPReg *val1) void HELPER(frem)(CPUM68KState *env, FPReg *res, FPReg *val0, FPReg *val1) { - uint32_t quotient; - int sign; + FPReg fp_quot; + floatx80 fp_rem; - res->d = floatx80_rem(val1->d, val0->d, &env->fp_status); + fp_rem = floatx80_rem(val1->d, val0->d, &env->fp_status); + if (!floatx80_is_any_nan(fp_rem)) { + float_status fp_status = { }; + uint32_t quotient; + int sign; - if (floatx80_is_any_nan(res->d)) { - return; + /* Calculate quotient directly using round to nearest mode */ + set_float_rounding_mode(float_round_nearest_even, &fp_status); + set_floatx80_rounding_precision( + get_floatx80_rounding_precision(&env->fp_status), &fp_status); + fp_quot.d = floatx80_div(val1->d, val0->d, &fp_status); + + sign = extractFloatx80Sign(fp_quot.d); + quotient = floatx80_to_int32(floatx80_abs(fp_quot.d), &env->fp_status); + make_quotient(env, sign, quotient); } - sign = extractFloatx80Sign(res->d); - quotient = floatx80_to_int32(floatx80_abs(res->d), &env->fp_status); - make_quotient(env, sign, quotient); + res->d = fp_rem; } void HELPER(fgetexp)(CPUM68KState *env, FPReg *res, FPReg *val)