?? fpu_trig.c
字號:
pop();
}
return;
}
}
static void fpatan(void)
{
FPU_REG *st1_ptr = &st(1);
char st1_tag = st1_ptr->tag;
char st1_sign = st1_ptr->sign, st0_sign = FPU_st0_ptr->sign;
clear_C1();
if ( !((FPU_st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid)) )
{
int saved_control, saved_status;
FPU_REG sum;
char inverted;
#ifdef DENORM_OPERAND
if ( ((FPU_st0_ptr->exp <= EXP_UNDER) ||
(st1_ptr->exp <= EXP_UNDER)) && (denormal_operand()) )
return;
#endif DENORM_OPERAND
/* We use the general purpose arithmetic so we need to save these. */
saved_status = partial_status;
saved_control = control_word;
control_word = FULL_PRECISION;
st1_ptr->sign = FPU_st0_ptr->sign = SIGN_POS;
if ( (compare(st1_ptr) & ~COMP_Denormal) == COMP_A_lt_B )
{
inverted = 1;
reg_div(FPU_st0_ptr, st1_ptr, &sum, FULL_PRECISION);
}
else
{
inverted = 0;
if ( (st0_sign == 0) &&
(st1_ptr->exp - FPU_st0_ptr->exp < -64) )
{
control_word = saved_control;
partial_status = saved_status;
reg_div(st1_ptr, FPU_st0_ptr, st1_ptr,
control_word | PR_64_BITS);
st1_ptr->sign = st1_sign;
pop();
set_precision_flag_down();
return;
}
reg_div(st1_ptr, FPU_st0_ptr, &sum, FULL_PRECISION);
}
poly_atan(&sum);
if ( inverted )
{
reg_sub(&CONST_PI2, &sum, &sum, FULL_PRECISION);
}
if ( st0_sign )
{
reg_sub(&CONST_PI, &sum, &sum, FULL_PRECISION);
}
sum.sign = st1_sign;
/* All of the basic arithmetic is done now */
control_word = saved_control;
partial_status = saved_status;
reg_move(&sum, st1_ptr);
}
else if ( (FPU_st0_tag == TW_Empty) || (st1_tag == TW_Empty) )
{
stack_underflow_pop(1);
return;
}
else if ( (FPU_st0_tag == TW_NaN) || (st1_tag == TW_NaN) )
{
if ( !real_2op_NaN(FPU_st0_ptr, st1_ptr, st1_ptr) )
pop();
return;
}
else if ( (FPU_st0_tag == TW_Infinity) || (st1_tag == TW_Infinity) )
{
char sign = st1_ptr->sign;
if ( FPU_st0_tag == TW_Infinity )
{
if ( st1_tag == TW_Infinity )
{
if ( FPU_st0_ptr->sign == SIGN_POS )
{ reg_move(&CONST_PI4, st1_ptr); }
else
reg_add(&CONST_PI4, &CONST_PI2, st1_ptr, FULL_PRECISION);
}
else
{
#ifdef DENORM_OPERAND
if ( st1_tag != TW_Zero )
{
if ( (st1_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
return;
}
#endif DENORM_OPERAND
if ( FPU_st0_ptr->sign == SIGN_POS )
{
reg_move(&CONST_Z, st1_ptr);
st1_ptr->sign = sign; /* An 80486 preserves the sign */
pop();
return;
}
else
reg_move(&CONST_PI, st1_ptr);
}
}
else
{
/* st(1) is infinity, st(0) not infinity */
#ifdef DENORM_OPERAND
if ( FPU_st0_tag != TW_Zero )
{
if ( (FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
return;
}
#endif DENORM_OPERAND
reg_move(&CONST_PI2, st1_ptr);
}
st1_ptr->sign = sign;
}
else if ( st1_tag == TW_Zero )
{
/* st(0) must be valid or zero */
char sign = st1_ptr->sign;
#ifdef DENORM_OPERAND
if ( FPU_st0_tag != TW_Zero )
{
if ( (FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
return;
}
#endif DENORM_OPERAND
if ( FPU_st0_ptr->sign == SIGN_POS )
{ /* An 80486 preserves the sign */ pop(); return; }
else
reg_move(&CONST_PI, st1_ptr);
st1_ptr->sign = sign;
}
else if ( FPU_st0_tag == TW_Zero )
{
/* st(1) must be TW_Valid here */
char sign = st1_ptr->sign;
#ifdef DENORM_OPERAND
if ( (st1_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
return;
#endif DENORM_OPERAND
reg_move(&CONST_PI2, st1_ptr);
st1_ptr->sign = sign;
}
#ifdef PARANOID
else
EXCEPTION(EX_INTERNAL | 0x125);
#endif PARANOID
pop();
set_precision_flag_up(); /* We do not really know if up or down */
}
static void fprem(void)
{
do_fprem(RC_CHOP);
}
static void fprem1(void)
{
do_fprem(RC_RND);
}
static void fyl2xp1(void)
{
FPU_REG *st1_ptr = &st(1);
char st1_tag = st1_ptr->tag;
clear_C1();
if ( !((FPU_st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid)) )
{
int saved_control, saved_status;
#ifdef DENORM_OPERAND
if ( ((FPU_st0_ptr->exp <= EXP_UNDER) ||
(st1_ptr->exp <= EXP_UNDER)) && denormal_operand() )
return;
#endif DENORM_OPERAND
/* We use the general purpose arithmetic so we need to save these. */
saved_status = partial_status;
saved_control = control_word;
control_word = FULL_PRECISION;
if ( poly_l2p1(FPU_st0_ptr, FPU_st0_ptr) )
{
#ifdef PECULIAR_486 /* Stupid 80486 doesn't worry about log(negative). */
st1_ptr->sign ^= SIGN_POS^SIGN_NEG;
control_word = saved_control;
partial_status = saved_status;
set_precision_flag_down();
#else
if ( arith_invalid(st1_ptr) ) /* poly_l2p1() returned invalid */
return;
#endif PECULIAR_486
pop(); return;
}
/* Enough of the basic arithmetic is done now */
control_word = saved_control;
partial_status = saved_status;
/* Let the multiply set the flags */
reg_mul(FPU_st0_ptr, st1_ptr, st1_ptr, FULL_PRECISION);
pop();
}
else if ( (FPU_st0_tag == TW_Empty) | (st1_tag == TW_Empty) )
{
stack_underflow_pop(1);
return;
}
else if ( FPU_st0_tag == TW_Zero )
{
if ( st1_tag <= TW_Zero )
{
#ifdef DENORM_OPERAND
if ( (st1_tag == TW_Valid) && (st1_ptr->exp <= EXP_UNDER) &&
(denormal_operand()) )
return;
#endif DENORM_OPERAND
FPU_st0_ptr->sign ^= st1_ptr->sign;
reg_move(FPU_st0_ptr, st1_ptr);
}
else if ( st1_tag == TW_Infinity )
{
/* Infinity*log(1) */
if ( !arith_invalid(st1_ptr) )
pop();
return;
}
else if ( st1_tag == TW_NaN )
{
if ( !real_2op_NaN(FPU_st0_ptr, st1_ptr, st1_ptr) )
pop();
return;
}
#ifdef PARANOID
else
{
EXCEPTION(EX_INTERNAL | 0x116);
return;
}
#endif PARANOID
pop(); return;
}
else if ( FPU_st0_tag == TW_Valid )
{
if ( st1_tag == TW_Zero )
{
if ( FPU_st0_ptr->sign == SIGN_NEG )
{
if ( FPU_st0_ptr->exp >= EXP_BIAS )
{
/* st(0) holds <= -1.0 */
#ifdef PECULIAR_486 /* Stupid 80486 doesn't worry about log(negative). */
st1_ptr->sign ^= SIGN_POS^SIGN_NEG;
#else
if ( arith_invalid(st1_ptr) ) return;
#endif PECULIAR_486
pop(); return;
}
#ifdef DENORM_OPERAND
if ( (FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
return;
#endif DENORM_OPERAND
st1_ptr->sign ^= SIGN_POS^SIGN_NEG;
pop(); return;
}
#ifdef DENORM_OPERAND
if ( (FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
return;
#endif DENORM_OPERAND
pop(); return;
}
if ( st1_tag == TW_Infinity )
{
if ( FPU_st0_ptr->sign == SIGN_NEG )
{
if ( (FPU_st0_ptr->exp >= EXP_BIAS) &&
!((FPU_st0_ptr->sigh == 0x80000000) &&
(FPU_st0_ptr->sigl == 0)) )
{
/* st(0) holds < -1.0 */
#ifdef PECULIAR_486 /* Stupid 80486 doesn't worry about log(negative). */
st1_ptr->sign ^= SIGN_POS^SIGN_NEG;
#else
if ( arith_invalid(st1_ptr) ) return;
#endif PECULIAR_486
pop(); return;
}
#ifdef DENORM_OPERAND
if ( (FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
return;
#endif DENORM_OPERAND
st1_ptr->sign ^= SIGN_POS^SIGN_NEG;
pop(); return;
}
#ifdef DENORM_OPERAND
if ( (FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
return;
#endif DENORM_OPERAND
pop(); return;
}
if ( st1_tag == TW_NaN )
{
if ( !real_2op_NaN(FPU_st0_ptr, st1_ptr, st1_ptr) )
pop();
return;
}
}
else if ( FPU_st0_tag == TW_NaN )
{
if ( !real_2op_NaN(FPU_st0_ptr, st1_ptr, st1_ptr) )
pop();
return;
}
else if ( FPU_st0_tag == TW_Infinity )
{
if ( st1_tag == TW_NaN )
{
if ( !real_2op_NaN(FPU_st0_ptr, st1_ptr, st1_ptr) )
pop();
return;
}
else if ( FPU_st0_ptr->sign == SIGN_NEG )
{
int exponent = st1_ptr->exp;
#ifndef PECULIAR_486
/* This should have higher priority than denormals, but... */
if ( arith_invalid(st1_ptr) ) /* log(-infinity) */
return;
#endif PECULIAR_486
#ifdef DENORM_OPERAND
if ( st1_tag != TW_Zero )
{
if ( (exponent <= EXP_UNDER) && (denormal_operand()) )
return;
}
#endif DENORM_OPERAND
#ifdef PECULIAR_486
/* Denormal operands actually get higher priority */
if ( arith_invalid(st1_ptr) ) /* log(-infinity) */
return;
#endif PECULIAR_486
pop();
return;
}
else if ( st1_tag == TW_Zero )
{
/* log(infinity) */
if ( !arith_invalid(st1_ptr) )
pop();
return;
}
/* st(1) must be valid here. */
#ifdef DENORM_OPERAND
if ( (st1_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
return;
#endif DENORM_OPERAND
/* The Manual says that log(Infinity) is invalid, but a real
80486 sensibly says that it is o.k. */
{ char sign = st1_ptr->sign;
reg_move(&CONST_INF, st1_ptr);
st1_ptr->sign = sign;
}
pop();
return;
}
#ifdef PARANOID
else
{
EXCEPTION(EX_INTERNAL | 0x117);
}
#endif PARANOID
}
static void fscale(void)
{
FPU_REG *st1_ptr = &st(1);
char st1_tag = st1_ptr->tag;
int old_cw = control_word;
char sign = FPU_st0_ptr->sign;
clear_C1();
if ( !((FPU_st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid)) )
{
long scale;
FPU_REG tmp;
#ifdef DENORM_OPERAND
if ( ((FPU_st0_ptr->exp <= EXP_UNDER) ||
(st1_ptr->exp <= EXP_UNDER)) && (denormal_operand()) )
return;
#endif DENORM_OPERAND
if ( st1_ptr->exp > EXP_BIAS + 30 )
{
/* 2^31 is far too large, would require 2^(2^30) or 2^(-2^30) */
char sign;
if ( st1_ptr->sign == SIGN_POS )
{
EXCEPTION(EX_Overflow);
sign = FPU_st0_ptr->sign;
reg_move(&CONST_INF, FPU_st0_ptr);
FPU_st0_ptr->sign = sign;
}
else
{
EXCEPTION(EX_Underflow);
sign = FPU_st0_ptr->sign;
reg_move(&CONST_Z, FPU_st0_ptr);
FPU_st0_ptr->sign = sign;
}
return;
}
control_word &= ~CW_RC;
control_word |= RC_CHOP;
reg_move(st1_ptr, &tmp);
round_to_int(&tmp); /* This can never overflow here */
control_word = old_cw;
scale = st1_ptr->sign ? -tmp.sigl : tmp.sigl;
scale += FPU_st0_ptr->exp;
FPU_st0_ptr->exp = scale;
/* Use round_reg() to properly detect under/overflow etc */
round_reg(FPU_st0_ptr, 0, control_word);
return;
}
else if ( FPU_st0_tag == TW_Valid )
{
if ( st1_tag == TW_Zero )
{
#ifdef DENORM_OPERAND
if ( (FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
return;
#endif DENORM_OPERAND
return;
}
if ( st1_tag == TW_Infinity )
{
#ifdef DENORM_OPERAND
if ( (FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
return;
#endif DENORM_OPERAND
if ( st1_ptr->sign == SIGN_POS )
{ reg_move(&CONST_INF, FPU_st0_ptr); }
else
reg_move(&CONST_Z, FPU_st0_ptr);
FPU_st0_ptr->sign = sign;
return;
}
if ( st1_tag == TW_NaN )
{ real_2op_NaN(FPU_st0_ptr, st1_ptr, FPU_st0_ptr); return; }
}
else if ( FPU_st0_tag == TW_Zero )
{
if ( st1_tag == TW_Valid )
{
#ifdef DENORM_OPERAND
if ( (st1_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
return;
#endif DENORM_OPERAND
return;
}
else if ( st1_tag == TW_Zero ) { return; }
else if ( st1_tag == TW_Infinity )
{
if ( st1_ptr->sign == SIGN_NEG )
return;
else
{
arith_invalid(FPU_st0_ptr); /* Zero scaled by +Infinity */
return;
}
}
else if ( st1_tag == TW_NaN )
{ real_2op_NaN(FPU_st0_ptr, st1_ptr, FPU_st0_ptr); return; }
}
else if ( FPU_st0_tag == TW_Infinity )
{
if ( st1_tag == TW_Valid )
{
#ifdef DENORM_OPERAND
if ( (st1_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
return;
#endif DENORM_OPERAND
return;
}
if ( ((st1_tag == TW_Infinity) && (st1_ptr->sign == SIGN_POS))
|| (st1_tag == TW_Zero) )
return;
else if ( st1_tag == TW_Infinity )
{
arith_invalid(FPU_st0_ptr); /* Infinity scaled by -Infinity */
return;
}
else if ( st1_tag == TW_NaN )
{ real_2op_NaN(FPU_st0_ptr, st1_ptr, FPU_st0_ptr); return; }
}
else if ( FPU_st0_tag == TW_NaN )
{
if ( st1_tag != TW_Empty )
{ real_2op_NaN(FPU_st0_ptr, st1_ptr, FPU_st0_ptr); return; }
}
#ifdef PARANOID
if ( !((FPU_st0_tag == TW_Empty) || (st1_tag == TW_Empty)) )
{
EXCEPTION(EX_INTERNAL | 0x115);
return;
}
#endif
/* At least one of st(0), st(1) must be empty */
stack_underflow();
}
/*---------------------------------------------------------------------------*/
static FUNC const trig_table_a[] = {
f2xm1, fyl2x, fptan, fpatan, fxtract, fprem1, fdecstp, fincstp
};
void trig_a(void)
{
(trig_table_a[FPU_rm])();
}
static FUNC const trig_table_b[] =
{
fprem, fyl2xp1, fsqrt_, fsincos, frndint_, fscale, fsin, fcos
};
void trig_b(void)
{
(trig_table_b[FPU_rm])();
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -