[PATCH 2/2] target/sh4: fixup tcg generation for sh4 `fmov` instructions.
Randy Schifflin <[email protected]> Wed, 29 Jul 2026 13:55:08 -0700
| Newsgroups | org.nongnu.qemu-trivial,org.nongnu.qemu-devel |
|---|---|
| Message-ID | <20260729-sh4-fix-fmov-instructions-b4-v1-2-65cc9679025a@gmail.com> |
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