aboutsummaryrefslogtreecommitdiff
path: root/target/sh4
diff options
context:
space:
mode:
authorZack Buhman <zack@buhman.org>2024-04-05 17:11:47 -1000
committerRichard Henderson <richard.henderson@linaro.org>2024-04-09 07:43:31 -1000
commit7227c0cd506eaab5b1d89d15832cac7e05ecb412 (patch)
tree8b3e6d9d0ca14105c8ef063827e5cd18481449c1 /target/sh4
parentc97e8977dcacb3fa8362ee28bcee75ceb01fceaa (diff)
downloadqemu-7227c0cd506eaab5b1d89d15832cac7e05ecb412.zip
qemu-7227c0cd506eaab5b1d89d15832cac7e05ecb412.tar.gz
qemu-7227c0cd506eaab5b1d89d15832cac7e05ecb412.tar.bz2
target/sh4: Fix mac.w with saturation enabled
The saturation arithmetic logic in helper_macw is not correct. I tested and verified this behavior on a SH7091. Reviewd-by: Yoshinori Sato <ysato@users.sourceforge.jp> Signed-off-by: Zack Buhman <zack@buhman.org> Message-Id: <20240405233802.29128-3-zack@buhman.org> [rth: Reformat helper_macw, add a test case.] Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Diffstat (limited to 'target/sh4')
-rw-r--r--target/sh4/helper.h2
-rw-r--r--target/sh4/op_helper.c28
2 files changed, 18 insertions, 12 deletions
diff --git a/target/sh4/helper.h b/target/sh4/helper.h
index 64056e4..29011d3 100644
--- a/target/sh4/helper.h
+++ b/target/sh4/helper.h
@@ -12,7 +12,7 @@ DEF_HELPER_1(discard_movcal_backup, void, env)
DEF_HELPER_2(ocbi, void, env, i32)
DEF_HELPER_3(macl, void, env, s32, s32)
-DEF_HELPER_3(macw, void, env, i32, i32)
+DEF_HELPER_3(macw, void, env, s32, s32)
DEF_HELPER_2(ld_fpscr, void, env, i32)
diff --git a/target/sh4/op_helper.c b/target/sh4/op_helper.c
index d0bae0c..99394b7 100644
--- a/target/sh4/op_helper.c
+++ b/target/sh4/op_helper.c
@@ -177,22 +177,28 @@ void helper_macl(CPUSH4State *env, int32_t arg0, int32_t arg1)
env->mac = res;
}
-void helper_macw(CPUSH4State *env, uint32_t arg0, uint32_t arg1)
+void helper_macw(CPUSH4State *env, int32_t arg0, int32_t arg1)
{
- int64_t res;
+ /* Inputs are already sign-extended from 16 bits. */
+ int32_t mul = arg0 * arg1;
- res = ((uint64_t) env->mach << 32) | env->macl;
- res += (int64_t) (int16_t) arg0 *(int64_t) (int16_t) arg1;
- env->mach = (res >> 32) & 0xffffffff;
- env->macl = res & 0xffffffff;
if (env->sr & (1u << SR_S)) {
- if (res < -0x80000000) {
- env->mach = 1;
- env->macl = 0x80000000;
- } else if (res > 0x000000007fffffff) {
+ /*
+ * In saturation arithmetic mode, the accumulator is 32-bit
+ * with carry. MACH is not considered during the addition
+ * operation nor the 32-bit saturation logic.
+ */
+ int32_t res, macl = env->macl;
+
+ if (sadd32_overflow(macl, mul, &res)) {
+ res = macl < 0 ? INT32_MIN : INT32_MAX;
+ /* If overflow occurs, the MACH register is set to 1. */
env->mach = 1;
- env->macl = 0x7fffffff;
}
+ env->macl = res;
+ } else {
+ /* In non-saturation arithmetic mode, the accumulator is 64-bit */
+ env->mac += mul;
}
}