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

Randy Schifflin <[email protected]>
Newsgroups gmane.comp.emulators.qemu
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
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.