On Wed, 26 Aug 2026 17:36:22 +0900,
Oleg Endo wrote:
> 
> [1  <text/plain; UTF-8 (quoted-printable)>]
> 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
> [2 qemu-sh4-mac-same-reg.patch <text/x-patch; UTF-8 (base64)>]
> 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);

It is true that the current behavior differs from the pseudocode in the manual.
Wouldn't it be simpler to just generate a TCG that matches the pseudocode?
I'm sorry, I haven't actually tested this change yet.

diff --git a/target/sh4/translate.c b/target/sh4/translate.c
index e503a97b22..64fe2cd31d 100644
--- a/target/sh4/translate.c
+++ b/target/sh4/translate.c
@@ -801,13 +801,13 @@ static void _decode_opc(DisasContext * ctx)
         {
             TCGv arg0, arg1;
             arg0 = tcg_temp_new();
-            tcg_gen_qemu_ld_i32(arg0, REG(B7_4), ctx->memidx,
-                                MO_TESL | MO_ALIGN);
-            tcg_gen_addi_i32(REG(B7_4), REG(B7_4), 4);
             arg1 = tcg_temp_new();
             tcg_gen_qemu_ld_i32(arg1, REG(B11_8), ctx->memidx,
                                 MO_TESL | MO_ALIGN);
             tcg_gen_addi_i32(REG(B11_8), REG(B11_8), 4);
+            tcg_gen_qemu_ld_i32(arg0, REG(B7_4), ctx->memidx,
+                                MO_TESL | MO_ALIGN);
+            tcg_gen_addi_i32(REG(B7_4), REG(B7_4), 4);
             gen_helper_macl(tcg_env, arg0, arg1);
         }
         return;
@@ -815,13 +815,13 @@ static void _decode_opc(DisasContext * ctx)
         {
             TCGv arg0, arg1;
             arg0 = tcg_temp_new();
-            tcg_gen_qemu_ld_i32(arg0, REG(B7_4), ctx->memidx,
-                                MO_TESW | MO_ALIGN);
-            tcg_gen_addi_i32(REG(B7_4), REG(B7_4), 2);
             arg1 = tcg_temp_new();
             tcg_gen_qemu_ld_i32(arg1, REG(B11_8), ctx->memidx,
                                 MO_TESW | MO_ALIGN);
             tcg_gen_addi_i32(REG(B11_8), REG(B11_8), 2);
+            tcg_gen_qemu_ld_i32(arg0, REG(B7_4), ctx->memidx,
+                                MO_TESW | MO_ALIGN);
+            tcg_gen_addi_i32(REG(B7_4), REG(B7_4), 2);
             gen_helper_macw(tcg_env, arg0, arg1);
         }
         return;

-- 
Yosinori Sato

Reply via email to