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 279 *flags = (env->flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL
280 280 | DELAY_SLOT_TRUE | DELAY_SLOT_CLEARME)) /* Bits 0- 3 */
281 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 286 #endif /* _CPU_SH4_H */
... ...
target-sh4/helper.h
... ... @@ -3,6 +3,8 @@
3 3 DEF_HELPER_0(ldtlb, void)
4 4 DEF_HELPER_0(raise_illegal_instruction, void)
5 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 8 DEF_HELPER_0(debug, void)
7 9 DEF_HELPER_1(sleep, void, i32)
8 10 DEF_HELPER_1(trapa, void, i32)
... ...
target-sh4/op_helper.c
... ... @@ -89,6 +89,18 @@ void helper_raise_slot_illegal_instruction(void)
89 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 104 void helper_debug(void)
93 105 {
94 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 447 #define DREG(x) FREG(x) /* Assumes lsb of (x) is always 0 */
448 448  
449 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 458 #define CHECK_PRIVILEGED \
455 459 if (IS_USER(ctx)) { \
  460 + tcg_gen_movi_i32(cpu_pc, ctx->pc); \
456 461 gen_helper_raise_illegal_instruction(); \
457 462 ctx->bstate = BS_EXCP; \
458 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 479 static void _decode_opc(DisasContext * ctx)
462 480 {
463 481 #if 0
... ... @@ -1454,12 +1472,14 @@ static void _decode_opc(DisasContext * ctx)
1454 1472 LDST(mach, 0x400a, 0x4006, 0x000a, 0x4002, {})
1455 1473 LDST(macl, 0x401a, 0x4016, 0x001a, 0x4012, {})
1456 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 1476 case 0x406a: /* lds Rm,FPSCR */
  1477 + CHECK_FPU_ENABLED
1459 1478 gen_helper_ld_fpscr(REG(B11_8));
1460 1479 ctx->bstate = BS_STOP;
1461 1480 return;
1462 1481 case 0x4066: /* lds.l @Rm+,FPSCR */
  1482 + CHECK_FPU_ENABLED
1463 1483 {
1464 1484 TCGv addr = tcg_temp_new();
1465 1485 tcg_gen_qemu_ld32s(addr, REG(B11_8), ctx->memidx);
... ... @@ -1470,9 +1490,11 @@ static void _decode_opc(DisasContext * ctx)
1470 1490 }
1471 1491 return;
1472 1492 case 0x006a: /* sts FPSCR,Rn */
  1493 + CHECK_FPU_ENABLED
1473 1494 tcg_gen_andi_i32(REG(B11_8), cpu_fpscr, 0x003fffff);
1474 1495 return;
1475 1496 case 0x4062: /* sts FPSCR,@-Rn */
  1497 + CHECK_FPU_ENABLED
1476 1498 {
1477 1499 TCGv addr, val;
1478 1500 val = tcg_temp_new();
... ...