Пример #1
0
void
fxch_i()
{
	/* fxch st(i) */
	FPU_REG t;
	register FPU_REG *sti_ptr = &st(FPU_rm);

	if (FPU_st0_tag == TW_Empty) {
		if (sti_ptr->tag == TW_Empty) {
			stack_underflow();
			stack_underflow_i(FPU_rm);
			return;
		}
		reg_move(sti_ptr, FPU_st0_ptr);
		stack_underflow_i(FPU_rm);
		return;
	}
	if (sti_ptr->tag == TW_Empty) {
		reg_move(FPU_st0_ptr, sti_ptr);
		stack_underflow();
		return;
	}
	reg_move(FPU_st0_ptr, &t);
	reg_move(sti_ptr, FPU_st0_ptr);
	reg_move(&t, sti_ptr);
}
Пример #2
0
static int
trig_arg(FPU_REG * X)
{
    FPU_REG tmp, quot;
    int     rv;
    long long q;
    int     old_cw = control_word;

    control_word &= ~CW_RC;
    control_word |= RC_CHOP;

    reg_move(X, &quot);
    reg_div(&quot, &CONST_PI2, &quot, FULL_PRECISION);

    reg_move(&quot, &tmp);
    round_to_int(&tmp);
    if (tmp.sigh & 0x80000000)
        return -1;	/* |Arg| is >= 2^63 */
    tmp.exp = EXP_BIAS + 63;
    q = *(long long *) &(tmp.sigl);
    normalize(&tmp);

    reg_sub(&quot, &tmp, X, FULL_PRECISION);
    rv = q & 7;

    control_word = old_cw;
    return rv;;
}
Пример #3
0
static void
fptan(void)
{
    FPU_REG *st_new_ptr;
    int     q;
    char    arg_sign = FPU_st0_ptr->sign;

    if (STACK_OVERFLOW) {
        stack_overflow();
        return;
    }
    switch (FPU_st0_tag) {
    case TW_Valid:

#ifdef DENORM_OPERAND
        if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
            return;
#endif				/* DENORM_OPERAND */

        FPU_st0_ptr->sign = SIGN_POS;
        if ((q = trig_arg(FPU_st0_ptr)) != -1) {
            if (q & 1)
                reg_sub(&CONST_1, FPU_st0_ptr, FPU_st0_ptr, FULL_PRECISION);

            poly_tan(FPU_st0_ptr, FPU_st0_ptr);

            FPU_st0_ptr->sign = (q & 1) ^ arg_sign;

            if (FPU_st0_ptr->exp <= EXP_UNDER)
                arith_underflow(FPU_st0_ptr);

            push();
            reg_move(&CONST_1, FPU_st0_ptr);
            setcc(0);
        } else {
            /* Operand is out of range */
            setcc(SW_C2);
            FPU_st0_ptr->sign = arg_sign;	/* restore st(0) */
            return;
        }
        break;
    case TW_Infinity:
        /* Operand is out of range */
        setcc(SW_C2);
        FPU_st0_ptr->sign = arg_sign;	/* restore st(0) */
        return;
    case TW_Zero:
        push();
        reg_move(&CONST_1, FPU_st0_ptr);
        setcc(0);
        break;
    default:
        single_arg_error();
        break;
    }
}
Пример #4
0
void
fstp_i()
{
	/* fstp st(i) */
	reg_move(FPU_st0_ptr, &st(FPU_rm));
	pop();
}
Пример #5
0
void
search(short n, boolean is_auto)
{
    short s, i, j, row, col, t;
    short shown = 0, found = 0;
    static boolean reg_search;

    for (i = -1; i <= 1; i++) {
	for (j = -1; j <= 1; j++) {
	    row = rogue.row + i;
	    col = rogue.col + j;
	    if ((row < MIN_ROW) || (row >= (ROGUE_LINES - 1)) ||
		(col < 0) || (col >= ROGUE_COLUMNS)) {
		continue;
	    }
	    if (dungeon[row][col] & HIDDEN) {
		found++;
	    }
	}
    }
    for (s = 0; s < n; s++) {
	for (i = -1; i <= 1; i++) {
	    for (j = -1; j <= 1; j++) {
		row = rogue.row + i;
		col = rogue.col + j;
		if ((row < MIN_ROW) || (row >= (ROGUE_LINES - 1)) ||
		    (col < 0) || (col >= ROGUE_COLUMNS)) {
		    continue;
		}
		if (dungeon[row][col] & HIDDEN) {
		    if (rand_percent(17 + (rogue.exp + ring_exp))) {
			dungeon[row][col] &= (~HIDDEN);
			if ((!blind) && ((row != rogue.row) ||
					 (col != rogue.col))) {
			    mvaddch_rogue(row, col,
					  get_dungeon_char(row, col));
			}
			shown++;
			if (dungeon[row][col] & TRAP) {
			    t = trap_at(row, col);
			    message(trap_strings[t * 2], 1);
			}
		    }
		}
		if (((shown == found) && (found > 0)) || interrupted) {
		    return;
		}
	    }
	}
	if ((!is_auto) && (reg_search = !reg_search)) {
	    (void) reg_move();
	}
    }
}
Пример #6
0
static void
fld_const(FPU_REG * c)
{
	FPU_REG *st_new_ptr;

	if (STACK_OVERFLOW) {
		stack_overflow();
		return;
	}
	push();
	reg_move(c, FPU_st0_ptr);
	status_word &= ~SW_C1;
}
Пример #7
0
static void
f2xm1(void)
{
    switch (FPU_st0_tag) {
    case TW_Valid:
    {
        FPU_REG rv, tmp;

#ifdef DENORM_OPERAND
        if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
            return;
#endif				/* DENORM_OPERAND */

        if (FPU_st0_ptr->sign == SIGN_POS) {
            /* poly_2xm1(x) requires 0 < x < 1. */
            if (poly_2xm1(FPU_st0_ptr, &rv))
                return;	/* error */
            reg_mul(&rv, FPU_st0_ptr, FPU_st0_ptr, FULL_PRECISION);
        } else {
            /* **** Should change poly_2xm1() to at least handle numbers near 0 */
            /* poly_2xm1(x) doesn't handle negative
             * numbers. */
            /* So we compute (poly_2xm1(x+1)-1)/2, for -1
             * < x < 0 */
            reg_add(FPU_st0_ptr, &CONST_1, &tmp, FULL_PRECISION);
            poly_2xm1(&tmp, &rv);
            reg_mul(&rv, &tmp, &tmp, FULL_PRECISION);
            reg_sub(&tmp, &CONST_1, FPU_st0_ptr, FULL_PRECISION);
            FPU_st0_ptr->exp--;
            if (FPU_st0_ptr->exp <= EXP_UNDER)
                arith_underflow(FPU_st0_ptr);
        }
        return;
    }
    case TW_Zero:
        return;
    case TW_Infinity:
        if (FPU_st0_ptr->sign == SIGN_NEG) {
            /* -infinity gives -1 (p16-10) */
            reg_move(&CONST_1, FPU_st0_ptr);
            FPU_st0_ptr->sign = SIGN_NEG;
        }
        return;
    default:
        single_arg_error();
    }
}
Пример #8
0
void
vanish(object *obj, short rm, object *pack)
{
	if (obj->quantity > 1) {
		obj->quantity--;
	} else {
		if (obj->in_use_flags & BEING_WIELDED) {
			unwield(obj);
		} else if (obj->in_use_flags & BEING_WORN) {
			unwear(obj);
		} else if (obj->in_use_flags & ON_EITHER_HAND) {
			un_put_on(obj);
		}
		take_from_pack(obj, pack);
		free_object(obj);
	}
	if (rm) {
		reg_move();
	}
}
Пример #9
0
/* Convert a long to register */
static void
convert_l2reg(long *arg, FPU_REG * dest)
{
    long    num = *arg;

    if (num == 0) {
        reg_move(&CONST_Z, dest);
        return;
    }
    if (num > 0)
        dest->sign = SIGN_POS;
    else {
        num = -num;
        dest->sign = SIGN_NEG;
    }

    dest->sigh = num;
    dest->sigl = 0;
    dest->exp = EXP_BIAS + 31;
    dest->tag = TW_Valid;
    normalize(dest);
}
Пример #10
0
void
fld_i_()
{
	FPU_REG *st_new_ptr;

	if (STACK_OVERFLOW) {
		stack_overflow();
		return;
	}
	/* fld st(i) */
	if (NOT_EMPTY(FPU_rm)) {
		reg_move(&st(FPU_rm), st_new_ptr);
		push();
	} else {
		if (control_word & EX_Invalid) {
			/* The masked response */
			push();
			stack_underflow();
		} else
			EXCEPTION(EX_StackUnder);
	}

}
Пример #11
0
/*--- poly_atan() -----------------------------------------------------------+
 |                                                                           |
 +---------------------------------------------------------------------------*/
void
poly_atan(FPU_REG * arg)
{
	char    recursions = 0;
	short   exponent;
	FPU_REG odd_poly, even_poly, pos_poly, neg_poly;
	FPU_REG argSq;
	long long arg_signif, argSqSq;


#ifdef PARANOID
	if (arg->sign != 0) {	/* Can't hack a number < 0.0 */
		arith_invalid(arg);
		return;
	}			/* Need a positive number */
#endif				/* PARANOID */

	exponent = arg->exp - EXP_BIAS;

	if (arg->tag == TW_Zero) {
		/* Return 0.0 */
		reg_move(&CONST_Z, arg);
		return;
	}
	if (exponent >= -2) {
		/* argument is in the range  [0.25 .. 1.0] */
		if (exponent >= 0) {
#ifdef PARANOID
			if ((exponent == 0) &&
			    (arg->sigl == 0) && (arg->sigh == 0x80000000))
#endif				/* PARANOID */
			{
				reg_move(&CONST_PI4, arg);
				return;
			}
#ifdef PARANOID
			EXCEPTION(EX_INTERNAL | 0x104);	/* There must be a logic
							 * error */
#endif				/* PARANOID */
		}
		/* If the argument is greater than sqrt(2)-1 (=0.414213562...) */
		/* convert the argument by an identity for atan */
		if ((exponent >= -1) || (arg->sigh > 0xd413ccd0)) {
			FPU_REG numerator, denom;

			recursions++;

			arg_signif = *(long long *) &(arg->sigl);
			if (exponent < -1) {
				if (shrx(&arg_signif, -1 - exponent) >= (unsigned)0x80000000)
					arg_signif++;	/* round up */
			}
			*(long long *) &(numerator.sigl) = -arg_signif;
			numerator.exp = EXP_BIAS - 1;
			normalize(&numerator);	/* 1 - arg */

			arg_signif = *(long long *) &(arg->sigl);
			if (shrx(&arg_signif, -exponent) >= (unsigned)0x80000000)
				arg_signif++;	/* round up */
			*(long long *) &(denom.sigl) = arg_signif;
			denom.sigh |= 0x80000000;	/* 1 + arg */

			arg->exp = numerator.exp;
			reg_u_div(&numerator, &denom, arg, FULL_PRECISION);

			exponent = arg->exp - EXP_BIAS;
		}
	}
	*(long long *) &arg_signif = *(long long *) &(arg->sigl);

#ifdef PARANOID
	/* This must always be true */
	if (exponent >= -1) {
		EXCEPTION(EX_INTERNAL | 0x120);	/* There must be a logic error */
	}
#endif				/* PARANOID */

	/* shift the argument right by the required places */
	if (shrx(&arg_signif, -1 - exponent) >= (unsigned)0x80000000)
		arg_signif++;	/* round up */

	/* Now have arg_signif with binary point at the left .1xxxxxxxx */
	mul64(&arg_signif, &arg_signif, (long long *) (&argSq.sigl));
	mul64((long long *) (&argSq.sigl), (long long *) (&argSq.sigl), &argSqSq);

	/* will be a valid positive nr with expon = 0 */
	*(short *) &(pos_poly.sign) = 0;
	pos_poly.exp = EXP_BIAS;

	/* Do the basic fixed point polynomial evaluation */
	polynomial(&pos_poly.sigl, (unsigned *) &argSqSq,
	    (unsigned short (*)[4]) oddplterms, HIPOWERop - 1);
	mul64((long long *) (&argSq.sigl), (long long *) (&pos_poly.sigl),
	    (long long *) (&pos_poly.sigl));

	/* will be a valid positive nr with expon = 0 */
	*(short *) &(neg_poly.sign) = 0;
	neg_poly.exp = EXP_BIAS;

	/* Do the basic fixed point polynomial evaluation */
	polynomial(&neg_poly.sigl, (unsigned *) &argSqSq,
	    (unsigned short (*)[4]) oddnegterms, HIPOWERon - 1);

	/* Subtract the mantissas */
	*((long long *) (&pos_poly.sigl)) -= *((long long *) (&neg_poly.sigl));

	reg_move(&pos_poly, &odd_poly);
	poly_add_1(&odd_poly);

	/* The complete odd polynomial */
	reg_u_mul(&odd_poly, arg, &odd_poly, FULL_PRECISION);

	/* will be a valid positive nr with expon = 0 */
	*(short *) &(even_poly.sign) = 0;

	mul64((long long *) (&argSq.sigl),
	    (long long *) (&denomterm), (long long *) (&even_poly.sigl));

	poly_add_1(&even_poly);

	reg_div(&odd_poly, &even_poly, arg, FULL_PRECISION);

	if (recursions)
		reg_sub(&CONST_PI4, arg, arg, FULL_PRECISION);
}
Пример #12
0
/* Subtract b from a.  (a-b) -> dest */
void reg_sub(FPU_REG *a, FPU_REG *b, FPU_REG *dest, int control_w)
{
    int diff;

    if ( !(a->tag | b->tag) )
    {
        /* Both registers are valid */
        diff = a->exp - b->exp;
        if (!diff)
        {
            diff = a->sigh - b->sigh;  /* Works only if ms bits are identical */
            if (!diff)
            {
                diff = a->sigl > b->sigl;
                if (!diff)
                    diff = -(a->sigl < b->sigl);
            }
        }

        switch (a->sign*2 + b->sign)
        {
        case 0: /* P - P */
        case 3: /* N - N */
            if (diff > 0)
            {
                reg_u_sub(a, b, dest, control_w);
                dest->sign = a->sign;
            }
            else if ( diff == 0 )
            {
                reg_move(&CONST_Z, dest);
                /* sign depends upon rounding mode */
                dest->sign = ((control_w & CW_RC) != RC_DOWN)
                             ? SIGN_POS : SIGN_NEG;
            }
            else
            {
                reg_u_sub(b, a, dest, control_w);
                dest->sign = a->sign ^ SIGN_POS^SIGN_NEG;
            }
            return;
        case 1: /* P - N */
            reg_u_add(a, b, dest, control_w);
            dest->sign = SIGN_POS;
            return;
        case 2: /* N - P */
            reg_u_add(a, b, dest, control_w);
            dest->sign = SIGN_NEG;
            return;
        }
    }
    else
    {
        if ( (a->tag == TW_NaN) || (b->tag == TW_NaN) )
        {
            real_2op_NaN(a, b, dest);
            return;
        }
        else if (b->tag == TW_Zero)
        {
            if (a->tag == TW_Zero)
            {
                char same_signs = !(a->sign ^ b->sign);
                /* Both are zero, result will be zero. */
                reg_move(a, dest); /* Answer for different signs. */
                if (same_signs)
                {
                    /* Sign depends upon rounding mode */
                    dest->sign = ((control_w & CW_RC) != RC_DOWN)
                                 ? SIGN_POS : SIGN_NEG;
                }
            }
            else
                reg_move(a, dest);
            return;
        }
        else if (a->tag == TW_Zero)
        {
            reg_move(b, dest);
            dest->sign ^= SIGN_POS^SIGN_NEG;
            return;
        }
        else if (a->tag == TW_Infinity)
        {
            if (b->tag != TW_Infinity)
            {
                reg_move(a, dest);
                return;
            }
            if (a->sign == b->sign)
            {
                reg_move(&CONST_QNaN, dest);
                return;
            }
            reg_move(a, dest);
            return;
        }
        else if (b->tag == TW_Infinity)
        {
            reg_move(b, dest);
            dest->sign ^= SIGN_POS^SIGN_NEG;
            return;
        }
    }
#ifdef PARANOID
    EXCEPTION(EX_INTERNAL|0x110);
#endif
}
Пример #13
0
void load_store_instr(char type)
{
  FPU_REG *pop_ptr;  /* We need a version of FPU_st0_ptr which won't change. */

  pop_ptr = NULL;    /* Initialized just to stop compiler warnings. */
  switch ( type_table[(int) (unsigned) type] )
    {
    case _NONE_:
      break;
    case _REG0_:
      pop_ptr = &st(0);       /* Some of these instructions pop after
				 storing */

      FPU_st0_ptr = pop_ptr;      /* Set the global variables. */
      FPU_st0_tag = FPU_st0_ptr->tag;
      break;
    case _PUSH_:
      {
	pop_ptr = &st(-1);
	if ( pop_ptr->tag != TW_Empty )
	  { stack_overflow(); return; }
	top--;
      }
      break;
    case _null_:
      return Un_impl();
#ifdef PARANOID
    default:
      return EXCEPTION(EX_INTERNAL);
#endif PARANOID
    }

switch ( type )
  {
  case 000:       /* fld m32real */
    reg_load_single();
    reg_move(&FPU_loaded_data, pop_ptr);
    break;
  case 001:      /* fild m32int */
    reg_load_int32();
    reg_move(&FPU_loaded_data, pop_ptr);
    break;
  case 002:      /* fld m64real */
    reg_load_double();
    reg_move(&FPU_loaded_data, pop_ptr);
    break;
  case 003:      /* fild m16int */
    reg_load_int16();
    reg_move(&FPU_loaded_data, pop_ptr);
    break;
  case 010:      /* fst m32real */
    reg_store_single();
    break;
  case 011:      /* fist m32int */
    reg_store_int32();
    break;
  case 012:     /* fst m64real */
    reg_store_double();
    break;
  case 013:     /* fist m16int */
    reg_store_int16();
    break;
  case 014:     /* fstp m32real */
    if ( reg_store_single() )
      pop_0();  /* pop only if the number was actually stored
		 (see the 80486 manual p16-28) */
    break;
  case 015:     /* fistp m32int */
    if ( reg_store_int32() )
      pop_0();  /* pop only if the number was actually stored
		 (see the 80486 manual p16-28) */
    break;
  case 016:     /* fstp m64real */
    if ( reg_store_double() )
      pop_0();  /* pop only if the number was actually stored
		 (see the 80486 manual p16-28) */
    break;
  case 017:     /* fistp m16int */
    if ( reg_store_int16() )
      pop_0();  /* pop only if the number was actually stored
		 (see the 80486 manual p16-28) */
    break;
  case 020:     /* fldenv  m14/28byte */
    fldenv();
    break;
  case 022:     /* frstor m94/108byte */
    frstor();
    break;
  case 023:     /* fbld m80dec */
    reg_load_bcd();
    reg_move(&FPU_loaded_data, pop_ptr);
    break;
  case 024:     /* fldcw */
    RE_ENTRANT_CHECK_OFF
    control_word = get_fs_word((unsigned short *) FPU_data_address);
    RE_ENTRANT_CHECK_ON
#ifdef NO_UNDERFLOW_TRAP
    if ( !(control_word & EX_Underflow) )
      {
	control_word |= EX_Underflow;
      }
#endif
    FPU_data_address = (void *)data_operand_offset; /* We want no net effect */
    FPU_entry_eip = ip_offset;               /* We want no net effect */
    break;
  case 025:      /* fld m80real */
    reg_load_extended();
    reg_move(&FPU_loaded_data, pop_ptr);
    break;
  case 027:      /* fild m64int */
    reg_load_int64();
    reg_move(&FPU_loaded_data, pop_ptr);
    break;
  case 030:     /* fstenv  m14/28byte */
    fstenv();
    FPU_data_address = (void *)data_operand_offset; /* We want no net effect */
    FPU_entry_eip = ip_offset;               /* We want no net effect */
    break;
  case 032:      /* fsave */
    fsave();
    FPU_data_address = (void *)data_operand_offset; /* We want no net effect */
    FPU_entry_eip = ip_offset;               /* We want no net effect */
    break;
  case 033:      /* fbstp m80dec */
    if ( reg_store_bcd() )
      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
    verify_area(VERIFY_WRITE,FPU_data_address,2);
    put_fs_word(control_word, (short *) FPU_data_address);
    RE_ENTRANT_CHECK_ON
    FPU_data_address = (void *)data_operand_offset; /* We want no net effect */
    FPU_entry_eip = ip_offset;               /* We want no net effect */
    break;
  case 035:      /* fstp m80real */
    if ( reg_store_extended() )
      pop_0();  /* pop only if the number was actually stored
		 (see the 80486 manual p16-28) */
    break;
  case 036:      /* fstsw m2byte */
    status_word &= ~SW_TOP;
    status_word |= (top&7) << SW_TOPS;
    RE_ENTRANT_CHECK_OFF
    verify_area(VERIFY_WRITE,FPU_data_address,2);
    put_fs_word(status_word,(short *) FPU_data_address);
    RE_ENTRANT_CHECK_ON
    FPU_data_address = (void *)data_operand_offset; /* We want no net effect */
    FPU_entry_eip = ip_offset;               /* We want no net effect */
    break;
  case 037:      /* fistp m64int */
    if ( reg_store_int64() )
      pop_0();  /* pop only if the number was actually stored
		 (see the 80486 manual p16-28) */
    break;
  }
}
Пример #14
0
void reg_add(FPU_REG *a, FPU_REG *b, FPU_REG *dest, int control_w)
{
    int diff;

    if ( !(a->tag | b->tag) )
    {
        /* Both registers are valid */
        if (!(a->sign ^ b->sign))
        {
            /* signs are the same */
            reg_u_add(a, b, dest, control_w);
            dest->sign = a->sign;
            return;
        }

        /* The signs are different, so do a subtraction */
        diff = a->exp - b->exp;
        if (!diff)
        {
            diff = a->sigh - b->sigh;  /* Works only if ms bits are identical */
            if (!diff)
            {
                diff = a->sigl > b->sigl;
                if (!diff)
                    diff = -(a->sigl < b->sigl);
            }
        }

        if (diff > 0)
        {
            reg_u_sub(a, b, dest, control_w);
            dest->sign = a->sign;
        }
        else if ( diff == 0 )
        {
            reg_move(&CONST_Z, dest);
            /* sign depends upon rounding mode */
            dest->sign = ((control_w & CW_RC) != RC_DOWN)
                         ? SIGN_POS : SIGN_NEG;
        }
        else
        {
            reg_u_sub(b, a, dest, control_w);
            dest->sign = b->sign;
        }
        return;
    }
    else
    {
        if ( (a->tag == TW_NaN) || (b->tag == TW_NaN) )
        {
            real_2op_NaN(a, b, dest);
            return;
        }
        else if (a->tag == TW_Zero)
        {
            if (b->tag == TW_Zero)
            {
                char different_signs = a->sign ^ b->sign;
                /* Both are zero, result will be zero. */
                reg_move(a, dest);
                if (different_signs)
                {
                    /* Signs are different. */
                    /* Sign of answer depends upon rounding mode. */
                    dest->sign = ((control_w & CW_RC) != RC_DOWN)
                                 ? SIGN_POS : SIGN_NEG;
                }
            }
            else
                reg_move(b, dest);
            return;
        }
        else if (b->tag == TW_Zero)
        {
            reg_move(a, dest);
            return;
        }
        else if (a->tag == TW_Infinity)
        {
            if (b->tag != TW_Infinity)
            {
                reg_move(a, dest);
                return;
            }
            /* They are both + or - infinity */
            if (a->sign == b->sign)
            {
                reg_move(a, dest);
                return;
            }
            reg_move(&CONST_QNaN, dest);	/* inf - inf is undefined. */
            return;
        }
        else if (b->tag == TW_Infinity)
        {
            reg_move(b, dest);
            return;
        }
    }
#ifdef PARANOID
    EXCEPTION(EX_INTERNAL|0x101);
#endif
}
Пример #15
0
void
fst_i_()
{
	/* fst st(i) */
	reg_move(FPU_st0_ptr, &st(FPU_rm));
}
Пример #16
0
/*--- poly_sine() -----------------------------------------------------------+
 |                                                                           |
 +---------------------------------------------------------------------------*/
void	poly_sine(FPU_REG const *arg, FPU_REG *result)
{
  int                 exponent, echange;
  Xsig                accumulator, argSqrd, argTo4;
  unsigned long       fix_up, adj;
  unsigned long long  fixed_arg;


#ifdef PARANOID
  if ( arg->tag == TW_Zero )
    {
      /* Return 0.0 */
      reg_move(&CONST_Z, result);
      return;
    }
#endif PARANOID

  exponent = arg->exp - EXP_BIAS;

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

  /* Split into two ranges, for arguments below and above 1.0 */
  /* The boundary between upper and lower is approx 0.88309101259 */
  if ( (exponent < -1) || ((exponent == -1) && (arg->sigh <= 0xe21240aa)) )
    {
      /* The argument is <= 0.88309101259 */

      argSqrd.msw = arg->sigh; argSqrd.midw = arg->sigl; argSqrd.lsw = 0;
      mul64_Xsig(&argSqrd, &significand(arg));
      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);    /* Divide by four */
      accumulator.msw |= 0x80000000;  /* Add 1.0 */

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

      /* Divide by four, FPU_REG compatible, etc */
      exponent = 3*exponent + EXP_BIAS;

      /* The minimum exponent difference is 3 */
      shr_Xsig(&accumulator, arg->exp - exponent);

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

      echange = round_Xsig(&accumulator);

      result->exp = arg->exp + echange;
    }
  else
    {
      /* The argument is > 0.88309101259 */
      /* We use sin(arg) = cos(pi/2-arg) */

      fixed_arg = significand(arg);

      if ( exponent == 0 )
	{
	  /* The argument is >= 1.0 */

	  /* Put the binary point at the left. */
	  fixed_arg <<= 1;
	}
      /* pi/2 in hex is: 1.921fb54442d18469 898CC51701B839A2 52049C1 */
      fixed_arg = 0x921fb54442d18469LL - fixed_arg;

      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;  /* A zero accumulator here would cause problems */
      negate_Xsig(&accumulator);

      /* The basic computation is complete. Now fix the answer to
	 compensate for the error due to the approximation used for
	 pi/2
	 */

      /* This has an exponent of -65 */
      fix_up = 0x898cc517;
      /* The fix-up needs to be improved for larger args */
      if ( argSqrd.msw & 0xffc00000 )
	{
	  /* Get about 32 bit precision in these: */
	  mul_32_32(0x898cc517, argSqrd.msw, &adj);
	  fix_up -= adj/6;
	}
      mul_32_32(fix_up, LL_MSW(fixed_arg), &fix_up);

      adj = accumulator.lsw;    /* temp save */
      accumulator.lsw -= fix_up;
      if ( accumulator.lsw > adj )
	XSIG_LL(accumulator) --;

      echange = round_Xsig(&accumulator);

      result->exp = EXP_BIAS - 1 + echange;
    }

  significand(result) = XSIG_LL(accumulator);
  result->tag = TW_Valid;
  result->sign = arg->sign;

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

}
Пример #17
0
/*--- poly_sine() -----------------------------------------------------------+
 |                                                                           |
 +---------------------------------------------------------------------------*/
void	poly_sine(FPU_REG const *arg, FPU_REG *result)
{
  short	exponent;
  FPU_REG	fixed_arg, arg_sqrd, arg_to_4, accum, negaccum;
  
  
  exponent = arg->exp - EXP_BIAS;
  
  if ( arg->tag == TW_Zero )
    {
      /* Return 0.0 */
      reg_move(&CONST_Z, result);
      return;
    }
  
#ifdef PARANOID
  if ( arg->sign != 0 )	/* Can't hack a number < 0.0 */
    {
      EXCEPTION(EX_Invalid);
      reg_move(&CONST_QNaN, result);
      return;
    }
  
  if ( exponent >= 0 )	/* Can't hack a number > 1.0 */
    {
      if ( (exponent == 0) && (arg->sigl == 0) && (arg->sigh == 0x80000000) )
	{
	  reg_move(&CONST_1, result);
	  return;
	}
      EXCEPTION(EX_Invalid);
      reg_move(&CONST_QNaN, result);
      return;
    }
#endif PARANOID
  
  fixed_arg.sigl = arg->sigl;
  fixed_arg.sigh = arg->sigh;
  if ( exponent < -1 )
    {
      /* shift the argument right by the required places */
      if ( shrx(&(fixed_arg.sigl), -1-exponent) >= 0x80000000U )
	significand(&fixed_arg)++;	/* round up */
    }
  
  mul64(&significand(&fixed_arg), &significand(&fixed_arg),
	&significand(&arg_sqrd));
  mul64(&significand(&arg_sqrd), &significand(&arg_sqrd),
	&significand(&arg_to_4));
  
  /* will be a valid positive nr with expon = 0 */
  *(short *)&(accum.sign) = 0;
  accum.exp = 0;

  /* Do the basic fixed point polynomial evaluation */
  polynomial(&(accum.sigl), &(arg_to_4.sigl), lterms, HIPOWER-1);
  
  /* will be a valid positive nr with expon = 0 */
  *(short *)&(negaccum.sign) = 0;
  negaccum.exp = 0;
  
  /* Do the basic fixed point polynomial evaluation */
  polynomial(&(negaccum.sigl), &(arg_to_4.sigl), negterms, HIPOWER-1);
  mul64(&significand(&arg_sqrd), &significand(&negaccum),
	&significand(&negaccum));

  /* Subtract the mantissas */
  significand(&accum) -= significand(&negaccum);
  
  /* Convert to 64 bit signed-compatible */
  accum.exp = EXP_BIAS - 1 + accum.exp;

  reg_move(&accum, result);

  normalize(result);

  reg_mul(result, arg, result, FULL_PRECISION);
  reg_u_add(result, arg, result, FULL_PRECISION);
  
  if ( result->exp >= EXP_BIAS )
    {
      /* A small overflow may be possible... but an illegal result. */
      if (    (result->exp > EXP_BIAS) /* Larger or equal 2.0 */
	  || (result->sigl > 1)	  /* Larger than 1.0+msb */
	  ||	(result->sigh != 0x80000000) /* Much > 1.0 */
	  )
	{
#ifdef DEBUGGING
	  RE_ENTRANT_CHECK_OFF;
	  printk("\nEXP=%d, MS=%08x, LS=%08x\n", result->exp,
		 result->sigh, result->sigl);
	  RE_ENTRANT_CHECK_ON;
#endif DEBUGGING
	  EXCEPTION(EX_INTERNAL|0x103);
	}
      
#ifdef DEBUGGING
      RE_ENTRANT_CHECK_OFF;
      printk("\n***CORRECTING ILLEGAL RESULT*** in poly_sin() computation\n");
      printk("EXP=%d, MS=%08x, LS=%08x\n", result->exp,
	     result->sigh, result->sigl);
      RE_ENTRANT_CHECK_ON;
#endif DEBUGGING

      result->sigl = 0;	/* Truncate the result to 1.00 */
    }

}
Пример #18
0
static void
fxtract(void)
{
    FPU_REG *st_new_ptr;
    register FPU_REG *st1_ptr = FPU_st0_ptr;	/* anticipate */

    if (STACK_OVERFLOW) {
        stack_overflow();
        return;
    }
    if (!(FPU_st0_tag ^ TW_Valid)) {
        long    e;

#ifdef DENORM_OPERAND
        if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
            return;
#endif				/* DENORM_OPERAND */

        push();
        reg_move(st1_ptr, FPU_st0_ptr);
        FPU_st0_ptr->exp = EXP_BIAS;
        e = st1_ptr->exp - EXP_BIAS;
        convert_l2reg(&e, st1_ptr);
        return;
    } else if (FPU_st0_tag == TW_Zero) {
        char    sign = FPU_st0_ptr->sign;
        divide_by_zero(SIGN_NEG, FPU_st0_ptr);
        push();
        reg_move(&CONST_Z, FPU_st0_ptr);
        FPU_st0_ptr->sign = sign;
        return;
    } else if (FPU_st0_tag == TW_Infinity) {
        char    sign = FPU_st0_ptr->sign;
        FPU_st0_ptr->sign = SIGN_POS;
        push();
        reg_move(&CONST_INF, FPU_st0_ptr);
        FPU_st0_ptr->sign = sign;
        return;
    } else if (FPU_st0_tag == TW_NaN) {
        if (!(FPU_st0_ptr->sigh & 0x40000000)) {	/* Signaling ? */
            EXCEPTION(EX_Invalid);
            /* Convert to a QNaN */
            FPU_st0_ptr->sigh |= 0x40000000;
        }
        push();
        reg_move(st1_ptr, FPU_st0_ptr);
        return;
    } else if (FPU_st0_tag == TW_Empty) {
        /* Is this the correct
         * behaviour? */
        if (control_word & EX_Invalid) {
            stack_underflow();
            push();
            stack_underflow();
        } else
            EXCEPTION(EX_StackUnder);
    }
#ifdef PARANOID
    else
        EXCEPTION(EX_INTERNAL | 0x119);
#endif				/* PARANOID */
}
Пример #19
0
/*--- poly_tan() ------------------------------------------------------------+
 |                                                                           |
 +---------------------------------------------------------------------------*/
void
poly_tan(FPU_REG * arg, FPU_REG * y_reg)
{
	char    invert = 0;
	short   exponent;
	FPU_REG odd_poly, even_poly, pos_poly, neg_poly;
	FPU_REG argSq;
	long long arg_signif, argSqSq;


	exponent = arg->exp - EXP_BIAS;

	if (arg->tag == TW_Zero) {
		/* Return 0.0 */
		reg_move(&CONST_Z, y_reg);
		return;
	}
	if (exponent >= -1) {
		/* argument is in the range  [0.5 .. 1.0] */
		if (exponent >= 0) {
#ifdef PARANOID
			if ((exponent == 0) &&
			    (arg->sigl == 0) && (arg->sigh == 0x80000000))
#endif				/* PARANOID */
			{
				arith_overflow(y_reg);
				return;
			}
#ifdef PARANOID
			EXCEPTION(EX_INTERNAL | 0x104);	/* There must be a logic
							 * error */
			return;
#endif				/* PARANOID */
		}
		/* The argument is in the range  [0.5 .. 1.0) */
		/* Convert the argument to a number in the range  (0.0 .. 0.5] */
		*((long long *) (&arg->sigl)) = -*((long long *) (&arg->sigl));
		normalize(arg);	/* Needed later */
		exponent = arg->exp - EXP_BIAS;
		invert = 1;
	}
#ifdef PARANOID
	if (arg->sign != 0) {	/* Can't hack a number < 0.0 */
		arith_invalid(y_reg);
		return;
	}			/* Need a positive number */
#endif				/* PARANOID */

	*(long long *) &arg_signif = *(long long *) &(arg->sigl);
	if (exponent < -1) {
		/* shift the argument right by the required places */
		if (shrx(&arg_signif, -1 - exponent) >= (unsigned)0x80000000)
			arg_signif++;	/* round up */
	}
	mul64(&arg_signif, &arg_signif, (long long *) (&argSq.sigl));
	mul64((long long *) (&argSq.sigl), (long long *) (&argSq.sigl), &argSqSq);

	/* will be a valid positive nr with expon = 0 */
	*(short *) &(pos_poly.sign) = 0;
	pos_poly.exp = EXP_BIAS;

	/* Do the basic fixed point polynomial evaluation */
	polynomial((u_int *) &pos_poly.sigl, (unsigned *) &argSqSq, oddplterms, HIPOWERop - 1);

	/* will be a valid positive nr with expon = 0 */
	*(short *) &(neg_poly.sign) = 0;
	neg_poly.exp = EXP_BIAS;

	/* Do the basic fixed point polynomial evaluation */
	polynomial((u_int *) &neg_poly.sigl, (unsigned *) &argSqSq, oddnegterms, HIPOWERon - 1);
	mul64((long long *) (&argSq.sigl), (long long *) (&neg_poly.sigl),
	    (long long *) (&neg_poly.sigl));

	/* Subtract the mantissas */
	*((long long *) (&pos_poly.sigl)) -= *((long long *) (&neg_poly.sigl));

	/* Convert to 64 bit signed-compatible */
	pos_poly.exp -= 1;

	reg_move(&pos_poly, &odd_poly);
	normalize(&odd_poly);

	reg_mul(&odd_poly, arg, &odd_poly, FULL_PRECISION);
	reg_u_add(&odd_poly, arg, &odd_poly, FULL_PRECISION);	/* This is just the odd
								 * polynomial */


	/* will be a valid positive nr with expon = 0 */
	*(short *) &(pos_poly.sign) = 0;
	pos_poly.exp = EXP_BIAS;

	/* Do the basic fixed point polynomial evaluation */
	polynomial((u_int *) &pos_poly.sigl, (unsigned *) &argSqSq, evenplterms, HIPOWERep - 1);
	mul64((long long *) (&argSq.sigl),
	    (long long *) (&pos_poly.sigl), (long long *) (&pos_poly.sigl));

	/* will be a valid positive nr with expon = 0 */
	*(short *) &(neg_poly.sign) = 0;
	neg_poly.exp = EXP_BIAS;

	/* Do the basic fixed point polynomial evaluation */
	polynomial((u_int *) &neg_poly.sigl, (unsigned *) &argSqSq, evennegterms, HIPOWERen - 1);

	/* Subtract the mantissas */
	*((long long *) (&neg_poly.sigl)) -= *((long long *) (&pos_poly.sigl));
	/* and multiply by argSq */

	/* Convert argSq to a valid reg number */
	*(short *) &(argSq.sign) = 0;
	argSq.exp = EXP_BIAS - 1;
	normalize(&argSq);

	/* Convert to 64 bit signed-compatible */
	neg_poly.exp -= 1;

	reg_move(&neg_poly, &even_poly);
	normalize(&even_poly);

	reg_mul(&even_poly, &argSq, &even_poly, FULL_PRECISION);
	reg_add(&even_poly, &argSq, &even_poly, FULL_PRECISION);
	reg_sub(&CONST_1, &even_poly, &even_poly, FULL_PRECISION);	/* This is just the even
									 * polynomial */

	/* Now ready to copy the results */
	if (invert) {
		reg_div(&even_poly, &odd_poly, y_reg, FULL_PRECISION);
	} else {
		reg_div(&odd_poly, &even_poly, y_reg, FULL_PRECISION);
	}

}
Пример #20
0
/*--- poly_cos() ------------------------------------------------------------+
 |                                                                           |
 +---------------------------------------------------------------------------*/
void	poly_cos(FPU_REG const *arg, FPU_REG *result)
{
  long int            exponent, exp2, echange;
  Xsig                accumulator, argSqrd, fix_up, argTo4;
  unsigned long       adj;
  unsigned long long  fixed_arg;


#ifdef PARANOID
  if ( arg->tag == TW_Zero )
    {
      /* Return 1.0 */
      reg_move(&CONST_1, result);
      return;
    }

  if ( (arg->exp > EXP_BIAS)
      || ((arg->exp == EXP_BIAS)
	  && (significand(arg) > 0xc90fdaa22168c234LL)) )
    {
      EXCEPTION(EX_Invalid);
      reg_move(&CONST_QNaN, result);
      return;
    }
#endif PARANOID

  exponent = arg->exp - EXP_BIAS;

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

  if ( (exponent < -1) || ((exponent == -1) && (arg->sigh <= 0xb00d6f54)) )
    {
      /* arg is < 0.687705 */

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

      if ( exponent < -1 )
	{
	  /* shift the argument right by the required places */
	  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(arg));
      mul64_Xsig(&accumulator, &significand(arg));
      shr_Xsig(&accumulator, -2*(1+exponent));

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

      add_Xsig_Xsig(&accumulator, &argSqrd);

      shr_Xsig(&accumulator, 1);

      /* It doesn't matter if accumulator is all zero here, the
	 following code will work ok */
      negate_Xsig(&accumulator);

      if ( accumulator.lsw & 0x80000000 )
	XSIG_LL(accumulator) ++;
      if ( accumulator.msw == 0 )
	{
	  /* The result is 1.0 */
	  reg_move(&CONST_1, result);
	}
      else
	{
	  significand(result) = XSIG_LL(accumulator);
      
	  /* will be a valid positive nr with expon = -1 */
	  *(short *)&(result->sign) = 0;
	  result->exp = EXP_BIAS - 1;
	}
    }
  else
    {
      fixed_arg = significand(arg);

      if ( exponent == 0 )
	{
	  /* The argument is >= 1.0 */

	  /* Put the binary point at the left. */
	  fixed_arg <<= 1;
	}
      /* pi/2 in hex is: 1.921fb54442d18469 898CC51701B839A2 52049C1 */
      fixed_arg = 0x921fb54442d18469LL - fixed_arg;

      exponent = -1;
      exp2 = -1;

      /* A shift is needed here only for a narrow range of arguments,
	 i.e. for fixed_arg approx 2^-32, but we pick up more... */
      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 )
	{
	  /* shift the argument right by the required places */
	  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);    /* Divide by four */
      accumulator.msw |= 0x80000000;  /* Add 1.0 */

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

      /* Divide by four, FPU_REG compatible, etc */
      exponent = 3*exponent;

      /* The minimum exponent difference is 3 */
      shr_Xsig(&accumulator, exp2 - exponent);

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

      /* The basic computation is complete. Now fix the answer to
	 compensate for the error due to the approximation used for
	 pi/2
	 */

      /* This has an exponent of -65 */
      XSIG_LL(fix_up) = 0x898cc51701b839a2ll;
      fix_up.lsw = 0;

      /* The fix-up needs to be improved for larger args */
      if ( argSqrd.msw & 0xffc00000 )
	{
	  /* Get about 32 bit precision in these: */
	  mul_32_32(0x898cc517, argSqrd.msw, &adj);
	  fix_up.msw -= adj/2;
	  mul_32_32(0x898cc517, argTo4.msw, &adj);
	  fix_up.msw += adj/24;
	}

      exp2 += norm_Xsig(&accumulator);
      shr_Xsig(&accumulator, 1); /* Prevent overflow */
      exp2++;
      shr_Xsig(&fix_up, 65 + exp2);

      add_Xsig_Xsig(&accumulator, &fix_up);

      echange = round_Xsig(&accumulator);

      result->exp = exp2 + EXP_BIAS + echange;
      *(short *)&(result->sign) = 0;      /* Is a valid positive nr */
      significand(result) = XSIG_LL(accumulator);
    }

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

}