summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--target-sh4/cpu.h3
-rw-r--r--target-sh4/helper.h2
-rw-r--r--target-sh4/op_helper.c12
-rw-r--r--target-sh4/translate.c30
4 files changed, 42 insertions, 5 deletions
diff --git a/target-sh4/cpu.h b/target-sh4/cpu.h
index 23ecded55f..02ee24198b 100644
--- a/target-sh4/cpu.h
+++ b/target-sh4/cpu.h
@@ -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 */
diff --git a/target-sh4/helper.h b/target-sh4/helper.h
index e8fd050efe..631e7e1968 100644
--- a/target-sh4/helper.h
+++ b/target-sh4/helper.h
@@ -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)
diff --git a/target-sh4/op_helper.c b/target-sh4/op_helper.c
index f3e73004a7..63522194f7 100644
--- a/target-sh4/op_helper.c
+++ b/target-sh4/op_helper.c
@@ -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;
diff --git a/target-sh4/translate.c b/target-sh4/translate.c
index 505b19690f..50b82e080c 100644
--- a/target-sh4/translate.c
+++ b/target-sh4/translate.c
@@ -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();