Hi!
It seems the implementation of the mac.w / mac.l insn is wrong:
mac.w @Rm+,@Rn+
mac.l @Rm+,@Rn+
Qemu's implementation first reads both mems, then applies the post-inc.
However,
mac.w @R0+,@R0+
should actually do:
read @(R0 + 0)
R0 += 2
read @(R0 + 2)
R0 += 2
That's also how GDB sh-sim implements it.
The attached patch fixes it.
I ran into this issue recently when trying to use qemu for sh4.
I'm not on the list, so please add me in CC in the reply.
Best regards,
Oleg Endo
diff --git a/target/sh4/translate.c b/target/sh4/translate.c
index 53b0921..efbc8ab 100644
--- a/target/sh4/translate.c
+++ b/target/sh4/translate.c
@@ -809,8 +809,17 @@ static void _decode_opc(DisasContext * ctx)
tcg_gen_qemu_ld_i32(arg0, REG(B7_4), ctx->memidx,
MO_TESL | MO_ALIGN);
arg1 = tcg_temp_new();
- tcg_gen_qemu_ld_i32(arg1, REG(B11_8), ctx->memidx,
- MO_TESL | MO_ALIGN);
+ if (B7_4 == B11_8) {
+ /* When Rm and Rn are the same register, the second
+ operand is read after the first post-increment. */
+ TCGv addr = tcg_temp_new();
+ tcg_gen_addi_i32(addr, REG(B11_8), 4);
+ tcg_gen_qemu_ld_i32(arg1, addr, ctx->memidx,
+ MO_TESL | MO_ALIGN);
+ } else {
+ tcg_gen_qemu_ld_i32(arg1, REG(B11_8), ctx->memidx,
+ MO_TESL | MO_ALIGN);
+ }
gen_helper_macl(tcg_env, arg0, arg1);
tcg_gen_addi_i32(REG(B7_4), REG(B7_4), 4);
tcg_gen_addi_i32(REG(B11_8), REG(B11_8), 4);
@@ -823,8 +832,16 @@ static void _decode_opc(DisasContext * ctx)
tcg_gen_qemu_ld_i32(arg0, REG(B7_4), ctx->memidx,
MO_TESW | MO_ALIGN);
arg1 = tcg_temp_new();
- tcg_gen_qemu_ld_i32(arg1, REG(B11_8), ctx->memidx,
- MO_TESW | MO_ALIGN);
+ if (B7_4 == B11_8) {
+ /* See mac.l above. */
+ TCGv addr = tcg_temp_new();
+ tcg_gen_addi_i32(addr, REG(B11_8), 2);
+ tcg_gen_qemu_ld_i32(arg1, addr, ctx->memidx,
+ MO_TESW | MO_ALIGN);
+ } else {
+ tcg_gen_qemu_ld_i32(arg1, REG(B11_8), ctx->memidx,
+ MO_TESW | MO_ALIGN);
+ }
gen_helper_macw(tcg_env, arg0, arg1);
tcg_gen_addi_i32(REG(B11_8), REG(B11_8), 2);
tcg_gen_addi_i32(REG(B7_4), REG(B7_4), 2);