📄 errors.c
字号:
}
else
printk("FPU emulator: Unknown Exception: 0x%04x!\n", n);
if ( n == EX_INTERNAL )
{
printk("FPU emulator: Internal error type 0x%04x\n", int_type);
emu_printall();
}
#ifdef PRINT_MESSAGES
else
emu_printall();
#endif PRINT_MESSAGES
/*
* The 80486 generates an interrupt on the next non-control FPU
* instruction. So we need some means of flagging it.
* We use the ES (Error Summary) bit for this, assuming that
* this is the way a real FPU does it (until I can check it out),
* if not, then some method such as the following kludge might
* be needed.
*/
/* regs[0].tag |= TW_FPU_Interrupt; */
}
RE_ENTRANT_CHECK_ON;
#ifdef __DEBUG__
math_abort(FPU_info,SIGFPE);
#endif __DEBUG__
}
/* Real operation attempted on two operands, one a NaN. */
/* Returns nz if the exception is unmasked */
asmlinkage int real_2op_NaN(FPU_REG const *a, FPU_REG const *b, FPU_REG *dest)
{
FPU_REG const *x;
int signalling;
/* The default result for the case of two "equal" NaNs (signs may
differ) is chosen to reproduce 80486 behaviour */
x = a;
if (a->tag == TW_NaN)
{
if (b->tag == TW_NaN)
{
signalling = !(a->sigh & b->sigh & 0x40000000);
/* find the "larger" */
if ( significand(a) < significand(b) )
x = b;
}
else
{
/* return the quiet version of the NaN in a */
signalling = !(a->sigh & 0x40000000);
}
}
else
#ifdef PARANOID
if (b->tag == TW_NaN)
#endif PARANOID
{
signalling = !(b->sigh & 0x40000000);
x = b;
}
#ifdef PARANOID
else
{
signalling = 0;
EXCEPTION(EX_INTERNAL|0x113);
x = &CONST_QNaN;
}
#endif PARANOID
if ( !signalling )
{
if ( !(x->sigh & 0x80000000) ) /* pseudo-NaN ? */
x = &CONST_QNaN;
reg_move(x, dest);
return 0;
}
if ( control_word & CW_Invalid )
{
/* The masked response */
if ( !(x->sigh & 0x80000000) ) /* pseudo-NaN ? */
x = &CONST_QNaN;
reg_move(x, dest);
/* ensure a Quiet NaN */
dest->sigh |= 0x40000000;
}
EXCEPTION(EX_Invalid);
return !(control_word & CW_Invalid);
}
/* Invalid arith operation on Valid registers */
/* Returns nz if the exception is unmasked */
asmlinkage int arith_invalid(FPU_REG *dest)
{
EXCEPTION(EX_Invalid);
if ( control_word & CW_Invalid )
{
/* The masked response */
reg_move(&CONST_QNaN, dest);
}
return !(control_word & CW_Invalid);
}
/* Divide a finite number by zero */
asmlinkage int divide_by_zero(int sign, FPU_REG *dest)
{
if ( control_word & CW_ZeroDiv )
{
/* The masked response */
reg_move(&CONST_INF, dest);
dest->sign = (unsigned char)sign;
}
EXCEPTION(EX_ZeroDiv);
return !(control_word & CW_ZeroDiv);
}
/* This may be called often, so keep it lean */
int set_precision_flag(int flags)
{
if ( control_word & CW_Precision )
{
partial_status &= ~(SW_C1 & flags);
partial_status |= flags; /* The masked response */
return 0;
}
else
{
exception(flags);
return 1;
}
}
/* This may be called often, so keep it lean */
asmlinkage void set_precision_flag_up(void)
{
if ( control_word & CW_Precision )
partial_status |= (SW_Precision | SW_C1); /* The masked response */
else
exception(EX_Precision | SW_C1);
}
/* This may be called often, so keep it lean */
asmlinkage void set_precision_flag_down(void)
{
if ( control_word & CW_Precision )
{ /* The masked response */
partial_status &= ~SW_C1;
partial_status |= SW_Precision;
}
else
exception(EX_Precision);
}
asmlinkage int denormal_operand(void)
{
if ( control_word & CW_Denormal )
{ /* The masked response */
partial_status |= SW_Denorm_Op;
return 0;
}
else
{
exception(EX_Denormal);
return 1;
}
}
asmlinkage int arith_overflow(FPU_REG *dest)
{
if ( control_word & CW_Overflow )
{
char sign;
/* The masked response */
/* ###### The response here depends upon the rounding mode */
sign = dest->sign;
reg_move(&CONST_INF, dest);
dest->sign = sign;
}
else
{
/* Subtract the magic number from the exponent */
dest->exp -= (3 * (1 << 13));
}
EXCEPTION(EX_Overflow);
if ( control_word & CW_Overflow )
{
/* The overflow exception is masked. */
/* By definition, precision is lost.
The roundup bit (C1) is also set because we have
"rounded" upwards to Infinity. */
EXCEPTION(EX_Precision | SW_C1);
return !(control_word & CW_Precision);
}
return !(control_word & CW_Overflow);
}
asmlinkage int arith_underflow(FPU_REG *dest)
{
if ( control_word & CW_Underflow )
{
/* The masked response */
if ( dest->exp <= EXP_UNDER - 63 )
{
reg_move(&CONST_Z, dest);
partial_status &= ~SW_C1; /* Round down. */
}
}
else
{
/* Add the magic number to the exponent. */
dest->exp += (3 * (1 << 13));
}
EXCEPTION(EX_Underflow);
if ( control_word & CW_Underflow )
{
/* The underflow exception is masked. */
EXCEPTION(EX_Precision);
return !(control_word & CW_Precision);
}
return !(control_word & CW_Underflow);
}
void stack_overflow(void)
{
if ( control_word & CW_Invalid )
{
/* The masked response */
top--;
reg_move(&CONST_QNaN, FPU_st0_ptr = &st(0));
}
EXCEPTION(EX_StackOver);
return;
}
void stack_underflow(void)
{
if ( control_word & CW_Invalid )
{
/* The masked response */
reg_move(&CONST_QNaN, FPU_st0_ptr);
}
EXCEPTION(EX_StackUnder);
return;
}
void stack_underflow_i(int i)
{
if ( control_word & CW_Invalid )
{
/* The masked response */
reg_move(&CONST_QNaN, &(st(i)));
}
EXCEPTION(EX_StackUnder);
return;
}
void stack_underflow_pop(int i)
{
if ( control_word & CW_Invalid )
{
/* The masked response */
reg_move(&CONST_QNaN, &(st(i)));
pop();
}
EXCEPTION(EX_StackUnder);
return;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -