?? op_helper.c
字號(hào):
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_MAX; 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_MAX; 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 |= 0x7FFULL << 52; 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#endifvoid 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_SOFTFLOATvoid 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_EMULATIONvoid 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((isinfinity(FT0) && iszero(FT1)) || (iszero(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 { double d; 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 */ p.i |= 0xFFF80000ULL << 32;#endif FT0 = p.d; }}void do_fctiwz (void){ union { double d; 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 */ p.i |= 0xFFF80000ULL << 32;#endif FT0 = p.d; }}#if defined(TARGET_PPC64)void do_fcfid (void){ union { double d; uint64_t i; } p; p.d = FT0; FT0 = int64_to_float64(p.i, &env->fp_status);}void do_fctid (void){ union { double d; 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);
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -