Commit d8299bccf265b72db967a064e8151660b78cdfae

Authored by aurel32
1 parent 54604f74

SH4: Implement FD bit

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
@@ -279,7 +279,8 @@ static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc, @@ -279,7 +279,8 @@ static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc,
279 *flags = (env->flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL 279 *flags = (env->flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL
280 | DELAY_SLOT_TRUE | DELAY_SLOT_CLEARME)) /* Bits 0- 3 */ 280 | DELAY_SLOT_TRUE | DELAY_SLOT_CLEARME)) /* Bits 0- 3 */
281 | (env->fpscr & (FPSCR_FR | FPSCR_SZ | FPSCR_PR)) /* Bits 19-21 */ 281 | (env->fpscr & (FPSCR_FR | FPSCR_SZ | FPSCR_PR)) /* Bits 19-21 */
282 - | (env->sr & (SR_MD | SR_RB)); /* Bits 29-30 */ 282 + | (env->sr & (SR_MD | SR_RB)) /* Bits 29-30 */
  283 + | (env->sr & SR_FD); /* Bit 15 */
283 } 284 }
284 285
285 #endif /* _CPU_SH4_H */ 286 #endif /* _CPU_SH4_H */
target-sh4/helper.h
@@ -3,6 +3,8 @@ @@ -3,6 +3,8 @@
3 DEF_HELPER_0(ldtlb, void) 3 DEF_HELPER_0(ldtlb, void)
4 DEF_HELPER_0(raise_illegal_instruction, void) 4 DEF_HELPER_0(raise_illegal_instruction, void)
5 DEF_HELPER_0(raise_slot_illegal_instruction, void) 5 DEF_HELPER_0(raise_slot_illegal_instruction, void)
  6 +DEF_HELPER_0(raise_fpu_disable, void)
  7 +DEF_HELPER_0(raise_slot_fpu_disable, void)
6 DEF_HELPER_0(debug, void) 8 DEF_HELPER_0(debug, void)
7 DEF_HELPER_1(sleep, void, i32) 9 DEF_HELPER_1(sleep, void, i32)
8 DEF_HELPER_1(trapa, void, i32) 10 DEF_HELPER_1(trapa, void, i32)
target-sh4/op_helper.c
@@ -89,6 +89,18 @@ void helper_raise_slot_illegal_instruction(void) @@ -89,6 +89,18 @@ void helper_raise_slot_illegal_instruction(void)
89 cpu_loop_exit(); 89 cpu_loop_exit();
90 } 90 }
91 91
  92 +void helper_raise_fpu_disable(void)
  93 +{
  94 + env->exception_index = 0x800;
  95 + cpu_loop_exit();
  96 +}
  97 +
  98 +void helper_raise_slot_fpu_disable(void)
  99 +{
  100 + env->exception_index = 0x820;
  101 + cpu_loop_exit();
  102 +}
  103 +
92 void helper_debug(void) 104 void helper_debug(void)
93 { 105 {
94 env->exception_index = EXCP_DEBUG; 106 env->exception_index = EXCP_DEBUG;
target-sh4/translate.c
@@ -447,17 +447,35 @@ static inline void gen_store_fpr64 (TCGv_i64 t, int reg) @@ -447,17 +447,35 @@ static inline void gen_store_fpr64 (TCGv_i64 t, int reg)
447 #define DREG(x) FREG(x) /* Assumes lsb of (x) is always 0 */ 447 #define DREG(x) FREG(x) /* Assumes lsb of (x) is always 0 */
448 448
449 #define CHECK_NOT_DELAY_SLOT \ 449 #define CHECK_NOT_DELAY_SLOT \
450 - if (ctx->flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL)) \  
451 - {gen_helper_raise_slot_illegal_instruction(); ctx->bstate = BS_EXCP; \  
452 - return;} 450 + if (ctx->flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL)) \
  451 + { \
  452 + tcg_gen_movi_i32(cpu_pc, ctx->pc-2); \
  453 + gen_helper_raise_slot_illegal_instruction(); \
  454 + ctx->bstate = BS_EXCP; \
  455 + return; \
  456 + }
453 457
454 #define CHECK_PRIVILEGED \ 458 #define CHECK_PRIVILEGED \
455 if (IS_USER(ctx)) { \ 459 if (IS_USER(ctx)) { \
  460 + tcg_gen_movi_i32(cpu_pc, ctx->pc); \
456 gen_helper_raise_illegal_instruction(); \ 461 gen_helper_raise_illegal_instruction(); \
457 ctx->bstate = BS_EXCP; \ 462 ctx->bstate = BS_EXCP; \
458 return; \ 463 return; \
459 } 464 }
460 465
  466 +#define CHECK_FPU_ENABLED \
  467 + if (ctx->flags & SR_FD) { \
  468 + if (ctx->flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL)) { \
  469 + tcg_gen_movi_i32(cpu_pc, ctx->pc-2); \
  470 + gen_helper_raise_slot_fpu_disable(); \
  471 + } else { \
  472 + tcg_gen_movi_i32(cpu_pc, ctx->pc); \
  473 + gen_helper_raise_fpu_disable(); \
  474 + } \
  475 + ctx->bstate = BS_EXCP; \
  476 + return; \
  477 + }
  478 +
461 static void _decode_opc(DisasContext * ctx) 479 static void _decode_opc(DisasContext * ctx)
462 { 480 {
463 #if 0 481 #if 0
@@ -1454,12 +1472,14 @@ static void _decode_opc(DisasContext * ctx) @@ -1454,12 +1472,14 @@ static void _decode_opc(DisasContext * ctx)
1454 LDST(mach, 0x400a, 0x4006, 0x000a, 0x4002, {}) 1472 LDST(mach, 0x400a, 0x4006, 0x000a, 0x4002, {})
1455 LDST(macl, 0x401a, 0x4016, 0x001a, 0x4012, {}) 1473 LDST(macl, 0x401a, 0x4016, 0x001a, 0x4012, {})
1456 LDST(pr, 0x402a, 0x4026, 0x002a, 0x4022, {}) 1474 LDST(pr, 0x402a, 0x4026, 0x002a, 0x4022, {})
1457 - LDST(fpul, 0x405a, 0x4056, 0x005a, 0x4052, {}) 1475 + LDST(fpul, 0x405a, 0x4056, 0x005a, 0x4052, {CHECK_FPU_ENABLED})
1458 case 0x406a: /* lds Rm,FPSCR */ 1476 case 0x406a: /* lds Rm,FPSCR */
  1477 + CHECK_FPU_ENABLED
1459 gen_helper_ld_fpscr(REG(B11_8)); 1478 gen_helper_ld_fpscr(REG(B11_8));
1460 ctx->bstate = BS_STOP; 1479 ctx->bstate = BS_STOP;
1461 return; 1480 return;
1462 case 0x4066: /* lds.l @Rm+,FPSCR */ 1481 case 0x4066: /* lds.l @Rm+,FPSCR */
  1482 + CHECK_FPU_ENABLED
1463 { 1483 {
1464 TCGv addr = tcg_temp_new(); 1484 TCGv addr = tcg_temp_new();
1465 tcg_gen_qemu_ld32s(addr, REG(B11_8), ctx->memidx); 1485 tcg_gen_qemu_ld32s(addr, REG(B11_8), ctx->memidx);
@@ -1470,9 +1490,11 @@ static void _decode_opc(DisasContext * ctx) @@ -1470,9 +1490,11 @@ static void _decode_opc(DisasContext * ctx)
1470 } 1490 }
1471 return; 1491 return;
1472 case 0x006a: /* sts FPSCR,Rn */ 1492 case 0x006a: /* sts FPSCR,Rn */
  1493 + CHECK_FPU_ENABLED
1473 tcg_gen_andi_i32(REG(B11_8), cpu_fpscr, 0x003fffff); 1494 tcg_gen_andi_i32(REG(B11_8), cpu_fpscr, 0x003fffff);
1474 return; 1495 return;
1475 case 0x4062: /* sts FPSCR,@-Rn */ 1496 case 0x4062: /* sts FPSCR,@-Rn */
  1497 + CHECK_FPU_ENABLED
1476 { 1498 {
1477 TCGv addr, val; 1499 TCGv addr, val;
1478 val = tcg_temp_new(); 1500 val = tcg_temp_new();