diff options
author | Zack Buhman <zack@buhman.org> | 2024-04-05 15:17:39 -1000 |
---|---|---|
committer | Richard Henderson <richard.henderson@linaro.org> | 2024-04-09 07:43:31 -1000 |
commit | c97e8977dcacb3fa8362ee28bcee75ceb01fceaa (patch) | |
tree | f40cc4213017d220ec95e3674f0428a8cce12f34 /target/sh4/op_helper.c | |
parent | 7d95db5e78a24d3315e3112d26909a7262355cb7 (diff) |
target/sh4: Fix mac.l with saturation enabled
The saturation arithmetic logic in helper_macl is not correct.
I tested and verified this behavior on a SH7091.
Signed-off-by: Zack Buhman <zack@buhman.org>
Message-Id: <20240404162641.27528-2-zack@buhman.org>
[rth: Reformat helper_macl, 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/op_helper.c')
-rw-r--r-- | target/sh4/op_helper.c | 23 |
1 files changed, 13 insertions, 10 deletions
diff --git a/target/sh4/op_helper.c b/target/sh4/op_helper.c index 4559d0d376..d0bae0cc00 100644 --- a/target/sh4/op_helper.c +++ b/target/sh4/op_helper.c @@ -158,20 +158,23 @@ void helper_ocbi(CPUSH4State *env, uint32_t address) } } -void helper_macl(CPUSH4State *env, uint32_t arg0, uint32_t arg1) +void helper_macl(CPUSH4State *env, int32_t arg0, int32_t arg1) { + const int64_t min = -(1ll << 47); + const int64_t max = (1ll << 47) - 1; + int64_t mul = (int64_t)arg0 * arg1; + int64_t mac = env->mac; int64_t res; - res = ((uint64_t) env->mach << 32) | env->macl; - res += (int64_t) (int32_t) arg0 *(int64_t) (int32_t) arg1; - env->mach = (res >> 32) & 0xffffffff; - env->macl = res & 0xffffffff; - if (env->sr & (1u << SR_S)) { - if (res < 0) - env->mach |= 0xffff0000; - else - env->mach &= 0x00007fff; + if (!(env->sr & (1u << SR_S))) { + res = mac + mul; + } else if (sadd64_overflow(mac, mul, &res)) { + res = mac < 0 ? min : max; + } else { + res = MIN(MAX(res, min), max); } + + env->mac = res; } void helper_macw(CPUSH4State *env, uint32_t arg0, uint32_t arg1) |