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