Commit e864cabdc0a38bb598ddcf88b264896dc6f3e3b2
1 parent
a7222580
PowerPC bugfixes:
- must clear carry bit when doing addic with a zero immediate value - fix missing RETURN in micro-operation that would lead to random failures and crashes - add USE_PRECISE_EMULATION compilation-time option to choose between getting exact floating point results and fast but less accurate computation. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2526 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
5 changed files
with
110 additions
and
4 deletions
target-ppc/exec.h
... | ... | @@ -27,6 +27,10 @@ |
27 | 27 | #include "cpu.h" |
28 | 28 | #include "exec-all.h" |
29 | 29 | |
30 | +/* For normal operations, precise emulation should not be needed */ | |
31 | +//#define USE_PRECISE_EMULATION 1 | |
32 | +#define USE_PRECISE_EMULATION 0 | |
33 | + | |
30 | 34 | register struct CPUPPCState *env asm(AREG0); |
31 | 35 | #if TARGET_LONG_BITS > HOST_LONG_BITS |
32 | 36 | /* no registers can be used */ | ... | ... |
target-ppc/op.c
... | ... | @@ -261,10 +261,15 @@ PPC_OP(load_xer_cr) |
261 | 261 | RETURN(); |
262 | 262 | } |
263 | 263 | |
264 | -PPC_OP(clear_xer_cr) | |
264 | +PPC_OP(clear_xer_ov) | |
265 | 265 | { |
266 | 266 | xer_so = 0; |
267 | 267 | xer_ov = 0; |
268 | + RETURN(); | |
269 | +} | |
270 | + | |
271 | +PPC_OP(clear_xer_ca) | |
272 | +{ | |
268 | 273 | xer_ca = 0; |
269 | 274 | RETURN(); |
270 | 275 | } |
... | ... | @@ -714,6 +719,7 @@ void OPPROTO op_check_addo (void) |
714 | 719 | xer_so = 1; |
715 | 720 | xer_ov = 1; |
716 | 721 | } |
722 | + RETURN(); | |
717 | 723 | } |
718 | 724 | |
719 | 725 | #if defined(TARGET_PPC64) |
... | ... | @@ -726,6 +732,7 @@ void OPPROTO op_check_addo_64 (void) |
726 | 732 | xer_so = 1; |
727 | 733 | xer_ov = 1; |
728 | 734 | } |
735 | + RETURN(); | |
729 | 736 | } |
730 | 737 | #endif |
731 | 738 | |
... | ... | @@ -1643,16 +1650,24 @@ PPC_OP(fsel) |
1643 | 1650 | /* fmadd - fmadd. */ |
1644 | 1651 | PPC_OP(fmadd) |
1645 | 1652 | { |
1653 | +#if USE_PRECISE_EMULATION | |
1654 | + do_fmadd(); | |
1655 | +#else | |
1646 | 1656 | FT0 = float64_mul(FT0, FT1, &env->fp_status); |
1647 | 1657 | FT0 = float64_add(FT0, FT2, &env->fp_status); |
1658 | +#endif | |
1648 | 1659 | RETURN(); |
1649 | 1660 | } |
1650 | 1661 | |
1651 | 1662 | /* fmsub - fmsub. */ |
1652 | 1663 | PPC_OP(fmsub) |
1653 | 1664 | { |
1665 | +#if USE_PRECISE_EMULATION | |
1666 | + do_fmsub(); | |
1667 | +#else | |
1654 | 1668 | FT0 = float64_mul(FT0, FT1, &env->fp_status); |
1655 | 1669 | FT0 = float64_sub(FT0, FT2, &env->fp_status); |
1670 | +#endif | |
1656 | 1671 | RETURN(); |
1657 | 1672 | } |
1658 | 1673 | |
... | ... | @@ -2378,6 +2393,7 @@ void OPPROTO op_store_booke_tsr (void) |
2378 | 2393 | void OPPROTO op_splatw_T1_64 (void) |
2379 | 2394 | { |
2380 | 2395 | T1_64 = (T1_64 << 32) | (T1_64 & 0x00000000FFFFFFFFULL); |
2396 | + RETURN(); | |
2381 | 2397 | } |
2382 | 2398 | |
2383 | 2399 | void OPPROTO op_splatwi_T0_64 (void) |
... | ... | @@ -2385,6 +2401,7 @@ void OPPROTO op_splatwi_T0_64 (void) |
2385 | 2401 | uint64_t tmp = PARAM1; |
2386 | 2402 | |
2387 | 2403 | T0_64 = (tmp << 32) | tmp; |
2404 | + RETURN(); | |
2388 | 2405 | } |
2389 | 2406 | |
2390 | 2407 | void OPPROTO op_splatwi_T1_64 (void) |
... | ... | @@ -2392,6 +2409,7 @@ void OPPROTO op_splatwi_T1_64 (void) |
2392 | 2409 | uint64_t tmp = PARAM1; |
2393 | 2410 | |
2394 | 2411 | T1_64 = (tmp << 32) | tmp; |
2412 | + RETURN(); | |
2395 | 2413 | } |
2396 | 2414 | |
2397 | 2415 | void OPPROTO op_extsh_T1_64 (void) | ... | ... |
target-ppc/op_helper.c
... | ... | @@ -615,11 +615,13 @@ void do_fctiw (void) |
615 | 615 | uint64_t i; |
616 | 616 | } p; |
617 | 617 | |
618 | + p.i = float64_to_int32(FT0, &env->fp_status); | |
619 | +#if USE_PRECISE_EMULATION | |
618 | 620 | /* XXX: higher bits are not supposed to be significant. |
619 | 621 | * to make tests easier, return the same as a real PowerPC 750 (aka G3) |
620 | 622 | */ |
621 | - p.i = float64_to_int32(FT0, &env->fp_status); | |
622 | 623 | p.i |= 0xFFF80000ULL << 32; |
624 | +#endif | |
623 | 625 | FT0 = p.d; |
624 | 626 | } |
625 | 627 | |
... | ... | @@ -630,26 +632,96 @@ void do_fctiwz (void) |
630 | 632 | uint64_t i; |
631 | 633 | } p; |
632 | 634 | |
635 | + p.i = float64_to_int32_round_to_zero(FT0, &env->fp_status); | |
636 | +#if USE_PRECISE_EMULATION | |
633 | 637 | /* XXX: higher bits are not supposed to be significant. |
634 | 638 | * to make tests easier, return the same as a real PowerPC 750 (aka G3) |
635 | 639 | */ |
636 | - p.i = float64_to_int32_round_to_zero(FT0, &env->fp_status); | |
637 | 640 | p.i |= 0xFFF80000ULL << 32; |
641 | +#endif | |
638 | 642 | FT0 = p.d; |
639 | 643 | } |
640 | 644 | |
645 | +#if USE_PRECISE_EMULATION | |
646 | +void do_fmadd (void) | |
647 | +{ | |
648 | +#ifdef FLOAT128 | |
649 | + float128 ft0_128, ft1_128; | |
650 | + | |
651 | + ft0_128 = float64_to_float128(FT0, &env->fp_status); | |
652 | + ft1_128 = float64_to_float128(FT1, &env->fp_status); | |
653 | + ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status); | |
654 | + ft1_128 = float64_to_float128(FT2, &env->fp_status); | |
655 | + ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status); | |
656 | + FT0 = float128_to_float64(ft0_128, &env->fp_status); | |
657 | +#else | |
658 | + /* This is OK on x86 hosts */ | |
659 | + FT0 = (FT0 * FT1) + FT2; | |
660 | +#endif | |
661 | +} | |
662 | + | |
663 | +void do_fmsub (void) | |
664 | +{ | |
665 | +#ifdef FLOAT128 | |
666 | + float128 ft0_128, ft1_128; | |
667 | + | |
668 | + ft0_128 = float64_to_float128(FT0, &env->fp_status); | |
669 | + ft1_128 = float64_to_float128(FT1, &env->fp_status); | |
670 | + ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status); | |
671 | + ft1_128 = float64_to_float128(FT2, &env->fp_status); | |
672 | + ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status); | |
673 | + FT0 = float128_to_float64(ft0_128, &env->fp_status); | |
674 | +#else | |
675 | + /* This is OK on x86 hosts */ | |
676 | + FT0 = (FT0 * FT1) - FT2; | |
677 | +#endif | |
678 | +} | |
679 | +#endif /* USE_PRECISE_EMULATION */ | |
680 | + | |
641 | 681 | void do_fnmadd (void) |
642 | 682 | { |
683 | +#if USE_PRECISE_EMULATION | |
684 | +#ifdef FLOAT128 | |
685 | + float128 ft0_128, ft1_128; | |
686 | + | |
687 | + ft0_128 = float64_to_float128(FT0, &env->fp_status); | |
688 | + ft1_128 = float64_to_float128(FT1, &env->fp_status); | |
689 | + ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status); | |
690 | + ft1_128 = float64_to_float128(FT2, &env->fp_status); | |
691 | + ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status); | |
692 | + FT0 = float128_to_float64(ft0_128, &env->fp_status); | |
693 | +#else | |
694 | + /* This is OK on x86 hosts */ | |
695 | + FT0 = (FT0 * FT1) + FT2; | |
696 | +#endif | |
697 | +#else | |
643 | 698 | FT0 = float64_mul(FT0, FT1, &env->fp_status); |
644 | 699 | FT0 = float64_add(FT0, FT2, &env->fp_status); |
700 | +#endif | |
645 | 701 | if (likely(!isnan(FT0))) |
646 | 702 | FT0 = float64_chs(FT0); |
647 | 703 | } |
648 | 704 | |
649 | 705 | void do_fnmsub (void) |
650 | 706 | { |
707 | +#if USE_PRECISE_EMULATION | |
708 | +#ifdef FLOAT128 | |
709 | + float128 ft0_128, ft1_128; | |
710 | + | |
711 | + ft0_128 = float64_to_float128(FT0, &env->fp_status); | |
712 | + ft1_128 = float64_to_float128(FT1, &env->fp_status); | |
713 | + ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status); | |
714 | + ft1_128 = float64_to_float128(FT2, &env->fp_status); | |
715 | + ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status); | |
716 | + FT0 = float128_to_float64(ft0_128, &env->fp_status); | |
717 | +#else | |
718 | + /* This is OK on x86 hosts */ | |
719 | + FT0 = (FT0 * FT1) - FT2; | |
720 | +#endif | |
721 | +#else | |
651 | 722 | FT0 = float64_mul(FT0, FT1, &env->fp_status); |
652 | 723 | FT0 = float64_sub(FT0, FT2, &env->fp_status); |
724 | +#endif | |
653 | 725 | if (likely(!isnan(FT0))) |
654 | 726 | FT0 = float64_chs(FT0); |
655 | 727 | } |
... | ... | @@ -667,7 +739,12 @@ void do_fres (void) |
667 | 739 | } p; |
668 | 740 | |
669 | 741 | if (likely(isnormal(FT0))) { |
742 | +#if USE_PRECISE_EMULATION | |
743 | + FT0 = float64_div(1.0, FT0, &env->fp_status); | |
744 | + FT0 = float64_to_float32(FT0, &env->fp_status); | |
745 | +#else | |
670 | 746 | FT0 = float32_div(1.0, FT0, &env->fp_status); |
747 | +#endif | |
671 | 748 | } else { |
672 | 749 | p.d = FT0; |
673 | 750 | if (p.i == 0x8000000000000000ULL) { | ... | ... |
target-ppc/op_helper.h
... | ... | @@ -93,6 +93,10 @@ void do_fsqrt (void); |
93 | 93 | void do_fres (void); |
94 | 94 | void do_frsqrte (void); |
95 | 95 | void do_fsel (void); |
96 | +#if USE_PRECISE_EMULATION | |
97 | +void do_fmadd (void); | |
98 | +void do_fmsub (void); | |
99 | +#endif | |
96 | 100 | void do_fnmadd (void); |
97 | 101 | void do_fnmsub (void); |
98 | 102 | void do_fctiw (void); | ... | ... |
target-ppc/translate.c
... | ... | @@ -781,6 +781,8 @@ GEN_HANDLER(addic, 0x0C, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) |
781 | 781 | else |
782 | 782 | #endif |
783 | 783 | gen_op_check_addc(); |
784 | + } else { | |
785 | + gen_op_clear_xer_ca(); | |
784 | 786 | } |
785 | 787 | gen_op_store_T0_gpr(rD(ctx->opcode)); |
786 | 788 | } |
... | ... | @@ -2804,7 +2806,8 @@ GEN_HANDLER(mcrxr, 0x1F, 0x00, 0x10, 0x007FF801, PPC_MISC) |
2804 | 2806 | { |
2805 | 2807 | gen_op_load_xer_cr(); |
2806 | 2808 | gen_op_store_T0_crf(crfD(ctx->opcode)); |
2807 | - gen_op_clear_xer_cr(); | |
2809 | + gen_op_clear_xer_ov(); | |
2810 | + gen_op_clear_xer_ca(); | |
2808 | 2811 | } |
2809 | 2812 | |
2810 | 2813 | /* mfcr */ | ... | ... |