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,6 +27,10 @@ | ||
27 | #include "cpu.h" | 27 | #include "cpu.h" |
28 | #include "exec-all.h" | 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 | register struct CPUPPCState *env asm(AREG0); | 34 | register struct CPUPPCState *env asm(AREG0); |
31 | #if TARGET_LONG_BITS > HOST_LONG_BITS | 35 | #if TARGET_LONG_BITS > HOST_LONG_BITS |
32 | /* no registers can be used */ | 36 | /* no registers can be used */ |
target-ppc/op.c
@@ -261,10 +261,15 @@ PPC_OP(load_xer_cr) | @@ -261,10 +261,15 @@ PPC_OP(load_xer_cr) | ||
261 | RETURN(); | 261 | RETURN(); |
262 | } | 262 | } |
263 | 263 | ||
264 | -PPC_OP(clear_xer_cr) | 264 | +PPC_OP(clear_xer_ov) |
265 | { | 265 | { |
266 | xer_so = 0; | 266 | xer_so = 0; |
267 | xer_ov = 0; | 267 | xer_ov = 0; |
268 | + RETURN(); | ||
269 | +} | ||
270 | + | ||
271 | +PPC_OP(clear_xer_ca) | ||
272 | +{ | ||
268 | xer_ca = 0; | 273 | xer_ca = 0; |
269 | RETURN(); | 274 | RETURN(); |
270 | } | 275 | } |
@@ -714,6 +719,7 @@ void OPPROTO op_check_addo (void) | @@ -714,6 +719,7 @@ void OPPROTO op_check_addo (void) | ||
714 | xer_so = 1; | 719 | xer_so = 1; |
715 | xer_ov = 1; | 720 | xer_ov = 1; |
716 | } | 721 | } |
722 | + RETURN(); | ||
717 | } | 723 | } |
718 | 724 | ||
719 | #if defined(TARGET_PPC64) | 725 | #if defined(TARGET_PPC64) |
@@ -726,6 +732,7 @@ void OPPROTO op_check_addo_64 (void) | @@ -726,6 +732,7 @@ void OPPROTO op_check_addo_64 (void) | ||
726 | xer_so = 1; | 732 | xer_so = 1; |
727 | xer_ov = 1; | 733 | xer_ov = 1; |
728 | } | 734 | } |
735 | + RETURN(); | ||
729 | } | 736 | } |
730 | #endif | 737 | #endif |
731 | 738 | ||
@@ -1643,16 +1650,24 @@ PPC_OP(fsel) | @@ -1643,16 +1650,24 @@ PPC_OP(fsel) | ||
1643 | /* fmadd - fmadd. */ | 1650 | /* fmadd - fmadd. */ |
1644 | PPC_OP(fmadd) | 1651 | PPC_OP(fmadd) |
1645 | { | 1652 | { |
1653 | +#if USE_PRECISE_EMULATION | ||
1654 | + do_fmadd(); | ||
1655 | +#else | ||
1646 | FT0 = float64_mul(FT0, FT1, &env->fp_status); | 1656 | FT0 = float64_mul(FT0, FT1, &env->fp_status); |
1647 | FT0 = float64_add(FT0, FT2, &env->fp_status); | 1657 | FT0 = float64_add(FT0, FT2, &env->fp_status); |
1658 | +#endif | ||
1648 | RETURN(); | 1659 | RETURN(); |
1649 | } | 1660 | } |
1650 | 1661 | ||
1651 | /* fmsub - fmsub. */ | 1662 | /* fmsub - fmsub. */ |
1652 | PPC_OP(fmsub) | 1663 | PPC_OP(fmsub) |
1653 | { | 1664 | { |
1665 | +#if USE_PRECISE_EMULATION | ||
1666 | + do_fmsub(); | ||
1667 | +#else | ||
1654 | FT0 = float64_mul(FT0, FT1, &env->fp_status); | 1668 | FT0 = float64_mul(FT0, FT1, &env->fp_status); |
1655 | FT0 = float64_sub(FT0, FT2, &env->fp_status); | 1669 | FT0 = float64_sub(FT0, FT2, &env->fp_status); |
1670 | +#endif | ||
1656 | RETURN(); | 1671 | RETURN(); |
1657 | } | 1672 | } |
1658 | 1673 | ||
@@ -2378,6 +2393,7 @@ void OPPROTO op_store_booke_tsr (void) | @@ -2378,6 +2393,7 @@ void OPPROTO op_store_booke_tsr (void) | ||
2378 | void OPPROTO op_splatw_T1_64 (void) | 2393 | void OPPROTO op_splatw_T1_64 (void) |
2379 | { | 2394 | { |
2380 | T1_64 = (T1_64 << 32) | (T1_64 & 0x00000000FFFFFFFFULL); | 2395 | T1_64 = (T1_64 << 32) | (T1_64 & 0x00000000FFFFFFFFULL); |
2396 | + RETURN(); | ||
2381 | } | 2397 | } |
2382 | 2398 | ||
2383 | void OPPROTO op_splatwi_T0_64 (void) | 2399 | void OPPROTO op_splatwi_T0_64 (void) |
@@ -2385,6 +2401,7 @@ void OPPROTO op_splatwi_T0_64 (void) | @@ -2385,6 +2401,7 @@ void OPPROTO op_splatwi_T0_64 (void) | ||
2385 | uint64_t tmp = PARAM1; | 2401 | uint64_t tmp = PARAM1; |
2386 | 2402 | ||
2387 | T0_64 = (tmp << 32) | tmp; | 2403 | T0_64 = (tmp << 32) | tmp; |
2404 | + RETURN(); | ||
2388 | } | 2405 | } |
2389 | 2406 | ||
2390 | void OPPROTO op_splatwi_T1_64 (void) | 2407 | void OPPROTO op_splatwi_T1_64 (void) |
@@ -2392,6 +2409,7 @@ void OPPROTO op_splatwi_T1_64 (void) | @@ -2392,6 +2409,7 @@ void OPPROTO op_splatwi_T1_64 (void) | ||
2392 | uint64_t tmp = PARAM1; | 2409 | uint64_t tmp = PARAM1; |
2393 | 2410 | ||
2394 | T1_64 = (tmp << 32) | tmp; | 2411 | T1_64 = (tmp << 32) | tmp; |
2412 | + RETURN(); | ||
2395 | } | 2413 | } |
2396 | 2414 | ||
2397 | void OPPROTO op_extsh_T1_64 (void) | 2415 | void OPPROTO op_extsh_T1_64 (void) |
target-ppc/op_helper.c
@@ -615,11 +615,13 @@ void do_fctiw (void) | @@ -615,11 +615,13 @@ void do_fctiw (void) | ||
615 | uint64_t i; | 615 | uint64_t i; |
616 | } p; | 616 | } p; |
617 | 617 | ||
618 | + p.i = float64_to_int32(FT0, &env->fp_status); | ||
619 | +#if USE_PRECISE_EMULATION | ||
618 | /* XXX: higher bits are not supposed to be significant. | 620 | /* XXX: higher bits are not supposed to be significant. |
619 | * to make tests easier, return the same as a real PowerPC 750 (aka G3) | 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 | p.i |= 0xFFF80000ULL << 32; | 623 | p.i |= 0xFFF80000ULL << 32; |
624 | +#endif | ||
623 | FT0 = p.d; | 625 | FT0 = p.d; |
624 | } | 626 | } |
625 | 627 | ||
@@ -630,26 +632,96 @@ void do_fctiwz (void) | @@ -630,26 +632,96 @@ void do_fctiwz (void) | ||
630 | uint64_t i; | 632 | uint64_t i; |
631 | } p; | 633 | } p; |
632 | 634 | ||
635 | + p.i = float64_to_int32_round_to_zero(FT0, &env->fp_status); | ||
636 | +#if USE_PRECISE_EMULATION | ||
633 | /* XXX: higher bits are not supposed to be significant. | 637 | /* XXX: higher bits are not supposed to be significant. |
634 | * to make tests easier, return the same as a real PowerPC 750 (aka G3) | 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 | p.i |= 0xFFF80000ULL << 32; | 640 | p.i |= 0xFFF80000ULL << 32; |
641 | +#endif | ||
638 | FT0 = p.d; | 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 | void do_fnmadd (void) | 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 | FT0 = float64_mul(FT0, FT1, &env->fp_status); | 698 | FT0 = float64_mul(FT0, FT1, &env->fp_status); |
644 | FT0 = float64_add(FT0, FT2, &env->fp_status); | 699 | FT0 = float64_add(FT0, FT2, &env->fp_status); |
700 | +#endif | ||
645 | if (likely(!isnan(FT0))) | 701 | if (likely(!isnan(FT0))) |
646 | FT0 = float64_chs(FT0); | 702 | FT0 = float64_chs(FT0); |
647 | } | 703 | } |
648 | 704 | ||
649 | void do_fnmsub (void) | 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 | FT0 = float64_mul(FT0, FT1, &env->fp_status); | 722 | FT0 = float64_mul(FT0, FT1, &env->fp_status); |
652 | FT0 = float64_sub(FT0, FT2, &env->fp_status); | 723 | FT0 = float64_sub(FT0, FT2, &env->fp_status); |
724 | +#endif | ||
653 | if (likely(!isnan(FT0))) | 725 | if (likely(!isnan(FT0))) |
654 | FT0 = float64_chs(FT0); | 726 | FT0 = float64_chs(FT0); |
655 | } | 727 | } |
@@ -667,7 +739,12 @@ void do_fres (void) | @@ -667,7 +739,12 @@ void do_fres (void) | ||
667 | } p; | 739 | } p; |
668 | 740 | ||
669 | if (likely(isnormal(FT0))) { | 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 | FT0 = float32_div(1.0, FT0, &env->fp_status); | 746 | FT0 = float32_div(1.0, FT0, &env->fp_status); |
747 | +#endif | ||
671 | } else { | 748 | } else { |
672 | p.d = FT0; | 749 | p.d = FT0; |
673 | if (p.i == 0x8000000000000000ULL) { | 750 | if (p.i == 0x8000000000000000ULL) { |
target-ppc/op_helper.h
@@ -93,6 +93,10 @@ void do_fsqrt (void); | @@ -93,6 +93,10 @@ void do_fsqrt (void); | ||
93 | void do_fres (void); | 93 | void do_fres (void); |
94 | void do_frsqrte (void); | 94 | void do_frsqrte (void); |
95 | void do_fsel (void); | 95 | void do_fsel (void); |
96 | +#if USE_PRECISE_EMULATION | ||
97 | +void do_fmadd (void); | ||
98 | +void do_fmsub (void); | ||
99 | +#endif | ||
96 | void do_fnmadd (void); | 100 | void do_fnmadd (void); |
97 | void do_fnmsub (void); | 101 | void do_fnmsub (void); |
98 | void do_fctiw (void); | 102 | void do_fctiw (void); |
target-ppc/translate.c
@@ -781,6 +781,8 @@ GEN_HANDLER(addic, 0x0C, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) | @@ -781,6 +781,8 @@ GEN_HANDLER(addic, 0x0C, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) | ||
781 | else | 781 | else |
782 | #endif | 782 | #endif |
783 | gen_op_check_addc(); | 783 | gen_op_check_addc(); |
784 | + } else { | ||
785 | + gen_op_clear_xer_ca(); | ||
784 | } | 786 | } |
785 | gen_op_store_T0_gpr(rD(ctx->opcode)); | 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,7 +2806,8 @@ GEN_HANDLER(mcrxr, 0x1F, 0x00, 0x10, 0x007FF801, PPC_MISC) | ||
2804 | { | 2806 | { |
2805 | gen_op_load_xer_cr(); | 2807 | gen_op_load_xer_cr(); |
2806 | gen_op_store_T0_crf(crfD(ctx->opcode)); | 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 | /* mfcr */ | 2813 | /* mfcr */ |