Commit 7c58044c0ab79f11604f71aa04b4691baacef886

Authored by j_mayer
1 parent a32ff1ad

Fix PowerPC FPSCR update and floating-point exception generation

in most useful cases.


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3458 c046a42c-6fe2-441c-8c8c-71466251a162
darwin-user/main.c
... ... @@ -224,11 +224,6 @@ void cpu_loop(CPUPPCState *env)
224 224 case POWERPC_EXCP_FP:
225 225 EXCP_DUMP(env, "Floating point program exception\n");
226 226 /* Set FX */
227   - env->fpscr[7] |= 0x8;
228   - /* Finally, update FEX */
229   - if ((((env->fpscr[7] & 0x3) << 3) | (env->fpscr[6] >> 1)) &
230   - ((env->fpscr[1] << 1) | (env->fpscr[0] >> 3)))
231   - env->fpscr[7] |= 0x4;
232 227 info.si_signo = SIGFPE;
233 228 info.si_errno = 0;
234 229 switch (env->error_code & 0xF) {
... ... @@ -248,7 +243,7 @@ void cpu_loop(CPUPPCState *env)
248 243 case POWERPC_EXCP_FP_VXSOFT:
249 244 info.si_code = FPE_FLTINV;
250 245 break;
251   - case POWERPC_EXCP_FP_VXNAN:
  246 + case POWERPC_EXCP_FP_VXSNAN:
252 247 case POWERPC_EXCP_FP_VXISI:
253 248 case POWERPC_EXCP_FP_VXIDI:
254 249 case POWERPC_EXCP_FP_VXIMZ:
... ...
linux-user/main.c
... ... @@ -829,12 +829,6 @@ void cpu_loop(CPUPPCState *env)
829 829 switch (env->error_code & ~0xF) {
830 830 case POWERPC_EXCP_FP:
831 831 EXCP_DUMP(env, "Floating point program exception\n");
832   - /* Set FX */
833   - env->fpscr[7] |= 0x8;
834   - /* Finally, update FEX */
835   - if ((((env->fpscr[7] & 0x3) << 3) | (env->fpscr[6] >> 1)) &
836   - ((env->fpscr[1] << 1) | (env->fpscr[0] >> 3)))
837   - env->fpscr[7] |= 0x4;
838 832 info.si_signo = TARGET_SIGFPE;
839 833 info.si_errno = 0;
840 834 switch (env->error_code & 0xF) {
... ... @@ -854,7 +848,7 @@ void cpu_loop(CPUPPCState *env)
854 848 case POWERPC_EXCP_FP_VXSOFT:
855 849 info.si_code = TARGET_FPE_FLTINV;
856 850 break;
857   - case POWERPC_EXCP_FP_VXNAN:
  851 + case POWERPC_EXCP_FP_VXSNAN:
858 852 case POWERPC_EXCP_FP_VXISI:
859 853 case POWERPC_EXCP_FP_VXIDI:
860 854 case POWERPC_EXCP_FP_VXIMZ:
... ...
target-ppc/cpu.h
... ... @@ -239,7 +239,7 @@ enum {
239 239 POWERPC_EXCP_FP_UX = 0x02, /* FP underflow */
240 240 POWERPC_EXCP_FP_ZX = 0x03, /* FP divide by zero */
241 241 POWERPC_EXCP_FP_XX = 0x04, /* FP inexact */
242   - POWERPC_EXCP_FP_VXNAN = 0x05, /* FP invalid SNaN op */
  242 + POWERPC_EXCP_FP_VXSNAN = 0x05, /* FP invalid SNaN op */
243 243 POWERPC_EXCP_FP_VXISI = 0x06, /* FP invalid infinite subtraction */
244 244 POWERPC_EXCP_FP_VXIDI = 0x07, /* FP invalid infinite divide */
245 245 POWERPC_EXCP_FP_VXZDZ = 0x08, /* FP invalid zero divide */
... ... @@ -433,14 +433,84 @@ enum {
433 433 POWERPC_FLAG_PMM = 0x00000400,
434 434 };
435 435  
  436 +/*****************************************************************************/
  437 +/* Floating point status and control register */
  438 +#define FPSCR_FX 31 /* Floating-point exception summary */
  439 +#define FPSCR_FEX 30 /* Floating-point enabled exception summary */
  440 +#define FPSCR_VX 29 /* Floating-point invalid operation exception summ. */
  441 +#define FPSCR_OX 28 /* Floating-point overflow exception */
  442 +#define FPSCR_UX 27 /* Floating-point underflow exception */
  443 +#define FPSCR_ZX 26 /* Floating-point zero divide exception */
  444 +#define FPSCR_XX 25 /* Floating-point inexact exception */
  445 +#define FPSCR_VXSNAN 24 /* Floating-point invalid operation exception (sNan) */
  446 +#define FPSCR_VXISI 23 /* Floating-point invalid operation exception (inf) */
  447 +#define FPSCR_VXIDI 22 /* Floating-point invalid operation exception (inf) */
  448 +#define FPSCR_VXZDZ 21 /* Floating-point invalid operation exception (zero) */
  449 +#define FPSCR_VXIMZ 20 /* Floating-point invalid operation exception (inf) */
  450 +#define FPSCR_VXVC 19 /* Floating-point invalid operation exception (comp) */
  451 +#define FPSCR_FR 18 /* Floating-point fraction rounded */
  452 +#define FPSCR_FI 17 /* Floating-point fraction inexact */
  453 +#define FPSCR_C 16 /* Floating-point result class descriptor */
  454 +#define FPSCR_FL 15 /* Floating-point less than or negative */
  455 +#define FPSCR_FG 14 /* Floating-point greater than or negative */
  456 +#define FPSCR_FE 13 /* Floating-point equal or zero */
  457 +#define FPSCR_FU 12 /* Floating-point unordered or NaN */
  458 +#define FPSCR_FPCC 12 /* Floating-point condition code */
  459 +#define FPSCR_FPRF 12 /* Floating-point result flags */
  460 +#define FPSCR_VXSOFT 10 /* Floating-point invalid operation exception (soft) */
  461 +#define FPSCR_VXSQRT 9 /* Floating-point invalid operation exception (sqrt) */
  462 +#define FPSCR_VXCVI 8 /* Floating-point invalid operation exception (int) */
  463 +#define FPSCR_VE 7 /* Floating-point invalid operation exception enable */
  464 +#define FPSCR_OE 6 /* Floating-point overflow exception enable */
  465 +#define FPSCR_UE 5 /* Floating-point undeflow exception enable */
  466 +#define FPSCR_ZE 4 /* Floating-point zero divide exception enable */
  467 +#define FPSCR_XE 3 /* Floating-point inexact exception enable */
  468 +#define FPSCR_NI 2 /* Floating-point non-IEEE mode */
  469 +#define FPSCR_RN1 1
  470 +#define FPSCR_RN 0 /* Floating-point rounding control */
  471 +#define fpscr_fex (((env->fpscr) >> FPSCR_FEX) & 0x1)
  472 +#define fpscr_vx (((env->fpscr) >> FPSCR_VX) & 0x1)
  473 +#define fpscr_ox (((env->fpscr) >> FPSCR_OX) & 0x1)
  474 +#define fpscr_ux (((env->fpscr) >> FPSCR_UX) & 0x1)
  475 +#define fpscr_zx (((env->fpscr) >> FPSCR_ZX) & 0x1)
  476 +#define fpscr_xx (((env->fpscr) >> FPSCR_XX) & 0x1)
  477 +#define fpscr_vxsnan (((env->fpscr) >> FPSCR_VXSNAN) & 0x1)
  478 +#define fpscr_vxisi (((env->fpscr) >> FPSCR_VXISI) & 0x1)
  479 +#define fpscr_vxidi (((env->fpscr) >> FPSCR_VXIDI) & 0x1)
  480 +#define fpscr_vxzdz (((env->fpscr) >> FPSCR_VXZDZ) & 0x1)
  481 +#define fpscr_vximz (((env->fpscr) >> FPSCR_VXIMZ) & 0x1)
  482 +#define fpscr_vxvc (((env->fpscr) >> FPSCR_VXVC) & 0x1)
  483 +#define fpscr_fpcc (((env->fpscr) >> FPSCR_FPCC) & 0xF)
  484 +#define fpscr_vxsoft (((env->fpscr) >> FPSCR_VXSOFT) & 0x1)
  485 +#define fpscr_vxsqrt (((env->fpscr) >> FPSCR_VXSQRT) & 0x1)
  486 +#define fpscr_vxcvi (((env->fpscr) >> FPSCR_VXCVI) & 0x1)
  487 +#define fpscr_ve (((env->fpscr) >> FPSCR_VE) & 0x1)
  488 +#define fpscr_oe (((env->fpscr) >> FPSCR_OE) & 0x1)
  489 +#define fpscr_ue (((env->fpscr) >> FPSCR_UE) & 0x1)
  490 +#define fpscr_ze (((env->fpscr) >> FPSCR_ZE) & 0x1)
  491 +#define fpscr_xe (((env->fpscr) >> FPSCR_XE) & 0x1)
  492 +#define fpscr_ni (((env->fpscr) >> FPSCR_NI) & 0x1)
  493 +#define fpscr_rn (((env->fpscr) >> FPSCR_RN) & 0x3)
  494 +/* Invalid operation exception summary */
  495 +#define fpscr_ix ((env->fpscr) & ((1 << FPSCR_VXSNAN) | (1 << FPSCR_VXISI) | \
  496 + (1 << FPSCR_VXIDI) | (1 << FPSCR_VXZDZ) | \
  497 + (1 << FPSCR_VXIMZ) | (1 << FPSCR_VXVC) | \
  498 + (1 << FPSCR_VXSOFT) | (1 << FPSCR_VXSQRT) | \
  499 + (1 << FPSCR_VXCVI)))
  500 +/* exception summary */
  501 +#define fpscr_ex (((env->fpscr) >> FPSCR_XX) & 0x1F)
  502 +/* enabled exception summary */
  503 +#define fpscr_eex (((env->fpscr) >> FPSCR_XX) & ((env->fpscr) >> FPSCR_XE) & \
  504 + 0x1F)
  505 +
  506 +/*****************************************************************************/
  507 +/* The whole PowerPC CPU context */
436 508 #if defined(TARGET_PPC64H)
437 509 #define NB_MMU_MODES 3
438 510 #else
439 511 #define NB_MMU_MODES 2
440 512 #endif
441 513  
442   -/*****************************************************************************/
443   -/* The whole PowerPC CPU context */
444 514 struct CPUPPCState {
445 515 /* First are the most commonly used resources
446 516 * during translated code execution
... ... @@ -482,7 +552,7 @@ struct CPUPPCState {
482 552 /* floating point registers */
483 553 float64 fpr[32];
484 554 /* floating point status and control register */
485   - uint8_t fpscr[8];
  555 + uint32_t fpscr;
486 556  
487 557 CPU_COMMON
488 558  
... ...
target-ppc/helper.c
... ... @@ -2130,6 +2130,8 @@ static always_inline void powerpc_excp (CPUState *env,
2130 2130 fprintf(logfile, "Ignore floating point exception\n");
2131 2131 }
2132 2132 #endif
  2133 + env->exception_index = POWERPC_EXCP_NONE;
  2134 + env->error_code = 0;
2133 2135 return;
2134 2136 }
2135 2137 new_msr &= ~((target_ulong)1 << MSR_RI);
... ... @@ -2138,12 +2140,6 @@ static always_inline void powerpc_excp (CPUState *env,
2138 2140 new_msr |= (target_ulong)1 << MSR_HV;
2139 2141 #endif
2140 2142 msr |= 0x00100000;
2141   - /* Set FX */
2142   - env->fpscr[7] |= 0x8;
2143   - /* Finally, update FEX */
2144   - if ((((env->fpscr[7] & 0x3) << 3) | (env->fpscr[6] >> 1)) &
2145   - ((env->fpscr[1] << 1) | (env->fpscr[0] >> 3)))
2146   - env->fpscr[7] |= 0x4;
2147 2143 if (msr_fe0 != msr_fe1) {
2148 2144 msr |= 0x00010000;
2149 2145 goto store_current;
... ... @@ -2199,8 +2195,11 @@ static always_inline void powerpc_excp (CPUState *env,
2199 2195 /* XXX: To be removed */
2200 2196 if (env->gpr[3] == 0x113724fa && env->gpr[4] == 0x77810f9b &&
2201 2197 env->osi_call) {
2202   - if (env->osi_call(env) != 0)
  2198 + if (env->osi_call(env) != 0) {
  2199 + env->exception_index = POWERPC_EXCP_NONE;
  2200 + env->error_code = 0;
2203 2201 return;
  2202 + }
2204 2203 }
2205 2204 if (loglevel & CPU_LOG_INT) {
2206 2205 dump_syscall(env);
... ...
target-ppc/op.c
... ... @@ -135,13 +135,6 @@ void OPPROTO op_set_Rc0 (void)
135 135 RETURN();
136 136 }
137 137  
138   -/* Set Rc1 (for floating point arithmetic) */
139   -void OPPROTO op_set_Rc1 (void)
140   -{
141   - env->crf[1] = env->fpscr[7];
142   - RETURN();
143   -}
144   -
145 138 /* Constants load */
146 139 void OPPROTO op_reset_T0 (void)
147 140 {
... ... @@ -552,21 +545,108 @@ void OPPROTO op_store_dbatl (void)
552 545 #endif /* !defined(CONFIG_USER_ONLY) */
553 546  
554 547 /* FPSCR */
555   -void OPPROTO op_load_fpscr (void)
  548 +#ifdef CONFIG_SOFTFLOAT
  549 +void OPPROTO op_reset_fpstatus (void)
556 550 {
557   - do_load_fpscr();
  551 + env->fp_status.float_exception_flags = 0;
558 552 RETURN();
559 553 }
  554 +#endif
560 555  
561   -void OPPROTO op_store_fpscr (void)
  556 +void OPPROTO op_compute_fprf (void)
562 557 {
563   - do_store_fpscr(PARAM1);
  558 + do_compute_fprf(PARAM1);
564 559 RETURN();
565 560 }
566 561  
567   -void OPPROTO op_reset_scrfx (void)
  562 +#ifdef CONFIG_SOFTFLOAT
  563 +void OPPROTO op_float_check_status (void)
568 564 {
569   - env->fpscr[7] &= ~0x8;
  565 + do_float_check_status();
  566 + RETURN();
  567 +}
  568 +#else
  569 +void OPPROTO op_float_check_status (void)
  570 +{
  571 + if (env->exception_index == POWERPC_EXCP_PROGRAM &&
  572 + (env->error_code & POWERPC_EXCP_FP)) {
  573 + /* Differred floating-point exception after target FPR update */
  574 + if (msr_fe0 != 0 || msr_fe1 != 0)
  575 + do_raise_exception_err(env->exception_index, env->error_code);
  576 + }
  577 + RETURN();
  578 +}
  579 +#endif
  580 +
  581 +#if defined(WORDS_BIGENDIAN)
  582 +#define WORD0 0
  583 +#define WORD1 1
  584 +#else
  585 +#define WORD0 1
  586 +#define WORD1 0
  587 +#endif
  588 +void OPPROTO op_load_fpscr_FT0 (void)
  589 +{
  590 + /* The 32 MSB of the target fpr are undefined.
  591 + * They'll be zero...
  592 + */
  593 + union {
  594 + float64 d;
  595 + struct {
  596 + uint32_t u[2];
  597 + } s;
  598 + } u;
  599 +
  600 + u.s.u[WORD0] = 0;
  601 + u.s.u[WORD1] = env->fpscr;
  602 + FT0 = u.d;
  603 + RETURN();
  604 +}
  605 +
  606 +void OPPROTO op_set_FT0 (void)
  607 +{
  608 + union {
  609 + float64 d;
  610 + struct {
  611 + uint32_t u[2];
  612 + } s;
  613 + } u;
  614 +
  615 + u.s.u[WORD0] = 0;
  616 + u.s.u[WORD1] = PARAM1;
  617 + FT0 = u.d;
  618 + RETURN();
  619 +}
  620 +#undef WORD0
  621 +#undef WORD1
  622 +
  623 +void OPPROTO op_load_fpscr_T0 (void)
  624 +{
  625 + T0 = (env->fpscr >> PARAM1) & 0xF;
  626 + RETURN();
  627 +}
  628 +
  629 +void OPPROTO op_load_fpcc (void)
  630 +{
  631 + T0 = fpscr_fpcc;
  632 + RETURN();
  633 +}
  634 +
  635 +void OPPROTO op_fpscr_resetbit (void)
  636 +{
  637 + env->fpscr &= PARAM1;
  638 + RETURN();
  639 +}
  640 +
  641 +void OPPROTO op_fpscr_setbit (void)
  642 +{
  643 + do_fpscr_setbit(PARAM1);
  644 + RETURN();
  645 +}
  646 +
  647 +void OPPROTO op_store_fpscr (void)
  648 +{
  649 + do_store_fpscr(PARAM1);
570 650 RETURN();
571 651 }
572 652  
... ... @@ -1702,28 +1782,44 @@ void OPPROTO op_srli_T1_64 (void)
1702 1782 /* fadd - fadd. */
1703 1783 void OPPROTO op_fadd (void)
1704 1784 {
  1785 +#if USE_PRECISE_EMULATION
  1786 + do_fadd();
  1787 +#else
1705 1788 FT0 = float64_add(FT0, FT1, &env->fp_status);
  1789 +#endif
1706 1790 RETURN();
1707 1791 }
1708 1792  
1709 1793 /* fsub - fsub. */
1710 1794 void OPPROTO op_fsub (void)
1711 1795 {
  1796 +#if USE_PRECISE_EMULATION
  1797 + do_fsub();
  1798 +#else
1712 1799 FT0 = float64_sub(FT0, FT1, &env->fp_status);
  1800 +#endif
1713 1801 RETURN();
1714 1802 }
1715 1803  
1716 1804 /* fmul - fmul. */
1717 1805 void OPPROTO op_fmul (void)
1718 1806 {
  1807 +#if USE_PRECISE_EMULATION
  1808 + do_fmul();
  1809 +#else
1719 1810 FT0 = float64_mul(FT0, FT1, &env->fp_status);
  1811 +#endif
1720 1812 RETURN();
1721 1813 }
1722 1814  
1723 1815 /* fdiv - fdiv. */
1724 1816 void OPPROTO op_fdiv (void)
1725 1817 {
  1818 +#if USE_PRECISE_EMULATION
  1819 + do_fdiv();
  1820 +#else
1726 1821 FT0 = float64_div(FT0, FT1, &env->fp_status);
  1822 +#endif
1727 1823 RETURN();
1728 1824 }
1729 1825  
... ... @@ -1805,7 +1901,11 @@ void OPPROTO op_fnmsub (void)
1805 1901 /* frsp - frsp. */
1806 1902 void OPPROTO op_frsp (void)
1807 1903 {
  1904 +#if USE_PRECISE_EMULATION
  1905 + do_frsp();
  1906 +#else
1808 1907 FT0 = float64_to_float32(FT0, &env->fp_status);
  1908 +#endif
1809 1909 RETURN();
1810 1910 }
1811 1911  
... ...
target-ppc/op_helper.c
... ... @@ -51,14 +51,6 @@ void do_raise_exception_err (uint32_t exception, int error_code)
51 51 #if 0
52 52 printf("Raise exception %3x code : %d\n", exception, error_code);
53 53 #endif
54   - switch (exception) {
55   - case POWERPC_EXCP_PROGRAM:
56   - if (error_code == POWERPC_EXCP_FP && msr_fe0 == 0 && msr_fe1 == 0)
57   - return;
58   - break;
59   - default:
60   - break;
61   - }
62 54 env->exception_index = exception;
63 55 env->error_code = error_code;
64 56 cpu_loop_exit();
... ... @@ -107,77 +99,6 @@ void do_store_pri (int prio)
107 99 }
108 100 #endif
109 101  
110   -void do_load_fpscr (void)
111   -{
112   - /* The 32 MSB of the target fpr are undefined.
113   - * They'll be zero...
114   - */
115   - union {
116   - float64 d;
117   - struct {
118   - uint32_t u[2];
119   - } s;
120   - } u;
121   - int i;
122   -
123   -#if defined(WORDS_BIGENDIAN)
124   -#define WORD0 0
125   -#define WORD1 1
126   -#else
127   -#define WORD0 1
128   -#define WORD1 0
129   -#endif
130   - u.s.u[WORD0] = 0;
131   - u.s.u[WORD1] = 0;
132   - for (i = 0; i < 8; i++)
133   - u.s.u[WORD1] |= env->fpscr[i] << (4 * i);
134   - FT0 = u.d;
135   -}
136   -
137   -void do_store_fpscr (uint32_t mask)
138   -{
139   - /*
140   - * We use only the 32 LSB of the incoming fpr
141   - */
142   - union {
143   - double d;
144   - struct {
145   - uint32_t u[2];
146   - } s;
147   - } u;
148   - int i, rnd_type;
149   -
150   - u.d = FT0;
151   - if (mask & 0x80)
152   - env->fpscr[0] = (env->fpscr[0] & 0x9) | ((u.s.u[WORD1] >> 28) & ~0x9);
153   - for (i = 1; i < 7; i++) {
154   - if (mask & (1 << (7 - i)))
155   - env->fpscr[i] = (u.s.u[WORD1] >> (4 * (7 - i))) & 0xF;
156   - }
157   - /* TODO: update FEX & VX */
158   - /* Set rounding mode */
159   - switch (env->fpscr[0] & 0x3) {
160   - case 0:
161   - /* Best approximation (round to nearest) */
162   - rnd_type = float_round_nearest_even;
163   - break;
164   - case 1:
165   - /* Smaller magnitude (round toward zero) */
166   - rnd_type = float_round_to_zero;
167   - break;
168   - case 2:
169   - /* Round toward +infinite */
170   - rnd_type = float_round_up;
171   - break;
172   - default:
173   - case 3:
174   - /* Round toward -infinite */
175   - rnd_type = float_round_down;
176   - break;
177   - }
178   - set_float_rounding_mode(rnd_type, &env->fp_status);
179   -}
180   -
181 102 target_ulong ppc_load_dump_spr (int sprn)
182 103 {
183 104 if (loglevel != 0) {
... ... @@ -553,6 +474,538 @@ void do_popcntb_64 (void)
553 474  
554 475 /*****************************************************************************/
555 476 /* Floating point operations helpers */
  477 +static inline int fpisneg (float64 f)
  478 +{
  479 + union {
  480 + float64 f;
  481 + uint64_t u;
  482 + } u;
  483 +
  484 + u.f = f;
  485 +
  486 + return u.u >> 63 != 0;
  487 +}
  488 +
  489 +static inline int isden (float f)
  490 +{
  491 + union {
  492 + float64 f;
  493 + uint64_t u;
  494 + } u;
  495 +
  496 + u.f = f;
  497 +
  498 + return ((u.u >> 52) & 0x7FF) == 0;
  499 +}
  500 +
  501 +static inline int iszero (float64 f)
  502 +{
  503 + union {
  504 + float64 f;
  505 + uint64_t u;
  506 + } u;
  507 +
  508 + u.f = f;
  509 +
  510 + return (u.u & ~0x8000000000000000ULL) == 0;
  511 +}
  512 +
  513 +static inline int isinfinity (float64 f)
  514 +{
  515 + union {
  516 + float64 f;
  517 + uint64_t u;
  518 + } u;
  519 +
  520 + u.f = f;
  521 +
  522 + return ((u.u >> 51) & 0x3FF) == 0x3FF &&
  523 + (u.u & 0x000FFFFFFFFFFFFFULL) == 0;
  524 +}
  525 +
  526 +void do_compute_fprf (int set_fprf)
  527 +{
  528 + int isneg;
  529 +
  530 + isneg = fpisneg(FT0);
  531 + if (unlikely(float64_is_nan(FT0))) {
  532 + if (float64_is_signaling_nan(FT0)) {
  533 + /* Signaling NaN: flags are undefined */
  534 + T0 = 0x00;
  535 + } else {
  536 + /* Quiet NaN */
  537 + T0 = 0x11;
  538 + }
  539 + } else if (unlikely(isinfinity(FT0))) {
  540 + /* +/- infinity */
  541 + if (isneg)
  542 + T0 = 0x09;
  543 + else
  544 + T0 = 0x05;
  545 + } else {
  546 + if (iszero(FT0)) {
  547 + /* +/- zero */
  548 + if (isneg)
  549 + T0 = 0x12;
  550 + else
  551 + T0 = 0x02;
  552 + } else {
  553 + if (isden(FT0)) {
  554 + /* Denormalized numbers */
  555 + T0 = 0x10;
  556 + } else {
  557 + /* Normalized numbers */
  558 + T0 = 0x00;
  559 + }
  560 + if (isneg) {
  561 + T0 |= 0x08;
  562 + } else {
  563 + T0 |= 0x04;
  564 + }
  565 + }
  566 + }
  567 + if (set_fprf) {
  568 + /* We update FPSCR_FPRF */
  569 + env->fpscr &= ~(0x1F << FPSCR_FPRF);
  570 + env->fpscr |= T0 << FPSCR_FPRF;
  571 + }
  572 + /* We just need fpcc to update Rc1 */
  573 + T0 &= 0xF;
  574 +}
  575 +
  576 +/* Floating-point invalid operations exception */
  577 +static always_inline void fload_invalid_op_excp (int op)
  578 +{
  579 + int ve;
  580 +
  581 + ve = fpscr_ve;
  582 + if (op & POWERPC_EXCP_FP_VXSNAN) {
  583 + /* Operation on signaling NaN */
  584 + env->fpscr |= 1 << FPSCR_VXSNAN;
  585 + }
  586 + if (op & POWERPC_EXCP_FP_VXSOFT) {
  587 + /* Software-defined condition */
  588 + env->fpscr |= 1 << FPSCR_VXSOFT;
  589 + }
  590 + switch (op & ~(POWERPC_EXCP_FP_VXSOFT | POWERPC_EXCP_FP_VXSNAN)) {
  591 + case POWERPC_EXCP_FP_VXISI:
  592 + /* Magnitude subtraction of infinities */
  593 + env->fpscr |= 1 << FPSCR_VXISI;
  594 + goto update_arith;
  595 + case POWERPC_EXCP_FP_VXIDI:
  596 + /* Division of infinity by infinity */
  597 + env->fpscr |= 1 << FPSCR_VXIDI;
  598 + goto update_arith;
  599 + case POWERPC_EXCP_FP_VXZDZ:
  600 + /* Division of zero by zero */
  601 + env->fpscr |= 1 << FPSCR_VXZDZ;
  602 + goto update_arith;
  603 + case POWERPC_EXCP_FP_VXIMZ:
  604 + /* Multiplication of zero by infinity */
  605 + env->fpscr |= 1 << FPSCR_VXIMZ;
  606 + goto update_arith;
  607 + case POWERPC_EXCP_FP_VXVC:
  608 + /* Ordered comparison of NaN */
  609 + env->fpscr |= 1 << FPSCR_VXVC;
  610 + env->fpscr &= ~(0xF << FPSCR_FPCC);
  611 + env->fpscr |= 0x11 << FPSCR_FPCC;
  612 + /* We must update the target FPR before raising the exception */
  613 + if (ve != 0) {
  614 + env->exception_index = POWERPC_EXCP_PROGRAM;
  615 + env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_VXVC;
  616 + /* Update the floating-point enabled exception summary */
  617 + env->fpscr |= 1 << FPSCR_FEX;
  618 + /* Exception is differed */
  619 + ve = 0;
  620 + }
  621 + break;
  622 + case POWERPC_EXCP_FP_VXSQRT:
  623 + /* Square root of a negative number */
  624 + env->fpscr |= 1 << FPSCR_VXSQRT;
  625 + update_arith:
  626 + env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
  627 + if (ve == 0) {
  628 + /* Set the result to quiet NaN */
  629 + FT0 = (uint64_t)-1;
  630 + env->fpscr &= ~(0xF << FPSCR_FPCC);
  631 + env->fpscr |= 0x11 << FPSCR_FPCC;
  632 + }
  633 + break;
  634 + case POWERPC_EXCP_FP_VXCVI:
  635 + /* Invalid conversion */
  636 + env->fpscr |= 1 << FPSCR_VXCVI;
  637 + env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
  638 + if (ve == 0) {
  639 + /* Set the result to quiet NaN */
  640 + FT0 = (uint64_t)-1;
  641 + env->fpscr &= ~(0xF << FPSCR_FPCC);
  642 + env->fpscr |= 0x11 << FPSCR_FPCC;
  643 + }
  644 + break;
  645 + }
  646 + /* Update the floating-point invalid operation summary */
  647 + env->fpscr |= 1 << FPSCR_VX;
  648 + /* Update the floating-point exception summary */
  649 + env->fpscr |= 1 << FPSCR_FX;
  650 + if (ve != 0) {
  651 + /* Update the floating-point enabled exception summary */
  652 + env->fpscr |= 1 << FPSCR_FEX;
  653 + if (msr_fe0 != 0 || msr_fe1 != 0)
  654 + do_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_FP | op);
  655 + }
  656 +}
  657 +
  658 +static always_inline void float_zero_divide_excp (void)
  659 +{
  660 + union {
  661 + float64 f;
  662 + uint64_t u;
  663 + } u0, u1;
  664 +
  665 +
  666 + env->fpscr |= 1 << FPSCR_ZX;
  667 + env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
  668 + /* Update the floating-point exception summary */
  669 + env->fpscr |= 1 << FPSCR_FX;
  670 + if (fpscr_ze != 0) {
  671 + /* Update the floating-point enabled exception summary */
  672 + env->fpscr |= 1 << FPSCR_FEX;
  673 + if (msr_fe0 != 0 || msr_fe1 != 0) {
  674 + do_raise_exception_err(POWERPC_EXCP_PROGRAM,
  675 + POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX);
  676 + }
  677 + } else {
  678 + /* Set the result to infinity */
  679 + u0.f = FT0;
  680 + u1.f = FT1;
  681 + u0.u = ((u0.u ^ u1.u) & 0x8000000000000000ULL);
  682 + u0.u |= 0x3FFULL << 51;
  683 + FT0 = u0.f;
  684 + }
  685 +}
  686 +
  687 +static always_inline void float_overflow_excp (void)
  688 +{
  689 + env->fpscr |= 1 << FPSCR_OX;
  690 + /* Update the floating-point exception summary */
  691 + env->fpscr |= 1 << FPSCR_FX;
  692 + if (fpscr_oe != 0) {
  693 + /* XXX: should adjust the result */
  694 + /* Update the floating-point enabled exception summary */
  695 + env->fpscr |= 1 << FPSCR_FEX;
  696 + /* We must update the target FPR before raising the exception */
  697 + env->exception_index = POWERPC_EXCP_PROGRAM;
  698 + env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_OX;
  699 + } else {
  700 + env->fpscr |= 1 << FPSCR_XX;
  701 + env->fpscr |= 1 << FPSCR_FI;
  702 + }
  703 +}
  704 +
  705 +static always_inline void float_underflow_excp (void)
  706 +{
  707 + env->fpscr |= 1 << FPSCR_UX;
  708 + /* Update the floating-point exception summary */
  709 + env->fpscr |= 1 << FPSCR_FX;
  710 + if (fpscr_ue != 0) {
  711 + /* XXX: should adjust the result */
  712 + /* Update the floating-point enabled exception summary */
  713 + env->fpscr |= 1 << FPSCR_FEX;
  714 + /* We must update the target FPR before raising the exception */
  715 + env->exception_index = POWERPC_EXCP_PROGRAM;
  716 + env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_UX;
  717 + }
  718 +}
  719 +
  720 +static always_inline void float_inexact_excp (void)
  721 +{
  722 + env->fpscr |= 1 << FPSCR_XX;
  723 + /* Update the floating-point exception summary */
  724 + env->fpscr |= 1 << FPSCR_FX;
  725 + if (fpscr_xe != 0) {
  726 + /* Update the floating-point enabled exception summary */
  727 + env->fpscr |= 1 << FPSCR_FEX;
  728 + /* We must update the target FPR before raising the exception */
  729 + env->exception_index = POWERPC_EXCP_PROGRAM;
  730 + env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_XX;
  731 + }
  732 +}
  733 +
  734 +static always_inline void fpscr_set_rounding_mode (void)
  735 +{
  736 + int rnd_type;
  737 +
  738 + /* Set rounding mode */
  739 + switch (fpscr_rn) {
  740 + case 0:
  741 + /* Best approximation (round to nearest) */
  742 + rnd_type = float_round_nearest_even;
  743 + break;
  744 + case 1:
  745 + /* Smaller magnitude (round toward zero) */
  746 + rnd_type = float_round_to_zero;
  747 + break;
  748 + case 2:
  749 + /* Round toward +infinite */
  750 + rnd_type = float_round_up;
  751 + break;
  752 + default:
  753 + case 3:
  754 + /* Round toward -infinite */
  755 + rnd_type = float_round_down;
  756 + break;
  757 + }
  758 + set_float_rounding_mode(rnd_type, &env->fp_status);
  759 +}
  760 +
  761 +void do_fpscr_setbit (int bit)
  762 +{
  763 + int prev;
  764 +
  765 + prev = (env->fpscr >> bit) & 1;
  766 + env->fpscr |= 1 << bit;
  767 + if (prev == 0) {
  768 + switch (bit) {
  769 + case FPSCR_VX:
  770 + env->fpscr |= 1 << FPSCR_FX;
  771 + if (fpscr_ve)
  772 + goto raise_ve;
  773 + case FPSCR_OX:
  774 + env->fpscr |= 1 << FPSCR_FX;
  775 + if (fpscr_oe)
  776 + goto raise_oe;
  777 + break;
  778 + case FPSCR_UX:
  779 + env->fpscr |= 1 << FPSCR_FX;
  780 + if (fpscr_ue)
  781 + goto raise_ue;
  782 + break;
  783 + case FPSCR_ZX:
  784 + env->fpscr |= 1 << FPSCR_FX;
  785 + if (fpscr_ze)
  786 + goto raise_ze;
  787 + break;
  788 + case FPSCR_XX:
  789 + env->fpscr |= 1 << FPSCR_FX;
  790 + if (fpscr_xe)
  791 + goto raise_xe;
  792 + break;
  793 + case FPSCR_VXSNAN:
  794 + case FPSCR_VXISI:
  795 + case FPSCR_VXIDI:
  796 + case FPSCR_VXZDZ:
  797 + case FPSCR_VXIMZ:
  798 + case FPSCR_VXVC:
  799 + case FPSCR_VXSOFT:
  800 + case FPSCR_VXSQRT:
  801 + case FPSCR_VXCVI:
  802 + env->fpscr |= 1 << FPSCR_VX;
  803 + env->fpscr |= 1 << FPSCR_FX;
  804 + if (fpscr_ve != 0)
  805 + goto raise_ve;
  806 + break;
  807 + case FPSCR_VE:
  808 + if (fpscr_vx != 0) {
  809 + raise_ve:
  810 + env->error_code = POWERPC_EXCP_FP;
  811 + if (fpscr_vxsnan)
  812 + env->error_code |= POWERPC_EXCP_FP_VXSNAN;
  813 + if (fpscr_vxisi)
  814 + env->error_code |= POWERPC_EXCP_FP_VXISI;
  815 + if (fpscr_vxidi)
  816 + env->error_code |= POWERPC_EXCP_FP_VXIDI;
  817 + if (fpscr_vxzdz)
  818 + env->error_code |= POWERPC_EXCP_FP_VXZDZ;
  819 + if (fpscr_vximz)
  820 + env->error_code |= POWERPC_EXCP_FP_VXIMZ;
  821 + if (fpscr_vxvc)
  822 + env->error_code |= POWERPC_EXCP_FP_VXVC;
  823 + if (fpscr_vxsoft)
  824 + env->error_code |= POWERPC_EXCP_FP_VXSOFT;
  825 + if (fpscr_vxsqrt)
  826 + env->error_code |= POWERPC_EXCP_FP_VXSQRT;
  827 + if (fpscr_vxcvi)
  828 + env->error_code |= POWERPC_EXCP_FP_VXCVI;
  829 + goto raise_excp;
  830 + }
  831 + break;
  832 + case FPSCR_OE:
  833 + if (fpscr_ox != 0) {
  834 + raise_oe:
  835 + env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_OX;
  836 + goto raise_excp;
  837 + }
  838 + break;
  839 + case FPSCR_UE:
  840 + if (fpscr_ux != 0) {
  841 + raise_ue:
  842 + env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_UX;
  843 + goto raise_excp;
  844 + }
  845 + break;
  846 + case FPSCR_ZE:
  847 + if (fpscr_zx != 0) {
  848 + raise_ze:
  849 + env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX;
  850 + goto raise_excp;
  851 + }
  852 + break;
  853 + case FPSCR_XE:
  854 + if (fpscr_xx != 0) {
  855 + raise_xe:
  856 + env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_XX;
  857 + goto raise_excp;
  858 + }
  859 + break;
  860 + case FPSCR_RN1:
  861 + case FPSCR_RN:
  862 + fpscr_set_rounding_mode();
  863 + break;
  864 + default:
  865 + break;
  866 + raise_excp:
  867 + /* Update the floating-point enabled exception summary */
  868 + env->fpscr |= 1 << FPSCR_FEX;
  869 + /* We have to update Rc1 before raising the exception */
  870 + env->exception_index = POWERPC_EXCP_PROGRAM;
  871 + break;
  872 + }
  873 + }
  874 +}
  875 +
  876 +#if defined(WORDS_BIGENDIAN)
  877 +#define WORD0 0
  878 +#define WORD1 1
  879 +#else
  880 +#define WORD0 1
  881 +#define WORD1 0
  882 +#endif
  883 +void do_store_fpscr (uint32_t mask)
  884 +{
  885 + /*
  886 + * We use only the 32 LSB of the incoming fpr
  887 + */
  888 + union {
  889 + double d;
  890 + struct {
  891 + uint32_t u[2];
  892 + } s;
  893 + } u;
  894 + uint32_t prev, new;
  895 + int i;
  896 +
  897 + u.d = FT0;
  898 + prev = env->fpscr;
  899 + new = u.s.u[WORD1];
  900 + new &= ~0x90000000;
  901 + new |= prev & 0x90000000;
  902 + for (i = 0; i < 7; i++) {
  903 + if (mask & (1 << i)) {
  904 + env->fpscr &= ~(0xF << (4 * i));
  905 + env->fpscr |= new & (0xF << (4 * i));
  906 + }
  907 + }
  908 + /* Update VX and FEX */
  909 + if (fpscr_ix != 0)
  910 + env->fpscr |= 1 << FPSCR_VX;
  911 + if ((fpscr_ex & fpscr_eex) != 0) {
  912 + env->fpscr |= 1 << FPSCR_FEX;
  913 + env->exception_index = POWERPC_EXCP_PROGRAM;
  914 + /* XXX: we should compute it properly */
  915 + env->error_code = POWERPC_EXCP_FP;
  916 + }
  917 + fpscr_set_rounding_mode();
  918 +}
  919 +#undef WORD0
  920 +#undef WORD1
  921 +
  922 +#ifdef CONFIG_SOFTFLOAT
  923 +void do_float_check_status (void)
  924 +{
  925 + if (env->exception_index == POWERPC_EXCP_PROGRAM &&
  926 + (env->error_code & POWERPC_EXCP_FP)) {
  927 + /* Differred floating-point exception after target FPR update */
  928 + if (msr_fe0 != 0 || msr_fe1 != 0)
  929 + do_raise_exception_err(env->exception_index, env->error_code);
  930 + } else if (env->fp_status.float_exception_flags & float_flag_overflow) {
  931 + float_overflow_excp();
  932 + } else if (env->fp_status.float_exception_flags & float_flag_underflow) {
  933 + float_underflow_excp();
  934 + } else if (env->fp_status.float_exception_flags & float_flag_inexact) {
  935 + float_inexact_excp();
  936 + }
  937 +}
  938 +#endif
  939 +
  940 +#if USE_PRECISE_EMULATION
  941 +void do_fadd (void)
  942 +{
  943 + if (unlikely(float64_is_signaling_nan(FT0) ||
  944 + float64_is_signaling_nan(FT1))) {
  945 + /* sNaN addition */
  946 + fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
  947 + } else if (likely(isfinite(FT0) || isfinite(FT1) ||
  948 + fpisneg(FT0) == fpisneg(FT1))) {
  949 + FT0 = float64_add(FT0, FT1, &env->fp_status);
  950 + } else {
  951 + /* Magnitude subtraction of infinities */
  952 + fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
  953 + }
  954 +}
  955 +
  956 +void do_fsub (void)
  957 +{
  958 + if (unlikely(float64_is_signaling_nan(FT0) ||
  959 + float64_is_signaling_nan(FT1))) {
  960 + /* sNaN subtraction */
  961 + fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
  962 + } else if (likely(isfinite(FT0) || isfinite(FT1) ||
  963 + fpisneg(FT0) != fpisneg(FT1))) {
  964 + FT0 = float64_sub(FT0, FT1, &env->fp_status);
  965 + } else {
  966 + /* Magnitude subtraction of infinities */
  967 + fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
  968 + }
  969 +}
  970 +
  971 +void do_fmul (void)
  972 +{
  973 + if (unlikely(float64_is_signaling_nan(FT0) ||
  974 + float64_is_signaling_nan(FT1))) {
  975 + /* sNaN multiplication */
  976 + fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
  977 + } else if (unlikely((ifinf(FT0) && iszero(FT1)) ||
  978 + (inzero(FT0) && isinfinity(FT1)))) {
  979 + /* Multiplication of zero by infinity */
  980 + fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
  981 + } else {
  982 + FT0 = float64_mul(FT0, FT1, &env->fp_status);
  983 + }
  984 +}
  985 +
  986 +void do_fdiv (void)
  987 +{
  988 + if (unlikely(float64_is_signaling_nan(FT0) ||
  989 + float64_is_signaling_nan(FT1))) {
  990 + /* sNaN division */
  991 + fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
  992 + } else if (unlikely(isinfinity(FT0) && isinfinity(FT1))) {
  993 + /* Division of infinity by infinity */
  994 + fload_invalid_op_excp(POWERPC_EXCP_FP_VXIDI);
  995 + } else if (unlikely(iszero(FT1))) {
  996 + if (iszero(FT0)) {
  997 + /* Division of zero by zero */
  998 + fload_invalid_op_excp(POWERPC_EXCP_FP_VXZDZ);
  999 + } else {
  1000 + /* Division by zero */
  1001 + float_zero_divide_excp();
  1002 + }
  1003 + } else {
  1004 + FT0 = float64_div(FT0, FT1, &env->fp_status);
  1005 + }
  1006 +}
  1007 +#endif /* USE_PRECISE_EMULATION */
  1008 +
556 1009 void do_fctiw (void)
557 1010 {
558 1011 union {
... ... @@ -560,14 +1013,22 @@ void do_fctiw (void)
560 1013 uint64_t i;
561 1014 } p;
562 1015  
563   - p.i = float64_to_int32(FT0, &env->fp_status);
  1016 + if (unlikely(float64_is_signaling_nan(FT0))) {
  1017 + /* sNaN conversion */
  1018 + fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
  1019 + } else if (unlikely(float64_is_nan(FT0) || isinfinity(FT0))) {
  1020 + /* qNan / infinity conversion */
  1021 + fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
  1022 + } else {
  1023 + p.i = float64_to_int32(FT0, &env->fp_status);
564 1024 #if USE_PRECISE_EMULATION
565   - /* XXX: higher bits are not supposed to be significant.
566   - * to make tests easier, return the same as a real PowerPC 750 (aka G3)
567   - */
568   - p.i |= 0xFFF80000ULL << 32;
  1025 + /* XXX: higher bits are not supposed to be significant.
  1026 + * to make tests easier, return the same as a real PowerPC 750
  1027 + */
  1028 + p.i |= 0xFFF80000ULL << 32;
569 1029 #endif
570   - FT0 = p.d;
  1030 + FT0 = p.d;
  1031 + }
571 1032 }
572 1033  
573 1034 void do_fctiwz (void)
... ... @@ -577,14 +1038,22 @@ void do_fctiwz (void)
577 1038 uint64_t i;
578 1039 } p;
579 1040  
580   - p.i = float64_to_int32_round_to_zero(FT0, &env->fp_status);
  1041 + if (unlikely(float64_is_signaling_nan(FT0))) {
  1042 + /* sNaN conversion */
  1043 + fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
  1044 + } else if (unlikely(float64_is_nan(FT0) || isinfinity(FT0))) {
  1045 + /* qNan / infinity conversion */
  1046 + fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
  1047 + } else {
  1048 + p.i = float64_to_int32_round_to_zero(FT0, &env->fp_status);
581 1049 #if USE_PRECISE_EMULATION
582   - /* XXX: higher bits are not supposed to be significant.
583   - * to make tests easier, return the same as a real PowerPC 750 (aka G3)
584   - */
585   - p.i |= 0xFFF80000ULL << 32;
  1050 + /* XXX: higher bits are not supposed to be significant.
  1051 + * to make tests easier, return the same as a real PowerPC 750
  1052 + */
  1053 + p.i |= 0xFFF80000ULL << 32;
586 1054 #endif
587   - FT0 = p.d;
  1055 + FT0 = p.d;
  1056 + }
588 1057 }
589 1058  
590 1059 #if defined(TARGET_PPC64)
... ... @@ -606,8 +1075,16 @@ void do_fctid (void)
606 1075 uint64_t i;
607 1076 } p;
608 1077  
609   - p.i = float64_to_int64(FT0, &env->fp_status);
610   - FT0 = p.d;
  1078 + if (unlikely(float64_is_signaling_nan(FT0))) {
  1079 + /* sNaN conversion */
  1080 + fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
  1081 + } else if (unlikely(float64_is_nan(FT0) || isinfinity(FT0))) {
  1082 + /* qNan / infinity conversion */
  1083 + fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
  1084 + } else {
  1085 + p.i = float64_to_int64(FT0, &env->fp_status);
  1086 + FT0 = p.d;
  1087 + }
611 1088 }
612 1089  
613 1090 void do_fctidz (void)
... ... @@ -617,20 +1094,34 @@ void do_fctidz (void)
617 1094 uint64_t i;
618 1095 } p;
619 1096  
620   - p.i = float64_to_int64_round_to_zero(FT0, &env->fp_status);
621   - FT0 = p.d;
  1097 + if (unlikely(float64_is_signaling_nan(FT0))) {
  1098 + /* sNaN conversion */
  1099 + fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
  1100 + } else if (unlikely(float64_is_nan(FT0) || isinfinity(FT0))) {
  1101 + /* qNan / infinity conversion */
  1102 + fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
  1103 + } else {
  1104 + p.i = float64_to_int64_round_to_zero(FT0, &env->fp_status);
  1105 + FT0 = p.d;
  1106 + }
622 1107 }
623 1108  
624 1109 #endif
625 1110  
626 1111 static always_inline void do_fri (int rounding_mode)
627 1112 {
628   - int curmode;
629   -
630   - curmode = env->fp_status.float_rounding_mode;
631   - set_float_rounding_mode(rounding_mode, &env->fp_status);
632   - FT0 = float64_round_to_int(FT0, &env->fp_status);
633   - set_float_rounding_mode(curmode, &env->fp_status);
  1113 + if (unlikely(float64_is_signaling_nan(FT0))) {
  1114 + /* sNaN round */
  1115 + fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
  1116 + } else if (unlikely(float64_is_nan(FT0) || isinfinity(FT0))) {
  1117 + /* qNan / infinity round */
  1118 + fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
  1119 + } else {
  1120 + set_float_rounding_mode(rounding_mode, &env->fp_status);
  1121 + FT0 = float64_round_to_int(FT0, &env->fp_status);
  1122 + /* Restore rounding mode from FPSCR */
  1123 + fpscr_set_rounding_mode();
  1124 + }
634 1125 }
635 1126  
636 1127 void do_frin (void)
... ... @@ -656,90 +1147,142 @@ void do_frim (void)
656 1147 #if USE_PRECISE_EMULATION
657 1148 void do_fmadd (void)
658 1149 {
  1150 + if (unlikely(float64_is_signaling_nan(FT0) ||
  1151 + float64_is_signaling_nan(FT1) ||
  1152 + float64_is_signaling_nan(FT2))) {
  1153 + /* sNaN operation */
  1154 + fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
  1155 + } else {
659 1156 #ifdef FLOAT128
660   - float128 ft0_128, ft1_128;
661   -
662   - ft0_128 = float64_to_float128(FT0, &env->fp_status);
663   - ft1_128 = float64_to_float128(FT1, &env->fp_status);
664   - ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
665   - ft1_128 = float64_to_float128(FT2, &env->fp_status);
666   - ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
667   - FT0 = float128_to_float64(ft0_128, &env->fp_status);
  1157 + /* This is the way the PowerPC specification defines it */
  1158 + float128 ft0_128, ft1_128;
  1159 +
  1160 + ft0_128 = float64_to_float128(FT0, &env->fp_status);
  1161 + ft1_128 = float64_to_float128(FT1, &env->fp_status);
  1162 + ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
  1163 + ft1_128 = float64_to_float128(FT2, &env->fp_status);
  1164 + ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
  1165 + FT0 = float128_to_float64(ft0_128, &env->fp_status);
668 1166 #else
669   - /* This is OK on x86 hosts */
670   - FT0 = (FT0 * FT1) + FT2;
  1167 + /* This is OK on x86 hosts */
  1168 + FT0 = (FT0 * FT1) + FT2;
671 1169 #endif
  1170 + }
672 1171 }
673 1172  
674 1173 void do_fmsub (void)
675 1174 {
  1175 + if (unlikely(float64_is_signaling_nan(FT0) ||
  1176 + float64_is_signaling_nan(FT1) ||
  1177 + float64_is_signaling_nan(FT2))) {
  1178 + /* sNaN operation */
  1179 + fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
  1180 + } else {
676 1181 #ifdef FLOAT128
677   - float128 ft0_128, ft1_128;
678   -
679   - ft0_128 = float64_to_float128(FT0, &env->fp_status);
680   - ft1_128 = float64_to_float128(FT1, &env->fp_status);
681   - ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
682   - ft1_128 = float64_to_float128(FT2, &env->fp_status);
683   - ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
684   - FT0 = float128_to_float64(ft0_128, &env->fp_status);
  1182 + /* This is the way the PowerPC specification defines it */
  1183 + float128 ft0_128, ft1_128;
  1184 +
  1185 + ft0_128 = float64_to_float128(FT0, &env->fp_status);
  1186 + ft1_128 = float64_to_float128(FT1, &env->fp_status);
  1187 + ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
  1188 + ft1_128 = float64_to_float128(FT2, &env->fp_status);
  1189 + ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
  1190 + FT0 = float128_to_float64(ft0_128, &env->fp_status);
685 1191 #else
686   - /* This is OK on x86 hosts */
687   - FT0 = (FT0 * FT1) - FT2;
  1192 + /* This is OK on x86 hosts */
  1193 + FT0 = (FT0 * FT1) - FT2;
688 1194 #endif
  1195 + }
689 1196 }
690 1197 #endif /* USE_PRECISE_EMULATION */
691 1198  
692 1199 void do_fnmadd (void)
693 1200 {
  1201 + if (unlikely(float64_is_signaling_nan(FT0) ||
  1202 + float64_is_signaling_nan(FT1) ||
  1203 + float64_is_signaling_nan(FT2))) {
  1204 + /* sNaN operation */
  1205 + fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
  1206 + } else {
694 1207 #if USE_PRECISE_EMULATION
695 1208 #ifdef FLOAT128
696   - float128 ft0_128, ft1_128;
697   -
698   - ft0_128 = float64_to_float128(FT0, &env->fp_status);
699   - ft1_128 = float64_to_float128(FT1, &env->fp_status);
700   - ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
701   - ft1_128 = float64_to_float128(FT2, &env->fp_status);
702   - ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
703   - FT0 = float128_to_float64(ft0_128, &env->fp_status);
  1209 + /* This is the way the PowerPC specification defines it */
  1210 + float128 ft0_128, ft1_128;
  1211 +
  1212 + ft0_128 = float64_to_float128(FT0, &env->fp_status);
  1213 + ft1_128 = float64_to_float128(FT1, &env->fp_status);
  1214 + ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
  1215 + ft1_128 = float64_to_float128(FT2, &env->fp_status);
  1216 + ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
  1217 + FT0 = float128_to_float64(ft0_128, &env->fp_status);
704 1218 #else
705   - /* This is OK on x86 hosts */
706   - FT0 = (FT0 * FT1) + FT2;
  1219 + /* This is OK on x86 hosts */
  1220 + FT0 = (FT0 * FT1) + FT2;
707 1221 #endif
708 1222 #else
709   - FT0 = float64_mul(FT0, FT1, &env->fp_status);
710   - FT0 = float64_add(FT0, FT2, &env->fp_status);
  1223 + FT0 = float64_mul(FT0, FT1, &env->fp_status);
  1224 + FT0 = float64_add(FT0, FT2, &env->fp_status);
711 1225 #endif
712   - if (likely(!isnan(FT0)))
713   - FT0 = float64_chs(FT0);
  1226 + if (likely(!isnan(FT0)))
  1227 + FT0 = float64_chs(FT0);
  1228 + }
714 1229 }
715 1230  
716 1231 void do_fnmsub (void)
717 1232 {
  1233 + if (unlikely(float64_is_signaling_nan(FT0) ||
  1234 + float64_is_signaling_nan(FT1) ||
  1235 + float64_is_signaling_nan(FT2))) {
  1236 + /* sNaN operation */
  1237 + fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
  1238 + } else {
718 1239 #if USE_PRECISE_EMULATION
719 1240 #ifdef FLOAT128
720   - float128 ft0_128, ft1_128;
721   -
722   - ft0_128 = float64_to_float128(FT0, &env->fp_status);
723   - ft1_128 = float64_to_float128(FT1, &env->fp_status);
724   - ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
725   - ft1_128 = float64_to_float128(FT2, &env->fp_status);
726   - ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
727   - FT0 = float128_to_float64(ft0_128, &env->fp_status);
  1241 + /* This is the way the PowerPC specification defines it */
  1242 + float128 ft0_128, ft1_128;
  1243 +
  1244 + ft0_128 = float64_to_float128(FT0, &env->fp_status);
  1245 + ft1_128 = float64_to_float128(FT1, &env->fp_status);
  1246 + ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
  1247 + ft1_128 = float64_to_float128(FT2, &env->fp_status);
  1248 + ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
  1249 + FT0 = float128_to_float64(ft0_128, &env->fp_status);
728 1250 #else
729   - /* This is OK on x86 hosts */
730   - FT0 = (FT0 * FT1) - FT2;
  1251 + /* This is OK on x86 hosts */
  1252 + FT0 = (FT0 * FT1) - FT2;
731 1253 #endif
732 1254 #else
733   - FT0 = float64_mul(FT0, FT1, &env->fp_status);
734   - FT0 = float64_sub(FT0, FT2, &env->fp_status);
  1255 + FT0 = float64_mul(FT0, FT1, &env->fp_status);
  1256 + FT0 = float64_sub(FT0, FT2, &env->fp_status);
735 1257 #endif
736   - if (likely(!isnan(FT0)))
737   - FT0 = float64_chs(FT0);
  1258 + if (likely(!isnan(FT0)))
  1259 + FT0 = float64_chs(FT0);
  1260 + }
738 1261 }
739 1262  
  1263 +#if USE_PRECISE_EMULATION
  1264 +void do_frsp (void)
  1265 +{
  1266 + if (unlikely(float64_is_signaling_nan(FT0))) {
  1267 + /* sNaN square root */
  1268 + fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
  1269 + } else {
  1270 + FT0 = float64_to_float32(FT0, &env->fp_status);
  1271 + }
  1272 +}
  1273 +#endif /* USE_PRECISE_EMULATION */
  1274 +
740 1275 void do_fsqrt (void)
741 1276 {
742   - FT0 = float64_sqrt(FT0, &env->fp_status);
  1277 + if (unlikely(float64_is_signaling_nan(FT0))) {
  1278 + /* sNaN square root */
  1279 + fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
  1280 + } else if (unlikely(fpisneg(FT0) && !iszero(FT0))) {
  1281 + /* Square root of a negative nonzero number */
  1282 + fload_invalid_op_excp(POWERPC_EXCP_FP_VXSQRT);
  1283 + } else {
  1284 + FT0 = float64_sqrt(FT0, &env->fp_status);
  1285 + }
743 1286 }
744 1287  
745 1288 void do_fre (void)
... ... @@ -749,7 +1292,13 @@ void do_fre (void)
749 1292 uint64_t i;
750 1293 } p;
751 1294  
752   - if (likely(isnormal(FT0))) {
  1295 + if (unlikely(float64_is_signaling_nan(FT0))) {
  1296 + /* sNaN reciprocal */
  1297 + fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
  1298 + } else if (unlikely(iszero(FT0))) {
  1299 + /* Zero reciprocal */
  1300 + float_zero_divide_excp();
  1301 + } else if (likely(isnormal(FT0))) {
753 1302 FT0 = float64_div(1.0, FT0, &env->fp_status);
754 1303 } else {
755 1304 p.d = FT0;
... ... @@ -759,7 +1308,7 @@ void do_fre (void)
759 1308 p.i = 0x7FF0000000000000ULL;
760 1309 } else if (isnan(FT0)) {
761 1310 p.i = 0x7FF8000000000000ULL;
762   - } else if (FT0 < 0.0) {
  1311 + } else if (fpisneg(FT0)) {
763 1312 p.i = 0x8000000000000000ULL;
764 1313 } else {
765 1314 p.i = 0x0000000000000000ULL;
... ... @@ -775,7 +1324,13 @@ void do_fres (void)
775 1324 uint64_t i;
776 1325 } p;
777 1326  
778   - if (likely(isnormal(FT0))) {
  1327 + if (unlikely(float64_is_signaling_nan(FT0))) {
  1328 + /* sNaN reciprocal */
  1329 + fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
  1330 + } else if (unlikely(iszero(FT0))) {
  1331 + /* Zero reciprocal */
  1332 + float_zero_divide_excp();
  1333 + } else if (likely(isnormal(FT0))) {
779 1334 #if USE_PRECISE_EMULATION
780 1335 FT0 = float64_div(1.0, FT0, &env->fp_status);
781 1336 FT0 = float64_to_float32(FT0, &env->fp_status);
... ... @@ -790,7 +1345,7 @@ void do_fres (void)
790 1345 p.i = 0x7FF0000000000000ULL;
791 1346 } else if (isnan(FT0)) {
792 1347 p.i = 0x7FF8000000000000ULL;
793   - } else if (FT0 < 0.0) {
  1348 + } else if (fpisneg(FT0)) {
794 1349 p.i = 0x8000000000000000ULL;
795 1350 } else {
796 1351 p.i = 0x0000000000000000ULL;
... ... @@ -806,7 +1361,13 @@ void do_frsqrte (void)
806 1361 uint64_t i;
807 1362 } p;
808 1363  
809   - if (likely(isnormal(FT0) && FT0 > 0.0)) {
  1364 + if (unlikely(float64_is_signaling_nan(FT0))) {
  1365 + /* sNaN reciprocal square root */
  1366 + fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
  1367 + } else if (unlikely(fpisneg(FT0) && !iszero(FT0))) {
  1368 + /* Reciprocal square root of a negative nonzero number */
  1369 + fload_invalid_op_excp(POWERPC_EXCP_FP_VXSQRT);
  1370 + } else if (likely(isnormal(FT0))) {
810 1371 FT0 = float64_sqrt(FT0, &env->fp_status);
811 1372 FT0 = float32_div(1.0, FT0, &env->fp_status);
812 1373 } else {
... ... @@ -816,9 +1377,8 @@ void do_frsqrte (void)
816 1377 } else if (p.i == 0x0000000000000000ULL) {
817 1378 p.i = 0x7FF0000000000000ULL;
818 1379 } else if (isnan(FT0)) {
819   - if (!(p.i & 0x0008000000000000ULL))
820   - p.i |= 0x000FFFFFFFFFFFFFULL;
821   - } else if (FT0 < 0) {
  1380 + p.i |= 0x000FFFFFFFFFFFFFULL;
  1381 + } else if (fpisneg(FT0)) {
822 1382 p.i = 0x7FF8000000000000ULL;
823 1383 } else {
824 1384 p.i = 0x0000000000000000ULL;
... ... @@ -829,7 +1389,7 @@ void do_frsqrte (void)
829 1389  
830 1390 void do_fsel (void)
831 1391 {
832   - if (FT0 >= 0)
  1392 + if (!fpisneg(FT0) || iszero(FT0))
833 1393 FT0 = FT1;
834 1394 else
835 1395 FT0 = FT2;
... ... @@ -837,7 +1397,11 @@ void do_fsel (void)
837 1397  
838 1398 void do_fcmpu (void)
839 1399 {
840   - if (likely(!isnan(FT0) && !isnan(FT1))) {
  1400 + if (unlikely(float64_is_signaling_nan(FT0) ||
  1401 + float64_is_signaling_nan(FT1))) {
  1402 + /* sNaN comparison */
  1403 + fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
  1404 + } else {
841 1405 if (float64_lt(FT0, FT1, &env->fp_status)) {
842 1406 T0 = 0x08UL;
843 1407 } else if (!float64_le(FT0, FT1, &env->fp_status)) {
... ... @@ -845,18 +1409,25 @@ void do_fcmpu (void)
845 1409 } else {
846 1410 T0 = 0x02UL;
847 1411 }
848   - } else {
849   - T0 = 0x01UL;
850   - env->fpscr[4] |= 0x1;
851   - env->fpscr[6] |= 0x1;
852 1412 }
853   - env->fpscr[3] = T0;
  1413 + env->fpscr &= ~(0x0F << FPSCR_FPRF);
  1414 + env->fpscr |= T0 << FPSCR_FPRF;
854 1415 }
855 1416  
856 1417 void do_fcmpo (void)
857 1418 {
858   - env->fpscr[4] &= ~0x1;
859   - if (likely(!isnan(FT0) && !isnan(FT1))) {
  1419 + if (unlikely(float64_is_nan(FT0) ||
  1420 + float64_is_nan(FT1))) {
  1421 + if (float64_is_signaling_nan(FT0) ||
  1422 + float64_is_signaling_nan(FT1)) {
  1423 + /* sNaN comparison */
  1424 + fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN |
  1425 + POWERPC_EXCP_FP_VXVC);
  1426 + } else {
  1427 + /* qNaN comparison */
  1428 + fload_invalid_op_excp(POWERPC_EXCP_FP_VXVC);
  1429 + }
  1430 + } else {
860 1431 if (float64_lt(FT0, FT1, &env->fp_status)) {
861 1432 T0 = 0x08UL;
862 1433 } else if (!float64_le(FT0, FT1, &env->fp_status)) {
... ... @@ -864,19 +1435,9 @@ void do_fcmpo (void)
864 1435 } else {
865 1436 T0 = 0x02UL;
866 1437 }
867   - } else {
868   - T0 = 0x01UL;
869   - env->fpscr[4] |= 0x1;
870   - if (!float64_is_signaling_nan(FT0) || !float64_is_signaling_nan(FT1)) {
871   - /* Quiet NaN case */
872   - env->fpscr[6] |= 0x1;
873   - if (!(env->fpscr[1] & 0x8))
874   - env->fpscr[4] |= 0x8;
875   - } else {
876   - env->fpscr[4] |= 0x8;
877   - }
878 1438 }
879   - env->fpscr[3] = T0;
  1439 + env->fpscr &= ~(0x0F << FPSCR_FPRF);
  1440 + env->fpscr |= T0 << FPSCR_FPRF;
880 1441 }
881 1442  
882 1443 #if !defined (CONFIG_USER_ONLY)
... ...
target-ppc/op_helper.h
... ... @@ -60,7 +60,7 @@ void do_store_cr (uint32_t mask);
60 60 #if defined(TARGET_PPC64)
61 61 void do_store_pri (int prio);
62 62 #endif
63   -void do_load_fpscr (void);
  63 +void do_fpscr_setbit (int bit);
64 64 void do_store_fpscr (uint32_t mask);
65 65 target_ulong ppc_load_dump_spr (int sprn);
66 66 void ppc_store_dump_spr (int sprn, target_ulong val);
... ... @@ -94,6 +94,16 @@ void do_popcntb_64 (void);
94 94 #endif
95 95  
96 96 /* Floating-point arithmetic helpers */
  97 +void do_compute_fprf (int set_class);
  98 +#ifdef CONFIG_SOFTFLOAT
  99 +void do_float_check_status (void);
  100 +#endif
  101 +#if USE_PRECISE_EMULATION
  102 +void do_fadd (void);
  103 +void do_fsub (void);
  104 +void do_fmul (void);
  105 +void do_fdiv (void);
  106 +#endif
97 107 void do_fsqrt (void);
98 108 void do_fre (void);
99 109 void do_fres (void);
... ... @@ -105,6 +115,9 @@ void do_fmsub (void);
105 115 #endif
106 116 void do_fnmadd (void);
107 117 void do_fnmsub (void);
  118 +#if USE_PRECISE_EMULATION
  119 +void do_frsp (void);
  120 +#endif
108 121 void do_fctiw (void);
109 122 void do_fctiwz (void);
110 123 #if defined(TARGET_PPC64)
... ...
target-ppc/op_template.h
... ... @@ -165,39 +165,6 @@ void OPPROTO glue(op_store_T1_crf_crf, REG) (void)
165 165 RETURN();
166 166 }
167 167  
168   -/* Floating point condition and status register moves */
169   -void OPPROTO glue(op_load_fpscr_T0_fpscr, REG) (void)
170   -{
171   - T0 = env->fpscr[REG];
172   - RETURN();
173   -}
174   -
175   -#if REG == 0
176   -void OPPROTO glue(op_store_T0_fpscr_fpscr, REG) (void)
177   -{
178   - env->fpscr[REG] = (env->fpscr[REG] & 0x9) | (T0 & ~0x9);
179   - RETURN();
180   -}
181   -
182   -void OPPROTO glue(op_clear_fpscr_fpscr, REG) (void)
183   -{
184   - env->fpscr[REG] = (env->fpscr[REG] & 0x9);
185   - RETURN();
186   -}
187   -#else
188   -void OPPROTO glue(op_store_T0_fpscr_fpscr, REG) (void)
189   -{
190   - env->fpscr[REG] = T0;
191   - RETURN();
192   -}
193   -
194   -void OPPROTO glue(op_clear_fpscr_fpscr, REG) (void)
195   -{
196   - env->fpscr[REG] = 0x0;
197   - RETURN();
198   -}
199   -#endif
200   -
201 168 #endif /* REG <= 7 */
202 169  
203 170 /* floating point registers moves */
... ...
target-ppc/translate.c
... ... @@ -32,6 +32,7 @@
32 32 //#define PPC_DEBUG_DISAS
33 33 //#define DEBUG_MEMORY_ACCESSES
34 34 //#define DO_PPC_STATISTICS
  35 +//#define OPTIMIZE_FPRF_UPDATE
35 36  
36 37 /*****************************************************************************/
37 38 /* Code translation helpers */
... ... @@ -50,6 +51,10 @@ enum {
50 51  
51 52 static uint16_t *gen_opc_ptr;
52 53 static uint32_t *gen_opparam_ptr;
  54 +#if defined(OPTIMIZE_FPRF_UPDATE)
  55 +static uint16_t *gen_fprf_buf[OPC_BUF_SIZE];
  56 +static uint16_t **gen_fprf_ptr;
  57 +#endif
53 58  
54 59 #include "gen-op.h"
55 60  
... ... @@ -117,16 +122,6 @@ GEN8(gen_op_load_crf_T1, gen_op_load_crf_T1_crf);
117 122 GEN8(gen_op_store_T0_crf, gen_op_store_T0_crf_crf);
118 123 GEN8(gen_op_store_T1_crf, gen_op_store_T1_crf_crf);
119 124  
120   -/* Floating point condition and status register moves */
121   -GEN8(gen_op_load_fpscr_T0, gen_op_load_fpscr_T0_fpscr);
122   -GEN8(gen_op_store_T0_fpscr, gen_op_store_T0_fpscr_fpscr);
123   -GEN8(gen_op_clear_fpscr, gen_op_clear_fpscr_fpscr);
124   -static always_inline void gen_op_store_T0_fpscri (int n, uint8_t param)
125   -{
126   - gen_op_set_T0(param);
127   - gen_op_store_T0_fpscr(n);
128   -}
129   -
130 125 /* General purpose registers moves */
131 126 GEN32(gen_op_load_gpr_T0, gen_op_load_gpr_T0_gpr);
132 127 GEN32(gen_op_load_gpr_T1, gen_op_load_gpr_T1_gpr);
... ... @@ -199,6 +194,44 @@ static always_inline void gen_set_Rc0 (DisasContext *ctx)
199 194 gen_op_set_Rc0();
200 195 }
201 196  
  197 +static always_inline void gen_reset_fpstatus (void)
  198 +{
  199 +#ifdef CONFIG_SOFTFLOAT
  200 + gen_op_reset_fpstatus();
  201 +#endif
  202 +}
  203 +
  204 +static always_inline void gen_compute_fprf (int set_fprf, int set_rc)
  205 +{
  206 + if (set_fprf != 0) {
  207 + /* This case might be optimized later */
  208 +#if defined(OPTIMIZE_FPRF_UPDATE)
  209 + *gen_fprf_ptr++ = gen_opc_ptr;
  210 +#endif
  211 + gen_op_compute_fprf(1);
  212 + if (unlikely(set_rc))
  213 + gen_op_store_T0_crf(1);
  214 + gen_op_float_check_status();
  215 + } else if (unlikely(set_rc)) {
  216 + /* We always need to compute fpcc */
  217 + gen_op_compute_fprf(0);
  218 + gen_op_store_T0_crf(1);
  219 + if (set_fprf)
  220 + gen_op_float_check_status();
  221 + }
  222 +}
  223 +
  224 +static always_inline void gen_optimize_fprf (void)
  225 +{
  226 +#if defined(OPTIMIZE_FPRF_UPDATE)
  227 + uint16_t **ptr;
  228 +
  229 + for (ptr = gen_fprf_buf; ptr != (gen_fprf_ptr - 1); ptr++)
  230 + *ptr = INDEX_op_nop1;
  231 + gen_fprf_ptr = gen_fprf_buf;
  232 +#endif
  233 +}
  234 +
202 235 static always_inline void gen_update_nip (DisasContext *ctx, target_ulong nip)
203 236 {
204 237 #if defined(TARGET_PPC64)
... ... @@ -497,6 +530,8 @@ enum {
497 530 PPC_CACHE_DCBZ = 0x0000400000000000ULL,
498 531 /* dcbz instruction with tunable cache line size */
499 532 PPC_CACHE_DCBZT = 0x0000800000000000ULL,
  533 + /* frsqrtes extension */
  534 + PPC_FLOAT_FRSQRTES = 0x0001000000000000ULL,
500 535 };
501 536  
502 537 /*****************************************************************************/
... ... @@ -1656,124 +1691,127 @@ __GEN_LOGICAL2(srd, 0x1B, 0x10, PPC_64B);
1656 1691 #endif
1657 1692  
1658 1693 /*** Floating-Point arithmetic ***/
1659   -#define _GEN_FLOAT_ACB(name, op, op1, op2, isfloat, type) \
  1694 +#define _GEN_FLOAT_ACB(name, op, op1, op2, isfloat, set_fprf, type) \
1660 1695 GEN_HANDLER(f##name, op1, op2, 0xFF, 0x00000000, type) \
1661 1696 { \
1662 1697 if (unlikely(!ctx->fpu_enabled)) { \
1663 1698 GEN_EXCP_NO_FP(ctx); \
1664 1699 return; \
1665 1700 } \
1666   - gen_op_reset_scrfx(); \
1667 1701 gen_op_load_fpr_FT0(rA(ctx->opcode)); \
1668 1702 gen_op_load_fpr_FT1(rC(ctx->opcode)); \
1669 1703 gen_op_load_fpr_FT2(rB(ctx->opcode)); \
  1704 + gen_reset_fpstatus(); \
1670 1705 gen_op_f##op(); \
1671 1706 if (isfloat) { \
1672 1707 gen_op_frsp(); \
1673 1708 } \
1674 1709 gen_op_store_FT0_fpr(rD(ctx->opcode)); \
1675   - if (unlikely(Rc(ctx->opcode) != 0)) \
1676   - gen_op_set_Rc1(); \
  1710 + gen_compute_fprf(set_fprf, Rc(ctx->opcode) != 0); \
1677 1711 }
1678 1712  
1679   -#define GEN_FLOAT_ACB(name, op2, type) \
1680   -_GEN_FLOAT_ACB(name, name, 0x3F, op2, 0, type); \
1681   -_GEN_FLOAT_ACB(name##s, name, 0x3B, op2, 1, type);
  1713 +#define GEN_FLOAT_ACB(name, op2, set_fprf, type) \
  1714 +_GEN_FLOAT_ACB(name, name, 0x3F, op2, 0, set_fprf, type); \
  1715 +_GEN_FLOAT_ACB(name##s, name, 0x3B, op2, 1, set_fprf, type);
1682 1716  
1683   -#define _GEN_FLOAT_AB(name, op, op1, op2, inval, isfloat) \
1684   -GEN_HANDLER(f##name, op1, op2, 0xFF, inval, PPC_FLOAT) \
  1717 +#define _GEN_FLOAT_AB(name, op, op1, op2, inval, isfloat, set_fprf, type) \
  1718 +GEN_HANDLER(f##name, op1, op2, 0xFF, inval, type) \
1685 1719 { \
1686 1720 if (unlikely(!ctx->fpu_enabled)) { \
1687 1721 GEN_EXCP_NO_FP(ctx); \
1688 1722 return; \
1689 1723 } \
1690   - gen_op_reset_scrfx(); \
1691 1724 gen_op_load_fpr_FT0(rA(ctx->opcode)); \
1692 1725 gen_op_load_fpr_FT1(rB(ctx->opcode)); \
  1726 + gen_reset_fpstatus(); \
1693 1727 gen_op_f##op(); \
1694 1728 if (isfloat) { \
1695 1729 gen_op_frsp(); \
1696 1730 } \
1697 1731 gen_op_store_FT0_fpr(rD(ctx->opcode)); \
1698   - if (unlikely(Rc(ctx->opcode) != 0)) \
1699   - gen_op_set_Rc1(); \
  1732 + gen_compute_fprf(set_fprf, Rc(ctx->opcode) != 0); \
1700 1733 }
1701   -#define GEN_FLOAT_AB(name, op2, inval) \
1702   -_GEN_FLOAT_AB(name, name, 0x3F, op2, inval, 0); \
1703   -_GEN_FLOAT_AB(name##s, name, 0x3B, op2, inval, 1);
  1734 +#define GEN_FLOAT_AB(name, op2, inval, set_fprf, type) \
  1735 +_GEN_FLOAT_AB(name, name, 0x3F, op2, inval, 0, set_fprf, type); \
  1736 +_GEN_FLOAT_AB(name##s, name, 0x3B, op2, inval, 1, set_fprf, type);
1704 1737  
1705   -#define _GEN_FLOAT_AC(name, op, op1, op2, inval, isfloat) \
1706   -GEN_HANDLER(f##name, op1, op2, 0xFF, inval, PPC_FLOAT) \
  1738 +#define _GEN_FLOAT_AC(name, op, op1, op2, inval, isfloat, set_fprf, type) \
  1739 +GEN_HANDLER(f##name, op1, op2, 0xFF, inval, type) \
1707 1740 { \
1708 1741 if (unlikely(!ctx->fpu_enabled)) { \
1709 1742 GEN_EXCP_NO_FP(ctx); \
1710 1743 return; \
1711 1744 } \
1712   - gen_op_reset_scrfx(); \
1713 1745 gen_op_load_fpr_FT0(rA(ctx->opcode)); \
1714 1746 gen_op_load_fpr_FT1(rC(ctx->opcode)); \
  1747 + gen_reset_fpstatus(); \
1715 1748 gen_op_f##op(); \
1716 1749 if (isfloat) { \
1717 1750 gen_op_frsp(); \
1718 1751 } \
1719 1752 gen_op_store_FT0_fpr(rD(ctx->opcode)); \
1720   - if (unlikely(Rc(ctx->opcode) != 0)) \
1721   - gen_op_set_Rc1(); \
  1753 + gen_compute_fprf(set_fprf, Rc(ctx->opcode) != 0); \
1722 1754 }
1723   -#define GEN_FLOAT_AC(name, op2, inval) \
1724   -_GEN_FLOAT_AC(name, name, 0x3F, op2, inval, 0); \
1725   -_GEN_FLOAT_AC(name##s, name, 0x3B, op2, inval, 1);
  1755 +#define GEN_FLOAT_AC(name, op2, inval, set_fprf, type) \
  1756 +_GEN_FLOAT_AC(name, name, 0x3F, op2, inval, 0, set_fprf, type); \
  1757 +_GEN_FLOAT_AC(name##s, name, 0x3B, op2, inval, 1, set_fprf, type);
1726 1758  
1727   -#define GEN_FLOAT_B(name, op2, op3, type) \
  1759 +#define GEN_FLOAT_B(name, op2, op3, set_fprf, type) \
1728 1760 GEN_HANDLER(f##name, 0x3F, op2, op3, 0x001F0000, type) \
1729 1761 { \
1730 1762 if (unlikely(!ctx->fpu_enabled)) { \
1731 1763 GEN_EXCP_NO_FP(ctx); \
1732 1764 return; \
1733 1765 } \
1734   - gen_op_reset_scrfx(); \
1735 1766 gen_op_load_fpr_FT0(rB(ctx->opcode)); \
  1767 + gen_reset_fpstatus(); \
1736 1768 gen_op_f##name(); \
1737 1769 gen_op_store_FT0_fpr(rD(ctx->opcode)); \
1738   - if (unlikely(Rc(ctx->opcode) != 0)) \
1739   - gen_op_set_Rc1(); \
  1770 + gen_compute_fprf(set_fprf, Rc(ctx->opcode) != 0); \
1740 1771 }
1741 1772  
1742   -#define GEN_FLOAT_BS(name, op1, op2, type) \
  1773 +#define GEN_FLOAT_BS(name, op1, op2, set_fprf, type) \
1743 1774 GEN_HANDLER(f##name, op1, op2, 0xFF, 0x001F07C0, type) \
1744 1775 { \
1745 1776 if (unlikely(!ctx->fpu_enabled)) { \
1746 1777 GEN_EXCP_NO_FP(ctx); \
1747 1778 return; \
1748 1779 } \
1749   - gen_op_reset_scrfx(); \
1750 1780 gen_op_load_fpr_FT0(rB(ctx->opcode)); \
  1781 + gen_reset_fpstatus(); \
1751 1782 gen_op_f##name(); \
1752 1783 gen_op_store_FT0_fpr(rD(ctx->opcode)); \
1753   - if (unlikely(Rc(ctx->opcode) != 0)) \
1754   - gen_op_set_Rc1(); \
  1784 + gen_compute_fprf(set_fprf, Rc(ctx->opcode) != 0); \
1755 1785 }
1756 1786  
1757 1787 /* fadd - fadds */
1758   -GEN_FLOAT_AB(add, 0x15, 0x000007C0);
  1788 +GEN_FLOAT_AB(add, 0x15, 0x000007C0, 1, PPC_FLOAT);
1759 1789 /* fdiv - fdivs */
1760   -GEN_FLOAT_AB(div, 0x12, 0x000007C0);
  1790 +GEN_FLOAT_AB(div, 0x12, 0x000007C0, 1, PPC_FLOAT);
1761 1791 /* fmul - fmuls */
1762   -GEN_FLOAT_AC(mul, 0x19, 0x0000F800);
  1792 +GEN_FLOAT_AC(mul, 0x19, 0x0000F800, 1, PPC_FLOAT);
1763 1793  
1764 1794 /* fre */
1765   -GEN_FLOAT_BS(re, 0x3F, 0x18, PPC_FLOAT_EXT);
  1795 +GEN_FLOAT_BS(re, 0x3F, 0x18, 1, PPC_FLOAT_EXT);
1766 1796  
1767 1797 /* fres */
1768   -GEN_FLOAT_BS(res, 0x3B, 0x18, PPC_FLOAT_FRES);
  1798 +GEN_FLOAT_BS(res, 0x3B, 0x18, 1, PPC_FLOAT_FRES);
1769 1799  
1770 1800 /* frsqrte */
1771   -GEN_FLOAT_BS(rsqrte, 0x3F, 0x1A, PPC_FLOAT_FRSQRTE);
  1801 +GEN_FLOAT_BS(rsqrte, 0x3F, 0x1A, 1, PPC_FLOAT_FRSQRTE);
  1802 +
  1803 +/* frsqrtes */
  1804 +static always_inline void gen_op_frsqrtes (void)
  1805 +{
  1806 + gen_op_frsqrte();
  1807 + gen_op_frsp();
  1808 +}
  1809 +GEN_FLOAT_BS(rsqrtes, 0x3F, 0x1A, 1, PPC_FLOAT_FRSQRTES);
1772 1810  
1773 1811 /* fsel */
1774   -_GEN_FLOAT_ACB(sel, sel, 0x3F, 0x17, 0, PPC_FLOAT_FSEL);
  1812 +_GEN_FLOAT_ACB(sel, sel, 0x3F, 0x17, 0, 0, PPC_FLOAT_FSEL);
1775 1813 /* fsub - fsubs */
1776   -GEN_FLOAT_AB(sub, 0x14, 0x000007C0);
  1814 +GEN_FLOAT_AB(sub, 0x14, 0x000007C0, 1, PPC_FLOAT);
1777 1815 /* Optional: */
1778 1816 /* fsqrt */
1779 1817 GEN_HANDLER(fsqrt, 0x3F, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_FSQRT)
... ... @@ -1782,12 +1820,11 @@ GEN_HANDLER(fsqrt, 0x3F, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_FSQRT)
1782 1820 GEN_EXCP_NO_FP(ctx);
1783 1821 return;
1784 1822 }
1785   - gen_op_reset_scrfx();
1786 1823 gen_op_load_fpr_FT0(rB(ctx->opcode));
  1824 + gen_reset_fpstatus();
1787 1825 gen_op_fsqrt();
1788 1826 gen_op_store_FT0_fpr(rD(ctx->opcode));
1789   - if (unlikely(Rc(ctx->opcode) != 0))
1790   - gen_op_set_Rc1();
  1827 + gen_compute_fprf(1, Rc(ctx->opcode) != 0);
1791 1828 }
1792 1829  
1793 1830 GEN_HANDLER(fsqrts, 0x3B, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_FSQRT)
... ... @@ -1796,49 +1833,48 @@ GEN_HANDLER(fsqrts, 0x3B, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_FSQRT)
1796 1833 GEN_EXCP_NO_FP(ctx);
1797 1834 return;
1798 1835 }
1799   - gen_op_reset_scrfx();
1800 1836 gen_op_load_fpr_FT0(rB(ctx->opcode));
  1837 + gen_reset_fpstatus();
1801 1838 gen_op_fsqrt();
1802 1839 gen_op_frsp();
1803 1840 gen_op_store_FT0_fpr(rD(ctx->opcode));
1804   - if (unlikely(Rc(ctx->opcode) != 0))
1805   - gen_op_set_Rc1();
  1841 + gen_compute_fprf(1, Rc(ctx->opcode) != 0);
1806 1842 }
1807 1843  
1808 1844 /*** Floating-Point multiply-and-add ***/
1809 1845 /* fmadd - fmadds */
1810   -GEN_FLOAT_ACB(madd, 0x1D, PPC_FLOAT);
  1846 +GEN_FLOAT_ACB(madd, 0x1D, 1, PPC_FLOAT);
1811 1847 /* fmsub - fmsubs */
1812   -GEN_FLOAT_ACB(msub, 0x1C, PPC_FLOAT);
  1848 +GEN_FLOAT_ACB(msub, 0x1C, 1, PPC_FLOAT);
1813 1849 /* fnmadd - fnmadds */
1814   -GEN_FLOAT_ACB(nmadd, 0x1F, PPC_FLOAT);
  1850 +GEN_FLOAT_ACB(nmadd, 0x1F, 1, PPC_FLOAT);
1815 1851 /* fnmsub - fnmsubs */
1816   -GEN_FLOAT_ACB(nmsub, 0x1E, PPC_FLOAT);
  1852 +GEN_FLOAT_ACB(nmsub, 0x1E, 1, PPC_FLOAT);
1817 1853  
1818 1854 /*** Floating-Point round & convert ***/
1819 1855 /* fctiw */
1820   -GEN_FLOAT_B(ctiw, 0x0E, 0x00, PPC_FLOAT);
  1856 +GEN_FLOAT_B(ctiw, 0x0E, 0x00, 0, PPC_FLOAT);
1821 1857 /* fctiwz */
1822   -GEN_FLOAT_B(ctiwz, 0x0F, 0x00, PPC_FLOAT);
  1858 +GEN_FLOAT_B(ctiwz, 0x0F, 0x00, 0, PPC_FLOAT);
1823 1859 /* frsp */
1824   -GEN_FLOAT_B(rsp, 0x0C, 0x00, PPC_FLOAT);
  1860 +GEN_FLOAT_B(rsp, 0x0C, 0x00, 1, PPC_FLOAT);
1825 1861 #if defined(TARGET_PPC64)
1826 1862 /* fcfid */
1827   -GEN_FLOAT_B(cfid, 0x0E, 0x1A, PPC_64B);
  1863 +GEN_FLOAT_B(cfid, 0x0E, 0x1A, 1, PPC_64B);
1828 1864 /* fctid */
1829   -GEN_FLOAT_B(ctid, 0x0E, 0x19, PPC_64B);
  1865 +GEN_FLOAT_B(ctid, 0x0E, 0x19, 0, PPC_64B);
1830 1866 /* fctidz */
1831   -GEN_FLOAT_B(ctidz, 0x0F, 0x19, PPC_64B);
  1867 +GEN_FLOAT_B(ctidz, 0x0F, 0x19, 0, PPC_64B);
1832 1868 #endif
1833 1869  
1834 1870 /* frin */
1835   -GEN_FLOAT_B(rin, 0x08, 0x0C, PPC_FLOAT_EXT);
  1871 +GEN_FLOAT_B(rin, 0x08, 0x0C, 1, PPC_FLOAT_EXT);
1836 1872 /* friz */
1837   -GEN_FLOAT_B(riz, 0x08, 0x0D, PPC_FLOAT_EXT);
  1873 +GEN_FLOAT_B(riz, 0x08, 0x0D, 1, PPC_FLOAT_EXT);
1838 1874 /* frip */
1839   -GEN_FLOAT_B(rip, 0x08, 0x0E, PPC_FLOAT_EXT);
  1875 +GEN_FLOAT_B(rip, 0x08, 0x0E, 1, PPC_FLOAT_EXT);
1840 1876 /* frim */
1841   -GEN_FLOAT_B(rim, 0x08, 0x0F, PPC_FLOAT_EXT);
  1877 +GEN_FLOAT_B(rim, 0x08, 0x0F, 1, PPC_FLOAT_EXT);
1842 1878  
1843 1879 /*** Floating-Point compare ***/
1844 1880 /* fcmpo */
... ... @@ -1848,11 +1884,12 @@ GEN_HANDLER(fcmpo, 0x3F, 0x00, 0x01, 0x00600001, PPC_FLOAT)
1848 1884 GEN_EXCP_NO_FP(ctx);
1849 1885 return;
1850 1886 }
1851   - gen_op_reset_scrfx();
1852 1887 gen_op_load_fpr_FT0(rA(ctx->opcode));
1853 1888 gen_op_load_fpr_FT1(rB(ctx->opcode));
  1889 + gen_reset_fpstatus();
1854 1890 gen_op_fcmpo();
1855 1891 gen_op_store_T0_crf(crfD(ctx->opcode));
  1892 + gen_op_float_check_status();
1856 1893 }
1857 1894  
1858 1895 /* fcmpu */
... ... @@ -1862,47 +1899,54 @@ GEN_HANDLER(fcmpu, 0x3F, 0x00, 0x00, 0x00600001, PPC_FLOAT)
1862 1899 GEN_EXCP_NO_FP(ctx);
1863 1900 return;
1864 1901 }
1865   - gen_op_reset_scrfx();
1866 1902 gen_op_load_fpr_FT0(rA(ctx->opcode));
1867 1903 gen_op_load_fpr_FT1(rB(ctx->opcode));
  1904 + gen_reset_fpstatus();
1868 1905 gen_op_fcmpu();
1869 1906 gen_op_store_T0_crf(crfD(ctx->opcode));
  1907 + gen_op_float_check_status();
1870 1908 }
1871 1909  
1872 1910 /*** Floating-point move ***/
1873 1911 /* fabs */
1874   -GEN_FLOAT_B(abs, 0x08, 0x08, PPC_FLOAT);
  1912 +/* XXX: beware that fabs never checks for NaNs nor update FPSCR */
  1913 +GEN_FLOAT_B(abs, 0x08, 0x08, 0, PPC_FLOAT);
1875 1914  
1876 1915 /* fmr - fmr. */
  1916 +/* XXX: beware that fmr never checks for NaNs nor update FPSCR */
1877 1917 GEN_HANDLER(fmr, 0x3F, 0x08, 0x02, 0x001F0000, PPC_FLOAT)
1878 1918 {
1879 1919 if (unlikely(!ctx->fpu_enabled)) {
1880 1920 GEN_EXCP_NO_FP(ctx);
1881 1921 return;
1882 1922 }
1883   - gen_op_reset_scrfx();
1884 1923 gen_op_load_fpr_FT0(rB(ctx->opcode));
1885 1924 gen_op_store_FT0_fpr(rD(ctx->opcode));
1886   - if (unlikely(Rc(ctx->opcode) != 0))
1887   - gen_op_set_Rc1();
  1925 + gen_compute_fprf(0, Rc(ctx->opcode) != 0);
1888 1926 }
1889 1927  
1890 1928 /* fnabs */
1891   -GEN_FLOAT_B(nabs, 0x08, 0x04, PPC_FLOAT);
  1929 +/* XXX: beware that fnabs never checks for NaNs nor update FPSCR */
  1930 +GEN_FLOAT_B(nabs, 0x08, 0x04, 0, PPC_FLOAT);
1892 1931 /* fneg */
1893   -GEN_FLOAT_B(neg, 0x08, 0x01, PPC_FLOAT);
  1932 +/* XXX: beware that fneg never checks for NaNs nor update FPSCR */
  1933 +GEN_FLOAT_B(neg, 0x08, 0x01, 0, PPC_FLOAT);
1894 1934  
1895 1935 /*** Floating-Point status & ctrl register ***/
1896 1936 /* mcrfs */
1897 1937 GEN_HANDLER(mcrfs, 0x3F, 0x00, 0x02, 0x0063F801, PPC_FLOAT)
1898 1938 {
  1939 + int bfa;
  1940 +
1899 1941 if (unlikely(!ctx->fpu_enabled)) {
1900 1942 GEN_EXCP_NO_FP(ctx);
1901 1943 return;
1902 1944 }
1903   - gen_op_load_fpscr_T0(crfS(ctx->opcode));
  1945 + gen_optimize_fprf();
  1946 + bfa = 4 * (7 - crfS(ctx->opcode));
  1947 + gen_op_load_fpscr_T0(bfa);
1904 1948 gen_op_store_T0_crf(crfD(ctx->opcode));
1905   - gen_op_clear_fpscr(crfS(ctx->opcode));
  1949 + gen_op_fpscr_resetbit(~(0xF << bfa));
1906 1950 }
1907 1951  
1908 1952 /* mffs */
... ... @@ -1912,10 +1956,11 @@ GEN_HANDLER(mffs, 0x3F, 0x07, 0x12, 0x001FF800, PPC_FLOAT)
1912 1956 GEN_EXCP_NO_FP(ctx);
1913 1957 return;
1914 1958 }
1915   - gen_op_load_fpscr();
  1959 + gen_optimize_fprf();
  1960 + gen_reset_fpstatus();
  1961 + gen_op_load_fpscr_FT0();
1916 1962 gen_op_store_FT0_fpr(rD(ctx->opcode));
1917   - if (unlikely(Rc(ctx->opcode) != 0))
1918   - gen_op_set_Rc1();
  1963 + gen_compute_fprf(0, Rc(ctx->opcode) != 0);
1919 1964 }
1920 1965  
1921 1966 /* mtfsb0 */
... ... @@ -1927,12 +1972,15 @@ GEN_HANDLER(mtfsb0, 0x3F, 0x06, 0x02, 0x001FF800, PPC_FLOAT)
1927 1972 GEN_EXCP_NO_FP(ctx);
1928 1973 return;
1929 1974 }
1930   - crb = crbD(ctx->opcode) >> 2;
1931   - gen_op_load_fpscr_T0(crb);
1932   - gen_op_andi_T0(~(1 << (crbD(ctx->opcode) & 0x03)));
1933   - gen_op_store_T0_fpscr(crb);
1934   - if (unlikely(Rc(ctx->opcode) != 0))
1935   - gen_op_set_Rc1();
  1975 + crb = 32 - (crbD(ctx->opcode) >> 2);
  1976 + gen_optimize_fprf();
  1977 + gen_reset_fpstatus();
  1978 + if (likely(crb != 30 && crb != 29))
  1979 + gen_op_fpscr_resetbit(~(1 << crb));
  1980 + if (unlikely(Rc(ctx->opcode) != 0)) {
  1981 + gen_op_load_fpcc();
  1982 + gen_op_set_Rc0();
  1983 + }
1936 1984 }
1937 1985  
1938 1986 /* mtfsb1 */
... ... @@ -1944,12 +1992,18 @@ GEN_HANDLER(mtfsb1, 0x3F, 0x06, 0x01, 0x001FF800, PPC_FLOAT)
1944 1992 GEN_EXCP_NO_FP(ctx);
1945 1993 return;
1946 1994 }
1947   - crb = crbD(ctx->opcode) >> 2;
1948   - gen_op_load_fpscr_T0(crb);
1949   - gen_op_ori(1 << (crbD(ctx->opcode) & 0x03));
1950   - gen_op_store_T0_fpscr(crb);
1951   - if (unlikely(Rc(ctx->opcode) != 0))
1952   - gen_op_set_Rc1();
  1995 + crb = 32 - (crbD(ctx->opcode) >> 2);
  1996 + gen_optimize_fprf();
  1997 + gen_reset_fpstatus();
  1998 + /* XXX: we pretend we can only do IEEE floating-point computations */
  1999 + if (likely(crb != FPSCR_FEX && crb != FPSCR_VX && crb != FPSCR_NI))
  2000 + gen_op_fpscr_setbit(crb);
  2001 + if (unlikely(Rc(ctx->opcode) != 0)) {
  2002 + gen_op_load_fpcc();
  2003 + gen_op_set_Rc0();
  2004 + }
  2005 + /* We can raise a differed exception */
  2006 + gen_op_float_check_status();
1953 2007 }
1954 2008  
1955 2009 /* mtfsf */
... ... @@ -1959,22 +2013,39 @@ GEN_HANDLER(mtfsf, 0x3F, 0x07, 0x16, 0x02010000, PPC_FLOAT)
1959 2013 GEN_EXCP_NO_FP(ctx);
1960 2014 return;
1961 2015 }
  2016 + gen_optimize_fprf();
1962 2017 gen_op_load_fpr_FT0(rB(ctx->opcode));
  2018 + gen_reset_fpstatus();
1963 2019 gen_op_store_fpscr(FM(ctx->opcode));
1964   - if (unlikely(Rc(ctx->opcode) != 0))
1965   - gen_op_set_Rc1();
  2020 + if (unlikely(Rc(ctx->opcode) != 0)) {
  2021 + gen_op_load_fpcc();
  2022 + gen_op_set_Rc0();
  2023 + }
  2024 + /* We can raise a differed exception */
  2025 + gen_op_float_check_status();
1966 2026 }
1967 2027  
1968 2028 /* mtfsfi */
1969 2029 GEN_HANDLER(mtfsfi, 0x3F, 0x06, 0x04, 0x006f0800, PPC_FLOAT)
1970 2030 {
  2031 + int bf, sh;
  2032 +
1971 2033 if (unlikely(!ctx->fpu_enabled)) {
1972 2034 GEN_EXCP_NO_FP(ctx);
1973 2035 return;
1974 2036 }
1975   - gen_op_store_T0_fpscri(crbD(ctx->opcode) >> 2, FPIMM(ctx->opcode));
1976   - if (unlikely(Rc(ctx->opcode) != 0))
1977   - gen_op_set_Rc1();
  2037 + bf = crbD(ctx->opcode) >> 2;
  2038 + sh = 7 - bf;
  2039 + gen_optimize_fprf();
  2040 + gen_op_set_FT0(FPIMM(ctx->opcode) << (4 * sh));
  2041 + gen_reset_fpstatus();
  2042 + gen_op_store_fpscr(1 << sh);
  2043 + if (unlikely(Rc(ctx->opcode) != 0)) {
  2044 + gen_op_load_fpcc();
  2045 + gen_op_set_Rc0();
  2046 + }
  2047 + /* We can raise a differed exception */
  2048 + gen_op_float_check_status();
1978 2049 }
1979 2050  
1980 2051 /*** Addressing modes ***/
... ... @@ -6717,6 +6788,9 @@ static always_inline int gen_intermediate_code_internal (CPUState *env,
6717 6788 gen_opc_ptr = gen_opc_buf;
6718 6789 gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
6719 6790 gen_opparam_ptr = gen_opparam_buf;
  6791 +#if defined(OPTIMIZE_FPRF_UPDATE)
  6792 + gen_fprf_ptr = gen_fprf_buf;
  6793 +#endif
6720 6794 nb_gen_labels = 0;
6721 6795 ctx.nip = pc_start;
6722 6796 ctx.tb = tb;
... ...