Full implementation of IEEE exceptions (Aurelien Jarno)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2625 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
parent
c185970a0e
commit
417454b032
@ -61,6 +61,8 @@ void do_fsqrts(void);
|
||||
void do_fsqrtd(void);
|
||||
void do_fcmps(void);
|
||||
void do_fcmpd(void);
|
||||
void do_fcmpes(void);
|
||||
void do_fcmped(void);
|
||||
#ifdef TARGET_SPARC64
|
||||
void do_fabsd(void);
|
||||
void do_fcmps_fcc1(void);
|
||||
@ -69,6 +71,12 @@ void do_fcmps_fcc2(void);
|
||||
void do_fcmpd_fcc2(void);
|
||||
void do_fcmps_fcc3(void);
|
||||
void do_fcmpd_fcc3(void);
|
||||
void do_fcmpes_fcc1(void);
|
||||
void do_fcmped_fcc1(void);
|
||||
void do_fcmpes_fcc2(void);
|
||||
void do_fcmped_fcc2(void);
|
||||
void do_fcmpes_fcc3(void);
|
||||
void do_fcmped_fcc3(void);
|
||||
void do_popc();
|
||||
void do_wrpstate();
|
||||
void do_done();
|
||||
@ -79,6 +87,7 @@ void do_ldd_user(target_ulong addr);
|
||||
void do_ldd_raw(target_ulong addr);
|
||||
void do_interrupt(int intno);
|
||||
void raise_exception(int tt);
|
||||
void check_ieee_exceptions();
|
||||
void memcpy32(target_ulong *dst, const target_ulong *src);
|
||||
target_ulong mmu_probe(CPUState *env, target_ulong address, int mmulev);
|
||||
void dump_mmu(CPUState *env);
|
||||
|
@ -1534,16 +1534,25 @@ void OPPROTO op_flush_T0(void)
|
||||
helper_flush(T0);
|
||||
}
|
||||
|
||||
void OPPROTO op_clear_ieee_excp_and_FTT(void)
|
||||
{
|
||||
env->fsr &= ~(FSR_FTT_MASK | FSR_CEXC_MASK);;
|
||||
}
|
||||
|
||||
#define F_OP(name, p) void OPPROTO op_f##name##p(void)
|
||||
|
||||
#define F_BINOP(name) \
|
||||
F_OP(name, s) \
|
||||
{ \
|
||||
set_float_exception_flags(0, &env->fp_status); \
|
||||
FT0 = float32_ ## name (FT0, FT1, &env->fp_status); \
|
||||
check_ieee_exceptions(); \
|
||||
} \
|
||||
F_OP(name, d) \
|
||||
{ \
|
||||
set_float_exception_flags(0, &env->fp_status); \
|
||||
DT0 = float64_ ## name (DT0, DT1, &env->fp_status); \
|
||||
check_ieee_exceptions(); \
|
||||
}
|
||||
|
||||
F_BINOP(add);
|
||||
@ -1554,9 +1563,11 @@ F_BINOP(div);
|
||||
|
||||
void OPPROTO op_fsmuld(void)
|
||||
{
|
||||
set_float_exception_flags(0, &env->fp_status);
|
||||
DT0 = float64_mul(float32_to_float64(FT0, &env->fp_status),
|
||||
float32_to_float64(FT1, &env->fp_status),
|
||||
&env->fp_status);
|
||||
check_ieee_exceptions();
|
||||
}
|
||||
|
||||
#define F_HELPER(name) \
|
||||
@ -1582,6 +1593,7 @@ F_OP(abs, s)
|
||||
}
|
||||
|
||||
F_HELPER(cmp);
|
||||
F_HELPER(cmpe);
|
||||
|
||||
#ifdef TARGET_SPARC64
|
||||
F_OP(neg, d)
|
||||
@ -1623,6 +1635,37 @@ void OPPROTO op_fcmpd_fcc3(void)
|
||||
{
|
||||
do_fcmpd_fcc3();
|
||||
}
|
||||
|
||||
void OPPROTO op_fcmpes_fcc1(void)
|
||||
{
|
||||
do_fcmpes_fcc1();
|
||||
}
|
||||
|
||||
void OPPROTO op_fcmped_fcc1(void)
|
||||
{
|
||||
do_fcmped_fcc1();
|
||||
}
|
||||
|
||||
void OPPROTO op_fcmpes_fcc2(void)
|
||||
{
|
||||
do_fcmpes_fcc2();
|
||||
}
|
||||
|
||||
void OPPROTO op_fcmped_fcc2(void)
|
||||
{
|
||||
do_fcmped_fcc2();
|
||||
}
|
||||
|
||||
void OPPROTO op_fcmpes_fcc3(void)
|
||||
{
|
||||
do_fcmpes_fcc3();
|
||||
}
|
||||
|
||||
void OPPROTO op_fcmped_fcc3(void)
|
||||
{
|
||||
do_fcmped_fcc3();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* Integer to float conversion. */
|
||||
@ -1631,23 +1674,31 @@ F_HELPER(ito);
|
||||
#else
|
||||
F_OP(ito, s)
|
||||
{
|
||||
set_float_exception_flags(0, &env->fp_status);
|
||||
FT0 = int32_to_float32(*((int32_t *)&FT1), &env->fp_status);
|
||||
check_ieee_exceptions();
|
||||
}
|
||||
|
||||
F_OP(ito, d)
|
||||
{
|
||||
set_float_exception_flags(0, &env->fp_status);
|
||||
DT0 = int32_to_float64(*((int32_t *)&FT1), &env->fp_status);
|
||||
check_ieee_exceptions();
|
||||
}
|
||||
|
||||
#ifdef TARGET_SPARC64
|
||||
F_OP(xto, s)
|
||||
{
|
||||
set_float_exception_flags(0, &env->fp_status);
|
||||
FT0 = int64_to_float32(*((int64_t *)&DT1), &env->fp_status);
|
||||
check_ieee_exceptions();
|
||||
}
|
||||
|
||||
F_OP(xto, d)
|
||||
{
|
||||
set_float_exception_flags(0, &env->fp_status);
|
||||
DT0 = int64_to_float64(*((int64_t *)&DT1), &env->fp_status);
|
||||
check_ieee_exceptions();
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
@ -1656,34 +1707,46 @@ F_OP(xto, d)
|
||||
/* floating point conversion */
|
||||
void OPPROTO op_fdtos(void)
|
||||
{
|
||||
set_float_exception_flags(0, &env->fp_status);
|
||||
FT0 = float64_to_float32(DT1, &env->fp_status);
|
||||
check_ieee_exceptions();
|
||||
}
|
||||
|
||||
void OPPROTO op_fstod(void)
|
||||
{
|
||||
set_float_exception_flags(0, &env->fp_status);
|
||||
DT0 = float32_to_float64(FT1, &env->fp_status);
|
||||
check_ieee_exceptions();
|
||||
}
|
||||
|
||||
/* Float to integer conversion. */
|
||||
void OPPROTO op_fstoi(void)
|
||||
{
|
||||
set_float_exception_flags(0, &env->fp_status);
|
||||
*((int32_t *)&FT0) = float32_to_int32_round_to_zero(FT1, &env->fp_status);
|
||||
check_ieee_exceptions();
|
||||
}
|
||||
|
||||
void OPPROTO op_fdtoi(void)
|
||||
{
|
||||
set_float_exception_flags(0, &env->fp_status);
|
||||
*((int32_t *)&FT0) = float64_to_int32_round_to_zero(DT1, &env->fp_status);
|
||||
check_ieee_exceptions();
|
||||
}
|
||||
|
||||
#ifdef TARGET_SPARC64
|
||||
void OPPROTO op_fstox(void)
|
||||
{
|
||||
set_float_exception_flags(0, &env->fp_status);
|
||||
*((int64_t *)&DT0) = float32_to_int64_round_to_zero(FT1, &env->fp_status);
|
||||
check_ieee_exceptions();
|
||||
}
|
||||
|
||||
void OPPROTO op_fdtox(void)
|
||||
{
|
||||
set_float_exception_flags(0, &env->fp_status);
|
||||
*((int64_t *)&DT0) = float64_to_int64_round_to_zero(DT1, &env->fp_status);
|
||||
check_ieee_exceptions();
|
||||
}
|
||||
|
||||
void OPPROTO op_fmovs_cc(void)
|
||||
|
@ -9,10 +9,43 @@ void raise_exception(int tt)
|
||||
cpu_loop_exit();
|
||||
}
|
||||
|
||||
void check_ieee_exceptions()
|
||||
{
|
||||
T0 = get_float_exception_flags(&env->fp_status);
|
||||
if (T0)
|
||||
{
|
||||
/* Copy IEEE 754 flags into FSR */
|
||||
if (T0 & float_flag_invalid)
|
||||
env->fsr |= FSR_NVC;
|
||||
if (T0 & float_flag_overflow)
|
||||
env->fsr |= FSR_OFC;
|
||||
if (T0 & float_flag_underflow)
|
||||
env->fsr |= FSR_UFC;
|
||||
if (T0 & float_flag_divbyzero)
|
||||
env->fsr |= FSR_DZC;
|
||||
if (T0 & float_flag_inexact)
|
||||
env->fsr |= FSR_NXC;
|
||||
|
||||
if ((env->fsr & FSR_CEXC_MASK) & ((env->fsr & FSR_TEM_MASK) >> 23))
|
||||
{
|
||||
/* Unmasked exception, generate a trap */
|
||||
env->fsr |= FSR_FTT_IEEE_EXCP;
|
||||
raise_exception(TT_FP_EXCP);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Accumulate exceptions */
|
||||
env->fsr |= (env->fsr & FSR_CEXC_MASK) << 5;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USE_INT_TO_FLOAT_HELPERS
|
||||
void do_fitos(void)
|
||||
{
|
||||
set_float_exception_flags(0, &env->fp_status);
|
||||
FT0 = int32_to_float32(*((int32_t *)&FT1), &env->fp_status);
|
||||
check_ieee_exceptions();
|
||||
}
|
||||
|
||||
void do_fitod(void)
|
||||
@ -35,23 +68,29 @@ void do_fabsd(void)
|
||||
|
||||
void do_fsqrts(void)
|
||||
{
|
||||
set_float_exception_flags(0, &env->fp_status);
|
||||
FT0 = float32_sqrt(FT1, &env->fp_status);
|
||||
check_ieee_exceptions();
|
||||
}
|
||||
|
||||
void do_fsqrtd(void)
|
||||
{
|
||||
set_float_exception_flags(0, &env->fp_status);
|
||||
DT0 = float64_sqrt(DT1, &env->fp_status);
|
||||
check_ieee_exceptions();
|
||||
}
|
||||
|
||||
#define GEN_FCMP(name, size, reg1, reg2, FS) \
|
||||
#define GEN_FCMP(name, size, reg1, reg2, FS, TRAP) \
|
||||
void glue(do_, name) (void) \
|
||||
{ \
|
||||
env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \
|
||||
switch (glue(size, _compare) (reg1, reg2, &env->fp_status)) { \
|
||||
case float_relation_unordered: \
|
||||
T0 = (FSR_FCC1 | FSR_FCC0) << FS; \
|
||||
if (env->fsr & FSR_NVM) { \
|
||||
if ((env->fsr & FSR_NVM) || TRAP) { \
|
||||
env->fsr |= T0; \
|
||||
env->fsr |= FSR_NVC; \
|
||||
env->fsr |= FSR_FTT_IEEE_EXCP; \
|
||||
raise_exception(TT_FP_EXCP); \
|
||||
} else { \
|
||||
env->fsr |= FSR_NVA; \
|
||||
@ -70,18 +109,30 @@ void do_fsqrtd(void)
|
||||
env->fsr |= T0; \
|
||||
}
|
||||
|
||||
GEN_FCMP(fcmps, float32, FT0, FT1, 0);
|
||||
GEN_FCMP(fcmpd, float64, DT0, DT1, 0);
|
||||
GEN_FCMP(fcmps, float32, FT0, FT1, 0, 0);
|
||||
GEN_FCMP(fcmpd, float64, DT0, DT1, 0, 0);
|
||||
|
||||
GEN_FCMP(fcmpes, float32, FT0, FT1, 0, 1);
|
||||
GEN_FCMP(fcmped, float64, DT0, DT1, 0, 1);
|
||||
|
||||
#ifdef TARGET_SPARC64
|
||||
GEN_FCMP(fcmps_fcc1, float32, FT0, FT1, 22);
|
||||
GEN_FCMP(fcmpd_fcc1, float64, DT0, DT1, 22);
|
||||
GEN_FCMP(fcmps_fcc1, float32, FT0, FT1, 22, 0);
|
||||
GEN_FCMP(fcmpd_fcc1, float64, DT0, DT1, 22, 0);
|
||||
|
||||
GEN_FCMP(fcmps_fcc2, float32, FT0, FT1, 24);
|
||||
GEN_FCMP(fcmpd_fcc2, float64, DT0, DT1, 24);
|
||||
GEN_FCMP(fcmps_fcc2, float32, FT0, FT1, 24, 0);
|
||||
GEN_FCMP(fcmpd_fcc2, float64, DT0, DT1, 24, 0);
|
||||
|
||||
GEN_FCMP(fcmps_fcc3, float32, FT0, FT1, 26);
|
||||
GEN_FCMP(fcmpd_fcc3, float64, DT0, DT1, 26);
|
||||
GEN_FCMP(fcmps_fcc3, float32, FT0, FT1, 26, 0);
|
||||
GEN_FCMP(fcmpd_fcc3, float64, DT0, DT1, 26, 0);
|
||||
|
||||
GEN_FCMP(fcmpes_fcc1, float32, FT0, FT1, 22, 1);
|
||||
GEN_FCMP(fcmped_fcc1, float64, DT0, DT1, 22, 1);
|
||||
|
||||
GEN_FCMP(fcmpes_fcc2, float32, FT0, FT1, 24, 1);
|
||||
GEN_FCMP(fcmped_fcc2, float64, DT0, DT1, 24, 1);
|
||||
|
||||
GEN_FCMP(fcmpes_fcc3, float32, FT0, FT1, 26, 1);
|
||||
GEN_FCMP(fcmped_fcc3, float64, DT0, DT1, 26, 1);
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
|
@ -943,6 +943,21 @@ static GenOpFunc * const gen_fcmpd[4] = {
|
||||
gen_op_fcmpd_fcc2,
|
||||
gen_op_fcmpd_fcc3,
|
||||
};
|
||||
|
||||
static GenOpFunc * const gen_fcmpes[4] = {
|
||||
gen_op_fcmpes,
|
||||
gen_op_fcmpes_fcc1,
|
||||
gen_op_fcmpes_fcc2,
|
||||
gen_op_fcmpes_fcc3,
|
||||
};
|
||||
|
||||
static GenOpFunc * const gen_fcmped[4] = {
|
||||
gen_op_fcmped,
|
||||
gen_op_fcmped_fcc1,
|
||||
gen_op_fcmped_fcc2,
|
||||
gen_op_fcmped_fcc3,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
static int gen_trap_ifnofpu(DisasContext * dc)
|
||||
@ -1289,6 +1304,7 @@ static void disas_sparc_insn(DisasContext * dc)
|
||||
} else if (xop == 0x34) { /* FPU Operations */
|
||||
if (gen_trap_ifnofpu(dc))
|
||||
goto jmp_insn;
|
||||
gen_op_clear_ieee_excp_and_FTT();
|
||||
rs1 = GET_FIELD(insn, 13, 17);
|
||||
rs2 = GET_FIELD(insn, 27, 31);
|
||||
xop = GET_FIELD(insn, 18, 26);
|
||||
@ -1476,6 +1492,7 @@ static void disas_sparc_insn(DisasContext * dc)
|
||||
#endif
|
||||
if (gen_trap_ifnofpu(dc))
|
||||
goto jmp_insn;
|
||||
gen_op_clear_ieee_excp_and_FTT();
|
||||
rs1 = GET_FIELD(insn, 13, 17);
|
||||
rs2 = GET_FIELD(insn, 27, 31);
|
||||
xop = GET_FIELD(insn, 18, 26);
|
||||
@ -1653,18 +1670,18 @@ static void disas_sparc_insn(DisasContext * dc)
|
||||
gen_op_load_fpr_FT0(rs1);
|
||||
gen_op_load_fpr_FT1(rs2);
|
||||
#ifdef TARGET_SPARC64
|
||||
gen_fcmps[rd & 3]();
|
||||
gen_fcmpes[rd & 3]();
|
||||
#else
|
||||
gen_op_fcmps(); /* XXX should trap if qNaN or sNaN */
|
||||
gen_op_fcmpes();
|
||||
#endif
|
||||
break;
|
||||
case 0x56: /* fcmped, V9 %fcc */
|
||||
gen_op_load_fpr_DT0(DFPREG(rs1));
|
||||
gen_op_load_fpr_DT1(DFPREG(rs2));
|
||||
#ifdef TARGET_SPARC64
|
||||
gen_fcmpd[rd & 3]();
|
||||
gen_fcmped[rd & 3]();
|
||||
#else
|
||||
gen_op_fcmpd(); /* XXX should trap if qNaN or sNaN */
|
||||
gen_op_fcmped();
|
||||
#endif
|
||||
break;
|
||||
case 0x57: /* fcmpeq */
|
||||
|
Loading…
Reference in New Issue
Block a user