Commit 7c58044c0ab79f11604f71aa04b4691baacef886
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
Showing
9 changed files
with
1122 additions
and
349 deletions
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; | ... | ... |