📄 fpu_trig.c
字号:
reg_sub(&CONST_PI, &sum, &sum, FULL_PRECISION); } if (quadrant & 1) sum.sign ^= SIGN_POS ^ SIGN_NEG; /* All of the basic arithmetic is done now */ control_word = saved_control; status_word = 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)) { 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_ptr->exp <= EXP_UNDER) && (denormal_operand())) return;#endif /* DENORM_OPERAND */ if (FPU_st0_ptr->sign == SIGN_POS) { reg_move(&CONST_Z, st1_ptr); pop(); return; } else reg_move(&CONST_PI, st1_ptr); } } else { /* st(1) is infinity, st(0) * not infinity */#ifdef DENORM_OPERAND 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_ptr->exp <= EXP_UNDER) && (denormal_operand())) return;#endif /* DENORM_OPERAND */ if (FPU_st0_ptr->sign == SIGN_POS) { reg_move(&CONST_Z, st1_ptr); 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 | 0x220);#endif /* PARANOID */ pop(); set_precision_flag_up();/* We do not really know if up or down */}static voidfprem(void){ fprem_kernel(RC_CHOP);}static voidfprem1(void){ fprem_kernel(RC_RND);}static voidfyl2xp1(void){ FPU_REG *st1_ptr = &st(1); char st1_tag = st1_ptr->tag; 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 = status_word; saved_control = control_word; control_word = FULL_PRECISION; if (poly_l2p1(FPU_st0_ptr, FPU_st0_ptr)) { arith_invalid(st1_ptr); /* poly_l2p1() returned * invalid */ pop(); return; } /* Enough of the basic arithmetic is done now */ control_word = saved_control; status_word = 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 */ st1_ptr->sign ^= FPU_st0_ptr->sign; reg_move(FPU_st0_ptr, st1_ptr); } else if (st1_tag == TW_Infinity) { arith_invalid(st1_ptr); /* Infinity*log(1) */ pop(); return; } else if (st1_tag == TW_NaN) { 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 */ arith_invalid(st1_ptr); /* infinity*log(1) */ 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 */ arith_invalid(st1_ptr); 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) { real_2op_NaN(FPU_st0_ptr, st1_ptr, st1_ptr); pop(); return; } } else if (FPU_st0_tag == TW_NaN) { real_2op_NaN(FPU_st0_ptr, st1_ptr, st1_ptr); pop(); return; } else if (FPU_st0_tag == TW_Infinity) { if (st1_tag == TW_NaN) { real_2op_NaN(FPU_st0_ptr, st1_ptr, st1_ptr); pop(); return; } else if ((FPU_st0_ptr->sign == SIGN_NEG) || (st1_tag == TW_Zero)) { arith_invalid(st1_ptr); /* log(infinity) */ 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 voidemu_fscale(void){ FPU_REG *st1_ptr = &st(1); char st1_tag = st1_ptr->tag; int old_cw = control_word; 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) { char sign = st1_ptr->sign;#ifdef DENORM_OPERAND if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand())) return;#endif /* DENORM_OPERAND */ if (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 trig_table_a[] = { f2xm1, fyl2x, fptan, fpatan, fxtract, fprem1, fdecstp, fincstp};voidtrig_a(void){ (trig_table_a[FPU_rm]) ();}static FUNC trig_table_b[] ={ fprem, fyl2xp1, fsqrt_, fsincos, frndint_, emu_fscale, fsin, fcos};voidtrig_b(void){ (trig_table_b[FPU_rm]) ();}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -