📄 reg_ld_s.c
字号:
reg_move(FPU_st0_ptr, &tmp); exp = tmp.exp - EXP_BIAS; if ( exp < DOUBLE_Emin ) /* It may be a denormal */ { int precision_loss; /* A denormal will always underflow. */#ifndef PECULIAR_486 /* An 80486 is supposed to be able to generate a denormal exception here, but... */ if ( FPU_st0_ptr->exp <= EXP_UNDER ) { /* Underflow has priority. */ if ( control_word & CW_Underflow ) denormal_operand(); }#endif PECULIAR_486 tmp.exp += -DOUBLE_Emin + 52; /* largest exp to be 51 */ if ( (precision_loss = round_to_int(&tmp)) ) {#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.sigh == 0x00100000) && (tmp.sigl == 0) && (FPU_st0_ptr->sigl & 0x000007ff)) )#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; } l[0] = tmp.sigl; l[1] = tmp.sigh; } else { if ( tmp.sigl & 0x000007ff ) { 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 = (tmp.sign == SIGN_POS) ? 0 : tmp.sigl & 0x7ff; break; case RC_UP: /* towards +infinity */ increment = (tmp.sign == SIGN_POS) ? tmp.sigl & 0x7ff : 0; break; case RC_CHOP: increment = 0; break; } /* Truncate the mantissa */ tmp.sigl &= 0xfffff800; if ( increment ) { set_precision_flag_up(); 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 set_precision_flag_down(); } 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 { /* Add the exponent */ l[1] |= (((exp+DOUBLE_Ebias) & 0x7ff) << 20); } } } else if (FPU_st0_tag == TW_Zero) { /* Number is zero */ l[0] = 0; l[1] = 0; } else if (FPU_st0_tag == TW_Infinity) { l[0] = 0; l[1] = 0x7ff00000; } else if (FPU_st0_tag == TW_NaN) { /* See if we can get a valid NaN from the FPU_REG */ l[0] = (FPU_st0_ptr->sigl >> 11) | (FPU_st0_ptr->sigh << 21); l[1] = ((FPU_st0_ptr->sigh >> 11) & 0xfffff); if ( !(FPU_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 if ( FPU_st0_tag == TW_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_verify_area(VERIFY_WRITE,(void *)dfloat,8); put_fs_long(0, (unsigned long *) dfloat); put_fs_long(0xfff80000, 1 + (unsigned long *) dfloat); RE_ENTRANT_CHECK_ON; return 1; } else return 0; } if (FPU_st0_ptr->sign) l[1] |= 0x80000000; RE_ENTRANT_CHECK_OFF; FPU_verify_area(VERIFY_WRITE,(void *)dfloat,8); put_fs_long(l[0], (unsigned long *)dfloat); put_fs_long(l[1], 1 + (unsigned long *)dfloat); RE_ENTRANT_CHECK_ON; return 1;}/* Put a float into user memory */int reg_store_single(void){ float *single = (float *)FPU_data_address; long templ; unsigned long increment = 0; /* avoid gcc warnings */ if (FPU_st0_tag == TW_Valid) { int exp; FPU_REG tmp; reg_move(FPU_st0_ptr, &tmp); exp = tmp.exp - EXP_BIAS; if ( exp < SINGLE_Emin ) { int precision_loss; /* A denormal will always underflow. */#ifndef PECULIAR_486 /* An 80486 is supposed to be able to generate a denormal exception here, but... */ if ( FPU_st0_ptr->exp <= EXP_UNDER ) { /* Underflow has priority. */ if ( control_word & CW_Underflow ) denormal_operand(); }#endif PECULIAR_486 tmp.exp += -SINGLE_Emin + 23; /* largest exp to be 22 */ if ( (precision_loss = round_to_int(&tmp)) ) {#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) && ((FPU_st0_ptr->sigh & 0x000000ff) || FPU_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 & EX_Underflow) ) return 0; } EXCEPTION(precision_loss); if ( !(control_word & EX_Precision) ) return 0; } templ = tmp.sigl; } else { if ( tmp.sigl | (tmp.sigh & 0x000000ff) ) { unsigned long sigh = tmp.sigh; unsigned long sigl = tmp.sigl; 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 = (tmp.sign == SIGN_POS) ? 0 : (sigl | (sigh & 0xff)); break; case RC_UP: /* towards +infinity */ increment = (tmp.sign == SIGN_POS) ? (sigl | (sigh & 0xff)) : 0; break; case RC_CHOP: increment = 0; break; } /* Truncate part of the mantissa */ tmp.sigl = 0; if (increment) { set_precision_flag_up(); 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 { set_precision_flag_down(); tmp.sigh &= 0xffffff00; /* Finish the truncation */ } } 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 respose is overflow to infinity. */ templ = 0x7f800000; } else templ |= ((exp+SINGLE_Ebias) & 0xff) << 23; } } else if (FPU_st0_tag == TW_Zero) { templ = 0; } else if (FPU_st0_tag == TW_Infinity) { templ = 0x7f800000; } else if (FPU_st0_tag == TW_NaN) { /* See if we can get a valid NaN from the FPU_REG */ templ = FPU_st0_ptr->sigh >> 8; if ( !(FPU_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 if ( FPU_st0_tag == TW_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_verify_area(VERIFY_WRITE,(void *)single,4); put_fs_long(0xffc00000, (unsigned long *) single); RE_ENTRANT_CHECK_ON; return 1; } else return 0; }#ifdef PARANOID else { EXCEPTION(EX_INTERNAL|0x106); return 0; }#endif if (FPU_st0_ptr->sign) templ |= 0x80000000; RE_ENTRANT_CHECK_OFF; FPU_verify_area(VERIFY_WRITE,(void *)single,4); put_fs_long(templ,(unsigned long *) single); RE_ENTRANT_CHECK_ON; return 1;}/* Put a long long into user memory */int reg_store_int64(void){ long long *d = (long long *)FPU_data_address; FPU_REG t; long long tll; int precision_loss; if ( FPU_st0_tag == TW_Empty ) { /* Empty register (stack underflow) */ EXCEPTION(EX_StackUnder); goto invalid_operand; } else if ( (FPU_st0_tag == TW_Infinity) || (FPU_st0_tag == TW_NaN) ) { EXCEPTION(EX_Invalid); goto invalid_operand; } reg_move(FPU_st0_ptr, &t); precision_loss = round_to_int(&t); ((long *)&tll)[0] = t.sigl; ((long *)&tll)[1] = t.sigh; if ( (precision_loss == 1) || ((t.sigh & 0x80000000) && !((t.sigh == 0x80000000) && (t.sigl == 0) && (t.sign == SIGN_NEG))) ) { 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 ( t.sign ) tll = - tll; } RE_ENTRANT_CHECK_OFF; FPU_verify_area(VERIFY_WRITE,(void *)d,8); put_fs_long(((long *)&tll)[0],(unsigned long *) d); put_fs_long(((long *)&tll)[1],1 + (unsigned long *) d); RE_ENTRANT_CHECK_ON; return 1;}/* Put a long into user memory */int reg_store_int32(void){ long *d = (long *)FPU_data_address; FPU_REG t; int precision_loss; if ( FPU_st0_tag == TW_Empty ) { /* Empty register (stack underflow) */ EXCEPTION(EX_StackUnder); goto invalid_operand; } else if ( (FPU_st0_tag == TW_Infinity) || (FPU_st0_tag == TW_NaN) ) { EXCEPTION(EX_Invalid); goto invalid_operand; } reg_move(FPU_st0_ptr, &t); precision_loss = round_to_int(&t); if (t.sigh || ((t.sigl & 0x80000000) && !((t.sigl == 0x80000000) && (t.sign == SIGN_NEG))) ) { 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" */ t.sigl = 0x80000000; } else return 0; } else { if ( precision_loss ) set_precision_flag(precision_loss); if ( t.sign ) t.sigl = -(long)t.sigl; } RE_ENTRANT_CHECK_OFF; FPU_verify_area(VERIFY_WRITE,d,4); put_fs_long(t.sigl, (unsigned long *) d); RE_ENTRANT_CHECK_ON; return 1;}/* Put a short into user memory */int reg_store_int16(void){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -