📄 reg_ld_str.c
字号:
/* This is a special case: see * sec 16.2.5.1 of the 80486 * book */ if (!(control_word & EX_Underflow)) return 0; } e = 0; ls = tmp.sigl; ms = tmp.sigh; } else { /* ****** ??? This should not be * possible */ EXCEPTION(EX_Underflow); /* Underflow */ /* This is a special case: see sec * 16.2.5.1 of the 80486 book */ if (control_word & EX_Underflow) { /* Underflow to zero */ ls = 0; ms = 0; e = FPU_st0_ptr->sign == SIGN_POS ? 0x7fff : 0xffff; } else return 0; } } else { ls = FPU_st0_ptr->sigl; ms = FPU_st0_ptr->sigh; } } else if (FPU_st0_tag == TW_Zero) { ls = ms = 0; e = 0; } else if (FPU_st0_tag == TW_Infinity) { ls = 0; ms = 0x80000000; e = 0x7fff; } else if (FPU_st0_tag == TW_NaN) { ls = FPU_st0_ptr->sigl; ms = FPU_st0_ptr->sigh; e = 0x7fff; } 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 */ ls = 0; ms = 0xc0000000; e = 0xffff; } else return 0; } else { /* We don't use TW_Denormal * yet ... perhaps never! */ EXCEPTION(EX_Invalid); /* Store a NaN */ e = 0x7fff; ls = 1; ms = 0x80000000; } REENTRANT_CHECK(OFF);/* verify_area(VERIFY_WRITE, d, 10); */ suword((unsigned long *) d, ls); suword(1 + (unsigned long *) d, ms); susword(4 + (short *) d, (unsigned short) e | sign); REENTRANT_CHECK(ON); return 1;}/* Put a double into user memory */intreg_store_double(void){ double *dfloat = (double *) FPU_data_address; unsigned long l[2]; if (FPU_st0_tag == TW_Valid) { int exp; FPU_REG tmp; reg_move(FPU_st0_ptr, &tmp); exp = tmp.exp - EXP_BIAS; if (exp < DOUBLE_Emin) { /* It may be a denormal */ /* Make a de-normal */ int precision_loss; if (exp <= -EXTENDED_Ebias) EXCEPTION(EX_Denormal); 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)) EXCEPTION(precision_loss); else#endif /* PECULIAR_486 */ { EXCEPTION(EX_Underflow | precision_loss); /* This is a special case: see sec * 16.2.5.1 of the 80486 book */ if (!(control_word & EX_Underflow)) return 0; } } l[0] = tmp.sigl; l[1] = tmp.sigh; } else { if (tmp.sigl & 0x000007ff) { unsigned long increment = 0; /* avoid gcc warnings */ 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); /* This is a special case: see sec 16.2.5.1 of * the 80486 book */ if (control_word & EX_Overflow) { /* Overflow to infinity */ l[0] = 0x00000000; /* Set to */ l[1] = 0x7ff00000; /* + INF */ } else return 0; } 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 (!(l[0] | l[1])) { /* This case does not seem to * be handled by the 80486 * specs */ EXCEPTION(EX_Invalid); /* Make the quiet NaN "real * indefinite" */ goto put_indefinite; } l[1] |= 0x7ff00000; } 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 */ put_indefinite: REENTRANT_CHECK(OFF); /* verify_area(VERIFY_W * RITE, (void *) * dfloat, 8); */ suword((unsigned long *) dfloat, 0); suword(1 + (unsigned long *) dfloat, 0xfff80000); REENTRANT_CHECK(ON); return 1; } else return 0; }#if 0 /* TW_Denormal is not used yet, and probably * won't be */ else if (FPU_st0_tag == TW_Denormal) { /* Extended real -> * double real will * always underflow */ l[0] = l[1] = 0; EXCEPTION(EX_Underflow); }#endif if (FPU_st0_ptr->sign) l[1] |= 0x80000000; REENTRANT_CHECK(OFF);/* verify_area(VERIFY_WRITE, (void *) dfloat, 8);*/ suword((u_long *) dfloat, l[0]); suword((u_long *) dfloat + 1, l[1]);/* suword(l[0], (unsigned long *) dfloat); suword(l[1], 1 + (unsigned long *) dfloat);*/ REENTRANT_CHECK(ON); return 1;}/* Put a float into user memory */intreg_store_single(void){ float *single = (float *) FPU_data_address; long templ = 0; 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) { /* Make a de-normal */ int precision_loss; if (exp <= -EXTENDED_Ebias) EXCEPTION(EX_Denormal); 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)) EXCEPTION(precision_loss); else#endif /* PECULIAR_486 */ { EXCEPTION(EX_Underflow | precision_loss); /* This is a special case: see sec * 16.2.5.1 of the 80486 book */ if (!(control_word & EX_Underflow)) return 0; } } templ = tmp.sigl; } else { if (tmp.sigl | (tmp.sigh & 0x000000ff)) { unsigned long increment = 0; /* avoid gcc warnings */ 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); /* This is a special case: see sec 16.2.5.1 of * the 80486 book */ if (control_word & EX_Overflow) { /* Overflow to infinity */ templ = 0x7f800000; } else return 0; } 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 (!(templ & 0x3fffff)) { /* This case does not seem to * be handled by the 80486 * specs */ EXCEPTION(EX_Invalid); /* Make the quiet NaN "real * indefinite" */ goto put_indefinite; } 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 */ put_indefinite: REENTRANT_CHECK(OFF);/* verify_area(VERIFY_WRITE, (void *) single, 4); */ suword((unsigned long *) single, 0xffc00000); REENTRANT_CHECK(ON); return 1; } else return 0; }#if 0 /* TW_Denormal is not used yet, and probably * won't be */ else if (FPU_st0_tag == TW_Denormal) { /* Extended real -> * real will always * underflow */ templ = 0; EXCEPTION(EX_Underflow); }#endif#ifdef PARANOID else { EXCEPTION(EX_INTERNAL | 0x106); return 0; }#endif if (FPU_st0_ptr->sign) templ |= 0x80000000; REENTRANT_CHECK(OFF);/* verify_area(VERIFY_WRITE, (void *) single, 4); */ suword((unsigned long *) single, templ); REENTRANT_CHECK(ON); return 1;}/* Put a long long into user memory */intreg_store_int64(void){ long long *d = (long long *) FPU_data_address; FPU_REG t; long long tll; 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 */ goto put_indefinite; } else return 0; } reg_move(FPU_st0_ptr, &t); round_to_int(&t); ((long *) &tll)[0] = t.sigl; ((long *) &tll)[1] = t.sigh; if ((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 */ if (control_word & EX_Invalid) { /* Produce "indefinite" */ put_indefinite: ((long *) &tll)[1] = 0x80000000;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -