From e864cabdc0a38bb598ddcf88b264896dc6f3e3b2 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Thu, 22 Mar 2007 22:17:08 +0000 Subject: [PATCH] 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 | 4 +++ target-ppc/op.c | 20 ++++++++++++- target-ppc/op_helper.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++++-- target-ppc/op_helper.h | 4 +++ target-ppc/translate.c | 5 +++- 5 files changed, 110 insertions(+), 4 deletions(-) diff --git a/target-ppc/exec.h b/target-ppc/exec.h index a10b62d..87e8c18 100644 --- a/target-ppc/exec.h +++ b/target-ppc/exec.h @@ -27,6 +27,10 @@ #include "cpu.h" #include "exec-all.h" +/* For normal operations, precise emulation should not be needed */ +//#define USE_PRECISE_EMULATION 1 +#define USE_PRECISE_EMULATION 0 + register struct CPUPPCState *env asm(AREG0); #if TARGET_LONG_BITS > HOST_LONG_BITS /* no registers can be used */ diff --git a/target-ppc/op.c b/target-ppc/op.c index f13f6f5..068ccb5 100644 --- a/target-ppc/op.c +++ b/target-ppc/op.c @@ -261,10 +261,15 @@ PPC_OP(load_xer_cr) RETURN(); } -PPC_OP(clear_xer_cr) +PPC_OP(clear_xer_ov) { xer_so = 0; xer_ov = 0; + RETURN(); +} + +PPC_OP(clear_xer_ca) +{ xer_ca = 0; RETURN(); } @@ -714,6 +719,7 @@ void OPPROTO op_check_addo (void) xer_so = 1; xer_ov = 1; } + RETURN(); } #if defined(TARGET_PPC64) @@ -726,6 +732,7 @@ void OPPROTO op_check_addo_64 (void) xer_so = 1; xer_ov = 1; } + RETURN(); } #endif @@ -1643,16 +1650,24 @@ PPC_OP(fsel) /* fmadd - fmadd. */ PPC_OP(fmadd) { +#if USE_PRECISE_EMULATION + do_fmadd(); +#else FT0 = float64_mul(FT0, FT1, &env->fp_status); FT0 = float64_add(FT0, FT2, &env->fp_status); +#endif RETURN(); } /* fmsub - fmsub. */ PPC_OP(fmsub) { +#if USE_PRECISE_EMULATION + do_fmsub(); +#else FT0 = float64_mul(FT0, FT1, &env->fp_status); FT0 = float64_sub(FT0, FT2, &env->fp_status); +#endif RETURN(); } @@ -2378,6 +2393,7 @@ void OPPROTO op_store_booke_tsr (void) void OPPROTO op_splatw_T1_64 (void) { T1_64 = (T1_64 << 32) | (T1_64 & 0x00000000FFFFFFFFULL); + RETURN(); } void OPPROTO op_splatwi_T0_64 (void) @@ -2385,6 +2401,7 @@ void OPPROTO op_splatwi_T0_64 (void) uint64_t tmp = PARAM1; T0_64 = (tmp << 32) | tmp; + RETURN(); } void OPPROTO op_splatwi_T1_64 (void) @@ -2392,6 +2409,7 @@ void OPPROTO op_splatwi_T1_64 (void) uint64_t tmp = PARAM1; T1_64 = (tmp << 32) | tmp; + RETURN(); } void OPPROTO op_extsh_T1_64 (void) diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index 756d164..45e4dde 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -615,11 +615,13 @@ void do_fctiw (void) uint64_t i; } p; + p.i = float64_to_int32(FT0, &env->fp_status); +#if USE_PRECISE_EMULATION /* XXX: higher bits are not supposed to be significant. * to make tests easier, return the same as a real PowerPC 750 (aka G3) */ - p.i = float64_to_int32(FT0, &env->fp_status); p.i |= 0xFFF80000ULL << 32; +#endif FT0 = p.d; } @@ -630,26 +632,96 @@ void do_fctiwz (void) uint64_t i; } p; + p.i = float64_to_int32_round_to_zero(FT0, &env->fp_status); +#if USE_PRECISE_EMULATION /* XXX: higher bits are not supposed to be significant. * to make tests easier, return the same as a real PowerPC 750 (aka G3) */ - p.i = float64_to_int32_round_to_zero(FT0, &env->fp_status); p.i |= 0xFFF80000ULL << 32; +#endif FT0 = p.d; } +#if USE_PRECISE_EMULATION +void do_fmadd (void) +{ +#ifdef FLOAT128 + float128 ft0_128, ft1_128; + + ft0_128 = float64_to_float128(FT0, &env->fp_status); + ft1_128 = float64_to_float128(FT1, &env->fp_status); + ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status); + ft1_128 = float64_to_float128(FT2, &env->fp_status); + ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status); + FT0 = float128_to_float64(ft0_128, &env->fp_status); +#else + /* This is OK on x86 hosts */ + FT0 = (FT0 * FT1) + FT2; +#endif +} + +void do_fmsub (void) +{ +#ifdef FLOAT128 + float128 ft0_128, ft1_128; + + ft0_128 = float64_to_float128(FT0, &env->fp_status); + ft1_128 = float64_to_float128(FT1, &env->fp_status); + ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status); + ft1_128 = float64_to_float128(FT2, &env->fp_status); + ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status); + FT0 = float128_to_float64(ft0_128, &env->fp_status); +#else + /* This is OK on x86 hosts */ + FT0 = (FT0 * FT1) - FT2; +#endif +} +#endif /* USE_PRECISE_EMULATION */ + void do_fnmadd (void) { +#if USE_PRECISE_EMULATION +#ifdef FLOAT128 + float128 ft0_128, ft1_128; + + ft0_128 = float64_to_float128(FT0, &env->fp_status); + ft1_128 = float64_to_float128(FT1, &env->fp_status); + ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status); + ft1_128 = float64_to_float128(FT2, &env->fp_status); + ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status); + FT0 = float128_to_float64(ft0_128, &env->fp_status); +#else + /* This is OK on x86 hosts */ + FT0 = (FT0 * FT1) + FT2; +#endif +#else FT0 = float64_mul(FT0, FT1, &env->fp_status); FT0 = float64_add(FT0, FT2, &env->fp_status); +#endif if (likely(!isnan(FT0))) FT0 = float64_chs(FT0); } void do_fnmsub (void) { +#if USE_PRECISE_EMULATION +#ifdef FLOAT128 + float128 ft0_128, ft1_128; + + ft0_128 = float64_to_float128(FT0, &env->fp_status); + ft1_128 = float64_to_float128(FT1, &env->fp_status); + ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status); + ft1_128 = float64_to_float128(FT2, &env->fp_status); + ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status); + FT0 = float128_to_float64(ft0_128, &env->fp_status); +#else + /* This is OK on x86 hosts */ + FT0 = (FT0 * FT1) - FT2; +#endif +#else FT0 = float64_mul(FT0, FT1, &env->fp_status); FT0 = float64_sub(FT0, FT2, &env->fp_status); +#endif if (likely(!isnan(FT0))) FT0 = float64_chs(FT0); } @@ -667,7 +739,12 @@ void do_fres (void) } p; if (likely(isnormal(FT0))) { +#if USE_PRECISE_EMULATION + FT0 = float64_div(1.0, FT0, &env->fp_status); + FT0 = float64_to_float32(FT0, &env->fp_status); +#else FT0 = float32_div(1.0, FT0, &env->fp_status); +#endif } else { p.d = FT0; if (p.i == 0x8000000000000000ULL) { diff --git a/target-ppc/op_helper.h b/target-ppc/op_helper.h index 3aa6045..fc3d8af 100644 --- a/target-ppc/op_helper.h +++ b/target-ppc/op_helper.h @@ -93,6 +93,10 @@ void do_fsqrt (void); void do_fres (void); void do_frsqrte (void); void do_fsel (void); +#if USE_PRECISE_EMULATION +void do_fmadd (void); +void do_fmsub (void); +#endif void do_fnmadd (void); void do_fnmsub (void); void do_fctiw (void); diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 90a9fc9..fb9b075 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -781,6 +781,8 @@ GEN_HANDLER(addic, 0x0C, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) else #endif gen_op_check_addc(); + } else { + gen_op_clear_xer_ca(); } gen_op_store_T0_gpr(rD(ctx->opcode)); } @@ -2804,7 +2806,8 @@ GEN_HANDLER(mcrxr, 0x1F, 0x00, 0x10, 0x007FF801, PPC_MISC) { gen_op_load_xer_cr(); gen_op_store_T0_crf(crfD(ctx->opcode)); - gen_op_clear_xer_cr(); + gen_op_clear_xer_ov(); + gen_op_clear_xer_ca(); } /* mfcr */ -- 2.7.4