⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fpu_trig.c

📁 LINUX 1.0 内核c源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
	    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 + -