Commit e864cabdc0a38bb598ddcf88b264896dc6f3e3b2

Authored by j_mayer
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
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 */
... ...