コード例 #1
0
ファイル: fpu_trig.c プロジェクト: chinnyannieb/empeg-hijack
static void single_arg_2_error(FPU_REG *st0_ptr, u_char st0_tag)
{
  int isNaN;

  switch ( st0_tag )
    {
    case TW_NaN:
      isNaN = (exponent(st0_ptr) == EXP_OVER) && (st0_ptr->sigh & 0x80000000);
      if ( isNaN && !(st0_ptr->sigh & 0x40000000) )   /* Signaling ? */
	{
	  EXCEPTION(EX_Invalid);
	  if ( control_word & CW_Invalid )
	    {
	      /* The masked response */
	      /* Convert to a QNaN */
	      st0_ptr->sigh |= 0x40000000;
	      push();
	      FPU_copy_to_reg0(st0_ptr, TAG_Special);
	    }
	}
      else if ( isNaN )
	{
	  /* A QNaN */
	  push();
	  FPU_copy_to_reg0(st0_ptr, TAG_Special);
	}
      else
	{
	  /* pseudoNaN or other unsupported */
	  EXCEPTION(EX_Invalid);
	  if ( control_word & CW_Invalid )
	    {
	      /* The masked response */
	      FPU_copy_to_reg0(&CONST_QNaN, TAG_Special);
	      push();
	      FPU_copy_to_reg0(&CONST_QNaN, TAG_Special);
	    }
	}
      break;              /* return with a NaN in st(0) */
#ifdef PARANOID
    default:
      EXCEPTION(EX_INTERNAL|0x0112);
#endif PARANOID
    }
}
コード例 #2
0
static void single_arg_2_error(FPU_REG *st0_ptr, u_char st0_tag)
{
	int isNaN;

	switch (st0_tag) {
	case TW_NaN:
		isNaN = (exponent(st0_ptr) == EXP_OVER)
		    && (st0_ptr->sigh & 0x80000000);
		if (isNaN && !(st0_ptr->sigh & 0x40000000)) {	
			EXCEPTION(EX_Invalid);
			if (control_word & CW_Invalid) {
				
				
				st0_ptr->sigh |= 0x40000000;
				push();
				FPU_copy_to_reg0(st0_ptr, TAG_Special);
			}
		} else if (isNaN) {
			
			push();
			FPU_copy_to_reg0(st0_ptr, TAG_Special);
		} else {
			
			EXCEPTION(EX_Invalid);
			if (control_word & CW_Invalid) {
				
				FPU_copy_to_reg0(&CONST_QNaN, TAG_Special);
				push();
				FPU_copy_to_reg0(&CONST_QNaN, TAG_Special);
			}
		}
		break;		
#ifdef PARANOID
	default:
		EXCEPTION(EX_INTERNAL | 0x0112);
#endif 
	}
}
コード例 #3
0
ファイル: fpu_trig.c プロジェクト: chinnyannieb/empeg-hijack
static void f2xm1(FPU_REG *st0_ptr, u_char tag)
{
  FPU_REG a;

  clear_C1();

  if ( tag == TAG_Valid )
    {
      /* For an 80486 FPU, the result is undefined if the arg is >= 1.0 */
      if ( exponent(st0_ptr) < 0 )
	{
	denormal_arg:

	  FPU_to_exp16(st0_ptr, &a);

	  /* poly_2xm1(x) requires 0 < st(0) < 1. */
	  poly_2xm1(getsign(st0_ptr), &a, st0_ptr);
	}
      set_precision_flag_up();   /* 80486 appears to always do this */
      return;
    }

  if ( tag == TAG_Zero )
    return;

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

  switch ( tag )
    {
    case TW_Denormal:
      if ( denormal_operand() < 0 )
	return;
      goto denormal_arg;
    case TW_Infinity:
      if ( signnegative(st0_ptr) )
	{
	  /* -infinity gives -1 (p16-10) */
	  FPU_copy_to_reg0(&CONST_1, TAG_Valid);
	  setnegative(st0_ptr);
	}
      return;
    default:
      single_arg_error(st0_ptr, tag);
    }
}
コード例 #4
0
static void f2xm1(FPU_REG *st0_ptr, u_char tag)
{
	FPU_REG a;

	clear_C1();

	if (tag == TAG_Valid) {
		
		if (exponent(st0_ptr) < 0) {
		      denormal_arg:

			FPU_to_exp16(st0_ptr, &a);

			
			poly_2xm1(getsign(st0_ptr), &a, st0_ptr);
		}
		set_precision_flag_up();	
		return;
	}

	if (tag == TAG_Zero)
		return;

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

	switch (tag) {
	case TW_Denormal:
		if (denormal_operand() < 0)
			return;
		goto denormal_arg;
	case TW_Infinity:
		if (signnegative(st0_ptr)) {
			
			FPU_copy_to_reg0(&CONST_1, TAG_Valid);
			setnegative(st0_ptr);
		}
		return;
	default:
		single_arg_error(st0_ptr, tag);
	}
}
コード例 #5
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 
}
コード例 #6
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);
}
コード例 #7
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;
}
コード例 #8
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;
}
コード例 #9
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);
}
コード例 #10
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;
}
コード例 #11
0
void poly_sine(FPU_REG *st0_ptr)
{
	int exponent, echange;
	Xsig accumulator, argSqrd, argTo4;
	unsigned long fix_up, adj;
	unsigned long long fixed_arg;
	FPU_REG result;

	exponent = exponent(st0_ptr);

	accumulator.lsw = accumulator.midw = accumulator.msw = 0;

	
	
	if ((exponent < -1)
	    || ((exponent == -1) && (st0_ptr->sigh <= 0xe21240aa))) {
		

		argSqrd.msw = st0_ptr->sigh;
		argSqrd.midw = st0_ptr->sigl;
		argSqrd.lsw = 0;
		mul64_Xsig(&argSqrd, &significand(st0_ptr));
		shr_Xsig(&argSqrd, 2 * (-1 - exponent));
		argTo4.msw = argSqrd.msw;
		argTo4.midw = argSqrd.midw;
		argTo4.lsw = argSqrd.lsw;
		mul_Xsig_Xsig(&argTo4, &argTo4);

		polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), neg_terms_l,
				N_COEFF_N - 1);
		mul_Xsig_Xsig(&accumulator, &argSqrd);
		negate_Xsig(&accumulator);

		polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), pos_terms_l,
				N_COEFF_P - 1);

		shr_Xsig(&accumulator, 2);	
		accumulator.msw |= 0x80000000;	

		mul64_Xsig(&accumulator, &significand(st0_ptr));
		mul64_Xsig(&accumulator, &significand(st0_ptr));
		mul64_Xsig(&accumulator, &significand(st0_ptr));

		
		exponent = 3 * exponent;

		
		shr_Xsig(&accumulator, exponent(st0_ptr) - exponent);

		negate_Xsig(&accumulator);
		XSIG_LL(accumulator) += significand(st0_ptr);

		echange = round_Xsig(&accumulator);

		setexponentpos(&result, exponent(st0_ptr) + echange);
	} else {
		
		

		fixed_arg = significand(st0_ptr);

		if (exponent == 0) {
			

			
			fixed_arg <<= 1;
		}
		
		fixed_arg = 0x921fb54442d18469LL - fixed_arg;
		
		if (fixed_arg == 0xffffffffffffffffLL)
			fixed_arg = 0;

		XSIG_LL(argSqrd) = fixed_arg;
		argSqrd.lsw = 0;
		mul64_Xsig(&argSqrd, &fixed_arg);

		XSIG_LL(argTo4) = XSIG_LL(argSqrd);
		argTo4.lsw = argSqrd.lsw;
		mul_Xsig_Xsig(&argTo4, &argTo4);

		polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), neg_terms_h,
				N_COEFF_NH - 1);
		mul_Xsig_Xsig(&accumulator, &argSqrd);
		negate_Xsig(&accumulator);

		polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), pos_terms_h,
				N_COEFF_PH - 1);
		negate_Xsig(&accumulator);

		mul64_Xsig(&accumulator, &fixed_arg);
		mul64_Xsig(&accumulator, &fixed_arg);

		shr_Xsig(&accumulator, 3);
		negate_Xsig(&accumulator);

		add_Xsig_Xsig(&accumulator, &argSqrd);

		shr_Xsig(&accumulator, 1);

		accumulator.lsw |= 1;	
		negate_Xsig(&accumulator);


		
		fix_up = 0x898cc517;
		
		if (argSqrd.msw & 0xffc00000) {
			
			fix_up -= mul_32_32(0x898cc517, argSqrd.msw) / 6;
		}
		fix_up = mul_32_32(fix_up, LL_MSW(fixed_arg));

		adj = accumulator.lsw;	
		accumulator.lsw -= fix_up;
		if (accumulator.lsw > adj)
			XSIG_LL(accumulator)--;

		echange = round_Xsig(&accumulator);

		setexponentpos(&result, echange - 1);
	}

	significand(&result) = XSIG_LL(accumulator);
	setsign(&result, getsign(st0_ptr));
	FPU_copy_to_reg0(&result, TAG_Valid);

#ifdef PARANOID
	if ((exponent(&result) >= 0)
	    && (significand(&result) > 0x8000000000000000LL)) {
		EXCEPTION(EX_INTERNAL | 0x150);
	}
#endif 

}
コード例 #12
0
void poly_cos(FPU_REG *st0_ptr)
{
	FPU_REG result;
	long int exponent, exp2, echange;
	Xsig accumulator, argSqrd, fix_up, argTo4;
	unsigned long long fixed_arg;

#ifdef PARANOID
	if ((exponent(st0_ptr) > 0)
	    || ((exponent(st0_ptr) == 0)
		&& (significand(st0_ptr) > 0xc90fdaa22168c234LL))) {
		EXCEPTION(EX_Invalid);
		FPU_copy_to_reg0(&CONST_QNaN, TAG_Special);
		return;
	}
#endif 

	exponent = exponent(st0_ptr);

	accumulator.lsw = accumulator.midw = accumulator.msw = 0;

	if ((exponent < -1)
	    || ((exponent == -1) && (st0_ptr->sigh <= 0xb00d6f54))) {
		

		argSqrd.msw = st0_ptr->sigh;
		argSqrd.midw = st0_ptr->sigl;
		argSqrd.lsw = 0;
		mul64_Xsig(&argSqrd, &significand(st0_ptr));

		if (exponent < -1) {
			
			shr_Xsig(&argSqrd, 2 * (-1 - exponent));
		}

		argTo4.msw = argSqrd.msw;
		argTo4.midw = argSqrd.midw;
		argTo4.lsw = argSqrd.lsw;
		mul_Xsig_Xsig(&argTo4, &argTo4);

		polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), neg_terms_h,
				N_COEFF_NH - 1);
		mul_Xsig_Xsig(&accumulator, &argSqrd);
		negate_Xsig(&accumulator);

		polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), pos_terms_h,
				N_COEFF_PH - 1);
		negate_Xsig(&accumulator);

		mul64_Xsig(&accumulator, &significand(st0_ptr));
		mul64_Xsig(&accumulator, &significand(st0_ptr));
		shr_Xsig(&accumulator, -2 * (1 + exponent));

		shr_Xsig(&accumulator, 3);
		negate_Xsig(&accumulator);

		add_Xsig_Xsig(&accumulator, &argSqrd);

		shr_Xsig(&accumulator, 1);

		negate_Xsig(&accumulator);

		if (accumulator.lsw & 0x80000000)
			XSIG_LL(accumulator)++;
		if (accumulator.msw == 0) {
			
			FPU_copy_to_reg0(&CONST_1, TAG_Valid);
			return;
		} else {
			significand(&result) = XSIG_LL(accumulator);

			
			setexponentpos(&result, -1);
		}
	} else {
		fixed_arg = significand(st0_ptr);

		if (exponent == 0) {
			

			
			fixed_arg <<= 1;
		}
		
		fixed_arg = 0x921fb54442d18469LL - fixed_arg;
		
		if (fixed_arg == 0xffffffffffffffffLL)
			fixed_arg = 0;

		exponent = -1;
		exp2 = -1;

		if (!(LL_MSW(fixed_arg) & 0xffff0000)) {
			fixed_arg <<= 16;
			exponent -= 16;
			exp2 -= 16;
		}

		XSIG_LL(argSqrd) = fixed_arg;
		argSqrd.lsw = 0;
		mul64_Xsig(&argSqrd, &fixed_arg);

		if (exponent < -1) {
			
			shr_Xsig(&argSqrd, 2 * (-1 - exponent));
		}

		argTo4.msw = argSqrd.msw;
		argTo4.midw = argSqrd.midw;
		argTo4.lsw = argSqrd.lsw;
		mul_Xsig_Xsig(&argTo4, &argTo4);

		polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), neg_terms_l,
				N_COEFF_N - 1);
		mul_Xsig_Xsig(&accumulator, &argSqrd);
		negate_Xsig(&accumulator);

		polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), pos_terms_l,
				N_COEFF_P - 1);

		shr_Xsig(&accumulator, 2);	
		accumulator.msw |= 0x80000000;	

		mul64_Xsig(&accumulator, &fixed_arg);
		mul64_Xsig(&accumulator, &fixed_arg);
		mul64_Xsig(&accumulator, &fixed_arg);

		
		exponent = 3 * exponent;

		
		shr_Xsig(&accumulator, exp2 - exponent);

		negate_Xsig(&accumulator);
		XSIG_LL(accumulator) += fixed_arg;


		
		XSIG_LL(fix_up) = 0x898cc51701b839a2ll;
		fix_up.lsw = 0;

		
		if (argSqrd.msw & 0xffc00000) {
			
			fix_up.msw -= mul_32_32(0x898cc517, argSqrd.msw) / 2;
			fix_up.msw += mul_32_32(0x898cc517, argTo4.msw) / 24;
		}

		exp2 += norm_Xsig(&accumulator);
		shr_Xsig(&accumulator, 1);	
		exp2++;
		shr_Xsig(&fix_up, 65 + exp2);

		add_Xsig_Xsig(&accumulator, &fix_up);

		echange = round_Xsig(&accumulator);

		setexponentpos(&result, exp2 + echange);
		significand(&result) = XSIG_LL(accumulator);
	}

	FPU_copy_to_reg0(&result, TAG_Valid);

#ifdef PARANOID
	if ((exponent(&result) >= 0)
	    && (significand(&result) > 0x8000000000000000LL)) {
		EXCEPTION(EX_INTERNAL | 0x151);
	}
#endif 

}