diff options
Diffstat (limited to 'target/ppc')
-rw-r--r-- | target/ppc/fpu_helper.c | 50 | ||||
-rw-r--r-- | target/ppc/helper.h | 2 |
2 files changed, 29 insertions, 23 deletions
diff --git a/target/ppc/fpu_helper.c b/target/ppc/fpu_helper.c index 9b39c4b..c20b9ae 100644 --- a/target/ppc/fpu_helper.c +++ b/target/ppc/fpu_helper.c @@ -545,9 +545,7 @@ static void do_float_check_status(CPUPPCState *env, uintptr_t raddr) int status = get_float_exception_flags(&env->fp_status); bool inexact_happened = false; - if (status & float_flag_divbyzero) { - float_zero_divide_excp(env, raddr); - } else if (status & float_flag_overflow) { + if (status & float_flag_overflow) { float_overflow_excp(env); } else if (status & float_flag_underflow) { float_underflow_excp(env); @@ -661,30 +659,32 @@ uint64_t helper_fmul(CPUPPCState *env, uint64_t arg1, uint64_t arg2) } /* fdiv - fdiv. */ -uint64_t helper_fdiv(CPUPPCState *env, uint64_t arg1, uint64_t arg2) +float64 helper_fdiv(CPUPPCState *env, float64 arg1, float64 arg2) { - CPU_DoubleU farg1, farg2; - - farg1.ll = arg1; - farg2.ll = arg2; + float64 ret = float64_div(arg1, arg2, &env->fp_status); + int status = get_float_exception_flags(&env->fp_status); - if (unlikely(float64_is_infinity(farg1.d) && - float64_is_infinity(farg2.d))) { - /* Division of infinity by infinity */ - farg1.ll = float_invalid_op_excp(env, POWERPC_EXCP_FP_VXIDI, 1); - } else if (unlikely(float64_is_zero(farg1.d) && float64_is_zero(farg2.d))) { - /* Division of zero by zero */ - farg1.ll = float_invalid_op_excp(env, POWERPC_EXCP_FP_VXZDZ, 1); - } else { - if (unlikely(float64_is_signaling_nan(farg1.d, &env->fp_status) || - float64_is_signaling_nan(farg2.d, &env->fp_status))) { - /* sNaN division */ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); + if (unlikely(status)) { + if (status & float_flag_invalid) { + /* Determine what kind of invalid operation was seen. */ + if (float64_is_infinity(arg1) && float64_is_infinity(arg2)) { + /* Division of infinity by infinity */ + float_invalid_op_excp(env, POWERPC_EXCP_FP_VXIDI, 1); + } else if (float64_is_zero(arg1) && float64_is_zero(arg2)) { + /* Division of zero by zero */ + float_invalid_op_excp(env, POWERPC_EXCP_FP_VXZDZ, 1); + } else if (float64_is_signaling_nan(arg1, &env->fp_status) || + float64_is_signaling_nan(arg2, &env->fp_status)) { + /* sNaN division */ + float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); + } + } + if (status & float_flag_divbyzero) { + float_zero_divide_excp(env, GETPC()); } - farg1.d = float64_div(farg1.d, farg2.d, &env->fp_status); } - return farg1.ll; + return ret; } @@ -1929,6 +1929,9 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf); \ } \ } \ + if (unlikely(tstat.float_exception_flags & float_flag_divbyzero)) { \ + float_zero_divide_excp(env, GETPC()); \ + } \ \ if (r2sp) { \ xt.fld = helper_frsp(env, xt.fld); \ @@ -1978,6 +1981,9 @@ void helper_xsdivqp(CPUPPCState *env, uint32_t opcode) float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); } } + if (unlikely(tstat.float_exception_flags & float_flag_divbyzero)) { + float_zero_divide_excp(env, GETPC()); + } helper_compute_fprf_float128(env, xt.f128); putVSR(rD(opcode) + 32, &xt, env); diff --git a/target/ppc/helper.h b/target/ppc/helper.h index 5706c24..1c453fa 100644 --- a/target/ppc/helper.h +++ b/target/ppc/helper.h @@ -88,7 +88,7 @@ DEF_HELPER_2(frim, i64, env, i64) DEF_HELPER_3(fadd, i64, env, i64, i64) DEF_HELPER_3(fsub, i64, env, i64, i64) DEF_HELPER_3(fmul, i64, env, i64, i64) -DEF_HELPER_3(fdiv, i64, env, i64, i64) +DEF_HELPER_3(fdiv, f64, env, f64, f64) DEF_HELPER_4(fmadd, i64, env, i64, i64, i64) DEF_HELPER_4(fmsub, i64, env, i64, i64, i64) DEF_HELPER_4(fnmadd, i64, env, i64, i64, i64) |