📄 reg_ld_str.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 + -