]> git.proxmox.com Git - qemu.git/commitdiff
SH4: Implement FD bit
authoraurel32 <aurel32@c046a42c-6fe2-441c-8c8c-71466251a162>
Sun, 7 Dec 2008 22:46:31 +0000 (22:46 +0000)
committeraurel32 <aurel32@c046a42c-6fe2-441c-8c8c-71466251a162>
Sun, 7 Dec 2008 22:46:31 +0000 (22:46 +0000)
SH4 manual say that if a floating point instruction is executed while
FD bit in the status register is 1, an exception should be raised. QEMU
presently does not do that, so the kernel does not initialize FP state
for any thread, nor does it save/restore FP state. The most apparent
consequence is that while recent gcc/libc expect double-precision mode
to be set by kernel, they run in single-precision mode, and all FP code
produces wrong values.

This patch fixes this. It also fixes a couple of places where PC was
not updated before handling an exception, although both those places
deal with invalid instruction and don't lead to any user-visible bugs.

(Vladimir Prus)

git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@5937 c046a42c-6fe2-441c-8c8c-71466251a162

target-sh4/cpu.h
target-sh4/helper.h
target-sh4/op_helper.c
target-sh4/translate.c

index 23ecded55fbb1722e4de647de388dc68f1ed0e83..02ee24198bcdc1d34b90efeba7512359b7d11904 100644 (file)
@@ -279,7 +279,8 @@ static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc,
     *flags = (env->flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL
                     | DELAY_SLOT_TRUE | DELAY_SLOT_CLEARME))   /* Bits  0- 3 */
             | (env->fpscr & (FPSCR_FR | FPSCR_SZ | FPSCR_PR))  /* Bits 19-21 */
-            | (env->sr & (SR_MD | SR_RB));                     /* Bits 29-30 */
+            | (env->sr & (SR_MD | SR_RB))                      /* Bits 29-30 */
+            | (env->sr & SR_FD);                               /* Bit 15 */
 }
 
 #endif                         /* _CPU_SH4_H */
index e8fd050efef485577c75ecd26dd2596e53b3fa2c..631e7e196801a8dc5c5faaa6fd4e5e6153a45ffc 100644 (file)
@@ -3,6 +3,8 @@
 DEF_HELPER_0(ldtlb, void)
 DEF_HELPER_0(raise_illegal_instruction, void)
 DEF_HELPER_0(raise_slot_illegal_instruction, void)
+DEF_HELPER_0(raise_fpu_disable, void)
+DEF_HELPER_0(raise_slot_fpu_disable, void)
 DEF_HELPER_0(debug, void)
 DEF_HELPER_1(sleep, void, i32)
 DEF_HELPER_1(trapa, void, i32)
index f3e73004a790313096f9718910d52aace7dc5a48..63522194f77dec85ad99f7b5aa59b8e6ff6e99d3 100644 (file)
@@ -89,6 +89,18 @@ void helper_raise_slot_illegal_instruction(void)
     cpu_loop_exit();
 }
 
+void helper_raise_fpu_disable(void)
+{
+  env->exception_index = 0x800;
+  cpu_loop_exit();
+}
+
+void helper_raise_slot_fpu_disable(void)
+{
+  env->exception_index = 0x820;
+  cpu_loop_exit();
+}
+
 void helper_debug(void)
 {
     env->exception_index = EXCP_DEBUG;
index 505b19690f4755d87dd27224c79f53e02160f555..50b82e080c387ed889cefd61a1a626de3c8660a4 100644 (file)
@@ -447,17 +447,35 @@ static inline void gen_store_fpr64 (TCGv_i64 t, int reg)
 #define DREG(x) FREG(x) /* Assumes lsb of (x) is always 0 */
 
 #define CHECK_NOT_DELAY_SLOT \
-  if (ctx->flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL)) \
-  {gen_helper_raise_slot_illegal_instruction(); ctx->bstate = BS_EXCP; \
-   return;}
+  if (ctx->flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL))     \
+  {                                                           \
+      tcg_gen_movi_i32(cpu_pc, ctx->pc-2);                    \
+      gen_helper_raise_slot_illegal_instruction();            \
+      ctx->bstate = BS_EXCP;                                  \
+      return;                                                 \
+  }
 
 #define CHECK_PRIVILEGED                                      \
   if (IS_USER(ctx)) {                                         \
+      tcg_gen_movi_i32(cpu_pc, ctx->pc);                      \
       gen_helper_raise_illegal_instruction();                 \
       ctx->bstate = BS_EXCP;                                  \
       return;                                                 \
   }
 
+#define CHECK_FPU_ENABLED                                       \
+  if (ctx->flags & SR_FD) {                                     \
+      if (ctx->flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL)) { \
+          tcg_gen_movi_i32(cpu_pc, ctx->pc-2);                  \
+          gen_helper_raise_slot_fpu_disable();                  \
+      } else {                                                  \
+          tcg_gen_movi_i32(cpu_pc, ctx->pc);                    \
+          gen_helper_raise_fpu_disable();                       \
+      }                                                         \
+      ctx->bstate = BS_EXCP;                                    \
+      return;                                                   \
+  }
+
 static void _decode_opc(DisasContext * ctx)
 {
 #if 0
@@ -1454,12 +1472,14 @@ static void _decode_opc(DisasContext * ctx)
        LDST(mach, 0x400a, 0x4006, 0x000a, 0x4002, {})
        LDST(macl, 0x401a, 0x4016, 0x001a, 0x4012, {})
        LDST(pr,   0x402a, 0x4026, 0x002a, 0x4022, {})
-       LDST(fpul, 0x405a, 0x4056, 0x005a, 0x4052, {})
+       LDST(fpul, 0x405a, 0x4056, 0x005a, 0x4052, {CHECK_FPU_ENABLED})
     case 0x406a:               /* lds Rm,FPSCR */
+       CHECK_FPU_ENABLED
        gen_helper_ld_fpscr(REG(B11_8));
        ctx->bstate = BS_STOP;
        return;
     case 0x4066:               /* lds.l @Rm+,FPSCR */
+       CHECK_FPU_ENABLED
        {
            TCGv addr = tcg_temp_new();
            tcg_gen_qemu_ld32s(addr, REG(B11_8), ctx->memidx);
@@ -1470,9 +1490,11 @@ static void _decode_opc(DisasContext * ctx)
        }
        return;
     case 0x006a:               /* sts FPSCR,Rn */
+       CHECK_FPU_ENABLED
        tcg_gen_andi_i32(REG(B11_8), cpu_fpscr, 0x003fffff);
        return;
     case 0x4062:               /* sts FPSCR,@-Rn */
+       CHECK_FPU_ENABLED
        {
            TCGv addr, val;
            val = tcg_temp_new();