mirror of https://github.com/xemu-project/xemu.git
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
This commit is contained in:
parent
a722258036
commit
e864cabdc0
|
@ -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 */
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 */
|
||||
|
|
Loading…
Reference in New Issue