📄 reg_ld_str.c
字号:
if ( tmp.sigl & 0x000007ff ) { precision_loss = 1; switch (control_word & CW_RC) { case RC_RND: /* Rounding can get a little messy.. */ increment = ((tmp.sigl & 0x7ff) > 0x400) | /* nearest */ ((tmp.sigl & 0xc00) == 0xc00); /* odd -> even */ break; case RC_DOWN: /* towards -infinity */ increment = signpositive(&tmp) ? 0 : tmp.sigl & 0x7ff; break; case RC_UP: /* towards +infinity */ increment = signpositive(&tmp) ? tmp.sigl & 0x7ff : 0; break; case RC_CHOP: increment = 0; break; } /* Truncate the mantissa */ tmp.sigl &= 0xfffff800; if ( increment ) { if ( tmp.sigl >= 0xfffff800 ) { /* the sigl part overflows */ if ( tmp.sigh == 0xffffffff ) { /* The sigh part overflows */ tmp.sigh = 0x80000000; exp++; if (exp >= EXP_OVER) goto overflow; } else { tmp.sigh ++; } tmp.sigl = 0x00000000; } else { /* We only need to increment sigl */ tmp.sigl += 0x00000800; } } } else precision_loss = 0; l[0] = (tmp.sigl >> 11) | (tmp.sigh << 21); l[1] = ((tmp.sigh >> 11) & 0xfffff); if ( exp > DOUBLE_Emax ) { overflow: EXCEPTION(EX_Overflow); if ( !(control_word & CW_Overflow) ) return 0; set_precision_flag_up(); if ( !(control_word & CW_Precision) ) return 0; /* This is a special case: see sec 16.2.5.1 of the 80486 book */ /* Overflow to infinity */ l[0] = 0x00000000; /* Set to */ l[1] = 0x7ff00000; /* + INF */ } else { if ( precision_loss ) { if ( increment ) set_precision_flag_up(); else set_precision_flag_down(); } /* Add the exponent */ l[1] |= (((exp+DOUBLE_Ebias) & 0x7ff) << 20); } } } else if (st0_tag == TAG_Zero) { /* Number is zero */ l[0] = 0; l[1] = 0; } else if ( st0_tag == TAG_Special ) { st0_tag = FPU_Special(st0_ptr); if ( st0_tag == TW_Denormal ) { /* A denormal will always underflow. */#ifndef PECULIAR_486 /* An 80486 is supposed to be able to generate a denormal exception here, but... */ /* Underflow has priority. */ if ( control_word & CW_Underflow ) denormal_operand();#endif /* PECULIAR_486 */ reg_copy(st0_ptr, &tmp); goto denormal_arg; } else if (st0_tag == TW_Infinity) { l[0] = 0; l[1] = 0x7ff00000; } else if (st0_tag == TW_NaN) { /* Is it really a NaN ? */ if ( (exponent(st0_ptr) == EXP_OVER) && (st0_ptr->sigh & 0x80000000) ) { /* See if we can get a valid NaN from the FPU_REG */ l[0] = (st0_ptr->sigl >> 11) | (st0_ptr->sigh << 21); l[1] = ((st0_ptr->sigh >> 11) & 0xfffff); if ( !(st0_ptr->sigh & 0x40000000) ) { /* It is a signalling NaN */ EXCEPTION(EX_Invalid); if ( !(control_word & CW_Invalid) ) return 0; l[1] |= (0x40000000 >> 11); } l[1] |= 0x7ff00000; } else { /* It is an unsupported data type */ EXCEPTION(EX_Invalid); if ( !(control_word & CW_Invalid) ) return 0; l[0] = 0; l[1] = 0xfff80000; } } } else if ( st0_tag == TAG_Empty ) { /* Empty register (stack underflow) */ EXCEPTION(EX_StackUnder); if ( control_word & CW_Invalid ) { /* The masked response */ /* Put out the QNaN indefinite */ RE_ENTRANT_CHECK_OFF; FPU_access_ok(VERIFY_WRITE,dfloat,8); FPU_put_user(0, (unsigned long __user *) dfloat); FPU_put_user(0xfff80000, 1 + (unsigned long __user *) dfloat); RE_ENTRANT_CHECK_ON; return 1; } else return 0; } if ( getsign(st0_ptr) ) l[1] |= 0x80000000; RE_ENTRANT_CHECK_OFF; FPU_access_ok(VERIFY_WRITE,dfloat,8); FPU_put_user(l[0], (unsigned long __user *)dfloat); FPU_put_user(l[1], 1 + (unsigned long __user *)dfloat); RE_ENTRANT_CHECK_ON; return 1;}/* Put a float into user memory */int FPU_store_single(FPU_REG *st0_ptr, u_char st0_tag, float __user *single){ long templ = 0; unsigned long increment = 0; /* avoid gcc warnings */ int precision_loss; int exp; FPU_REG tmp; if ( st0_tag == TAG_Valid ) { reg_copy(st0_ptr, &tmp); exp = exponent(&tmp); if ( exp < SINGLE_Emin ) { addexponent(&tmp, -SINGLE_Emin + 23); /* largest exp to be 22 */ denormal_arg: if ( (precision_loss = FPU_round_to_int(&tmp, st0_tag)) ) {#ifdef PECULIAR_486 /* Did it round to a non-denormal ? */ /* This behaviour might be regarded as peculiar, it appears that the 80486 rounds to the dest precision, then converts to decide underflow. */ if ( !((tmp.sigl == 0x00800000) && ((st0_ptr->sigh & 0x000000ff) || st0_ptr->sigl)) )#endif /* PECULIAR_486 */ { EXCEPTION(EX_Underflow); /* This is a special case: see sec 16.2.5.1 of the 80486 book */ if ( !(control_word & CW_Underflow) ) return 0; } EXCEPTION(precision_loss); if ( !(control_word & CW_Precision) ) return 0; } templ = tmp.sigl; } else { if ( tmp.sigl | (tmp.sigh & 0x000000ff) ) { unsigned long sigh = tmp.sigh; unsigned long sigl = tmp.sigl; precision_loss = 1; switch (control_word & CW_RC) { case RC_RND: increment = ((sigh & 0xff) > 0x80) /* more than half */ || (((sigh & 0xff) == 0x80) && sigl) /* more than half */ || ((sigh & 0x180) == 0x180); /* round to even */ break; case RC_DOWN: /* towards -infinity */ increment = signpositive(&tmp) ? 0 : (sigl | (sigh & 0xff)); break; case RC_UP: /* towards +infinity */ increment = signpositive(&tmp) ? (sigl | (sigh & 0xff)) : 0; break; case RC_CHOP: increment = 0; break; } /* Truncate part of the mantissa */ tmp.sigl = 0; if (increment) { if ( sigh >= 0xffffff00 ) { /* The sigh part overflows */ tmp.sigh = 0x80000000; exp++; if ( exp >= EXP_OVER ) goto overflow; } else { tmp.sigh &= 0xffffff00; tmp.sigh += 0x100; } } else { tmp.sigh &= 0xffffff00; /* Finish the truncation */ } } else precision_loss = 0; templ = (tmp.sigh >> 8) & 0x007fffff; if ( exp > SINGLE_Emax ) { overflow: EXCEPTION(EX_Overflow); if ( !(control_word & CW_Overflow) ) return 0; set_precision_flag_up(); if ( !(control_word & CW_Precision) ) return 0; /* This is a special case: see sec 16.2.5.1 of the 80486 book. */ /* Masked response is overflow to infinity. */ templ = 0x7f800000; } else { if ( precision_loss ) { if ( increment ) set_precision_flag_up(); else set_precision_flag_down(); } /* Add the exponent */ templ |= ((exp+SINGLE_Ebias) & 0xff) << 23; } } } else if (st0_tag == TAG_Zero) { templ = 0; } else if ( st0_tag == TAG_Special ) { st0_tag = FPU_Special(st0_ptr); if (st0_tag == TW_Denormal) { reg_copy(st0_ptr, &tmp); /* A denormal will always underflow. */#ifndef PECULIAR_486 /* An 80486 is supposed to be able to generate a denormal exception here, but... */ /* Underflow has priority. */ if ( control_word & CW_Underflow ) denormal_operand();#endif /* PECULIAR_486 */ goto denormal_arg; } else if (st0_tag == TW_Infinity) { templ = 0x7f800000; } else if (st0_tag == TW_NaN) { /* Is it really a NaN ? */ if ( (exponent(st0_ptr) == EXP_OVER) && (st0_ptr->sigh & 0x80000000) ) { /* See if we can get a valid NaN from the FPU_REG */ templ = st0_ptr->sigh >> 8; if ( !(st0_ptr->sigh & 0x40000000) ) { /* It is a signalling NaN */ EXCEPTION(EX_Invalid); if ( !(control_word & CW_Invalid) ) return 0; templ |= (0x40000000 >> 8); } templ |= 0x7f800000; } else { /* It is an unsupported data type */ EXCEPTION(EX_Invalid); if ( !(control_word & CW_Invalid) ) return 0; templ = 0xffc00000; } }#ifdef PARANOID else { EXCEPTION(EX_INTERNAL|0x164); return 0; }#endif } else if ( st0_tag == TAG_Empty ) { /* Empty register (stack underflow) */ EXCEPTION(EX_StackUnder); if ( control_word & EX_Invalid ) { /* The masked response */ /* Put out the QNaN indefinite */ RE_ENTRANT_CHECK_OFF; FPU_access_ok(VERIFY_WRITE,single,4); FPU_put_user(0xffc00000, (unsigned long __user *) single); RE_ENTRANT_CHECK_ON; return 1; } else return 0; }#ifdef PARANOID else { EXCEPTION(EX_INTERNAL|0x163); return 0; }#endif if ( getsign(st0_ptr) ) templ |= 0x80000000; RE_ENTRANT_CHECK_OFF; FPU_access_ok(VERIFY_WRITE,single,4); FPU_put_user(templ,(unsigned long __user *) single); RE_ENTRANT_CHECK_ON; return 1;}/* Put a long long into user memory */int FPU_store_int64(FPU_REG *st0_ptr, u_char st0_tag, long long __user *d){ FPU_REG t; long long tll; int precision_loss; if ( st0_tag == TAG_Empty ) { /* Empty register (stack underflow) */ EXCEPTION(EX_StackUnder); goto invalid_operand; } else if ( st0_tag == TAG_Special ) { st0_tag = FPU_Special(st0_ptr); if ( (st0_tag == TW_Infinity) || (st0_tag == TW_NaN) ) { EXCEPTION(EX_Invalid); goto invalid_operand; } } reg_copy(st0_ptr, &t); precision_loss = FPU_round_to_int(&t, st0_tag); ((long *)&tll)[0] = t.sigl; ((long *)&tll)[1] = t.sigh; if ( (precision_loss == 1) || ((t.sigh & 0x80000000) && !((t.sigh == 0x80000000) && (t.sigl == 0) && signnegative(&t))) ) { EXCEPTION(EX_Invalid); /* This is a special case: see sec 16.2.5.1 of the 80486 book */ invalid_operand: if ( control_word & EX_Invalid ) { /* Produce something like QNaN "indefinite" */ tll = 0x8000000000000000LL; } else return 0; } else { if ( precision_loss ) set_precision_flag(precision_loss); if ( signnegative(&t) ) tll = - tll; } RE_ENTRANT_CHECK_OFF; FPU_access_ok(VERIFY_WRITE,d,8); if (copy_to_user(d, &tll, 8)) FPU_abort; RE_ENTRANT_CHECK_ON; return 1;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -