Fix PowerPC FPSCR update and floating-point exception generation
in most useful cases. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3458 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
parent
a32ff1ad95
commit
7c58044c0a
@ -224,11 +224,6 @@ void cpu_loop(CPUPPCState *env)
|
||||
case POWERPC_EXCP_FP:
|
||||
EXCP_DUMP(env, "Floating point program exception\n");
|
||||
/* Set FX */
|
||||
env->fpscr[7] |= 0x8;
|
||||
/* Finally, update FEX */
|
||||
if ((((env->fpscr[7] & 0x3) << 3) | (env->fpscr[6] >> 1)) &
|
||||
((env->fpscr[1] << 1) | (env->fpscr[0] >> 3)))
|
||||
env->fpscr[7] |= 0x4;
|
||||
info.si_signo = SIGFPE;
|
||||
info.si_errno = 0;
|
||||
switch (env->error_code & 0xF) {
|
||||
@ -248,7 +243,7 @@ void cpu_loop(CPUPPCState *env)
|
||||
case POWERPC_EXCP_FP_VXSOFT:
|
||||
info.si_code = FPE_FLTINV;
|
||||
break;
|
||||
case POWERPC_EXCP_FP_VXNAN:
|
||||
case POWERPC_EXCP_FP_VXSNAN:
|
||||
case POWERPC_EXCP_FP_VXISI:
|
||||
case POWERPC_EXCP_FP_VXIDI:
|
||||
case POWERPC_EXCP_FP_VXIMZ:
|
||||
|
@ -829,12 +829,6 @@ void cpu_loop(CPUPPCState *env)
|
||||
switch (env->error_code & ~0xF) {
|
||||
case POWERPC_EXCP_FP:
|
||||
EXCP_DUMP(env, "Floating point program exception\n");
|
||||
/* Set FX */
|
||||
env->fpscr[7] |= 0x8;
|
||||
/* Finally, update FEX */
|
||||
if ((((env->fpscr[7] & 0x3) << 3) | (env->fpscr[6] >> 1)) &
|
||||
((env->fpscr[1] << 1) | (env->fpscr[0] >> 3)))
|
||||
env->fpscr[7] |= 0x4;
|
||||
info.si_signo = TARGET_SIGFPE;
|
||||
info.si_errno = 0;
|
||||
switch (env->error_code & 0xF) {
|
||||
@ -854,7 +848,7 @@ void cpu_loop(CPUPPCState *env)
|
||||
case POWERPC_EXCP_FP_VXSOFT:
|
||||
info.si_code = TARGET_FPE_FLTINV;
|
||||
break;
|
||||
case POWERPC_EXCP_FP_VXNAN:
|
||||
case POWERPC_EXCP_FP_VXSNAN:
|
||||
case POWERPC_EXCP_FP_VXISI:
|
||||
case POWERPC_EXCP_FP_VXIDI:
|
||||
case POWERPC_EXCP_FP_VXIMZ:
|
||||
|
@ -239,7 +239,7 @@ enum {
|
||||
POWERPC_EXCP_FP_UX = 0x02, /* FP underflow */
|
||||
POWERPC_EXCP_FP_ZX = 0x03, /* FP divide by zero */
|
||||
POWERPC_EXCP_FP_XX = 0x04, /* FP inexact */
|
||||
POWERPC_EXCP_FP_VXNAN = 0x05, /* FP invalid SNaN op */
|
||||
POWERPC_EXCP_FP_VXSNAN = 0x05, /* FP invalid SNaN op */
|
||||
POWERPC_EXCP_FP_VXISI = 0x06, /* FP invalid infinite subtraction */
|
||||
POWERPC_EXCP_FP_VXIDI = 0x07, /* FP invalid infinite divide */
|
||||
POWERPC_EXCP_FP_VXZDZ = 0x08, /* FP invalid zero divide */
|
||||
@ -433,14 +433,84 @@ enum {
|
||||
POWERPC_FLAG_PMM = 0x00000400,
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Floating point status and control register */
|
||||
#define FPSCR_FX 31 /* Floating-point exception summary */
|
||||
#define FPSCR_FEX 30 /* Floating-point enabled exception summary */
|
||||
#define FPSCR_VX 29 /* Floating-point invalid operation exception summ. */
|
||||
#define FPSCR_OX 28 /* Floating-point overflow exception */
|
||||
#define FPSCR_UX 27 /* Floating-point underflow exception */
|
||||
#define FPSCR_ZX 26 /* Floating-point zero divide exception */
|
||||
#define FPSCR_XX 25 /* Floating-point inexact exception */
|
||||
#define FPSCR_VXSNAN 24 /* Floating-point invalid operation exception (sNan) */
|
||||
#define FPSCR_VXISI 23 /* Floating-point invalid operation exception (inf) */
|
||||
#define FPSCR_VXIDI 22 /* Floating-point invalid operation exception (inf) */
|
||||
#define FPSCR_VXZDZ 21 /* Floating-point invalid operation exception (zero) */
|
||||
#define FPSCR_VXIMZ 20 /* Floating-point invalid operation exception (inf) */
|
||||
#define FPSCR_VXVC 19 /* Floating-point invalid operation exception (comp) */
|
||||
#define FPSCR_FR 18 /* Floating-point fraction rounded */
|
||||
#define FPSCR_FI 17 /* Floating-point fraction inexact */
|
||||
#define FPSCR_C 16 /* Floating-point result class descriptor */
|
||||
#define FPSCR_FL 15 /* Floating-point less than or negative */
|
||||
#define FPSCR_FG 14 /* Floating-point greater than or negative */
|
||||
#define FPSCR_FE 13 /* Floating-point equal or zero */
|
||||
#define FPSCR_FU 12 /* Floating-point unordered or NaN */
|
||||
#define FPSCR_FPCC 12 /* Floating-point condition code */
|
||||
#define FPSCR_FPRF 12 /* Floating-point result flags */
|
||||
#define FPSCR_VXSOFT 10 /* Floating-point invalid operation exception (soft) */
|
||||
#define FPSCR_VXSQRT 9 /* Floating-point invalid operation exception (sqrt) */
|
||||
#define FPSCR_VXCVI 8 /* Floating-point invalid operation exception (int) */
|
||||
#define FPSCR_VE 7 /* Floating-point invalid operation exception enable */
|
||||
#define FPSCR_OE 6 /* Floating-point overflow exception enable */
|
||||
#define FPSCR_UE 5 /* Floating-point undeflow exception enable */
|
||||
#define FPSCR_ZE 4 /* Floating-point zero divide exception enable */
|
||||
#define FPSCR_XE 3 /* Floating-point inexact exception enable */
|
||||
#define FPSCR_NI 2 /* Floating-point non-IEEE mode */
|
||||
#define FPSCR_RN1 1
|
||||
#define FPSCR_RN 0 /* Floating-point rounding control */
|
||||
#define fpscr_fex (((env->fpscr) >> FPSCR_FEX) & 0x1)
|
||||
#define fpscr_vx (((env->fpscr) >> FPSCR_VX) & 0x1)
|
||||
#define fpscr_ox (((env->fpscr) >> FPSCR_OX) & 0x1)
|
||||
#define fpscr_ux (((env->fpscr) >> FPSCR_UX) & 0x1)
|
||||
#define fpscr_zx (((env->fpscr) >> FPSCR_ZX) & 0x1)
|
||||
#define fpscr_xx (((env->fpscr) >> FPSCR_XX) & 0x1)
|
||||
#define fpscr_vxsnan (((env->fpscr) >> FPSCR_VXSNAN) & 0x1)
|
||||
#define fpscr_vxisi (((env->fpscr) >> FPSCR_VXISI) & 0x1)
|
||||
#define fpscr_vxidi (((env->fpscr) >> FPSCR_VXIDI) & 0x1)
|
||||
#define fpscr_vxzdz (((env->fpscr) >> FPSCR_VXZDZ) & 0x1)
|
||||
#define fpscr_vximz (((env->fpscr) >> FPSCR_VXIMZ) & 0x1)
|
||||
#define fpscr_vxvc (((env->fpscr) >> FPSCR_VXVC) & 0x1)
|
||||
#define fpscr_fpcc (((env->fpscr) >> FPSCR_FPCC) & 0xF)
|
||||
#define fpscr_vxsoft (((env->fpscr) >> FPSCR_VXSOFT) & 0x1)
|
||||
#define fpscr_vxsqrt (((env->fpscr) >> FPSCR_VXSQRT) & 0x1)
|
||||
#define fpscr_vxcvi (((env->fpscr) >> FPSCR_VXCVI) & 0x1)
|
||||
#define fpscr_ve (((env->fpscr) >> FPSCR_VE) & 0x1)
|
||||
#define fpscr_oe (((env->fpscr) >> FPSCR_OE) & 0x1)
|
||||
#define fpscr_ue (((env->fpscr) >> FPSCR_UE) & 0x1)
|
||||
#define fpscr_ze (((env->fpscr) >> FPSCR_ZE) & 0x1)
|
||||
#define fpscr_xe (((env->fpscr) >> FPSCR_XE) & 0x1)
|
||||
#define fpscr_ni (((env->fpscr) >> FPSCR_NI) & 0x1)
|
||||
#define fpscr_rn (((env->fpscr) >> FPSCR_RN) & 0x3)
|
||||
/* Invalid operation exception summary */
|
||||
#define fpscr_ix ((env->fpscr) & ((1 << FPSCR_VXSNAN) | (1 << FPSCR_VXISI) | \
|
||||
(1 << FPSCR_VXIDI) | (1 << FPSCR_VXZDZ) | \
|
||||
(1 << FPSCR_VXIMZ) | (1 << FPSCR_VXVC) | \
|
||||
(1 << FPSCR_VXSOFT) | (1 << FPSCR_VXSQRT) | \
|
||||
(1 << FPSCR_VXCVI)))
|
||||
/* exception summary */
|
||||
#define fpscr_ex (((env->fpscr) >> FPSCR_XX) & 0x1F)
|
||||
/* enabled exception summary */
|
||||
#define fpscr_eex (((env->fpscr) >> FPSCR_XX) & ((env->fpscr) >> FPSCR_XE) & \
|
||||
0x1F)
|
||||
|
||||
/*****************************************************************************/
|
||||
/* The whole PowerPC CPU context */
|
||||
#if defined(TARGET_PPC64H)
|
||||
#define NB_MMU_MODES 3
|
||||
#else
|
||||
#define NB_MMU_MODES 2
|
||||
#endif
|
||||
|
||||
/*****************************************************************************/
|
||||
/* The whole PowerPC CPU context */
|
||||
struct CPUPPCState {
|
||||
/* First are the most commonly used resources
|
||||
* during translated code execution
|
||||
@ -482,7 +552,7 @@ struct CPUPPCState {
|
||||
/* floating point registers */
|
||||
float64 fpr[32];
|
||||
/* floating point status and control register */
|
||||
uint8_t fpscr[8];
|
||||
uint32_t fpscr;
|
||||
|
||||
CPU_COMMON
|
||||
|
||||
|
@ -2130,6 +2130,8 @@ static always_inline void powerpc_excp (CPUState *env,
|
||||
fprintf(logfile, "Ignore floating point exception\n");
|
||||
}
|
||||
#endif
|
||||
env->exception_index = POWERPC_EXCP_NONE;
|
||||
env->error_code = 0;
|
||||
return;
|
||||
}
|
||||
new_msr &= ~((target_ulong)1 << MSR_RI);
|
||||
@ -2138,12 +2140,6 @@ static always_inline void powerpc_excp (CPUState *env,
|
||||
new_msr |= (target_ulong)1 << MSR_HV;
|
||||
#endif
|
||||
msr |= 0x00100000;
|
||||
/* Set FX */
|
||||
env->fpscr[7] |= 0x8;
|
||||
/* Finally, update FEX */
|
||||
if ((((env->fpscr[7] & 0x3) << 3) | (env->fpscr[6] >> 1)) &
|
||||
((env->fpscr[1] << 1) | (env->fpscr[0] >> 3)))
|
||||
env->fpscr[7] |= 0x4;
|
||||
if (msr_fe0 != msr_fe1) {
|
||||
msr |= 0x00010000;
|
||||
goto store_current;
|
||||
@ -2199,9 +2195,12 @@ static always_inline void powerpc_excp (CPUState *env,
|
||||
/* XXX: To be removed */
|
||||
if (env->gpr[3] == 0x113724fa && env->gpr[4] == 0x77810f9b &&
|
||||
env->osi_call) {
|
||||
if (env->osi_call(env) != 0)
|
||||
if (env->osi_call(env) != 0) {
|
||||
env->exception_index = POWERPC_EXCP_NONE;
|
||||
env->error_code = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (loglevel & CPU_LOG_INT) {
|
||||
dump_syscall(env);
|
||||
}
|
||||
|
130
target-ppc/op.c
130
target-ppc/op.c
@ -135,13 +135,6 @@ void OPPROTO op_set_Rc0 (void)
|
||||
RETURN();
|
||||
}
|
||||
|
||||
/* Set Rc1 (for floating point arithmetic) */
|
||||
void OPPROTO op_set_Rc1 (void)
|
||||
{
|
||||
env->crf[1] = env->fpscr[7];
|
||||
RETURN();
|
||||
}
|
||||
|
||||
/* Constants load */
|
||||
void OPPROTO op_reset_T0 (void)
|
||||
{
|
||||
@ -552,9 +545,102 @@ void OPPROTO op_store_dbatl (void)
|
||||
#endif /* !defined(CONFIG_USER_ONLY) */
|
||||
|
||||
/* FPSCR */
|
||||
void OPPROTO op_load_fpscr (void)
|
||||
#ifdef CONFIG_SOFTFLOAT
|
||||
void OPPROTO op_reset_fpstatus (void)
|
||||
{
|
||||
do_load_fpscr();
|
||||
env->fp_status.float_exception_flags = 0;
|
||||
RETURN();
|
||||
}
|
||||
#endif
|
||||
|
||||
void OPPROTO op_compute_fprf (void)
|
||||
{
|
||||
do_compute_fprf(PARAM1);
|
||||
RETURN();
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SOFTFLOAT
|
||||
void OPPROTO op_float_check_status (void)
|
||||
{
|
||||
do_float_check_status();
|
||||
RETURN();
|
||||
}
|
||||
#else
|
||||
void OPPROTO op_float_check_status (void)
|
||||
{
|
||||
if (env->exception_index == POWERPC_EXCP_PROGRAM &&
|
||||
(env->error_code & POWERPC_EXCP_FP)) {
|
||||
/* Differred floating-point exception after target FPR update */
|
||||
if (msr_fe0 != 0 || msr_fe1 != 0)
|
||||
do_raise_exception_err(env->exception_index, env->error_code);
|
||||
}
|
||||
RETURN();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(WORDS_BIGENDIAN)
|
||||
#define WORD0 0
|
||||
#define WORD1 1
|
||||
#else
|
||||
#define WORD0 1
|
||||
#define WORD1 0
|
||||
#endif
|
||||
void OPPROTO op_load_fpscr_FT0 (void)
|
||||
{
|
||||
/* The 32 MSB of the target fpr are undefined.
|
||||
* They'll be zero...
|
||||
*/
|
||||
union {
|
||||
float64 d;
|
||||
struct {
|
||||
uint32_t u[2];
|
||||
} s;
|
||||
} u;
|
||||
|
||||
u.s.u[WORD0] = 0;
|
||||
u.s.u[WORD1] = env->fpscr;
|
||||
FT0 = u.d;
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void OPPROTO op_set_FT0 (void)
|
||||
{
|
||||
union {
|
||||
float64 d;
|
||||
struct {
|
||||
uint32_t u[2];
|
||||
} s;
|
||||
} u;
|
||||
|
||||
u.s.u[WORD0] = 0;
|
||||
u.s.u[WORD1] = PARAM1;
|
||||
FT0 = u.d;
|
||||
RETURN();
|
||||
}
|
||||
#undef WORD0
|
||||
#undef WORD1
|
||||
|
||||
void OPPROTO op_load_fpscr_T0 (void)
|
||||
{
|
||||
T0 = (env->fpscr >> PARAM1) & 0xF;
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void OPPROTO op_load_fpcc (void)
|
||||
{
|
||||
T0 = fpscr_fpcc;
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void OPPROTO op_fpscr_resetbit (void)
|
||||
{
|
||||
env->fpscr &= PARAM1;
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void OPPROTO op_fpscr_setbit (void)
|
||||
{
|
||||
do_fpscr_setbit(PARAM1);
|
||||
RETURN();
|
||||
}
|
||||
|
||||
@ -564,12 +650,6 @@ void OPPROTO op_store_fpscr (void)
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void OPPROTO op_reset_scrfx (void)
|
||||
{
|
||||
env->fpscr[7] &= ~0x8;
|
||||
RETURN();
|
||||
}
|
||||
|
||||
/* crf operations */
|
||||
void OPPROTO op_getbit_T0 (void)
|
||||
{
|
||||
@ -1702,28 +1782,44 @@ void OPPROTO op_srli_T1_64 (void)
|
||||
/* fadd - fadd. */
|
||||
void OPPROTO op_fadd (void)
|
||||
{
|
||||
#if USE_PRECISE_EMULATION
|
||||
do_fadd();
|
||||
#else
|
||||
FT0 = float64_add(FT0, FT1, &env->fp_status);
|
||||
#endif
|
||||
RETURN();
|
||||
}
|
||||
|
||||
/* fsub - fsub. */
|
||||
void OPPROTO op_fsub (void)
|
||||
{
|
||||
#if USE_PRECISE_EMULATION
|
||||
do_fsub();
|
||||
#else
|
||||
FT0 = float64_sub(FT0, FT1, &env->fp_status);
|
||||
#endif
|
||||
RETURN();
|
||||
}
|
||||
|
||||
/* fmul - fmul. */
|
||||
void OPPROTO op_fmul (void)
|
||||
{
|
||||
#if USE_PRECISE_EMULATION
|
||||
do_fmul();
|
||||
#else
|
||||
FT0 = float64_mul(FT0, FT1, &env->fp_status);
|
||||
#endif
|
||||
RETURN();
|
||||
}
|
||||
|
||||
/* fdiv - fdiv. */
|
||||
void OPPROTO op_fdiv (void)
|
||||
{
|
||||
#if USE_PRECISE_EMULATION
|
||||
do_fdiv();
|
||||
#else
|
||||
FT0 = float64_div(FT0, FT1, &env->fp_status);
|
||||
#endif
|
||||
RETURN();
|
||||
}
|
||||
|
||||
@ -1805,7 +1901,11 @@ void OPPROTO op_fnmsub (void)
|
||||
/* frsp - frsp. */
|
||||
void OPPROTO op_frsp (void)
|
||||
{
|
||||
#if USE_PRECISE_EMULATION
|
||||
do_frsp();
|
||||
#else
|
||||
FT0 = float64_to_float32(FT0, &env->fp_status);
|
||||
#endif
|
||||
RETURN();
|
||||
}
|
||||
|
||||
|
@ -51,14 +51,6 @@ void do_raise_exception_err (uint32_t exception, int error_code)
|
||||
#if 0
|
||||
printf("Raise exception %3x code : %d\n", exception, error_code);
|
||||
#endif
|
||||
switch (exception) {
|
||||
case POWERPC_EXCP_PROGRAM:
|
||||
if (error_code == POWERPC_EXCP_FP && msr_fe0 == 0 && msr_fe1 == 0)
|
||||
return;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
env->exception_index = exception;
|
||||
env->error_code = error_code;
|
||||
cpu_loop_exit();
|
||||
@ -107,77 +99,6 @@ void do_store_pri (int prio)
|
||||
}
|
||||
#endif
|
||||
|
||||
void do_load_fpscr (void)
|
||||
{
|
||||
/* The 32 MSB of the target fpr are undefined.
|
||||
* They'll be zero...
|
||||
*/
|
||||
union {
|
||||
float64 d;
|
||||
struct {
|
||||
uint32_t u[2];
|
||||
} s;
|
||||
} u;
|
||||
int i;
|
||||
|
||||
#if defined(WORDS_BIGENDIAN)
|
||||
#define WORD0 0
|
||||
#define WORD1 1
|
||||
#else
|
||||
#define WORD0 1
|
||||
#define WORD1 0
|
||||
#endif
|
||||
u.s.u[WORD0] = 0;
|
||||
u.s.u[WORD1] = 0;
|
||||
for (i = 0; i < 8; i++)
|
||||
u.s.u[WORD1] |= env->fpscr[i] << (4 * i);
|
||||
FT0 = u.d;
|
||||
}
|
||||
|
||||
void do_store_fpscr (uint32_t mask)
|
||||
{
|
||||
/*
|
||||
* We use only the 32 LSB of the incoming fpr
|
||||
*/
|
||||
union {
|
||||
double d;
|
||||
struct {
|
||||
uint32_t u[2];
|
||||
} s;
|
||||
} u;
|
||||
int i, rnd_type;
|
||||
|
||||
u.d = FT0;
|
||||
if (mask & 0x80)
|
||||
env->fpscr[0] = (env->fpscr[0] & 0x9) | ((u.s.u[WORD1] >> 28) & ~0x9);
|
||||
for (i = 1; i < 7; i++) {
|
||||
if (mask & (1 << (7 - i)))
|
||||
env->fpscr[i] = (u.s.u[WORD1] >> (4 * (7 - i))) & 0xF;
|
||||
}
|
||||
/* TODO: update FEX & VX */
|
||||
/* Set rounding mode */
|
||||
switch (env->fpscr[0] & 0x3) {
|
||||
case 0:
|
||||
/* Best approximation (round to nearest) */
|
||||
rnd_type = float_round_nearest_even;
|
||||
break;
|
||||
case 1:
|
||||
/* Smaller magnitude (round toward zero) */
|
||||
rnd_type = float_round_to_zero;
|
||||
break;
|
||||
case 2:
|
||||
/* Round toward +infinite */
|
||||
rnd_type = float_round_up;
|
||||
break;
|
||||
default:
|
||||
case 3:
|
||||
/* Round toward -infinite */
|
||||
rnd_type = float_round_down;
|
||||
break;
|
||||
}
|
||||
set_float_rounding_mode(rnd_type, &env->fp_status);
|
||||
}
|
||||
|
||||
target_ulong ppc_load_dump_spr (int sprn)
|
||||
{
|
||||
if (loglevel != 0) {
|
||||
@ -553,6 +474,538 @@ void do_popcntb_64 (void)
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Floating point operations helpers */
|
||||
static inline int fpisneg (float64 f)
|
||||
{
|
||||
union {
|
||||
float64 f;
|
||||
uint64_t u;
|
||||
} u;
|
||||
|
||||
u.f = f;
|
||||
|
||||
return u.u >> 63 != 0;
|
||||
}
|
||||
|
||||
static inline int isden (float f)
|
||||
{
|
||||
union {
|
||||
float64 f;
|
||||
uint64_t u;
|
||||
} u;
|
||||
|
||||
u.f = f;
|
||||
|
||||
return ((u.u >> 52) & 0x7FF) == 0;
|
||||
}
|
||||
|
||||
static inline int iszero (float64 f)
|
||||
{
|
||||
union {
|
||||
float64 f;
|
||||
uint64_t u;
|
||||
} u;
|
||||
|
||||
u.f = f;
|
||||
|
||||
return (u.u & ~0x8000000000000000ULL) == 0;
|
||||
}
|
||||
|
||||
static inline int isinfinity (float64 f)
|
||||
{
|
||||
union {
|
||||
float64 f;
|
||||
uint64_t u;
|
||||
} u;
|
||||
|
||||
u.f = f;
|
||||
|
||||
return ((u.u >> 51) & 0x3FF) == 0x3FF &&
|
||||
(u.u & 0x000FFFFFFFFFFFFFULL) == 0;
|
||||
}
|
||||
|
||||
void do_compute_fprf (int set_fprf)
|
||||
{
|
||||
int isneg;
|
||||
|
||||
isneg = fpisneg(FT0);
|
||||
if (unlikely(float64_is_nan(FT0))) {
|
||||
if (float64_is_signaling_nan(FT0)) {
|
||||
/* Signaling NaN: flags are undefined */
|
||||
T0 = 0x00;
|
||||
} else {
|
||||
/* Quiet NaN */
|
||||
T0 = 0x11;
|
||||
}
|
||||
} else if (unlikely(isinfinity(FT0))) {
|
||||
/* +/- infinity */
|
||||
if (isneg)
|
||||
T0 = 0x09;
|
||||
else
|
||||
T0 = 0x05;
|
||||
} else {
|
||||
if (iszero(FT0)) {
|
||||
/* +/- zero */
|
||||
if (isneg)
|
||||
T0 = 0x12;
|
||||
else
|
||||
T0 = 0x02;
|
||||
} else {
|
||||
if (isden(FT0)) {
|
||||
/* Denormalized numbers */
|
||||
T0 = 0x10;
|
||||
} else {
|
||||
/* Normalized numbers */
|
||||
T0 = 0x00;
|
||||
}
|
||||
if (isneg) {
|
||||
T0 |= 0x08;
|
||||
} else {
|
||||
T0 |= 0x04;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (set_fprf) {
|
||||
/* We update FPSCR_FPRF */
|
||||
env->fpscr &= ~(0x1F << FPSCR_FPRF);
|
||||
env->fpscr |= T0 << FPSCR_FPRF;
|
||||
}
|
||||
/* We just need fpcc to update Rc1 */
|
||||
T0 &= 0xF;
|
||||
}
|
||||
|
||||
/* Floating-point invalid operations exception */
|
||||
static always_inline void fload_invalid_op_excp (int op)
|
||||
{
|
||||
int ve;
|
||||
|
||||
ve = fpscr_ve;
|
||||
if (op & POWERPC_EXCP_FP_VXSNAN) {
|
||||
/* Operation on signaling NaN */
|
||||
env->fpscr |= 1 << FPSCR_VXSNAN;
|
||||
}
|
||||
if (op & POWERPC_EXCP_FP_VXSOFT) {
|
||||
/* Software-defined condition */
|
||||
env->fpscr |= 1 << FPSCR_VXSOFT;
|
||||
}
|
||||
switch (op & ~(POWERPC_EXCP_FP_VXSOFT | POWERPC_EXCP_FP_VXSNAN)) {
|
||||
case POWERPC_EXCP_FP_VXISI:
|
||||
/* Magnitude subtraction of infinities */
|
||||
env->fpscr |= 1 << FPSCR_VXISI;
|
||||
goto update_arith;
|
||||
case POWERPC_EXCP_FP_VXIDI:
|
||||
/* Division of infinity by infinity */
|
||||
env->fpscr |= 1 << FPSCR_VXIDI;
|
||||
goto update_arith;
|
||||
case POWERPC_EXCP_FP_VXZDZ:
|
||||
/* Division of zero by zero */
|
||||
env->fpscr |= 1 << FPSCR_VXZDZ;
|
||||
goto update_arith;
|
||||
case POWERPC_EXCP_FP_VXIMZ:
|
||||
/* Multiplication of zero by infinity */
|
||||
env->fpscr |= 1 << FPSCR_VXIMZ;
|
||||
goto update_arith;
|
||||
case POWERPC_EXCP_FP_VXVC:
|
||||
/* Ordered comparison of NaN */
|
||||
env->fpscr |= 1 << FPSCR_VXVC;
|
||||
env->fpscr &= ~(0xF << FPSCR_FPCC);
|
||||
env->fpscr |= 0x11 << FPSCR_FPCC;
|
||||
/* We must update the target FPR before raising the exception */
|
||||
if (ve != 0) {
|
||||
env->exception_index = POWERPC_EXCP_PROGRAM;
|
||||
env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_VXVC;
|
||||
/* Update the floating-point enabled exception summary */
|
||||
env->fpscr |= 1 << FPSCR_FEX;
|
||||
/* Exception is differed */
|
||||
ve = 0;
|
||||
}
|
||||
break;
|
||||
case POWERPC_EXCP_FP_VXSQRT:
|
||||
/* Square root of a negative number */
|
||||
env->fpscr |= 1 << FPSCR_VXSQRT;
|
||||
update_arith:
|
||||
env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
|
||||
if (ve == 0) {
|
||||
/* Set the result to quiet NaN */
|
||||
FT0 = (uint64_t)-1;
|
||||
env->fpscr &= ~(0xF << FPSCR_FPCC);
|
||||
env->fpscr |= 0x11 << FPSCR_FPCC;
|
||||
}
|
||||
break;
|
||||
case POWERPC_EXCP_FP_VXCVI:
|
||||
/* Invalid conversion */
|
||||
env->fpscr |= 1 << FPSCR_VXCVI;
|
||||
env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
|
||||
if (ve == 0) {
|
||||
/* Set the result to quiet NaN */
|
||||
FT0 = (uint64_t)-1;
|
||||
env->fpscr &= ~(0xF << FPSCR_FPCC);
|
||||
env->fpscr |= 0x11 << FPSCR_FPCC;
|
||||
}
|
||||
break;
|
||||
}
|
||||
/* Update the floating-point invalid operation summary */
|
||||
env->fpscr |= 1 << FPSCR_VX;
|
||||
/* Update the floating-point exception summary */
|
||||
env->fpscr |= 1 << FPSCR_FX;
|
||||
if (ve != 0) {
|
||||
/* Update the floating-point enabled exception summary */
|
||||
env->fpscr |= 1 << FPSCR_FEX;
|
||||
if (msr_fe0 != 0 || msr_fe1 != 0)
|
||||
do_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_FP | op);
|
||||
}
|
||||
}
|
||||
|
||||
static always_inline void float_zero_divide_excp (void)
|
||||
{
|
||||
union {
|
||||
float64 f;
|
||||
uint64_t u;
|
||||
} u0, u1;
|
||||
|
||||
|
||||
env->fpscr |= 1 << FPSCR_ZX;
|
||||
env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
|
||||
/* Update the floating-point exception summary */
|
||||
env->fpscr |= 1 << FPSCR_FX;
|
||||
if (fpscr_ze != 0) {
|
||||
/* Update the floating-point enabled exception summary */
|
||||
env->fpscr |= 1 << FPSCR_FEX;
|
||||
if (msr_fe0 != 0 || msr_fe1 != 0) {
|
||||
do_raise_exception_err(POWERPC_EXCP_PROGRAM,
|
||||
POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX);
|
||||
}
|
||||
} else {
|
||||
/* Set the result to infinity */
|
||||
u0.f = FT0;
|
||||
u1.f = FT1;
|
||||
u0.u = ((u0.u ^ u1.u) & 0x8000000000000000ULL);
|
||||
u0.u |= 0x3FFULL << 51;
|
||||
FT0 = u0.f;
|
||||
}
|
||||
}
|
||||
|
||||
static always_inline void float_overflow_excp (void)
|
||||
{
|
||||
env->fpscr |= 1 << FPSCR_OX;
|
||||
/* Update the floating-point exception summary */
|
||||
env->fpscr |= 1 << FPSCR_FX;
|
||||
if (fpscr_oe != 0) {
|
||||
/* XXX: should adjust the result */
|
||||
/* Update the floating-point enabled exception summary */
|
||||
env->fpscr |= 1 << FPSCR_FEX;
|
||||
/* We must update the target FPR before raising the exception */
|
||||
env->exception_index = POWERPC_EXCP_PROGRAM;
|
||||
env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_OX;
|
||||
} else {
|
||||
env->fpscr |= 1 << FPSCR_XX;
|
||||
env->fpscr |= 1 << FPSCR_FI;
|
||||
}
|
||||
}
|
||||
|
||||
static always_inline void float_underflow_excp (void)
|
||||
{
|
||||
env->fpscr |= 1 << FPSCR_UX;
|
||||
/* Update the floating-point exception summary */
|
||||
env->fpscr |= 1 << FPSCR_FX;
|
||||
if (fpscr_ue != 0) {
|
||||
/* XXX: should adjust the result */
|
||||
/* Update the floating-point enabled exception summary */
|
||||
env->fpscr |= 1 << FPSCR_FEX;
|
||||
/* We must update the target FPR before raising the exception */
|
||||
env->exception_index = POWERPC_EXCP_PROGRAM;
|
||||
env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_UX;
|
||||
}
|
||||
}
|
||||
|
||||
static always_inline void float_inexact_excp (void)
|
||||
{
|
||||
env->fpscr |= 1 << FPSCR_XX;
|
||||
/* Update the floating-point exception summary */
|
||||
env->fpscr |= 1 << FPSCR_FX;
|
||||
if (fpscr_xe != 0) {
|
||||
/* Update the floating-point enabled exception summary */
|
||||
env->fpscr |= 1 << FPSCR_FEX;
|
||||
/* We must update the target FPR before raising the exception */
|
||||
env->exception_index = POWERPC_EXCP_PROGRAM;
|
||||
env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_XX;
|
||||
}
|
||||
}
|
||||
|
||||
static always_inline void fpscr_set_rounding_mode (void)
|
||||
{
|
||||
int rnd_type;
|
||||
|
||||
/* Set rounding mode */
|
||||
switch (fpscr_rn) {
|
||||
case 0:
|
||||
/* Best approximation (round to nearest) */
|
||||
rnd_type = float_round_nearest_even;
|
||||
break;
|
||||
case 1:
|
||||
/* Smaller magnitude (round toward zero) */
|
||||
rnd_type = float_round_to_zero;
|
||||
break;
|
||||
case 2:
|
||||
/* Round toward +infinite */
|
||||
rnd_type = float_round_up;
|
||||
break;
|
||||
default:
|
||||
case 3:
|
||||
/* Round toward -infinite */
|
||||
rnd_type = float_round_down;
|
||||
break;
|
||||
}
|
||||
set_float_rounding_mode(rnd_type, &env->fp_status);
|
||||
}
|
||||
|
||||
void do_fpscr_setbit (int bit)
|
||||
{
|
||||
int prev;
|
||||
|
||||
prev = (env->fpscr >> bit) & 1;
|
||||
env->fpscr |= 1 << bit;
|
||||
if (prev == 0) {
|
||||
switch (bit) {
|
||||
case FPSCR_VX:
|
||||
env->fpscr |= 1 << FPSCR_FX;
|
||||
if (fpscr_ve)
|
||||
goto raise_ve;
|
||||
case FPSCR_OX:
|
||||
env->fpscr |= 1 << FPSCR_FX;
|
||||
if (fpscr_oe)
|
||||
goto raise_oe;
|
||||
break;
|
||||
case FPSCR_UX:
|
||||
env->fpscr |= 1 << FPSCR_FX;
|
||||
if (fpscr_ue)
|
||||
goto raise_ue;
|
||||
break;
|
||||
case FPSCR_ZX:
|
||||
env->fpscr |= 1 << FPSCR_FX;
|
||||
if (fpscr_ze)
|
||||
goto raise_ze;
|
||||
break;
|
||||
case FPSCR_XX:
|
||||
env->fpscr |= 1 << FPSCR_FX;
|
||||
if (fpscr_xe)
|
||||
goto raise_xe;
|
||||
break;
|
||||
case FPSCR_VXSNAN:
|
||||
case FPSCR_VXISI:
|
||||
case FPSCR_VXIDI:
|
||||
case FPSCR_VXZDZ:
|
||||
case FPSCR_VXIMZ:
|
||||
case FPSCR_VXVC:
|
||||
case FPSCR_VXSOFT:
|
||||
case FPSCR_VXSQRT:
|
||||
case FPSCR_VXCVI:
|
||||
env->fpscr |= 1 << FPSCR_VX;
|
||||
env->fpscr |= 1 << FPSCR_FX;
|
||||
if (fpscr_ve != 0)
|
||||
goto raise_ve;
|
||||
break;
|
||||
case FPSCR_VE:
|
||||
if (fpscr_vx != 0) {
|
||||
raise_ve:
|
||||
env->error_code = POWERPC_EXCP_FP;
|
||||
if (fpscr_vxsnan)
|
||||
env->error_code |= POWERPC_EXCP_FP_VXSNAN;
|
||||
if (fpscr_vxisi)
|
||||
env->error_code |= POWERPC_EXCP_FP_VXISI;
|
||||
if (fpscr_vxidi)
|
||||
env->error_code |= POWERPC_EXCP_FP_VXIDI;
|
||||
if (fpscr_vxzdz)
|
||||
env->error_code |= POWERPC_EXCP_FP_VXZDZ;
|
||||
if (fpscr_vximz)
|
||||
env->error_code |= POWERPC_EXCP_FP_VXIMZ;
|
||||
if (fpscr_vxvc)
|
||||
env->error_code |= POWERPC_EXCP_FP_VXVC;
|
||||
if (fpscr_vxsoft)
|
||||
env->error_code |= POWERPC_EXCP_FP_VXSOFT;
|
||||
if (fpscr_vxsqrt)
|
||||
env->error_code |= POWERPC_EXCP_FP_VXSQRT;
|
||||
if (fpscr_vxcvi)
|
||||
env->error_code |= POWERPC_EXCP_FP_VXCVI;
|
||||
goto raise_excp;
|
||||
}
|
||||
break;
|
||||
case FPSCR_OE:
|
||||
if (fpscr_ox != 0) {
|
||||
raise_oe:
|
||||
env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_OX;
|
||||
goto raise_excp;
|
||||
}
|
||||
break;
|
||||
case FPSCR_UE:
|
||||
if (fpscr_ux != 0) {
|
||||
raise_ue:
|
||||
env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_UX;
|
||||
goto raise_excp;
|
||||
}
|
||||
break;
|
||||
case FPSCR_ZE:
|
||||
if (fpscr_zx != 0) {
|
||||
raise_ze:
|
||||
env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX;
|
||||
goto raise_excp;
|
||||
}
|
||||
break;
|
||||
case FPSCR_XE:
|
||||
if (fpscr_xx != 0) {
|
||||
raise_xe:
|
||||
env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_XX;
|
||||
goto raise_excp;
|
||||
}
|
||||
break;
|
||||
case FPSCR_RN1:
|
||||
case FPSCR_RN:
|
||||
fpscr_set_rounding_mode();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
raise_excp:
|
||||
/* Update the floating-point enabled exception summary */
|
||||
env->fpscr |= 1 << FPSCR_FEX;
|
||||
/* We have to update Rc1 before raising the exception */
|
||||
env->exception_index = POWERPC_EXCP_PROGRAM;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(WORDS_BIGENDIAN)
|
||||
#define WORD0 0
|
||||
#define WORD1 1
|
||||
#else
|
||||
#define WORD0 1
|
||||
#define WORD1 0
|
||||
#endif
|
||||
void do_store_fpscr (uint32_t mask)
|
||||
{
|
||||
/*
|
||||
* We use only the 32 LSB of the incoming fpr
|
||||
*/
|
||||
union {
|
||||
double d;
|
||||
struct {
|
||||
uint32_t u[2];
|
||||
} s;
|
||||
} u;
|
||||
uint32_t prev, new;
|
||||
int i;
|
||||
|
||||
u.d = FT0;
|
||||
prev = env->fpscr;
|
||||
new = u.s.u[WORD1];
|
||||
new &= ~0x90000000;
|
||||
new |= prev & 0x90000000;
|
||||
for (i = 0; i < 7; i++) {
|
||||
if (mask & (1 << i)) {
|
||||
env->fpscr &= ~(0xF << (4 * i));
|
||||
env->fpscr |= new & (0xF << (4 * i));
|
||||
}
|
||||
}
|
||||
/* Update VX and FEX */
|
||||
if (fpscr_ix != 0)
|
||||
env->fpscr |= 1 << FPSCR_VX;
|
||||
if ((fpscr_ex & fpscr_eex) != 0) {
|
||||
env->fpscr |= 1 << FPSCR_FEX;
|
||||
env->exception_index = POWERPC_EXCP_PROGRAM;
|
||||
/* XXX: we should compute it properly */
|
||||
env->error_code = POWERPC_EXCP_FP;
|
||||
}
|
||||
fpscr_set_rounding_mode();
|
||||
}
|
||||
#undef WORD0
|
||||
#undef WORD1
|
||||
|
||||
#ifdef CONFIG_SOFTFLOAT
|
||||
void do_float_check_status (void)
|
||||
{
|
||||
if (env->exception_index == POWERPC_EXCP_PROGRAM &&
|
||||
(env->error_code & POWERPC_EXCP_FP)) {
|
||||
/* Differred floating-point exception after target FPR update */
|
||||
if (msr_fe0 != 0 || msr_fe1 != 0)
|
||||
do_raise_exception_err(env->exception_index, env->error_code);
|
||||
} else if (env->fp_status.float_exception_flags & float_flag_overflow) {
|
||||
float_overflow_excp();
|
||||
} else if (env->fp_status.float_exception_flags & float_flag_underflow) {
|
||||
float_underflow_excp();
|
||||
} else if (env->fp_status.float_exception_flags & float_flag_inexact) {
|
||||
float_inexact_excp();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if USE_PRECISE_EMULATION
|
||||
void do_fadd (void)
|
||||
{
|
||||
if (unlikely(float64_is_signaling_nan(FT0) ||
|
||||
float64_is_signaling_nan(FT1))) {
|
||||
/* sNaN addition */
|
||||
fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
|
||||
} else if (likely(isfinite(FT0) || isfinite(FT1) ||
|
||||
fpisneg(FT0) == fpisneg(FT1))) {
|
||||
FT0 = float64_add(FT0, FT1, &env->fp_status);
|
||||
} else {
|
||||
/* Magnitude subtraction of infinities */
|
||||
fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
|
||||
}
|
||||
}
|
||||
|
||||
void do_fsub (void)
|
||||
{
|
||||
if (unlikely(float64_is_signaling_nan(FT0) ||
|
||||
float64_is_signaling_nan(FT1))) {
|
||||
/* sNaN subtraction */
|
||||
fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
|
||||
} else if (likely(isfinite(FT0) || isfinite(FT1) ||
|
||||
fpisneg(FT0) != fpisneg(FT1))) {
|
||||
FT0 = float64_sub(FT0, FT1, &env->fp_status);
|
||||
} else {
|
||||
/* Magnitude subtraction of infinities */
|
||||
fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
|
||||
}
|
||||
}
|
||||
|
||||
void do_fmul (void)
|
||||
{
|
||||
if (unlikely(float64_is_signaling_nan(FT0) ||
|
||||
float64_is_signaling_nan(FT1))) {
|
||||
/* sNaN multiplication */
|
||||
fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
|
||||
} else if (unlikely((ifinf(FT0) && iszero(FT1)) ||
|
||||
(inzero(FT0) && isinfinity(FT1)))) {
|
||||
/* Multiplication of zero by infinity */
|
||||
fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
|
||||
} else {
|
||||
FT0 = float64_mul(FT0, FT1, &env->fp_status);
|
||||
}
|
||||
}
|
||||
|
||||
void do_fdiv (void)
|
||||
{
|
||||
if (unlikely(float64_is_signaling_nan(FT0) ||
|
||||
float64_is_signaling_nan(FT1))) {
|
||||
/* sNaN division */
|
||||
fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
|
||||
} else if (unlikely(isinfinity(FT0) && isinfinity(FT1))) {
|
||||
/* Division of infinity by infinity */
|
||||
fload_invalid_op_excp(POWERPC_EXCP_FP_VXIDI);
|
||||
} else if (unlikely(iszero(FT1))) {
|
||||
if (iszero(FT0)) {
|
||||
/* Division of zero by zero */
|
||||
fload_invalid_op_excp(POWERPC_EXCP_FP_VXZDZ);
|
||||
} else {
|
||||
/* Division by zero */
|
||||
float_zero_divide_excp();
|
||||
}
|
||||
} else {
|
||||
FT0 = float64_div(FT0, FT1, &env->fp_status);
|
||||
}
|
||||
}
|
||||
#endif /* USE_PRECISE_EMULATION */
|
||||
|
||||
void do_fctiw (void)
|
||||
{
|
||||
union {
|
||||
@ -560,14 +1013,22 @@ void do_fctiw (void)
|
||||
uint64_t i;
|
||||
} p;
|
||||
|
||||
if (unlikely(float64_is_signaling_nan(FT0))) {
|
||||
/* sNaN conversion */
|
||||
fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
|
||||
} else if (unlikely(float64_is_nan(FT0) || isinfinity(FT0))) {
|
||||
/* qNan / infinity conversion */
|
||||
fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
|
||||
} else {
|
||||
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)
|
||||
* to make tests easier, return the same as a real PowerPC 750
|
||||
*/
|
||||
p.i |= 0xFFF80000ULL << 32;
|
||||
#endif
|
||||
FT0 = p.d;
|
||||
}
|
||||
}
|
||||
|
||||
void do_fctiwz (void)
|
||||
@ -577,14 +1038,22 @@ void do_fctiwz (void)
|
||||
uint64_t i;
|
||||
} p;
|
||||
|
||||
if (unlikely(float64_is_signaling_nan(FT0))) {
|
||||
/* sNaN conversion */
|
||||
fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
|
||||
} else if (unlikely(float64_is_nan(FT0) || isinfinity(FT0))) {
|
||||
/* qNan / infinity conversion */
|
||||
fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
|
||||
} else {
|
||||
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)
|
||||
* to make tests easier, return the same as a real PowerPC 750
|
||||
*/
|
||||
p.i |= 0xFFF80000ULL << 32;
|
||||
#endif
|
||||
FT0 = p.d;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(TARGET_PPC64)
|
||||
@ -606,8 +1075,16 @@ void do_fctid (void)
|
||||
uint64_t i;
|
||||
} p;
|
||||
|
||||
if (unlikely(float64_is_signaling_nan(FT0))) {
|
||||
/* sNaN conversion */
|
||||
fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
|
||||
} else if (unlikely(float64_is_nan(FT0) || isinfinity(FT0))) {
|
||||
/* qNan / infinity conversion */
|
||||
fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
|
||||
} else {
|
||||
p.i = float64_to_int64(FT0, &env->fp_status);
|
||||
FT0 = p.d;
|
||||
}
|
||||
}
|
||||
|
||||
void do_fctidz (void)
|
||||
@ -617,20 +1094,34 @@ void do_fctidz (void)
|
||||
uint64_t i;
|
||||
} p;
|
||||
|
||||
if (unlikely(float64_is_signaling_nan(FT0))) {
|
||||
/* sNaN conversion */
|
||||
fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
|
||||
} else if (unlikely(float64_is_nan(FT0) || isinfinity(FT0))) {
|
||||
/* qNan / infinity conversion */
|
||||
fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
|
||||
} else {
|
||||
p.i = float64_to_int64_round_to_zero(FT0, &env->fp_status);
|
||||
FT0 = p.d;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static always_inline void do_fri (int rounding_mode)
|
||||
{
|
||||
int curmode;
|
||||
|
||||
curmode = env->fp_status.float_rounding_mode;
|
||||
if (unlikely(float64_is_signaling_nan(FT0))) {
|
||||
/* sNaN round */
|
||||
fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
|
||||
} else if (unlikely(float64_is_nan(FT0) || isinfinity(FT0))) {
|
||||
/* qNan / infinity round */
|
||||
fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
|
||||
} else {
|
||||
set_float_rounding_mode(rounding_mode, &env->fp_status);
|
||||
FT0 = float64_round_to_int(FT0, &env->fp_status);
|
||||
set_float_rounding_mode(curmode, &env->fp_status);
|
||||
/* Restore rounding mode from FPSCR */
|
||||
fpscr_set_rounding_mode();
|
||||
}
|
||||
}
|
||||
|
||||
void do_frin (void)
|
||||
@ -656,7 +1147,14 @@ void do_frim (void)
|
||||
#if USE_PRECISE_EMULATION
|
||||
void do_fmadd (void)
|
||||
{
|
||||
if (unlikely(float64_is_signaling_nan(FT0) ||
|
||||
float64_is_signaling_nan(FT1) ||
|
||||
float64_is_signaling_nan(FT2))) {
|
||||
/* sNaN operation */
|
||||
fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
|
||||
} else {
|
||||
#ifdef FLOAT128
|
||||
/* This is the way the PowerPC specification defines it */
|
||||
float128 ft0_128, ft1_128;
|
||||
|
||||
ft0_128 = float64_to_float128(FT0, &env->fp_status);
|
||||
@ -669,11 +1167,19 @@ void do_fmadd (void)
|
||||
/* This is OK on x86 hosts */
|
||||
FT0 = (FT0 * FT1) + FT2;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void do_fmsub (void)
|
||||
{
|
||||
if (unlikely(float64_is_signaling_nan(FT0) ||
|
||||
float64_is_signaling_nan(FT1) ||
|
||||
float64_is_signaling_nan(FT2))) {
|
||||
/* sNaN operation */
|
||||
fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
|
||||
} else {
|
||||
#ifdef FLOAT128
|
||||
/* This is the way the PowerPC specification defines it */
|
||||
float128 ft0_128, ft1_128;
|
||||
|
||||
ft0_128 = float64_to_float128(FT0, &env->fp_status);
|
||||
@ -686,13 +1192,21 @@ void do_fmsub (void)
|
||||
/* This is OK on x86 hosts */
|
||||
FT0 = (FT0 * FT1) - FT2;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif /* USE_PRECISE_EMULATION */
|
||||
|
||||
void do_fnmadd (void)
|
||||
{
|
||||
if (unlikely(float64_is_signaling_nan(FT0) ||
|
||||
float64_is_signaling_nan(FT1) ||
|
||||
float64_is_signaling_nan(FT2))) {
|
||||
/* sNaN operation */
|
||||
fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
|
||||
} else {
|
||||
#if USE_PRECISE_EMULATION
|
||||
#ifdef FLOAT128
|
||||
/* This is the way the PowerPC specification defines it */
|
||||
float128 ft0_128, ft1_128;
|
||||
|
||||
ft0_128 = float64_to_float128(FT0, &env->fp_status);
|
||||
@ -711,12 +1225,20 @@ void do_fnmadd (void)
|
||||
#endif
|
||||
if (likely(!isnan(FT0)))
|
||||
FT0 = float64_chs(FT0);
|
||||
}
|
||||
}
|
||||
|
||||
void do_fnmsub (void)
|
||||
{
|
||||
if (unlikely(float64_is_signaling_nan(FT0) ||
|
||||
float64_is_signaling_nan(FT1) ||
|
||||
float64_is_signaling_nan(FT2))) {
|
||||
/* sNaN operation */
|
||||
fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
|
||||
} else {
|
||||
#if USE_PRECISE_EMULATION
|
||||
#ifdef FLOAT128
|
||||
/* This is the way the PowerPC specification defines it */
|
||||
float128 ft0_128, ft1_128;
|
||||
|
||||
ft0_128 = float64_to_float128(FT0, &env->fp_status);
|
||||
@ -735,11 +1257,32 @@ void do_fnmsub (void)
|
||||
#endif
|
||||
if (likely(!isnan(FT0)))
|
||||
FT0 = float64_chs(FT0);
|
||||
}
|
||||
}
|
||||
|
||||
#if USE_PRECISE_EMULATION
|
||||
void do_frsp (void)
|
||||
{
|
||||
if (unlikely(float64_is_signaling_nan(FT0))) {
|
||||
/* sNaN square root */
|
||||
fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
|
||||
} else {
|
||||
FT0 = float64_to_float32(FT0, &env->fp_status);
|
||||
}
|
||||
}
|
||||
#endif /* USE_PRECISE_EMULATION */
|
||||
|
||||
void do_fsqrt (void)
|
||||
{
|
||||
if (unlikely(float64_is_signaling_nan(FT0))) {
|
||||
/* sNaN square root */
|
||||
fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
|
||||
} else if (unlikely(fpisneg(FT0) && !iszero(FT0))) {
|
||||
/* Square root of a negative nonzero number */
|
||||
fload_invalid_op_excp(POWERPC_EXCP_FP_VXSQRT);
|
||||
} else {
|
||||
FT0 = float64_sqrt(FT0, &env->fp_status);
|
||||
}
|
||||
}
|
||||
|
||||
void do_fre (void)
|
||||
@ -749,7 +1292,13 @@ void do_fre (void)
|
||||
uint64_t i;
|
||||
} p;
|
||||
|
||||
if (likely(isnormal(FT0))) {
|
||||
if (unlikely(float64_is_signaling_nan(FT0))) {
|
||||
/* sNaN reciprocal */
|
||||
fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
|
||||
} else if (unlikely(iszero(FT0))) {
|
||||
/* Zero reciprocal */
|
||||
float_zero_divide_excp();
|
||||
} else if (likely(isnormal(FT0))) {
|
||||
FT0 = float64_div(1.0, FT0, &env->fp_status);
|
||||
} else {
|
||||
p.d = FT0;
|
||||
@ -759,7 +1308,7 @@ void do_fre (void)
|
||||
p.i = 0x7FF0000000000000ULL;
|
||||
} else if (isnan(FT0)) {
|
||||
p.i = 0x7FF8000000000000ULL;
|
||||
} else if (FT0 < 0.0) {
|
||||
} else if (fpisneg(FT0)) {
|
||||
p.i = 0x8000000000000000ULL;
|
||||
} else {
|
||||
p.i = 0x0000000000000000ULL;
|
||||
@ -775,7 +1324,13 @@ void do_fres (void)
|
||||
uint64_t i;
|
||||
} p;
|
||||
|
||||
if (likely(isnormal(FT0))) {
|
||||
if (unlikely(float64_is_signaling_nan(FT0))) {
|
||||
/* sNaN reciprocal */
|
||||
fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
|
||||
} else if (unlikely(iszero(FT0))) {
|
||||
/* Zero reciprocal */
|
||||
float_zero_divide_excp();
|
||||
} else 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);
|
||||
@ -790,7 +1345,7 @@ void do_fres (void)
|
||||
p.i = 0x7FF0000000000000ULL;
|
||||
} else if (isnan(FT0)) {
|
||||
p.i = 0x7FF8000000000000ULL;
|
||||
} else if (FT0 < 0.0) {
|
||||
} else if (fpisneg(FT0)) {
|
||||
p.i = 0x8000000000000000ULL;
|
||||
} else {
|
||||
p.i = 0x0000000000000000ULL;
|
||||
@ -806,7 +1361,13 @@ void do_frsqrte (void)
|
||||
uint64_t i;
|
||||
} p;
|
||||
|
||||
if (likely(isnormal(FT0) && FT0 > 0.0)) {
|
||||
if (unlikely(float64_is_signaling_nan(FT0))) {
|
||||
/* sNaN reciprocal square root */
|
||||
fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
|
||||
} else if (unlikely(fpisneg(FT0) && !iszero(FT0))) {
|
||||
/* Reciprocal square root of a negative nonzero number */
|
||||
fload_invalid_op_excp(POWERPC_EXCP_FP_VXSQRT);
|
||||
} else if (likely(isnormal(FT0))) {
|
||||
FT0 = float64_sqrt(FT0, &env->fp_status);
|
||||
FT0 = float32_div(1.0, FT0, &env->fp_status);
|
||||
} else {
|
||||
@ -816,9 +1377,8 @@ void do_frsqrte (void)
|
||||
} else if (p.i == 0x0000000000000000ULL) {
|
||||
p.i = 0x7FF0000000000000ULL;
|
||||
} else if (isnan(FT0)) {
|
||||
if (!(p.i & 0x0008000000000000ULL))
|
||||
p.i |= 0x000FFFFFFFFFFFFFULL;
|
||||
} else if (FT0 < 0) {
|
||||
} else if (fpisneg(FT0)) {
|
||||
p.i = 0x7FF8000000000000ULL;
|
||||
} else {
|
||||
p.i = 0x0000000000000000ULL;
|
||||
@ -829,7 +1389,7 @@ void do_frsqrte (void)
|
||||
|
||||
void do_fsel (void)
|
||||
{
|
||||
if (FT0 >= 0)
|
||||
if (!fpisneg(FT0) || iszero(FT0))
|
||||
FT0 = FT1;
|
||||
else
|
||||
FT0 = FT2;
|
||||
@ -837,7 +1397,11 @@ void do_fsel (void)
|
||||
|
||||
void do_fcmpu (void)
|
||||
{
|
||||
if (likely(!isnan(FT0) && !isnan(FT1))) {
|
||||
if (unlikely(float64_is_signaling_nan(FT0) ||
|
||||
float64_is_signaling_nan(FT1))) {
|
||||
/* sNaN comparison */
|
||||
fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
|
||||
} else {
|
||||
if (float64_lt(FT0, FT1, &env->fp_status)) {
|
||||
T0 = 0x08UL;
|
||||
} else if (!float64_le(FT0, FT1, &env->fp_status)) {
|
||||
@ -845,18 +1409,25 @@ void do_fcmpu (void)
|
||||
} else {
|
||||
T0 = 0x02UL;
|
||||
}
|
||||
} else {
|
||||
T0 = 0x01UL;
|
||||
env->fpscr[4] |= 0x1;
|
||||
env->fpscr[6] |= 0x1;
|
||||
}
|
||||
env->fpscr[3] = T0;
|
||||
env->fpscr &= ~(0x0F << FPSCR_FPRF);
|
||||
env->fpscr |= T0 << FPSCR_FPRF;
|
||||
}
|
||||
|
||||
void do_fcmpo (void)
|
||||
{
|
||||
env->fpscr[4] &= ~0x1;
|
||||
if (likely(!isnan(FT0) && !isnan(FT1))) {
|
||||
if (unlikely(float64_is_nan(FT0) ||
|
||||
float64_is_nan(FT1))) {
|
||||
if (float64_is_signaling_nan(FT0) ||
|
||||
float64_is_signaling_nan(FT1)) {
|
||||
/* sNaN comparison */
|
||||
fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN |
|
||||
POWERPC_EXCP_FP_VXVC);
|
||||
} else {
|
||||
/* qNaN comparison */
|
||||
fload_invalid_op_excp(POWERPC_EXCP_FP_VXVC);
|
||||
}
|
||||
} else {
|
||||
if (float64_lt(FT0, FT1, &env->fp_status)) {
|
||||
T0 = 0x08UL;
|
||||
} else if (!float64_le(FT0, FT1, &env->fp_status)) {
|
||||
@ -864,19 +1435,9 @@ void do_fcmpo (void)
|
||||
} else {
|
||||
T0 = 0x02UL;
|
||||
}
|
||||
} else {
|
||||
T0 = 0x01UL;
|
||||
env->fpscr[4] |= 0x1;
|
||||
if (!float64_is_signaling_nan(FT0) || !float64_is_signaling_nan(FT1)) {
|
||||
/* Quiet NaN case */
|
||||
env->fpscr[6] |= 0x1;
|
||||
if (!(env->fpscr[1] & 0x8))
|
||||
env->fpscr[4] |= 0x8;
|
||||
} else {
|
||||
env->fpscr[4] |= 0x8;
|
||||
}
|
||||
}
|
||||
env->fpscr[3] = T0;
|
||||
env->fpscr &= ~(0x0F << FPSCR_FPRF);
|
||||
env->fpscr |= T0 << FPSCR_FPRF;
|
||||
}
|
||||
|
||||
#if !defined (CONFIG_USER_ONLY)
|
||||
|
@ -60,7 +60,7 @@ void do_store_cr (uint32_t mask);
|
||||
#if defined(TARGET_PPC64)
|
||||
void do_store_pri (int prio);
|
||||
#endif
|
||||
void do_load_fpscr (void);
|
||||
void do_fpscr_setbit (int bit);
|
||||
void do_store_fpscr (uint32_t mask);
|
||||
target_ulong ppc_load_dump_spr (int sprn);
|
||||
void ppc_store_dump_spr (int sprn, target_ulong val);
|
||||
@ -94,6 +94,16 @@ void do_popcntb_64 (void);
|
||||
#endif
|
||||
|
||||
/* Floating-point arithmetic helpers */
|
||||
void do_compute_fprf (int set_class);
|
||||
#ifdef CONFIG_SOFTFLOAT
|
||||
void do_float_check_status (void);
|
||||
#endif
|
||||
#if USE_PRECISE_EMULATION
|
||||
void do_fadd (void);
|
||||
void do_fsub (void);
|
||||
void do_fmul (void);
|
||||
void do_fdiv (void);
|
||||
#endif
|
||||
void do_fsqrt (void);
|
||||
void do_fre (void);
|
||||
void do_fres (void);
|
||||
@ -105,6 +115,9 @@ void do_fmsub (void);
|
||||
#endif
|
||||
void do_fnmadd (void);
|
||||
void do_fnmsub (void);
|
||||
#if USE_PRECISE_EMULATION
|
||||
void do_frsp (void);
|
||||
#endif
|
||||
void do_fctiw (void);
|
||||
void do_fctiwz (void);
|
||||
#if defined(TARGET_PPC64)
|
||||
|
@ -165,39 +165,6 @@ void OPPROTO glue(op_store_T1_crf_crf, REG) (void)
|
||||
RETURN();
|
||||
}
|
||||
|
||||
/* Floating point condition and status register moves */
|
||||
void OPPROTO glue(op_load_fpscr_T0_fpscr, REG) (void)
|
||||
{
|
||||
T0 = env->fpscr[REG];
|
||||
RETURN();
|
||||
}
|
||||
|
||||
#if REG == 0
|
||||
void OPPROTO glue(op_store_T0_fpscr_fpscr, REG) (void)
|
||||
{
|
||||
env->fpscr[REG] = (env->fpscr[REG] & 0x9) | (T0 & ~0x9);
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void OPPROTO glue(op_clear_fpscr_fpscr, REG) (void)
|
||||
{
|
||||
env->fpscr[REG] = (env->fpscr[REG] & 0x9);
|
||||
RETURN();
|
||||
}
|
||||
#else
|
||||
void OPPROTO glue(op_store_T0_fpscr_fpscr, REG) (void)
|
||||
{
|
||||
env->fpscr[REG] = T0;
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void OPPROTO glue(op_clear_fpscr_fpscr, REG) (void)
|
||||
{
|
||||
env->fpscr[REG] = 0x0;
|
||||
RETURN();
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* REG <= 7 */
|
||||
|
||||
/* floating point registers moves */
|
||||
|
@ -32,6 +32,7 @@
|
||||
//#define PPC_DEBUG_DISAS
|
||||
//#define DEBUG_MEMORY_ACCESSES
|
||||
//#define DO_PPC_STATISTICS
|
||||
//#define OPTIMIZE_FPRF_UPDATE
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code translation helpers */
|
||||
@ -50,6 +51,10 @@ enum {
|
||||
|
||||
static uint16_t *gen_opc_ptr;
|
||||
static uint32_t *gen_opparam_ptr;
|
||||
#if defined(OPTIMIZE_FPRF_UPDATE)
|
||||
static uint16_t *gen_fprf_buf[OPC_BUF_SIZE];
|
||||
static uint16_t **gen_fprf_ptr;
|
||||
#endif
|
||||
|
||||
#include "gen-op.h"
|
||||
|
||||
@ -117,16 +122,6 @@ GEN8(gen_op_load_crf_T1, gen_op_load_crf_T1_crf);
|
||||
GEN8(gen_op_store_T0_crf, gen_op_store_T0_crf_crf);
|
||||
GEN8(gen_op_store_T1_crf, gen_op_store_T1_crf_crf);
|
||||
|
||||
/* Floating point condition and status register moves */
|
||||
GEN8(gen_op_load_fpscr_T0, gen_op_load_fpscr_T0_fpscr);
|
||||
GEN8(gen_op_store_T0_fpscr, gen_op_store_T0_fpscr_fpscr);
|
||||
GEN8(gen_op_clear_fpscr, gen_op_clear_fpscr_fpscr);
|
||||
static always_inline void gen_op_store_T0_fpscri (int n, uint8_t param)
|
||||
{
|
||||
gen_op_set_T0(param);
|
||||
gen_op_store_T0_fpscr(n);
|
||||
}
|
||||
|
||||
/* General purpose registers moves */
|
||||
GEN32(gen_op_load_gpr_T0, gen_op_load_gpr_T0_gpr);
|
||||
GEN32(gen_op_load_gpr_T1, gen_op_load_gpr_T1_gpr);
|
||||
@ -199,6 +194,44 @@ static always_inline void gen_set_Rc0 (DisasContext *ctx)
|
||||
gen_op_set_Rc0();
|
||||
}
|
||||
|
||||
static always_inline void gen_reset_fpstatus (void)
|
||||
{
|
||||
#ifdef CONFIG_SOFTFLOAT
|
||||
gen_op_reset_fpstatus();
|
||||
#endif
|
||||
}
|
||||
|
||||
static always_inline void gen_compute_fprf (int set_fprf, int set_rc)
|
||||
{
|
||||
if (set_fprf != 0) {
|
||||
/* This case might be optimized later */
|
||||
#if defined(OPTIMIZE_FPRF_UPDATE)
|
||||
*gen_fprf_ptr++ = gen_opc_ptr;
|
||||
#endif
|
||||
gen_op_compute_fprf(1);
|
||||
if (unlikely(set_rc))
|
||||
gen_op_store_T0_crf(1);
|
||||
gen_op_float_check_status();
|
||||
} else if (unlikely(set_rc)) {
|
||||
/* We always need to compute fpcc */
|
||||
gen_op_compute_fprf(0);
|
||||
gen_op_store_T0_crf(1);
|
||||
if (set_fprf)
|
||||
gen_op_float_check_status();
|
||||
}
|
||||
}
|
||||
|
||||
static always_inline void gen_optimize_fprf (void)
|
||||
{
|
||||
#if defined(OPTIMIZE_FPRF_UPDATE)
|
||||
uint16_t **ptr;
|
||||
|
||||
for (ptr = gen_fprf_buf; ptr != (gen_fprf_ptr - 1); ptr++)
|
||||
*ptr = INDEX_op_nop1;
|
||||
gen_fprf_ptr = gen_fprf_buf;
|
||||
#endif
|
||||
}
|
||||
|
||||
static always_inline void gen_update_nip (DisasContext *ctx, target_ulong nip)
|
||||
{
|
||||
#if defined(TARGET_PPC64)
|
||||
@ -497,6 +530,8 @@ enum {
|
||||
PPC_CACHE_DCBZ = 0x0000400000000000ULL,
|
||||
/* dcbz instruction with tunable cache line size */
|
||||
PPC_CACHE_DCBZT = 0x0000800000000000ULL,
|
||||
/* frsqrtes extension */
|
||||
PPC_FLOAT_FRSQRTES = 0x0001000000000000ULL,
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
@ -1656,124 +1691,127 @@ __GEN_LOGICAL2(srd, 0x1B, 0x10, PPC_64B);
|
||||
#endif
|
||||
|
||||
/*** Floating-Point arithmetic ***/
|
||||
#define _GEN_FLOAT_ACB(name, op, op1, op2, isfloat, type) \
|
||||
#define _GEN_FLOAT_ACB(name, op, op1, op2, isfloat, set_fprf, type) \
|
||||
GEN_HANDLER(f##name, op1, op2, 0xFF, 0x00000000, type) \
|
||||
{ \
|
||||
if (unlikely(!ctx->fpu_enabled)) { \
|
||||
GEN_EXCP_NO_FP(ctx); \
|
||||
return; \
|
||||
} \
|
||||
gen_op_reset_scrfx(); \
|
||||
gen_op_load_fpr_FT0(rA(ctx->opcode)); \
|
||||
gen_op_load_fpr_FT1(rC(ctx->opcode)); \
|
||||
gen_op_load_fpr_FT2(rB(ctx->opcode)); \
|
||||
gen_reset_fpstatus(); \
|
||||
gen_op_f##op(); \
|
||||
if (isfloat) { \
|
||||
gen_op_frsp(); \
|
||||
} \
|
||||
gen_op_store_FT0_fpr(rD(ctx->opcode)); \
|
||||
if (unlikely(Rc(ctx->opcode) != 0)) \
|
||||
gen_op_set_Rc1(); \
|
||||
gen_compute_fprf(set_fprf, Rc(ctx->opcode) != 0); \
|
||||
}
|
||||
|
||||
#define GEN_FLOAT_ACB(name, op2, type) \
|
||||
_GEN_FLOAT_ACB(name, name, 0x3F, op2, 0, type); \
|
||||
_GEN_FLOAT_ACB(name##s, name, 0x3B, op2, 1, type);
|
||||
#define GEN_FLOAT_ACB(name, op2, set_fprf, type) \
|
||||
_GEN_FLOAT_ACB(name, name, 0x3F, op2, 0, set_fprf, type); \
|
||||
_GEN_FLOAT_ACB(name##s, name, 0x3B, op2, 1, set_fprf, type);
|
||||
|
||||
#define _GEN_FLOAT_AB(name, op, op1, op2, inval, isfloat) \
|
||||
GEN_HANDLER(f##name, op1, op2, 0xFF, inval, PPC_FLOAT) \
|
||||
#define _GEN_FLOAT_AB(name, op, op1, op2, inval, isfloat, set_fprf, type) \
|
||||
GEN_HANDLER(f##name, op1, op2, 0xFF, inval, type) \
|
||||
{ \
|
||||
if (unlikely(!ctx->fpu_enabled)) { \
|
||||
GEN_EXCP_NO_FP(ctx); \
|
||||
return; \
|
||||
} \
|
||||
gen_op_reset_scrfx(); \
|
||||
gen_op_load_fpr_FT0(rA(ctx->opcode)); \
|
||||
gen_op_load_fpr_FT1(rB(ctx->opcode)); \
|
||||
gen_reset_fpstatus(); \
|
||||
gen_op_f##op(); \
|
||||
if (isfloat) { \
|
||||
gen_op_frsp(); \
|
||||
} \
|
||||
gen_op_store_FT0_fpr(rD(ctx->opcode)); \
|
||||
if (unlikely(Rc(ctx->opcode) != 0)) \
|
||||
gen_op_set_Rc1(); \
|
||||
gen_compute_fprf(set_fprf, Rc(ctx->opcode) != 0); \
|
||||
}
|
||||
#define GEN_FLOAT_AB(name, op2, inval) \
|
||||
_GEN_FLOAT_AB(name, name, 0x3F, op2, inval, 0); \
|
||||
_GEN_FLOAT_AB(name##s, name, 0x3B, op2, inval, 1);
|
||||
#define GEN_FLOAT_AB(name, op2, inval, set_fprf, type) \
|
||||
_GEN_FLOAT_AB(name, name, 0x3F, op2, inval, 0, set_fprf, type); \
|
||||
_GEN_FLOAT_AB(name##s, name, 0x3B, op2, inval, 1, set_fprf, type);
|
||||
|
||||
#define _GEN_FLOAT_AC(name, op, op1, op2, inval, isfloat) \
|
||||
GEN_HANDLER(f##name, op1, op2, 0xFF, inval, PPC_FLOAT) \
|
||||
#define _GEN_FLOAT_AC(name, op, op1, op2, inval, isfloat, set_fprf, type) \
|
||||
GEN_HANDLER(f##name, op1, op2, 0xFF, inval, type) \
|
||||
{ \
|
||||
if (unlikely(!ctx->fpu_enabled)) { \
|
||||
GEN_EXCP_NO_FP(ctx); \
|
||||
return; \
|
||||
} \
|
||||
gen_op_reset_scrfx(); \
|
||||
gen_op_load_fpr_FT0(rA(ctx->opcode)); \
|
||||
gen_op_load_fpr_FT1(rC(ctx->opcode)); \
|
||||
gen_reset_fpstatus(); \
|
||||
gen_op_f##op(); \
|
||||
if (isfloat) { \
|
||||
gen_op_frsp(); \
|
||||
} \
|
||||
gen_op_store_FT0_fpr(rD(ctx->opcode)); \
|
||||
if (unlikely(Rc(ctx->opcode) != 0)) \
|
||||
gen_op_set_Rc1(); \
|
||||
gen_compute_fprf(set_fprf, Rc(ctx->opcode) != 0); \
|
||||
}
|
||||
#define GEN_FLOAT_AC(name, op2, inval) \
|
||||
_GEN_FLOAT_AC(name, name, 0x3F, op2, inval, 0); \
|
||||
_GEN_FLOAT_AC(name##s, name, 0x3B, op2, inval, 1);
|
||||
#define GEN_FLOAT_AC(name, op2, inval, set_fprf, type) \
|
||||
_GEN_FLOAT_AC(name, name, 0x3F, op2, inval, 0, set_fprf, type); \
|
||||
_GEN_FLOAT_AC(name##s, name, 0x3B, op2, inval, 1, set_fprf, type);
|
||||
|
||||
#define GEN_FLOAT_B(name, op2, op3, type) \
|
||||
#define GEN_FLOAT_B(name, op2, op3, set_fprf, type) \
|
||||
GEN_HANDLER(f##name, 0x3F, op2, op3, 0x001F0000, type) \
|
||||
{ \
|
||||
if (unlikely(!ctx->fpu_enabled)) { \
|
||||
GEN_EXCP_NO_FP(ctx); \
|
||||
return; \
|
||||
} \
|
||||
gen_op_reset_scrfx(); \
|
||||
gen_op_load_fpr_FT0(rB(ctx->opcode)); \
|
||||
gen_reset_fpstatus(); \
|
||||
gen_op_f##name(); \
|
||||
gen_op_store_FT0_fpr(rD(ctx->opcode)); \
|
||||
if (unlikely(Rc(ctx->opcode) != 0)) \
|
||||
gen_op_set_Rc1(); \
|
||||
gen_compute_fprf(set_fprf, Rc(ctx->opcode) != 0); \
|
||||
}
|
||||
|
||||
#define GEN_FLOAT_BS(name, op1, op2, type) \
|
||||
#define GEN_FLOAT_BS(name, op1, op2, set_fprf, type) \
|
||||
GEN_HANDLER(f##name, op1, op2, 0xFF, 0x001F07C0, type) \
|
||||
{ \
|
||||
if (unlikely(!ctx->fpu_enabled)) { \
|
||||
GEN_EXCP_NO_FP(ctx); \
|
||||
return; \
|
||||
} \
|
||||
gen_op_reset_scrfx(); \
|
||||
gen_op_load_fpr_FT0(rB(ctx->opcode)); \
|
||||
gen_reset_fpstatus(); \
|
||||
gen_op_f##name(); \
|
||||
gen_op_store_FT0_fpr(rD(ctx->opcode)); \
|
||||
if (unlikely(Rc(ctx->opcode) != 0)) \
|
||||
gen_op_set_Rc1(); \
|
||||
gen_compute_fprf(set_fprf, Rc(ctx->opcode) != 0); \
|
||||
}
|
||||
|
||||
/* fadd - fadds */
|
||||
GEN_FLOAT_AB(add, 0x15, 0x000007C0);
|
||||
GEN_FLOAT_AB(add, 0x15, 0x000007C0, 1, PPC_FLOAT);
|
||||
/* fdiv - fdivs */
|
||||
GEN_FLOAT_AB(div, 0x12, 0x000007C0);
|
||||
GEN_FLOAT_AB(div, 0x12, 0x000007C0, 1, PPC_FLOAT);
|
||||
/* fmul - fmuls */
|
||||
GEN_FLOAT_AC(mul, 0x19, 0x0000F800);
|
||||
GEN_FLOAT_AC(mul, 0x19, 0x0000F800, 1, PPC_FLOAT);
|
||||
|
||||
/* fre */
|
||||
GEN_FLOAT_BS(re, 0x3F, 0x18, PPC_FLOAT_EXT);
|
||||
GEN_FLOAT_BS(re, 0x3F, 0x18, 1, PPC_FLOAT_EXT);
|
||||
|
||||
/* fres */
|
||||
GEN_FLOAT_BS(res, 0x3B, 0x18, PPC_FLOAT_FRES);
|
||||
GEN_FLOAT_BS(res, 0x3B, 0x18, 1, PPC_FLOAT_FRES);
|
||||
|
||||
/* frsqrte */
|
||||
GEN_FLOAT_BS(rsqrte, 0x3F, 0x1A, PPC_FLOAT_FRSQRTE);
|
||||
GEN_FLOAT_BS(rsqrte, 0x3F, 0x1A, 1, PPC_FLOAT_FRSQRTE);
|
||||
|
||||
/* frsqrtes */
|
||||
static always_inline void gen_op_frsqrtes (void)
|
||||
{
|
||||
gen_op_frsqrte();
|
||||
gen_op_frsp();
|
||||
}
|
||||
GEN_FLOAT_BS(rsqrtes, 0x3F, 0x1A, 1, PPC_FLOAT_FRSQRTES);
|
||||
|
||||
/* fsel */
|
||||
_GEN_FLOAT_ACB(sel, sel, 0x3F, 0x17, 0, PPC_FLOAT_FSEL);
|
||||
_GEN_FLOAT_ACB(sel, sel, 0x3F, 0x17, 0, 0, PPC_FLOAT_FSEL);
|
||||
/* fsub - fsubs */
|
||||
GEN_FLOAT_AB(sub, 0x14, 0x000007C0);
|
||||
GEN_FLOAT_AB(sub, 0x14, 0x000007C0, 1, PPC_FLOAT);
|
||||
/* Optional: */
|
||||
/* fsqrt */
|
||||
GEN_HANDLER(fsqrt, 0x3F, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_FSQRT)
|
||||
@ -1782,12 +1820,11 @@ GEN_HANDLER(fsqrt, 0x3F, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_FSQRT)
|
||||
GEN_EXCP_NO_FP(ctx);
|
||||
return;
|
||||
}
|
||||
gen_op_reset_scrfx();
|
||||
gen_op_load_fpr_FT0(rB(ctx->opcode));
|
||||
gen_reset_fpstatus();
|
||||
gen_op_fsqrt();
|
||||
gen_op_store_FT0_fpr(rD(ctx->opcode));
|
||||
if (unlikely(Rc(ctx->opcode) != 0))
|
||||
gen_op_set_Rc1();
|
||||
gen_compute_fprf(1, Rc(ctx->opcode) != 0);
|
||||
}
|
||||
|
||||
GEN_HANDLER(fsqrts, 0x3B, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_FSQRT)
|
||||
@ -1796,49 +1833,48 @@ GEN_HANDLER(fsqrts, 0x3B, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_FSQRT)
|
||||
GEN_EXCP_NO_FP(ctx);
|
||||
return;
|
||||
}
|
||||
gen_op_reset_scrfx();
|
||||
gen_op_load_fpr_FT0(rB(ctx->opcode));
|
||||
gen_reset_fpstatus();
|
||||
gen_op_fsqrt();
|
||||
gen_op_frsp();
|
||||
gen_op_store_FT0_fpr(rD(ctx->opcode));
|
||||
if (unlikely(Rc(ctx->opcode) != 0))
|
||||
gen_op_set_Rc1();
|
||||
gen_compute_fprf(1, Rc(ctx->opcode) != 0);
|
||||
}
|
||||
|
||||
/*** Floating-Point multiply-and-add ***/
|
||||
/* fmadd - fmadds */
|
||||
GEN_FLOAT_ACB(madd, 0x1D, PPC_FLOAT);
|
||||
GEN_FLOAT_ACB(madd, 0x1D, 1, PPC_FLOAT);
|
||||
/* fmsub - fmsubs */
|
||||
GEN_FLOAT_ACB(msub, 0x1C, PPC_FLOAT);
|
||||
GEN_FLOAT_ACB(msub, 0x1C, 1, PPC_FLOAT);
|
||||
/* fnmadd - fnmadds */
|
||||
GEN_FLOAT_ACB(nmadd, 0x1F, PPC_FLOAT);
|
||||
GEN_FLOAT_ACB(nmadd, 0x1F, 1, PPC_FLOAT);
|
||||
/* fnmsub - fnmsubs */
|
||||
GEN_FLOAT_ACB(nmsub, 0x1E, PPC_FLOAT);
|
||||
GEN_FLOAT_ACB(nmsub, 0x1E, 1, PPC_FLOAT);
|
||||
|
||||
/*** Floating-Point round & convert ***/
|
||||
/* fctiw */
|
||||
GEN_FLOAT_B(ctiw, 0x0E, 0x00, PPC_FLOAT);
|
||||
GEN_FLOAT_B(ctiw, 0x0E, 0x00, 0, PPC_FLOAT);
|
||||
/* fctiwz */
|
||||
GEN_FLOAT_B(ctiwz, 0x0F, 0x00, PPC_FLOAT);
|
||||
GEN_FLOAT_B(ctiwz, 0x0F, 0x00, 0, PPC_FLOAT);
|
||||
/* frsp */
|
||||
GEN_FLOAT_B(rsp, 0x0C, 0x00, PPC_FLOAT);
|
||||
GEN_FLOAT_B(rsp, 0x0C, 0x00, 1, PPC_FLOAT);
|
||||
#if defined(TARGET_PPC64)
|
||||
/* fcfid */
|
||||
GEN_FLOAT_B(cfid, 0x0E, 0x1A, PPC_64B);
|
||||
GEN_FLOAT_B(cfid, 0x0E, 0x1A, 1, PPC_64B);
|
||||
/* fctid */
|
||||
GEN_FLOAT_B(ctid, 0x0E, 0x19, PPC_64B);
|
||||
GEN_FLOAT_B(ctid, 0x0E, 0x19, 0, PPC_64B);
|
||||
/* fctidz */
|
||||
GEN_FLOAT_B(ctidz, 0x0F, 0x19, PPC_64B);
|
||||
GEN_FLOAT_B(ctidz, 0x0F, 0x19, 0, PPC_64B);
|
||||
#endif
|
||||
|
||||
/* frin */
|
||||
GEN_FLOAT_B(rin, 0x08, 0x0C, PPC_FLOAT_EXT);
|
||||
GEN_FLOAT_B(rin, 0x08, 0x0C, 1, PPC_FLOAT_EXT);
|
||||
/* friz */
|
||||
GEN_FLOAT_B(riz, 0x08, 0x0D, PPC_FLOAT_EXT);
|
||||
GEN_FLOAT_B(riz, 0x08, 0x0D, 1, PPC_FLOAT_EXT);
|
||||
/* frip */
|
||||
GEN_FLOAT_B(rip, 0x08, 0x0E, PPC_FLOAT_EXT);
|
||||
GEN_FLOAT_B(rip, 0x08, 0x0E, 1, PPC_FLOAT_EXT);
|
||||
/* frim */
|
||||
GEN_FLOAT_B(rim, 0x08, 0x0F, PPC_FLOAT_EXT);
|
||||
GEN_FLOAT_B(rim, 0x08, 0x0F, 1, PPC_FLOAT_EXT);
|
||||
|
||||
/*** Floating-Point compare ***/
|
||||
/* fcmpo */
|
||||
@ -1848,11 +1884,12 @@ GEN_HANDLER(fcmpo, 0x3F, 0x00, 0x01, 0x00600001, PPC_FLOAT)
|
||||
GEN_EXCP_NO_FP(ctx);
|
||||
return;
|
||||
}
|
||||
gen_op_reset_scrfx();
|
||||
gen_op_load_fpr_FT0(rA(ctx->opcode));
|
||||
gen_op_load_fpr_FT1(rB(ctx->opcode));
|
||||
gen_reset_fpstatus();
|
||||
gen_op_fcmpo();
|
||||
gen_op_store_T0_crf(crfD(ctx->opcode));
|
||||
gen_op_float_check_status();
|
||||
}
|
||||
|
||||
/* fcmpu */
|
||||
@ -1862,47 +1899,54 @@ GEN_HANDLER(fcmpu, 0x3F, 0x00, 0x00, 0x00600001, PPC_FLOAT)
|
||||
GEN_EXCP_NO_FP(ctx);
|
||||
return;
|
||||
}
|
||||
gen_op_reset_scrfx();
|
||||
gen_op_load_fpr_FT0(rA(ctx->opcode));
|
||||
gen_op_load_fpr_FT1(rB(ctx->opcode));
|
||||
gen_reset_fpstatus();
|
||||
gen_op_fcmpu();
|
||||
gen_op_store_T0_crf(crfD(ctx->opcode));
|
||||
gen_op_float_check_status();
|
||||
}
|
||||
|
||||
/*** Floating-point move ***/
|
||||
/* fabs */
|
||||
GEN_FLOAT_B(abs, 0x08, 0x08, PPC_FLOAT);
|
||||
/* XXX: beware that fabs never checks for NaNs nor update FPSCR */
|
||||
GEN_FLOAT_B(abs, 0x08, 0x08, 0, PPC_FLOAT);
|
||||
|
||||
/* fmr - fmr. */
|
||||
/* XXX: beware that fmr never checks for NaNs nor update FPSCR */
|
||||
GEN_HANDLER(fmr, 0x3F, 0x08, 0x02, 0x001F0000, PPC_FLOAT)
|
||||
{
|
||||
if (unlikely(!ctx->fpu_enabled)) {
|
||||
GEN_EXCP_NO_FP(ctx);
|
||||
return;
|
||||
}
|
||||
gen_op_reset_scrfx();
|
||||
gen_op_load_fpr_FT0(rB(ctx->opcode));
|
||||
gen_op_store_FT0_fpr(rD(ctx->opcode));
|
||||
if (unlikely(Rc(ctx->opcode) != 0))
|
||||
gen_op_set_Rc1();
|
||||
gen_compute_fprf(0, Rc(ctx->opcode) != 0);
|
||||
}
|
||||
|
||||
/* fnabs */
|
||||
GEN_FLOAT_B(nabs, 0x08, 0x04, PPC_FLOAT);
|
||||
/* XXX: beware that fnabs never checks for NaNs nor update FPSCR */
|
||||
GEN_FLOAT_B(nabs, 0x08, 0x04, 0, PPC_FLOAT);
|
||||
/* fneg */
|
||||
GEN_FLOAT_B(neg, 0x08, 0x01, PPC_FLOAT);
|
||||
/* XXX: beware that fneg never checks for NaNs nor update FPSCR */
|
||||
GEN_FLOAT_B(neg, 0x08, 0x01, 0, PPC_FLOAT);
|
||||
|
||||
/*** Floating-Point status & ctrl register ***/
|
||||
/* mcrfs */
|
||||
GEN_HANDLER(mcrfs, 0x3F, 0x00, 0x02, 0x0063F801, PPC_FLOAT)
|
||||
{
|
||||
int bfa;
|
||||
|
||||
if (unlikely(!ctx->fpu_enabled)) {
|
||||
GEN_EXCP_NO_FP(ctx);
|
||||
return;
|
||||
}
|
||||
gen_op_load_fpscr_T0(crfS(ctx->opcode));
|
||||
gen_optimize_fprf();
|
||||
bfa = 4 * (7 - crfS(ctx->opcode));
|
||||
gen_op_load_fpscr_T0(bfa);
|
||||
gen_op_store_T0_crf(crfD(ctx->opcode));
|
||||
gen_op_clear_fpscr(crfS(ctx->opcode));
|
||||
gen_op_fpscr_resetbit(~(0xF << bfa));
|
||||
}
|
||||
|
||||
/* mffs */
|
||||
@ -1912,10 +1956,11 @@ GEN_HANDLER(mffs, 0x3F, 0x07, 0x12, 0x001FF800, PPC_FLOAT)
|
||||
GEN_EXCP_NO_FP(ctx);
|
||||
return;
|
||||
}
|
||||
gen_op_load_fpscr();
|
||||
gen_optimize_fprf();
|
||||
gen_reset_fpstatus();
|
||||
gen_op_load_fpscr_FT0();
|
||||
gen_op_store_FT0_fpr(rD(ctx->opcode));
|
||||
if (unlikely(Rc(ctx->opcode) != 0))
|
||||
gen_op_set_Rc1();
|
||||
gen_compute_fprf(0, Rc(ctx->opcode) != 0);
|
||||
}
|
||||
|
||||
/* mtfsb0 */
|
||||
@ -1927,12 +1972,15 @@ GEN_HANDLER(mtfsb0, 0x3F, 0x06, 0x02, 0x001FF800, PPC_FLOAT)
|
||||
GEN_EXCP_NO_FP(ctx);
|
||||
return;
|
||||
}
|
||||
crb = crbD(ctx->opcode) >> 2;
|
||||
gen_op_load_fpscr_T0(crb);
|
||||
gen_op_andi_T0(~(1 << (crbD(ctx->opcode) & 0x03)));
|
||||
gen_op_store_T0_fpscr(crb);
|
||||
if (unlikely(Rc(ctx->opcode) != 0))
|
||||
gen_op_set_Rc1();
|
||||
crb = 32 - (crbD(ctx->opcode) >> 2);
|
||||
gen_optimize_fprf();
|
||||
gen_reset_fpstatus();
|
||||
if (likely(crb != 30 && crb != 29))
|
||||
gen_op_fpscr_resetbit(~(1 << crb));
|
||||
if (unlikely(Rc(ctx->opcode) != 0)) {
|
||||
gen_op_load_fpcc();
|
||||
gen_op_set_Rc0();
|
||||
}
|
||||
}
|
||||
|
||||
/* mtfsb1 */
|
||||
@ -1944,12 +1992,18 @@ GEN_HANDLER(mtfsb1, 0x3F, 0x06, 0x01, 0x001FF800, PPC_FLOAT)
|
||||
GEN_EXCP_NO_FP(ctx);
|
||||
return;
|
||||
}
|
||||
crb = crbD(ctx->opcode) >> 2;
|
||||
gen_op_load_fpscr_T0(crb);
|
||||
gen_op_ori(1 << (crbD(ctx->opcode) & 0x03));
|
||||
gen_op_store_T0_fpscr(crb);
|
||||
if (unlikely(Rc(ctx->opcode) != 0))
|
||||
gen_op_set_Rc1();
|
||||
crb = 32 - (crbD(ctx->opcode) >> 2);
|
||||
gen_optimize_fprf();
|
||||
gen_reset_fpstatus();
|
||||
/* XXX: we pretend we can only do IEEE floating-point computations */
|
||||
if (likely(crb != FPSCR_FEX && crb != FPSCR_VX && crb != FPSCR_NI))
|
||||
gen_op_fpscr_setbit(crb);
|
||||
if (unlikely(Rc(ctx->opcode) != 0)) {
|
||||
gen_op_load_fpcc();
|
||||
gen_op_set_Rc0();
|
||||
}
|
||||
/* We can raise a differed exception */
|
||||
gen_op_float_check_status();
|
||||
}
|
||||
|
||||
/* mtfsf */
|
||||
@ -1959,22 +2013,39 @@ GEN_HANDLER(mtfsf, 0x3F, 0x07, 0x16, 0x02010000, PPC_FLOAT)
|
||||
GEN_EXCP_NO_FP(ctx);
|
||||
return;
|
||||
}
|
||||
gen_optimize_fprf();
|
||||
gen_op_load_fpr_FT0(rB(ctx->opcode));
|
||||
gen_reset_fpstatus();
|
||||
gen_op_store_fpscr(FM(ctx->opcode));
|
||||
if (unlikely(Rc(ctx->opcode) != 0))
|
||||
gen_op_set_Rc1();
|
||||
if (unlikely(Rc(ctx->opcode) != 0)) {
|
||||
gen_op_load_fpcc();
|
||||
gen_op_set_Rc0();
|
||||
}
|
||||
/* We can raise a differed exception */
|
||||
gen_op_float_check_status();
|
||||
}
|
||||
|
||||
/* mtfsfi */
|
||||
GEN_HANDLER(mtfsfi, 0x3F, 0x06, 0x04, 0x006f0800, PPC_FLOAT)
|
||||
{
|
||||
int bf, sh;
|
||||
|
||||
if (unlikely(!ctx->fpu_enabled)) {
|
||||
GEN_EXCP_NO_FP(ctx);
|
||||
return;
|
||||
}
|
||||
gen_op_store_T0_fpscri(crbD(ctx->opcode) >> 2, FPIMM(ctx->opcode));
|
||||
if (unlikely(Rc(ctx->opcode) != 0))
|
||||
gen_op_set_Rc1();
|
||||
bf = crbD(ctx->opcode) >> 2;
|
||||
sh = 7 - bf;
|
||||
gen_optimize_fprf();
|
||||
gen_op_set_FT0(FPIMM(ctx->opcode) << (4 * sh));
|
||||
gen_reset_fpstatus();
|
||||
gen_op_store_fpscr(1 << sh);
|
||||
if (unlikely(Rc(ctx->opcode) != 0)) {
|
||||
gen_op_load_fpcc();
|
||||
gen_op_set_Rc0();
|
||||
}
|
||||
/* We can raise a differed exception */
|
||||
gen_op_float_check_status();
|
||||
}
|
||||
|
||||
/*** Addressing modes ***/
|
||||
@ -6717,6 +6788,9 @@ static always_inline int gen_intermediate_code_internal (CPUState *env,
|
||||
gen_opc_ptr = gen_opc_buf;
|
||||
gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
|
||||
gen_opparam_ptr = gen_opparam_buf;
|
||||
#if defined(OPTIMIZE_FPRF_UPDATE)
|
||||
gen_fprf_ptr = gen_fprf_buf;
|
||||
#endif
|
||||
nb_gen_labels = 0;
|
||||
ctx.nip = pc_start;
|
||||
ctx.tb = tb;
|
||||
|
Loading…
Reference in New Issue
Block a user