Re: [PATCH 2/2] target/sh4: fixup tcg generation for sh4 `fmov` instructions.

[email protected]
Newsgroups gmane.comp.emulators.qemu
Message-ID <[email protected]>
On Thu, 30 Jul 2026 05:55:08 +0900,
Randy Schifflin wrote:
> 
> Fixes TCG generation for sh4 `fmov` instructions.
> 
> Updates the current logic for these instructions to correctly handle
>   SH4 pair single-precision data transfer semantics.
>   According to the SH4 cpu manual, `fmov` between a double-precision
>   register operand and memory requires the precision mode to be
>   single-precision and the transfer size mode to be pairwise f32.
>   The result is reading/writing a pair of two f32 values to/from memory.
>   In little-endian mode, this has slightly different semantics than
>   the current implementation which handles reads/writes as a single
>   f64 value- the first and second words get incorrectly reversed.
> 
> Signed-off-by: Randy Schifflin <[email protected]>
> ---
>  target/sh4/translate.c | 82 +++++++++++++++++++++++++++++---------------------
>  1 file changed, 47 insertions(+), 35 deletions(-)
> 
> diff --git a/target/sh4/translate.c b/target/sh4/translate.c
> index 373950fd66..8fe3b15e50 100644
> --- a/target/sh4/translate.c
> +++ b/target/sh4/translate.c
> @@ -962,10 +962,14 @@ static void _decode_opc(DisasContext * ctx)
>      case 0xf00a: /* fmov {F,D,X}Rm,@Rn - FPSCR: Nothing */
>          CHECK_FPU_ENABLED
>          if (ctx->tbflags & FPSCR_SZ) {
> -            TCGv_i64 fp = tcg_temp_new_i64();
> -            gen_load_fpr64(ctx, fp, XHACK(B7_4));
> -            tcg_gen_qemu_st_i64(fp, REG(B11_8), ctx->memidx,
> -                                MO_TEUQ | MO_ALIGN);
> +            TCGv addr = tcg_temp_new_i32();
> +            int xsrc = XHACK(B7_4);
> +
> +            tcg_gen_qemu_st_i32(FREG(xsrc), REG(B11_8), ctx->memidx,
> +                                MO_TEUL | MO_ALIGN);
> +            tcg_gen_addi_i32(addr, REG(B11_8), 4);
> +            tcg_gen_qemu_st_i32(FREG(xsrc + 1), addr, ctx->memidx,
> +                                MO_TEUL | MO_ALIGN);
>          } else {
>              tcg_gen_qemu_st_i32(FREG(B7_4), REG(B11_8), ctx->memidx,
>                                  MO_TEUL | MO_ALIGN);
> @@ -974,23 +978,29 @@ static void _decode_opc(DisasContext * ctx)
>      case 0xf008: /* fmov @Rm,{F,D,X}Rn - FPSCR: Nothing */
>          CHECK_FPU_ENABLED
>          if (ctx->tbflags & FPSCR_SZ) {
> -            TCGv_i64 fp = tcg_temp_new_i64();
> -            tcg_gen_qemu_ld_i64(fp, REG(B7_4), ctx->memidx,
> -                                MO_TEUQ | MO_ALIGN);
> -            gen_store_fpr64(ctx, fp, XHACK(B11_8));
> +            TCGv addr = tcg_temp_new_i32();
> +            int xdst = XHACK(B11_8);
> +            tcg_gen_qemu_ld_i32(FREG(xdst), REG(B7_4), ctx->memidx,
> +                                MO_TEUL | MO_ALIGN);
> +            tcg_gen_addi_i32(addr, REG(B7_4), 4);
> +            tcg_gen_qemu_ld_i32(FREG(xdst + 1), addr, ctx->memidx,
> +                                MO_TEUL | MO_ALIGN);
>          } else {
>              tcg_gen_qemu_ld_i32(FREG(B11_8), REG(B7_4), ctx->memidx,
>                                  MO_TEUL | MO_ALIGN);
>          }
>          return;
> +
>      case 0xf009: /* fmov @Rm+,{F,D,X}Rn - FPSCR: Nothing */
>          CHECK_FPU_ENABLED
>          if (ctx->tbflags & FPSCR_SZ) {
> -            TCGv_i64 fp = tcg_temp_new_i64();
> -            tcg_gen_qemu_ld_i64(fp, REG(B7_4), ctx->memidx,
> -                                MO_TEUQ | MO_ALIGN);
> -            gen_store_fpr64(ctx, fp, XHACK(B11_8));
> -            tcg_gen_addi_i32(REG(B7_4), REG(B7_4), 8);
> +            int xdst = XHACK(B11_8);
> +            tcg_gen_qemu_ld_i32(FREG(xdst), REG(B7_4), ctx->memidx,
> +                                MO_TEUL | MO_ALIGN);
> +            tcg_gen_addi_i32(REG(B7_4), REG(B7_4), 4);
> +            tcg_gen_qemu_ld_i32(FREG(xdst + 1), REG(B7_4), ctx->memidx,
> +                                MO_TEUL | MO_ALIGN);
> +            tcg_gen_addi_i32(REG(B7_4), REG(B7_4), 4);
>          } else {
>              tcg_gen_qemu_ld_i32(FREG(B11_8), REG(B7_4), ctx->memidx,
>                                  MO_TEUL | MO_ALIGN);
> @@ -999,20 +1009,18 @@ static void _decode_opc(DisasContext * ctx)
>          return;
>      case 0xf00b: /* fmov {F,D,X}Rm,@-Rn - FPSCR: Nothing */
>          CHECK_FPU_ENABLED
> -        {
> -            TCGv addr = tcg_temp_new_i32();
> -            if (ctx->tbflags & FPSCR_SZ) {
> -                TCGv_i64 fp = tcg_temp_new_i64();
> -                gen_load_fpr64(ctx, fp, XHACK(B7_4));
> -                tcg_gen_subi_i32(addr, REG(B11_8), 8);
> -                tcg_gen_qemu_st_i64(fp, addr, ctx->memidx,
> -                                    MO_TEUQ | MO_ALIGN);
> -            } else {
> -                tcg_gen_subi_i32(addr, REG(B11_8), 4);
> -                tcg_gen_qemu_st_i32(FREG(B7_4), addr, ctx->memidx,
> -                                    MO_TEUL | MO_ALIGN);
> -            }
> -            tcg_gen_mov_i32(REG(B11_8), addr);
> +        if (ctx->tbflags & FPSCR_SZ) {
> +            int xdst = XHACK(B7_4);
> +            tcg_gen_subi_i32(REG(B11_8), REG(B11_8), 4);
> +            tcg_gen_qemu_st_i32(FREG(xdst + 1), REG(B11_8), ctx->memidx,
> +                                MO_TEUL | MO_ALIGN);
> +            tcg_gen_subi_i32(REG(B11_8), REG(B11_8), 4);
> +            tcg_gen_qemu_st_i32(FREG(xdst), REG(B11_8), ctx->memidx,
> +                                MO_TEUL | MO_ALIGN);
> +        } else {
> +            tcg_gen_subi_i32(REG(B11_8), REG(B11_8), 4);
> +            tcg_gen_qemu_st_i32(FREG(B7_4), REG(B11_8), ctx->memidx,
> +                                MO_TEUL | MO_ALIGN);
>          }
>          return;
>      case 0xf006: /* fmov @(R0,Rm),{F,D,X}Rm - FPSCR: Nothing */
> @@ -1021,10 +1029,12 @@ static void _decode_opc(DisasContext * ctx)
>              TCGv addr = tcg_temp_new_i32();
>              tcg_gen_add_i32(addr, REG(B7_4), REG(0));
>              if (ctx->tbflags & FPSCR_SZ) {
> -                TCGv_i64 fp = tcg_temp_new_i64();
> -                tcg_gen_qemu_ld_i64(fp, addr, ctx->memidx,
> -                                    MO_TEUQ | MO_ALIGN);
> -                gen_store_fpr64(ctx, fp, XHACK(B11_8));
> +                int xdst = XHACK(B11_8);
> +                tcg_gen_qemu_ld_i32(FREG(xdst), addr, ctx->memidx,
> +                                    MO_TEUL | MO_ALIGN);
> +                tcg_gen_addi_i32(addr, addr, 4);
> +                tcg_gen_qemu_ld_i32(FREG(xdst + 1), addr, ctx->memidx,
> +                                    MO_TEUL | MO_ALIGN);
>              } else {
>                  tcg_gen_qemu_ld_i32(FREG(B11_8), addr, ctx->memidx,
>                                      MO_TEUL | MO_ALIGN);
> @@ -1037,10 +1047,12 @@ static void _decode_opc(DisasContext * ctx)
>              TCGv addr = tcg_temp_new();
>              tcg_gen_add_i32(addr, REG(B11_8), REG(0));
>              if (ctx->tbflags & FPSCR_SZ) {
> -                TCGv_i64 fp = tcg_temp_new_i64();
> -                gen_load_fpr64(ctx, fp, XHACK(B7_4));
> -                tcg_gen_qemu_st_i64(fp, addr, ctx->memidx,
> -                                    MO_TEUQ | MO_ALIGN);
> +                int xsrc = XHACK(B7_4);
> +                tcg_gen_qemu_st_i32(FREG(xsrc), addr, ctx->memidx,
> +                                    MO_TEUL | MO_ALIGN);
> +                tcg_gen_addi_i32(addr, addr, 4);
> +                tcg_gen_qemu_st_i32(FREG(xsrc + 1), addr, ctx->memidx,
> +                                    MO_TEUL | MO_ALIGN);
>              } else {
>                  tcg_gen_qemu_st_i32(FREG(B7_4), addr, ctx->memidx,
>                                      MO_TEUL | MO_ALIGN);
> 
> -- 
> 2.43.0
> 

Reviewed-by: Yoshinori Sato <[email protected]>

-- 
Yosinori Sato
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.