コード例 #1
0
static void fsqrt_(FPU_REG *st0_ptr, u_char st0_tag)
{
	int expon;

	clear_C1();

	if (st0_tag == TAG_Valid) {
		u_char tag;

		if (signnegative(st0_ptr)) {
			arith_invalid(0);	
			return;
		}

		
		expon = exponent(st0_ptr);

	      denormal_arg:

		setexponent16(st0_ptr, (expon & 1));

		
		tag = wm_sqrt(st0_ptr, 0, 0, control_word, SIGN_POS);
		addexponent(st0_ptr, expon >> 1);
		FPU_settag0(tag);
		return;
	}
コード例 #2
0
ファイル: fpu_trig.c プロジェクト: 0-T-0/ps4-linux
static void fsqrt_(FPU_REG *st0_ptr, u_char st0_tag)
{
	int expon;

	clear_C1();

	if (st0_tag == TAG_Valid) {
		u_char tag;

		if (signnegative(st0_ptr)) {
			arith_invalid(0);	/* sqrt(negative) is invalid */
			return;
		}

		/* make st(0) in  [1.0 .. 4.0) */
		expon = exponent(st0_ptr);

	      denormal_arg:

		setexponent16(st0_ptr, (expon & 1));

		/* Do the computation, the sign of the result will be positive. */
		tag = wm_sqrt(st0_ptr, 0, 0, control_word, SIGN_POS);
		addexponent(st0_ptr, expon >> 1);
		FPU_settag0(tag);
		return;
	}
コード例 #3
0
ファイル: reg_constant.c プロジェクト: 0-T-0/ps4-linux
static void fld_const(FPU_REG const * c, int adj, u_char tag)
{
	FPU_REG *st_new_ptr;

	if (STACK_OVERFLOW) {
		FPU_stack_overflow();
		return;
	}
	push();
	reg_copy(c, st_new_ptr);
	st_new_ptr->sigl += adj;	/* For all our fldxxx constants, we don't need to
					   borrow or carry. */
	FPU_settag0(tag);
	clear_C1();
}
コード例 #4
0
static void fxtract(FPU_REG *st0_ptr, u_char st0_tag)
{
	FPU_REG *st_new_ptr;
	u_char sign;
	register FPU_REG *st1_ptr = st0_ptr;	

	if (STACK_OVERFLOW) {
		FPU_stack_overflow();
		return;
	}

	clear_C1();

	if (st0_tag == TAG_Valid) {
		long e;

		push();
		sign = getsign(st1_ptr);
		reg_copy(st1_ptr, st_new_ptr);
		setexponent16(st_new_ptr, exponent(st_new_ptr));

	      denormal_arg:

		e = exponent16(st_new_ptr);
		convert_l2reg(&e, 1);
		setexponentpos(st_new_ptr, 0);
		setsign(st_new_ptr, sign);
		FPU_settag0(TAG_Valid);	
		return;
	} else if (st0_tag == TAG_Zero) {
		sign = getsign(st0_ptr);

		if (FPU_divide_by_zero(0, SIGN_NEG) < 0)
			return;

		push();
		FPU_copy_to_reg0(&CONST_Z, TAG_Zero);
		setsign(st_new_ptr, sign);
		return;
	}

	if (st0_tag == TAG_Special)
		st0_tag = FPU_Special(st0_ptr);

	if (st0_tag == TW_Denormal) {
		if (denormal_operand() < 0)
			return;

		push();
		sign = getsign(st1_ptr);
		FPU_to_exp16(st1_ptr, st_new_ptr);
		goto denormal_arg;
	} else if (st0_tag == TW_Infinity) {
		sign = getsign(st0_ptr);
		setpositive(st0_ptr);
		push();
		FPU_copy_to_reg0(&CONST_INF, TAG_Special);
		setsign(st_new_ptr, sign);
		return;
	} else if (st0_tag == TW_NaN) {
		if (real_1op_NaN(st0_ptr) < 0)
			return;

		push();
		FPU_copy_to_reg0(st0_ptr, TAG_Special);
		return;
	} else if (st0_tag == TAG_Empty) {
		
		if (control_word & EX_Invalid) {
			FPU_stack_underflow();
			push();
			FPU_stack_underflow();
		} else
			EXCEPTION(EX_StackUnder);
	}
#ifdef PARANOID
	else
		EXCEPTION(EX_INTERNAL | 0x119);
#endif 
}
コード例 #5
0
static void fptan(FPU_REG *st0_ptr, u_char st0_tag)
{
	FPU_REG *st_new_ptr;
	int q;
	u_char arg_sign = getsign(st0_ptr);

	
	if (st0_tag == TAG_Empty) {
		FPU_stack_underflow();	
		if (control_word & CW_Invalid) {
			st_new_ptr = &st(-1);
			push();
			FPU_stack_underflow();	
		}
		return;
	}

	if (STACK_OVERFLOW) {
		FPU_stack_overflow();
		return;
	}

	if (st0_tag == TAG_Valid) {
		if (exponent(st0_ptr) > -40) {
			if ((q = trig_arg(st0_ptr, 0)) == -1) {
				
				return;
			}

			poly_tan(st0_ptr);
			setsign(st0_ptr, (q & 1) ^ (arg_sign != 0));
			set_precision_flag_up();	
		} else {
			
			

		      denormal_arg:

			FPU_to_exp16(st0_ptr, st0_ptr);

			st0_tag =
			    FPU_round(st0_ptr, 1, 0, FULL_PRECISION, arg_sign);
			FPU_settag0(st0_tag);
		}
		push();
		FPU_copy_to_reg0(&CONST_1, TAG_Valid);
		return;
	}

	if (st0_tag == TAG_Zero) {
		push();
		FPU_copy_to_reg0(&CONST_1, TAG_Valid);
		setcc(0);
		return;
	}

	if (st0_tag == TAG_Special)
		st0_tag = FPU_Special(st0_ptr);

	if (st0_tag == TW_Denormal) {
		if (denormal_operand() < 0)
			return;

		goto denormal_arg;
	}

	if (st0_tag == TW_Infinity) {
		
		if (arith_invalid(0) >= 0) {
			st_new_ptr = &st(-1);
			push();
			arith_invalid(0);
		}
		return;
	}

	single_arg_2_error(st0_ptr, st0_tag);
}
コード例 #6
0
static int trig_arg(FPU_REG *st0_ptr, int even)
{
	FPU_REG tmp;
	u_char tmptag;
	unsigned long long q;
	int old_cw = control_word, saved_status = partial_status;
	int tag, st0_tag = TAG_Valid;

	if (exponent(st0_ptr) >= 63) {
		partial_status |= SW_C2;	
		return -1;
	}

	control_word &= ~CW_RC;
	control_word |= RC_CHOP;

	setpositive(st0_ptr);
	tag = FPU_u_div(st0_ptr, &CONST_PI2, &tmp, PR_64_BITS | RC_CHOP | 0x3f,
			SIGN_POS);

	FPU_round_to_int(&tmp, tag);	
	q = significand(&tmp);
	if (q) {
		rem_kernel(significand(st0_ptr),
			   &significand(&tmp),
			   significand(&CONST_PI2),
			   q, exponent(st0_ptr) - exponent(&CONST_PI2));
		setexponent16(&tmp, exponent(&CONST_PI2));
		st0_tag = FPU_normalize(&tmp);
		FPU_copy_to_reg0(&tmp, st0_tag);
	}

	if ((even && !(q & 1)) || (!even && (q & 1))) {
		st0_tag =
		    FPU_sub(REV | LOADED | TAG_Valid, (int)&CONST_PI2,
			    FULL_PRECISION);

#ifdef BETTER_THAN_486
		
		if ((exponent(st0_ptr) <= exponent(&CONST_PI2extra) + 64)
		    || (q > 1)) {
			

			significand(&tmp) = q + 1;
			setexponent16(&tmp, 63);
			FPU_normalize(&tmp);
			tmptag =
			    FPU_u_mul(&CONST_PI2extra, &tmp, &tmp,
				      FULL_PRECISION, SIGN_POS,
				      exponent(&CONST_PI2extra) +
				      exponent(&tmp));
			setsign(&tmp, getsign(&CONST_PI2extra));
			st0_tag = FPU_add(&tmp, tmptag, 0, FULL_PRECISION);
			if (signnegative(st0_ptr)) {
				
				setpositive(st0_ptr);
				q++;
			}
		}
#endif 
	}
#ifdef BETTER_THAN_486
	else {
		
		if (((q > 0)
		     && (exponent(st0_ptr) <= exponent(&CONST_PI2extra) + 64))
		    || (q > 1)) {
			

			significand(&tmp) = q;
			setexponent16(&tmp, 63);
			FPU_normalize(&tmp);	
			tmptag =
			    FPU_u_mul(&CONST_PI2extra, &tmp, &tmp,
				      FULL_PRECISION, SIGN_POS,
				      exponent(&CONST_PI2extra) +
				      exponent(&tmp));
			setsign(&tmp, getsign(&CONST_PI2extra));
			st0_tag = FPU_sub(LOADED | (tmptag & 0x0f), (int)&tmp,
					  FULL_PRECISION);
			if ((exponent(st0_ptr) == exponent(&CONST_PI2)) &&
			    ((st0_ptr->sigh > CONST_PI2.sigh)
			     || ((st0_ptr->sigh == CONST_PI2.sigh)
				 && (st0_ptr->sigl > CONST_PI2.sigl)))) {
				
				st0_tag =
				    FPU_sub(REV | LOADED | TAG_Valid,
					    (int)&CONST_PI2, FULL_PRECISION);
				q++;
			}
		}
	}
#endif 

	FPU_settag0(st0_tag);
	control_word = old_cw;
	partial_status = saved_status & ~SW_C2;	

	return (q & 3) | even;
}
コード例 #7
0
ファイル: poly_tan.c プロジェクト: dmgerman/linux-pre-history
/*--- poly_tan() ------------------------------------------------------------+
 |                                                                           |
 +---------------------------------------------------------------------------*/
void	poly_tan(FPU_REG *st0_ptr)
{
  long int    		exponent;
  int                   invert;
  Xsig                  argSq, argSqSq, accumulatoro, accumulatore, accum,
                        argSignif, fix_up;
  unsigned long         adj;

  exponent = exponent(st0_ptr);

#ifdef PARANOID
  if ( signnegative(st0_ptr) )	/* Can't hack a number < 0.0 */
    { arith_invalid(0); return; }  /* Need a positive number */
#endif PARANOID

  /* Split the problem into two domains, smaller and larger than pi/4 */
  if ( (exponent == 0) || ((exponent == -1) && (st0_ptr->sigh > 0xc90fdaa2)) )
    {
      /* The argument is greater than (approx) pi/4 */
      invert = 1;
      accum.lsw = 0;
      XSIG_LL(accum) = significand(st0_ptr);
 
      if ( exponent == 0 )
	{
	  /* The argument is >= 1.0 */
	  /* Put the binary point at the left. */
	  XSIG_LL(accum) <<= 1;
	}
      /* pi/2 in hex is: 1.921fb54442d18469 898CC51701B839A2 52049C1 */
      XSIG_LL(accum) = 0x921fb54442d18469LL - XSIG_LL(accum);
      /* This is a special case which arises due to rounding. */
      if ( XSIG_LL(accum) == 0xffffffffffffffffLL )
	{
	  FPU_settag0(TAG_Valid);
	  significand(st0_ptr) = 0x8a51e04daabda360LL;
	  setexponent16(st0_ptr, (0x41 + EXTENDED_Ebias) | SIGN_Negative);
	  return;
	}

      argSignif.lsw = accum.lsw;
      XSIG_LL(argSignif) = XSIG_LL(accum);
      exponent = -1 + norm_Xsig(&argSignif);
    }
  else
    {
      invert = 0;
      argSignif.lsw = 0;
      XSIG_LL(accum) = XSIG_LL(argSignif) = significand(st0_ptr);
 
      if ( exponent < -1 )
	{
	  /* shift the argument right by the required places */
	  if ( FPU_shrx(&XSIG_LL(accum), -1-exponent) >= 0x80000000U )
	    XSIG_LL(accum) ++;	/* round up */
	}
    }

  XSIG_LL(argSq) = XSIG_LL(accum); argSq.lsw = accum.lsw;
  mul_Xsig_Xsig(&argSq, &argSq);
  XSIG_LL(argSqSq) = XSIG_LL(argSq); argSqSq.lsw = argSq.lsw;
  mul_Xsig_Xsig(&argSqSq, &argSqSq);

  /* Compute the negative terms for the numerator polynomial */
  accumulatoro.msw = accumulatoro.midw = accumulatoro.lsw = 0;
  polynomial_Xsig(&accumulatoro, &XSIG_LL(argSqSq), oddnegterm, HiPOWERon-1);
  mul_Xsig_Xsig(&accumulatoro, &argSq);
  negate_Xsig(&accumulatoro);
  /* Add the positive terms */
  polynomial_Xsig(&accumulatoro, &XSIG_LL(argSqSq), oddplterm, HiPOWERop-1);

  
  /* Compute the positive terms for the denominator polynomial */
  accumulatore.msw = accumulatore.midw = accumulatore.lsw = 0;
  polynomial_Xsig(&accumulatore, &XSIG_LL(argSqSq), evenplterm, HiPOWERep-1);
  mul_Xsig_Xsig(&accumulatore, &argSq);
  negate_Xsig(&accumulatore);
  /* Add the negative terms */
  polynomial_Xsig(&accumulatore, &XSIG_LL(argSqSq), evennegterm, HiPOWERen-1);
  /* Multiply by arg^2 */
  mul64_Xsig(&accumulatore, &XSIG_LL(argSignif));
  mul64_Xsig(&accumulatore, &XSIG_LL(argSignif));
  /* de-normalize and divide by 2 */
  shr_Xsig(&accumulatore, -2*(1+exponent) + 1);
  negate_Xsig(&accumulatore);      /* This does 1 - accumulator */

  /* Now find the ratio. */
  if ( accumulatore.msw == 0 )
    {
      /* accumulatoro must contain 1.0 here, (actually, 0) but it
	 really doesn't matter what value we use because it will
	 have negligible effect in later calculations
	 */
      XSIG_LL(accum) = 0x8000000000000000LL;
      accum.lsw = 0;
    }
  else
    {
      div_Xsig(&accumulatoro, &accumulatore, &accum);
    }

  /* Multiply by 1/3 * arg^3 */
  mul64_Xsig(&accum, &XSIG_LL(argSignif));
  mul64_Xsig(&accum, &XSIG_LL(argSignif));
  mul64_Xsig(&accum, &XSIG_LL(argSignif));
  mul64_Xsig(&accum, &twothirds);
  shr_Xsig(&accum, -2*(exponent+1));

  /* tan(arg) = arg + accum */
  add_two_Xsig(&accum, &argSignif, &exponent);

  if ( invert )
    {
      /* We now have the value of tan(pi_2 - arg) where pi_2 is an
	 approximation for pi/2
	 */
      /* The next step is to fix the answer to compensate for the
	 error due to the approximation used for pi/2
	 */

      /* This is (approx) delta, the error in our approx for pi/2
	 (see above). It has an exponent of -65
	 */
      XSIG_LL(fix_up) = 0x898cc51701b839a2LL;
      fix_up.lsw = 0;

      if ( exponent == 0 )
	adj = 0xffffffff;   /* We want approx 1.0 here, but
			       this is close enough. */
      else if ( exponent > -30 )
	{
	  adj = accum.msw >> -(exponent+1);      /* tan */
	  adj = mul_32_32(adj, adj);             /* tan^2 */
	}
      else
コード例 #8
0
ファイル: poly_2xm1.c プロジェクト: Pating/unilator
/*--- poly_2xm1() -----------------------------------------------------------+
 | Requires st(0) which is TAG_Valid and < 1.                                |
 +---------------------------------------------------------------------------*/
int	poly_2xm1(u_char sign, FPU_REG *arg, FPU_REG *result)
{
  s32       exponent, shift;
  u64       Xll;
  Xsig      accumulator, Denom, argSignif;
  u_char    tag;

  exponent = exponent16(arg);

#ifdef PARANOID
  if ( exponent >= 0 )    	/* Don't want a |number| >= 1.0 */
    {
      /* Number negative, too large, or not Valid. */
      EXCEPTION(EX_INTERNAL|0x127);
      return 1;
    }
#endif /* PARANOID */

  argSignif.lsw = 0;
  XSIG_LL(argSignif) = Xll = significand(arg);

  if ( exponent == -1 )
    {
      shift = (argSignif.msw & 0x40000000) ? 3 : 2;
      /* subtract 0.5 or 0.75 */
      exponent -= 2;
      XSIG_LL(argSignif) <<= 2;
      Xll <<= 2;
    }
  else if ( exponent == -2 )
    {
      shift = 1;
      /* subtract 0.25 */
      exponent--;
      XSIG_LL(argSignif) <<= 1;
      Xll <<= 1;
    }
  else
    shift = 0;

  if ( exponent < -2 )
    {
      /* Shift the argument right by the required places. */
      if ( FPU_shrx(&Xll, -2-exponent) >= 0x80000000U )
	Xll++;	/* round up */
    }

  accumulator.lsw = accumulator.midw = accumulator.msw = 0;
  polynomial_Xsig(&accumulator, &Xll, lterms, HIPOWER-1);
  mul_Xsig_Xsig(&accumulator, &argSignif);
  shr_Xsig(&accumulator, 3);

  mul_Xsig_Xsig(&argSignif, &hiterm);   /* The leading term */
  add_two_Xsig(&accumulator, &argSignif, &exponent);

  if ( shift )
    {
      /* The argument is large, use the identity:
	 f(x+a) = f(a) * (f(x) + 1) - 1;
	 */
      shr_Xsig(&accumulator, - exponent);
      accumulator.msw |= 0x80000000;      /* add 1.0 */
      mul_Xsig_Xsig(&accumulator, shiftterm[shift]);
      accumulator.msw &= 0x3fffffff;      /* subtract 1.0 */
      exponent = 1;
    }

  if ( sign != SIGN_POS )
    {
      /* The argument is negative, use the identity:
	     f(-x) = -f(x) / (1 + f(x))
	 */
      Denom.lsw = accumulator.lsw;
      XSIG_LL(Denom) = XSIG_LL(accumulator);
      if ( exponent < 0 )
	shr_Xsig(&Denom, - exponent);
      else if ( exponent > 0 )
	{
	  /* exponent must be 1 here */
	  XSIG_LL(Denom) <<= 1;
	  if ( Denom.lsw & 0x80000000 )
	    XSIG_LL(Denom) |= 1;
	  (Denom.lsw) <<= 1;
	}
      Denom.msw |= 0x80000000;      /* add 1.0 */
      div_Xsig(&accumulator, &Denom, &accumulator);
    }

  /* Convert to 64 bit signed-compatible */
  exponent += round_Xsig(&accumulator);

  result = &st(0);
  significand(result) = XSIG_LL(accumulator);
  setexponent16(result, exponent);

  tag = FPU_round(result, 1, 0, FULL_PRECISION, sign);

  setsign(result, sign);
  FPU_settag0(tag);

  return 0;

}
コード例 #9
0
ファイル: fpu_trig.c プロジェクト: 0-T-0/ps4-linux
/* Limited measurements show no results worse than 64 bit precision
   except for the results for arguments close to 2^63, where the
   precision of the result sometimes degrades to about 63.9 bits */
static int trig_arg(FPU_REG *st0_ptr, int even)
{
	FPU_REG tmp;
	u_char tmptag;
	unsigned long long q;
	int old_cw = control_word, saved_status = partial_status;
	int tag, st0_tag = TAG_Valid;

	if (exponent(st0_ptr) >= 63) {
		partial_status |= SW_C2;	/* Reduction incomplete. */
		return -1;
	}

	control_word &= ~CW_RC;
	control_word |= RC_CHOP;

	setpositive(st0_ptr);
	tag = FPU_u_div(st0_ptr, &CONST_PI2, &tmp, PR_64_BITS | RC_CHOP | 0x3f,
			SIGN_POS);

	FPU_round_to_int(&tmp, tag);	/* Fortunately, this can't overflow
					   to 2^64 */
	q = significand(&tmp);
	if (q) {
		rem_kernel(significand(st0_ptr),
			   &significand(&tmp),
			   significand(&CONST_PI2),
			   q, exponent(st0_ptr) - exponent(&CONST_PI2));
		setexponent16(&tmp, exponent(&CONST_PI2));
		st0_tag = FPU_normalize(&tmp);
		FPU_copy_to_reg0(&tmp, st0_tag);
	}

	if ((even && !(q & 1)) || (!even && (q & 1))) {
		st0_tag =
		    FPU_sub(REV | LOADED | TAG_Valid, (int)&CONST_PI2,
			    FULL_PRECISION);

#ifdef BETTER_THAN_486
		/* So far, the results are exact but based upon a 64 bit
		   precision approximation to pi/2. The technique used
		   now is equivalent to using an approximation to pi/2 which
		   is accurate to about 128 bits. */
		if ((exponent(st0_ptr) <= exponent(&CONST_PI2extra) + 64)
		    || (q > 1)) {
			/* This code gives the effect of having pi/2 to better than
			   128 bits precision. */

			significand(&tmp) = q + 1;
			setexponent16(&tmp, 63);
			FPU_normalize(&tmp);
			tmptag =
			    FPU_u_mul(&CONST_PI2extra, &tmp, &tmp,
				      FULL_PRECISION, SIGN_POS,
				      exponent(&CONST_PI2extra) +
				      exponent(&tmp));
			setsign(&tmp, getsign(&CONST_PI2extra));
			st0_tag = FPU_add(&tmp, tmptag, 0, FULL_PRECISION);
			if (signnegative(st0_ptr)) {
				/* CONST_PI2extra is negative, so the result of the addition
				   can be negative. This means that the argument is actually
				   in a different quadrant. The correction is always < pi/2,
				   so it can't overflow into yet another quadrant. */
				setpositive(st0_ptr);
				q++;
			}
		}
#endif /* BETTER_THAN_486 */
	}
#ifdef BETTER_THAN_486
	else {
		/* So far, the results are exact but based upon a 64 bit
		   precision approximation to pi/2. The technique used
		   now is equivalent to using an approximation to pi/2 which
		   is accurate to about 128 bits. */
		if (((q > 0)
		     && (exponent(st0_ptr) <= exponent(&CONST_PI2extra) + 64))
		    || (q > 1)) {
			/* This code gives the effect of having p/2 to better than
			   128 bits precision. */

			significand(&tmp) = q;
			setexponent16(&tmp, 63);
			FPU_normalize(&tmp);	/* This must return TAG_Valid */
			tmptag =
			    FPU_u_mul(&CONST_PI2extra, &tmp, &tmp,
				      FULL_PRECISION, SIGN_POS,
				      exponent(&CONST_PI2extra) +
				      exponent(&tmp));
			setsign(&tmp, getsign(&CONST_PI2extra));
			st0_tag = FPU_sub(LOADED | (tmptag & 0x0f), (int)&tmp,
					  FULL_PRECISION);
			if ((exponent(st0_ptr) == exponent(&CONST_PI2)) &&
			    ((st0_ptr->sigh > CONST_PI2.sigh)
			     || ((st0_ptr->sigh == CONST_PI2.sigh)
				 && (st0_ptr->sigl > CONST_PI2.sigl)))) {
				/* CONST_PI2extra is negative, so the result of the
				   subtraction can be larger than pi/2. This means
				   that the argument is actually in a different quadrant.
				   The correction is always < pi/2, so it can't overflow
				   into yet another quadrant. */
				st0_tag =
				    FPU_sub(REV | LOADED | TAG_Valid,
					    (int)&CONST_PI2, FULL_PRECISION);
				q++;
			}
		}
	}
#endif /* BETTER_THAN_486 */

	FPU_settag0(st0_tag);
	control_word = old_cw;
	partial_status = saved_status & ~SW_C2;	/* Reduction complete. */

	return (q & 3) | even;
}
コード例 #10
0
ファイル: fpu_trig.c プロジェクト: 0-T-0/ps4-linux
static void fptan(FPU_REG *st0_ptr, u_char st0_tag)
{
	FPU_REG *st_new_ptr;
	int q;
	u_char arg_sign = getsign(st0_ptr);

	/* Stack underflow has higher priority */
	if (st0_tag == TAG_Empty) {
		FPU_stack_underflow();	/* Puts a QNaN in st(0) */
		if (control_word & CW_Invalid) {
			st_new_ptr = &st(-1);
			push();
			FPU_stack_underflow();	/* Puts a QNaN in the new st(0) */
		}
		return;
	}

	if (STACK_OVERFLOW) {
		FPU_stack_overflow();
		return;
	}

	if (st0_tag == TAG_Valid) {
		if (exponent(st0_ptr) > -40) {
			if ((q = trig_arg(st0_ptr, 0)) == -1) {
				/* Operand is out of range */
				return;
			}

			poly_tan(st0_ptr);
			setsign(st0_ptr, (q & 1) ^ (arg_sign != 0));
			set_precision_flag_up();	/* We do not really know if up or down */
		} else {
			/* For a small arg, the result == the argument */
			/* Underflow may happen */

		      denormal_arg:

			FPU_to_exp16(st0_ptr, st0_ptr);

			st0_tag =
			    FPU_round(st0_ptr, 1, 0, FULL_PRECISION, arg_sign);
			FPU_settag0(st0_tag);
		}
		push();
		FPU_copy_to_reg0(&CONST_1, TAG_Valid);
		return;
	}

	if (st0_tag == TAG_Zero) {
		push();
		FPU_copy_to_reg0(&CONST_1, TAG_Valid);
		setcc(0);
		return;
	}

	if (st0_tag == TAG_Special)
		st0_tag = FPU_Special(st0_ptr);

	if (st0_tag == TW_Denormal) {
		if (denormal_operand() < 0)
			return;

		goto denormal_arg;
	}

	if (st0_tag == TW_Infinity) {
		/* The 80486 treats infinity as an invalid operand */
		if (arith_invalid(0) >= 0) {
			st_new_ptr = &st(-1);
			push();
			arith_invalid(0);
		}
		return;
	}

	single_arg_2_error(st0_ptr, st0_tag);
}
コード例 #11
0
ファイル: load_store.c プロジェクト: 12019/hg556a_source
int FPU_load_store(u_char type, fpu_addr_modes addr_modes,
		     void __user *data_address)
{
  FPU_REG loaded_data;
  FPU_REG *st0_ptr;
  u_char st0_tag = TAG_Empty;  /* This is just to stop a gcc warning. */
  u_char loaded_tag;

  st0_ptr = NULL;    /* Initialized just to stop compiler warnings. */

  if ( addr_modes.default_mode & PROTECTED )
    {
      if ( addr_modes.default_mode == SEG32 )
	{
	  if ( access_limit < data_sizes_32[type] )
	    math_abort(FPU_info,SIGSEGV);
	}
      else if ( addr_modes.default_mode == PM16 )
	{
	  if ( access_limit < data_sizes_16[type] )
	    math_abort(FPU_info,SIGSEGV);
	}
#ifdef PARANOID
      else
	EXCEPTION(EX_INTERNAL|0x140);
#endif /* PARANOID */
    }

  switch ( type_table[type] )
    {
    case _NONE_:
      break;
    case _REG0_:
      st0_ptr = &st(0);       /* Some of these instructions pop after
				 storing */
      st0_tag = FPU_gettag0();
      break;
    case _PUSH_:
      {
	if ( FPU_gettagi(-1) != TAG_Empty )
	  { FPU_stack_overflow(); return 0; }
	top--;
	st0_ptr = &st(0);
      }
      break;
    case _null_:
      FPU_illegal();
      return 0;
#ifdef PARANOID
    default:
      EXCEPTION(EX_INTERNAL|0x141);
      return 0;
#endif /* PARANOID */
    }

  switch ( type )
    {
    case 000:       /* fld m32real */
      clear_C1();
      loaded_tag = FPU_load_single((float __user *)data_address, &loaded_data);
      if ( (loaded_tag == TAG_Special)
	   && isNaN(&loaded_data)
	   && (real_1op_NaN(&loaded_data) < 0) )
	{
	  top++;
	  break;
	}
      FPU_copy_to_reg0(&loaded_data, loaded_tag);
      break;
    case 001:      /* fild m32int */
      clear_C1();
      loaded_tag = FPU_load_int32((long __user *)data_address, &loaded_data);
      FPU_copy_to_reg0(&loaded_data, loaded_tag);
      break;
    case 002:      /* fld m64real */
      clear_C1();
      loaded_tag = FPU_load_double((double __user *)data_address, &loaded_data);
      if ( (loaded_tag == TAG_Special)
	   && isNaN(&loaded_data)
	   && (real_1op_NaN(&loaded_data) < 0) )
	{
	  top++;
	  break;
	}
      FPU_copy_to_reg0(&loaded_data, loaded_tag);
      break;
    case 003:      /* fild m16int */
      clear_C1();
      loaded_tag = FPU_load_int16((short __user *)data_address, &loaded_data);
      FPU_copy_to_reg0(&loaded_data, loaded_tag);
      break;
    case 010:      /* fst m32real */
      clear_C1();
      FPU_store_single(st0_ptr, st0_tag, (float __user *)data_address);
      break;
    case 011:      /* fist m32int */
      clear_C1();
      FPU_store_int32(st0_ptr, st0_tag, (long __user *)data_address);
      break;
    case 012:     /* fst m64real */
      clear_C1();
      FPU_store_double(st0_ptr, st0_tag, (double __user *)data_address);
      break;
    case 013:     /* fist m16int */
      clear_C1();
      FPU_store_int16(st0_ptr, st0_tag, (short __user *)data_address);
      break;
    case 014:     /* fstp m32real */
      clear_C1();
      if ( FPU_store_single(st0_ptr, st0_tag, (float __user *)data_address) )
	pop_0();  /* pop only if the number was actually stored
		     (see the 80486 manual p16-28) */
      break;
    case 015:     /* fistp m32int */
      clear_C1();
      if ( FPU_store_int32(st0_ptr, st0_tag, (long __user *)data_address) )
	pop_0();  /* pop only if the number was actually stored
		     (see the 80486 manual p16-28) */
      break;
    case 016:     /* fstp m64real */
      clear_C1();
      if ( FPU_store_double(st0_ptr, st0_tag, (double __user *)data_address) )
	pop_0();  /* pop only if the number was actually stored
		     (see the 80486 manual p16-28) */
      break;
    case 017:     /* fistp m16int */
      clear_C1();
      if ( FPU_store_int16(st0_ptr, st0_tag, (short __user *)data_address) )
	pop_0();  /* pop only if the number was actually stored
		     (see the 80486 manual p16-28) */
      break;
    case 020:     /* fldenv  m14/28byte */
      fldenv(addr_modes, (u_char __user *)data_address);
      /* Ensure that the values just loaded are not changed by
	 fix-up operations. */
      return 1;
    case 022:     /* frstor m94/108byte */
      frstor(addr_modes, (u_char __user *)data_address);
      /* Ensure that the values just loaded are not changed by
	 fix-up operations. */
      return 1;
    case 023:     /* fbld m80dec */
      clear_C1();
      loaded_tag = FPU_load_bcd((u_char __user *)data_address);
      FPU_settag0(loaded_tag);
      break;
    case 024:     /* fldcw */
      RE_ENTRANT_CHECK_OFF;
      FPU_verify_area(VERIFY_READ, data_address, 2);
      FPU_get_user(control_word, (unsigned short __user *) data_address);
      RE_ENTRANT_CHECK_ON;
      if ( partial_status & ~control_word & CW_Exceptions )
	partial_status |= (SW_Summary | SW_Backward);
      else
	partial_status &= ~(SW_Summary | SW_Backward);
#ifdef PECULIAR_486
      control_word |= 0x40;  /* An 80486 appears to always set this bit */
#endif /* PECULIAR_486 */
      return 1;
    case 025:      /* fld m80real */
      clear_C1();
      loaded_tag = FPU_load_extended((long double __user *)data_address, 0);
      FPU_settag0(loaded_tag);
      break;
    case 027:      /* fild m64int */
      clear_C1();
      loaded_tag = FPU_load_int64((long long __user *)data_address);
      FPU_settag0(loaded_tag);
      break;
    case 030:     /* fstenv  m14/28byte */
      fstenv(addr_modes, (u_char __user *)data_address);
      return 1;
    case 032:      /* fsave */
      fsave(addr_modes, (u_char __user *)data_address);
      return 1;
    case 033:      /* fbstp m80dec */
      clear_C1();
      if ( FPU_store_bcd(st0_ptr, st0_tag, (u_char __user *)data_address) )
	pop_0();  /* pop only if the number was actually stored
		     (see the 80486 manual p16-28) */
      break;
    case 034:      /* fstcw m16int */
      RE_ENTRANT_CHECK_OFF;
      FPU_verify_area(VERIFY_WRITE,data_address,2);
      FPU_put_user(control_word, (unsigned short __user *) data_address);
      RE_ENTRANT_CHECK_ON;
      return 1;
    case 035:      /* fstp m80real */
      clear_C1();
      if ( FPU_store_extended(st0_ptr, st0_tag, (long double __user *)data_address) )
	pop_0();  /* pop only if the number was actually stored
		     (see the 80486 manual p16-28) */
      break;
    case 036:      /* fstsw m2byte */
      RE_ENTRANT_CHECK_OFF;
      FPU_verify_area(VERIFY_WRITE,data_address,2);
      FPU_put_user(status_word(),(unsigned short __user *) data_address);
      RE_ENTRANT_CHECK_ON;
      return 1;
    case 037:      /* fistp m64int */
      clear_C1();
      if ( FPU_store_int64(st0_ptr, st0_tag, (long long __user *)data_address) )
	pop_0();  /* pop only if the number was actually stored
		     (see the 80486 manual p16-28) */
      break;
    }
  return 0;
}
コード例 #12
0
int poly_2xm1(u_char sign, FPU_REG *arg, FPU_REG *result)
{
	long int exponent, shift;
	unsigned long long Xll;
	Xsig accumulator, Denom, argSignif;
	u_char tag;

	exponent = exponent16(arg);

#ifdef PARANOID
	if (exponent >= 0) {	/*                              */
		/*                                           */
		EXCEPTION(EX_INTERNAL | 0x127);
		return 1;
	}
#endif /*          */

	argSignif.lsw = 0;
	XSIG_LL(argSignif) = Xll = significand(arg);

	if (exponent == -1) {
		shift = (argSignif.msw & 0x40000000) ? 3 : 2;
		/*                      */
		exponent -= 2;
		XSIG_LL(argSignif) <<= 2;
		Xll <<= 2;
	} else if (exponent == -2) {
		shift = 1;
		/*               */
		exponent--;
		XSIG_LL(argSignif) <<= 1;
		Xll <<= 1;
	} else
		shift = 0;

	if (exponent < -2) {
		/*                                                  */
		if (FPU_shrx(&Xll, -2 - exponent) >= 0x80000000U)
			Xll++;	/*          */
	}

	accumulator.lsw = accumulator.midw = accumulator.msw = 0;
	polynomial_Xsig(&accumulator, &Xll, lterms, HIPOWER - 1);
	mul_Xsig_Xsig(&accumulator, &argSignif);
	shr_Xsig(&accumulator, 3);

	mul_Xsig_Xsig(&argSignif, &hiterm);	/*                  */
	add_two_Xsig(&accumulator, &argSignif, &exponent);

	if (shift) {
		/*                                         
                                    
   */
		shr_Xsig(&accumulator, -exponent);
		accumulator.msw |= 0x80000000;	/*         */
		mul_Xsig_Xsig(&accumulator, shiftterm[shift]);
		accumulator.msw &= 0x3fffffff;	/*              */
		exponent = 1;
	}

	if (sign != SIGN_POS) {
		/*                                            
                               
   */
		Denom.lsw = accumulator.lsw;
		XSIG_LL(Denom) = XSIG_LL(accumulator);
		if (exponent < 0)
			shr_Xsig(&Denom, -exponent);
		else if (exponent > 0) {
			/*                         */
			XSIG_LL(Denom) <<= 1;
			if (Denom.lsw & 0x80000000)
				XSIG_LL(Denom) |= 1;
			(Denom.lsw) <<= 1;
		}
		Denom.msw |= 0x80000000;	/*         */
		div_Xsig(&accumulator, &Denom, &accumulator);
	}

	/*                                     */
	exponent += round_Xsig(&accumulator);

	result = &st(0);
	significand(result) = XSIG_LL(accumulator);
	setexponent16(result, exponent);

	tag = FPU_round(result, 1, 0, FULL_PRECISION, sign);

	setsign(result, sign);
	FPU_settag0(tag);

	return 0;

}