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 */ | ... | ... |