📄 fpu_trig.c
字号:
if ( arith_invalid(1) < 0 ) return; } else if ( (st0_tag == TW_Denormal) && (denormal_operand() < 0) ) return; else { if ( exponent(st0_ptr) < 0 ) sign ^= SIGN_NEG; FPU_copy_to_reg1(&CONST_Z, TAG_Zero); setsign(st1_ptr, sign); } } else { /* One or both operands are denormals. */ if ( denormal_operand() < 0 ) return; goto both_valid; } } else if ( (st0_tag == TW_NaN) || (st1_tag == TW_NaN) ) { if ( real_2op_NaN(st0_ptr, st0_tag, 1, st0_ptr) < 0 ) return; } /* One or both arg must be an infinity */ else if ( st0_tag == TW_Infinity ) { if ( (signnegative(st0_ptr)) || (st1_tag == TAG_Zero) ) { /* log(-infinity) or 0*log(infinity) */ if ( arith_invalid(1) < 0 ) return; } else { u_char sign = getsign(st1_ptr); if ( (st1_tag == TW_Denormal) && (denormal_operand() < 0) ) return; FPU_copy_to_reg1(&CONST_INF, TAG_Special); setsign(st1_ptr, sign); } } /* st(1) must be infinity here */ else if ( ((st0_tag == TAG_Valid) || (st0_tag == TW_Denormal)) && ( signpositive(st0_ptr) ) ) { if ( exponent(st0_ptr) >= 0 ) { if ( (exponent(st0_ptr) == 0) && (st0_ptr->sigh == 0x80000000) && (st0_ptr->sigl == 0) ) { /* st(0) holds 1.0 */ /* infinity*log(1) */ if ( arith_invalid(1) < 0 ) return; } /* else st(0) is positive and > 1.0 */ } else { /* st(0) is positive and < 1.0 */ if ( (st0_tag == TW_Denormal) && (denormal_operand() < 0) ) return; changesign(st1_ptr); } } else { /* st(0) must be zero or negative */ if ( st0_tag == TAG_Zero ) { /* This should be invalid, but a real 80486 is happy with it. */#ifndef PECULIAR_486 sign = getsign(st1_ptr); if ( FPU_divide_by_zero(1, sign) < 0 ) return;#endif /* PECULIAR_486 */ changesign(st1_ptr); } else if ( arith_invalid(1) < 0 ) /* log(negative) */ return; } FPU_pop();}static void fpatan(FPU_REG *st0_ptr, u_char st0_tag){ FPU_REG *st1_ptr = &st(1); u_char st1_tag = FPU_gettagi(1); int tag; clear_C1(); if ( !((st0_tag ^ TAG_Valid) | (st1_tag ^ TAG_Valid)) ) { valid_atan: poly_atan(st0_ptr, st0_tag, st1_ptr, st1_tag); FPU_pop(); return; } if ( st0_tag == TAG_Special ) st0_tag = FPU_Special(st0_ptr); if ( st1_tag == TAG_Special ) st1_tag = FPU_Special(st1_ptr); if ( ((st0_tag == TAG_Valid) && (st1_tag == TW_Denormal)) || ((st0_tag == TW_Denormal) && (st1_tag == TAG_Valid)) || ((st0_tag == TW_Denormal) && (st1_tag == TW_Denormal)) ) { if ( denormal_operand() < 0 ) return; goto valid_atan; } else if ( (st0_tag == TAG_Empty) || (st1_tag == TAG_Empty) ) { FPU_stack_underflow_pop(1); return; } else if ( (st0_tag == TW_NaN) || (st1_tag == TW_NaN) ) { if ( real_2op_NaN(st0_ptr, st0_tag, 1, st0_ptr) >= 0 ) FPU_pop(); return; } else if ( (st0_tag == TW_Infinity) || (st1_tag == TW_Infinity) ) { u_char sign = getsign(st1_ptr); if ( st0_tag == TW_Infinity ) { if ( st1_tag == TW_Infinity ) { if ( signpositive(st0_ptr) ) { FPU_copy_to_reg1(&CONST_PI4, TAG_Valid); } else { setpositive(st1_ptr); tag = FPU_u_add(&CONST_PI4, &CONST_PI2, st1_ptr, FULL_PRECISION, SIGN_POS, exponent(&CONST_PI4), exponent(&CONST_PI2)); if ( tag >= 0 ) FPU_settagi(1, tag); } } else { if ( (st1_tag == TW_Denormal) && (denormal_operand() < 0) ) return; if ( signpositive(st0_ptr) ) { FPU_copy_to_reg1(&CONST_Z, TAG_Zero); setsign(st1_ptr, sign); /* An 80486 preserves the sign */ FPU_pop(); return; } else { FPU_copy_to_reg1(&CONST_PI, TAG_Valid); } } } else { /* st(1) is infinity, st(0) not infinity */ if ( (st0_tag == TW_Denormal) && (denormal_operand() < 0) ) return; FPU_copy_to_reg1(&CONST_PI2, TAG_Valid); } setsign(st1_ptr, sign); } else if ( st1_tag == TAG_Zero ) { /* st(0) must be valid or zero */ u_char sign = getsign(st1_ptr); if ( (st0_tag == TW_Denormal) && (denormal_operand() < 0) ) return; if ( signpositive(st0_ptr) ) { /* An 80486 preserves the sign */ FPU_pop(); return; } FPU_copy_to_reg1(&CONST_PI, TAG_Valid); setsign(st1_ptr, sign); } else if ( st0_tag == TAG_Zero ) { /* st(1) must be TAG_Valid here */ u_char sign = getsign(st1_ptr); if ( (st1_tag == TW_Denormal) && (denormal_operand() < 0) ) return; FPU_copy_to_reg1(&CONST_PI2, TAG_Valid); setsign(st1_ptr, sign); }#ifdef PARANOID else EXCEPTION(EX_INTERNAL | 0x125);#endif /* PARANOID */ FPU_pop(); set_precision_flag_up(); /* We do not really know if up or down */}static void fprem(FPU_REG *st0_ptr, u_char st0_tag){ do_fprem(st0_ptr, st0_tag, RC_CHOP);}static void fprem1(FPU_REG *st0_ptr, u_char st0_tag){ do_fprem(st0_ptr, st0_tag, RC_RND);}static void fyl2xp1(FPU_REG *st0_ptr, u_char st0_tag){ u_char sign, sign1; FPU_REG *st1_ptr = &st(1), a, b; u_char st1_tag = FPU_gettagi(1); clear_C1(); if ( !((st0_tag ^ TAG_Valid) | (st1_tag ^ TAG_Valid)) ) { valid_yl2xp1: sign = getsign(st0_ptr); sign1 = getsign(st1_ptr); FPU_to_exp16(st0_ptr, &a); FPU_to_exp16(st1_ptr, &b); if ( poly_l2p1(sign, sign1, &a, &b, st1_ptr) ) return; FPU_pop(); return; } if ( st0_tag == TAG_Special ) st0_tag = FPU_Special(st0_ptr); if ( st1_tag == TAG_Special ) st1_tag = FPU_Special(st1_ptr); if ( ((st0_tag == TAG_Valid) && (st1_tag == TW_Denormal)) || ((st0_tag == TW_Denormal) && (st1_tag == TAG_Valid)) || ((st0_tag == TW_Denormal) && (st1_tag == TW_Denormal)) ) { if ( denormal_operand() < 0 ) return; goto valid_yl2xp1; } else if ( (st0_tag == TAG_Empty) | (st1_tag == TAG_Empty) ) { FPU_stack_underflow_pop(1); return; } else if ( st0_tag == TAG_Zero ) { switch ( st1_tag ) { case TW_Denormal: if ( denormal_operand() < 0 ) return; case TAG_Zero: case TAG_Valid: setsign(st0_ptr, getsign(st0_ptr) ^ getsign(st1_ptr)); FPU_copy_to_reg1(st0_ptr, st0_tag); break; case TW_Infinity: /* Infinity*log(1) */ if ( arith_invalid(1) < 0 ) return; break; case TW_NaN: if ( real_2op_NaN(st0_ptr, st0_tag, 1, st0_ptr) < 0 ) return; break; default:#ifdef PARANOID EXCEPTION(EX_INTERNAL | 0x116); return;#endif /* PARANOID */ break; } } else if ( (st0_tag == TAG_Valid) || (st0_tag == TW_Denormal) ) { switch ( st1_tag ) { case TAG_Zero: if ( signnegative(st0_ptr) ) { if ( exponent(st0_ptr) >= 0 ) { /* st(0) holds <= -1.0 */#ifdef PECULIAR_486 /* Stupid 80486 doesn't worry about log(negative). */ changesign(st1_ptr);#else if ( arith_invalid(1) < 0 ) return;#endif /* PECULIAR_486 */ } else if ( (st0_tag == TW_Denormal) && (denormal_operand() < 0) ) return; else changesign(st1_ptr); } else if ( (st0_tag == TW_Denormal) && (denormal_operand() < 0) ) return; break; case TW_Infinity: if ( signnegative(st0_ptr) ) { if ( (exponent(st0_ptr) >= 0) && !((st0_ptr->sigh == 0x80000000) && (st0_ptr->sigl == 0)) ) { /* st(0) holds < -1.0 */#ifdef PECULIAR_486 /* Stupid 80486 doesn't worry about log(negative). */ changesign(st1_ptr);#else if ( arith_invalid(1) < 0 ) return;#endif /* PECULIAR_486 */ } else if ( (st0_tag == TW_Denormal) && (denormal_operand() < 0) ) return; else changesign(st1_ptr); } else if ( (st0_tag == TW_Denormal) && (denormal_operand() < 0) ) return; break; case TW_NaN: if ( real_2op_NaN(st0_ptr, st0_tag, 1, st0_ptr) < 0 ) return; } } else if ( st0_tag == TW_NaN ) { if ( real_2op_NaN(st0_ptr, st0_tag, 1, st0_ptr) < 0 ) return; } else if ( st0_tag == TW_Infinity ) { if ( st1_tag == TW_NaN ) { if ( real_2op_NaN(st0_ptr, st0_tag, 1, st0_ptr) < 0 ) return; } else if ( signnegative(st0_ptr) ) {#ifndef PECULIAR_486 /* This should have higher priority than denormals, but... */ if ( arith_invalid(1) < 0 ) /* log(-infinity) */ return;#endif /* PECULIAR_486 */ if ( (st1_tag == TW_Denormal) && (denormal_operand() < 0) ) return;#ifdef PECULIAR_486 /* Denormal operands actually get higher priority */ if ( arith_invalid(1) < 0 ) /* log(-infinity) */ return;#endif /* PECULIAR_486 */ } else if ( st1_tag == TAG_Zero ) { /* log(infinity) */ if ( arith_invalid(1) < 0 ) return; } /* st(1) must be valid here. */ else if ( (st1_tag == TW_Denormal) && (denormal_operand() < 0) ) return; /* The Manual says that log(Infinity) is invalid, but a real 80486 sensibly says that it is o.k. */ else { u_char sign = getsign(st1_ptr); FPU_copy_to_reg1(&CONST_INF, TAG_Special); setsign(st1_ptr, sign); } }#ifdef PARANOID else { EXCEPTION(EX_INTERNAL | 0x117); return; }#endif /* PARANOID */ FPU_pop(); return;}static void fscale(FPU_REG *st0_ptr, u_char st0_tag){ FPU_REG *st1_ptr = &st(1); u_char st1_tag = FPU_gettagi(1); int old_cw = control_word; u_char sign = getsign(st0_ptr); clear_C1(); if ( !((st0_tag ^ TAG_Valid) | (st1_tag ^ TAG_Valid)) ) { long scale; FPU_REG tmp; /* Convert register for internal use. */ setexponent16(st0_ptr, exponent(st0_ptr)); valid_scale: if ( exponent(st1_ptr) > 30 ) { /* 2^31 is far too large, would require 2^(2^30) or 2^(-2^30) */ if ( signpositive(st1_ptr) ) { EXCEPTION(EX_Overflow); FPU_copy_to_reg0(&CONST_INF, TAG_Special); } else { EXCEPTION(EX_Underflow); FPU_copy_to_reg0(&CONST_Z, TAG_Zero); } setsign(st0_ptr, sign); return; } control_word &= ~CW_RC; control_word |= RC_CHOP; reg_copy(st1_ptr, &tmp); FPU_round_to_int(&tmp, st1_tag); /* This can never overflow here */ control_word = old_cw; scale = signnegative(st1_ptr) ? -tmp.sigl : tmp.sigl; scale += exponent16(st0_ptr); setexponent16(st0_ptr, scale); /* Use FPU_round() to properly detect under/overflow etc */ FPU_round(st0_ptr, 0, 0, control_word, sign); return; } if ( st0_tag == TAG_Special ) st0_tag = FPU_Special(st0_ptr); if ( st1_tag == TAG_Special ) st1_tag = FPU_Special(st1_ptr); if ( (st0_tag == TAG_Valid) || (st0_tag == TW_Denormal) ) { switch ( st1_tag ) { case TAG_Valid: /* st(0) must be a denormal */ if ( (st0_tag == TW_Denormal) && (denormal_operand() < 0) ) return; FPU_to_exp16(st0_ptr, st0_ptr); /* Will not be left on stack */ goto valid_scale; case TAG_Zero: if ( st0_tag == TW_Denormal ) denormal_operand(); return; case TW_Denormal: denormal_operand(); return; case TW_Infinity: if ( (st0_tag == TW_Denormal) && (denormal_operand() < 0) ) return; if ( signpositive(st1_ptr) ) FPU_copy_to_reg0(&CONST_INF, TAG_Special); else FPU_copy_to_reg0(&CONST_Z, TAG_Zero); setsign(st0_ptr, sign); return; case TW_NaN: real_2op_NaN(st1_ptr, st1_tag, 0, st0_ptr); return; } } else if ( st0_tag == TAG_Zero ) { switch ( st1_tag ) { case TAG_Valid: case TAG_Zero: return; case TW_Denormal: denormal_operand(); return; case TW_Infinity: if ( signpositive(st1_ptr) ) arith_invalid(0); /* Zero scaled by +Infinity */ return; case TW_NaN: real_2op_NaN(st1_ptr, st1_tag, 0, st0_ptr); return; } } else if ( st0_tag == TW_Infinity ) { switch ( st1_tag ) { case TAG_Valid: case TAG_Zero: return; case TW_Denormal: denormal_operand(); return; case TW_Infinity: if ( signnegative(st1_ptr) ) arith_invalid(0); /* Infinity scaled by -Infinity */ return; case TW_NaN: real_2op_NaN(st1_ptr, st1_tag, 0, st0_ptr); return; } } else if ( st0_tag == TW_NaN ) { if ( st1_tag != TAG_Empty ) { real_2op_NaN(st1_ptr, st1_tag, 0, st0_ptr); return; } }#ifdef PARANOID if ( !((st0_tag == TAG_Empty) || (st1_tag == TAG_Empty)) ) { EXCEPTION(EX_INTERNAL | 0x115); return; }#endif /* At least one of st(0), st(1) must be empty */ FPU_stack_underflow();}/*---------------------------------------------------------------------------*/static FUNC_ST0 const trig_table_a[] = { f2xm1, fyl2x, fptan, fpatan, fxtract, fprem1, (FUNC_ST0)fdecstp, (FUNC_ST0)fincstp};void FPU_triga(void){ (trig_table_a[FPU_rm])(&st(0), FPU_gettag0());}static FUNC_ST0 const trig_table_b[] = { fprem, fyl2xp1, fsqrt_, fsincos, frndint_, fscale, (FUNC_ST0)fsin, fcos };void FPU_trigb(void){ (trig_table_b[FPU_rm])(&st(0), FPU_gettag0());}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -