diff options
author | Zack Buhman <zack@buhman.org> | 2024-04-05 17:11:47 -1000 |
---|---|---|
committer | Richard Henderson <richard.henderson@linaro.org> | 2024-04-09 07:43:31 -1000 |
commit | 7227c0cd506eaab5b1d89d15832cac7e05ecb412 (patch) | |
tree | 8b3e6d9d0ca14105c8ef063827e5cd18481449c1 /target/sh4 | |
parent | c97e8977dcacb3fa8362ee28bcee75ceb01fceaa (diff) | |
download | qemu-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.h | 2 | ||||
-rw-r--r-- | target/sh4/op_helper.c | 28 |
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; } } |