From 417454b0322ab1eed03615fe563d770fa7e4c9f9 Mon Sep 17 00:00:00 2001 From: blueswir1 Date: Fri, 6 Apr 2007 20:03:29 +0000 Subject: [PATCH] Full implementation of IEEE exceptions (Aurelien Jarno) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2625 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-sparc/exec.h | 9 +++++ target-sparc/op.c | 63 +++++++++++++++++++++++++++++++++++ target-sparc/op_helper.c | 71 ++++++++++++++++++++++++++++++++++------ target-sparc/translate.c | 25 +++++++++++--- 4 files changed, 154 insertions(+), 14 deletions(-) diff --git a/target-sparc/exec.h b/target-sparc/exec.h index 934f5ce965..8a9fa89ec6 100644 --- a/target-sparc/exec.h +++ b/target-sparc/exec.h @@ -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); diff --git a/target-sparc/op.c b/target-sparc/op.c index 2c89490484..c9f068457e 100644 --- a/target-sparc/op.c +++ b/target-sparc/op.c @@ -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) diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c index 8a9b7bb3c8..21612bd238 100644 --- a/target-sparc/op_helper.c +++ b/target-sparc/op_helper.c @@ -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, 0); +GEN_FCMP(fcmpd_fcc2, float64, DT0, DT1, 24, 0); + +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(fcmps_fcc2, float32, FT0, FT1, 24); -GEN_FCMP(fcmpd_fcc2, float64, DT0, DT1, 24); +GEN_FCMP(fcmpes_fcc2, float32, FT0, FT1, 24, 1); +GEN_FCMP(fcmped_fcc2, float64, DT0, DT1, 24, 1); -GEN_FCMP(fcmps_fcc3, float32, FT0, FT1, 26); -GEN_FCMP(fcmpd_fcc3, float64, DT0, DT1, 26); +GEN_FCMP(fcmpes_fcc3, float32, FT0, FT1, 26, 1); +GEN_FCMP(fcmped_fcc3, float64, DT0, DT1, 26, 1); #endif #if defined(CONFIG_USER_ONLY) diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 34a3357f97..0d71da3b86 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -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 */ -- GitLab