Exemple #1
0
void FPU_copy_to_reg0(FPU_REG const *r, u_char tag)
{
    int regnr = top;
    regnr &= 7;

    reg_copy(r, &st(0));

    fpu_tag_word &= ~(3 << (regnr * 2));
    fpu_tag_word |= (tag & 3) << (regnr * 2);
}
Exemple #2
0
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();
}
Exemple #3
0
static void phineas_rd_n (int n)
{
  switch (n)
    {
    case 0x0: /* 038: RTIME */
      reg_copy (c, clock_reg [timer_reg_sel]);
      break;
    case 0x1: /* 078: RTIMEST */
      reg_copy (c, clock_reg [timer_reg_sel]);
      /* start correction count ??? */
      break;
    case 0x2: /* 0b8: RALM */
      reg_copy (c, alarm_reg [timer_reg_sel]);
      break;
    case 0x3: /* 0f8: RSTS */
      reg_copy (c, timer_reg_sel ? accuracy_factor : timer_status);
      break;
    case 0x4: /* 138: RSCR */
      reg_copy (c, timer_scratch);
      break;
    case 0x5: /* 178: RINT */
      reg_copy (c, interval_timer);
      break;
    case 0x6: /* 1b8: ??? */
    case 0x7: /* 1f8: ??? */
    case 0x8: /* 238: ??? */
    case 0x9: /* 278: ??? */
    case 0xa: /* 2b8: ??? */
    case 0xb: /* 2f8: ??? */
    case 0xc: /* 338: ??? */
    case 0xd: /* 378: ??? */
    case 0xe: /* 3b8: ??? */
    case 0xf: /* 3f8: ??? */
      reg_zero (c);
      break;
    }
}
Exemple #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 
}
static
int add_sub_specials(FPU_REG const *a, u_char taga, u_char signa,
		     FPU_REG const *b, u_char tagb, u_char signb,
		     FPU_REG * dest, int deststnr, int control_w)
{
	if (((taga == TW_Denormal) || (tagb == TW_Denormal))
	    && (denormal_operand() < 0))
		return FPU_Exception;

	if (taga == TAG_Zero) {
		if (tagb == TAG_Zero) {
			
			u_char different_signs = signa ^ signb;

			FPU_copy_to_regi(a, TAG_Zero, deststnr);
			if (different_signs) {
				
				
				setsign(dest, ((control_w & CW_RC) != RC_DOWN)
					? SIGN_POS : SIGN_NEG);
			} else
				setsign(dest, signa);	
			return TAG_Zero;
		} else {
			reg_copy(b, dest);
			if ((tagb == TW_Denormal) && (b->sigh & 0x80000000)) {
				
				addexponent(dest, 1);
				tagb = TAG_Valid;
			} else if (tagb > TAG_Empty)
				tagb = TAG_Special;
			setsign(dest, signb);	
			FPU_settagi(deststnr, tagb);
			return tagb;
		}
	} else if (tagb == TAG_Zero) {
		reg_copy(a, dest);
		if ((taga == TW_Denormal) && (a->sigh & 0x80000000)) {
			
			addexponent(dest, 1);
			taga = TAG_Valid;
		} else if (taga > TAG_Empty)
			taga = TAG_Special;
		setsign(dest, signa);	
		FPU_settagi(deststnr, taga);
		return taga;
	} else if (taga == TW_Infinity) {
		if ((tagb != TW_Infinity) || (signa == signb)) {
			FPU_copy_to_regi(a, TAG_Special, deststnr);
			setsign(dest, signa);	
			return taga;
		}
		
		return arith_invalid(deststnr);
	} else if (tagb == TW_Infinity) {
		FPU_copy_to_regi(b, TAG_Special, deststnr);
		setsign(dest, signb);	
		return tagb;
	}
#ifdef PARANOID
	EXCEPTION(EX_INTERNAL | 0x101);
#endif

	return FPU_Exception;
}
Exemple #6
0
static
int add_sub_specials(FPU_REG const *a, u_char taga, u_char signa,
		     FPU_REG const *b, u_char tagb, u_char signb,
		     FPU_REG *dest, int deststnr, int control_w)
{
  if ( ((taga == TW_Denormal) || (tagb == TW_Denormal))
       && (denormal_operand() < 0) )
    return FPU_Exception;

  if (taga == TAG_Zero)
    {
      if (tagb == TAG_Zero)
	{
	  /* Both are zero, result will be zero. */
	  u_char different_signs = signa ^ signb;

	  FPU_copy_to_regi(a, TAG_Zero, deststnr);
	  if ( different_signs )
	    {
	      /* Signs are different. */
	      /* Sign of answer depends upon rounding mode. */
	      setsign(dest, ((control_w & CW_RC) != RC_DOWN)
		      ? SIGN_POS : SIGN_NEG);
	    }
	  else
	    setsign(dest, signa);  /* signa may differ from the sign of a. */
	  return TAG_Zero;
	}
      else
	{
	  reg_copy(b, dest);
	  if ( (tagb == TW_Denormal) && (b->sigh & 0x80000000) )
	    {
	      /* A pseudoDenormal, convert it. */
	      addexponent(dest, 1);
	      tagb = TAG_Valid;
	    }
	  else if ( tagb > TAG_Empty )
	    tagb = TAG_Special;
	  setsign(dest, signb);  /* signb may differ from the sign of b. */
	  FPU_settagi(deststnr, tagb);
	  return tagb;
	}
    }
  else if (tagb == TAG_Zero)
    {
      reg_copy(a, dest);
      if ( (taga == TW_Denormal) && (a->sigh & 0x80000000) )
	{
	  /* A pseudoDenormal */
	  addexponent(dest, 1);
	  taga = TAG_Valid;
	}
      else if ( taga > TAG_Empty )
	taga = TAG_Special;
      setsign(dest, signa);  /* signa may differ from the sign of a. */
      FPU_settagi(deststnr, taga);
      return taga;
    }
  else if (taga == TW_Infinity)
    {
      if ( (tagb != TW_Infinity) || (signa == signb) )
	{
	  FPU_copy_to_regi(a, TAG_Special, deststnr);
	  setsign(dest, signa);  /* signa may differ from the sign of a. */
	  return taga;
	}
      /* Infinity-Infinity is undefined. */
      return arith_invalid(deststnr);
    }
  else if (tagb == TW_Infinity)
    {
      FPU_copy_to_regi(b, TAG_Special, deststnr);
      setsign(dest, signb);  /* signb may differ from the sign of b. */
      return tagb;
    }

#ifdef PARANOID
  EXCEPTION(EX_INTERNAL|0x101);
#endif

  return FPU_Exception;
}
Exemple #7
0
static void phineas_wr_n (int n)
{
  switch (n)
    {
    case 0x0: /* 028: WTIME   write C to clock register */
      reg_copy (clock_reg [timer_reg_sel], c);
      clock_decr [timer_reg_sel] = 0;
      break;
    case 0x1: /* 068: WTIME-  write C to clock register and set to decr */ 
      reg_copy (clock_reg [timer_reg_sel], c);
      clock_decr [timer_reg_sel]= 1;
      break;
    case 0x2: /* 0a8: WALM    write C to alarm register */
      reg_copy (alarm_reg [timer_reg_sel], c);
      break;
    case 0x3: /* 0e8: WSTS */
      reg_copy (timer_reg_sel ? accuracy_factor : timer_status, c);
      break;
    case 0x4: /* 128: WSCR    write C to scratch register */
      reg_copy (timer_scratch, c);
      break;
    case 0x5: /* 168: WINTST  write C to interval timer and start */
      reg_copy (interval_timer, c);
      interval_running = 1;
      break;
    case 0x6: /* 1a8: ??? */
      break;
    case 0x7: /* 1e8: STPINT  stop interval timer */
      interval_running = 0;
      break;
    case 0x8: /* 228: WKUPOFF */
      if (timer_reg_sel == TIMER_A)
	sec_wakeup = 0;
      else
	min_wakeup = 0;
      break;
    case 0x9: /* 268: WKUPON */ break;
      if (timer_reg_sel == TIMER_A)
	sec_wakeup = 1;
      else
	min_wakeup = 1;
      break;
    case 0xa: /* 2a8: ALMOFF */ 
      alarm_enable [timer_reg_sel] = 0;
      break;
    case 0xb: /* 2e8: ALMON */
      alarm_enable [timer_reg_sel] = 1;
      break;
    case 0xc: /* 328: STOPC */
      clock_enable [timer_reg_sel] = 0; 
      break;
    case 0xd: /* 368: STARTC */
      clock_enable [timer_reg_sel] = 1;
      break;
    case 0xe: /* 3a8: TIMER=A */
      timer_reg_sel = TIMER_A;
      break;
    case 0xf: /* 3e8: TIMER=B */
      timer_reg_sel = TIMER_B;
      break;
    }
}
Exemple #8
0
/*
  Divide one register by another and put the result into a third register.
  */
int FPU_div(int flags, int rm, int control_w)
{
	FPU_REG x, y;
	FPU_REG const *a, *b, *st0_ptr, *st_ptr;
	FPU_REG *dest;
	u_char taga, tagb, signa, signb, sign, saved_sign;
	int tag, deststnr;

	if (flags & DEST_RM)
		deststnr = rm;
	else
		deststnr = 0;

	if (flags & REV) {
		b = &st(0);
		st0_ptr = b;
		tagb = FPU_gettag0();
		if (flags & LOADED) {
			a = (FPU_REG *) rm;
			taga = flags & 0x0f;
		} else {
			a = &st(rm);
			st_ptr = a;
			taga = FPU_gettagi(rm);
		}
	} else {
		a = &st(0);
		st0_ptr = a;
		taga = FPU_gettag0();
		if (flags & LOADED) {
			b = (FPU_REG *) rm;
			tagb = flags & 0x0f;
		} else {
			b = &st(rm);
			st_ptr = b;
			tagb = FPU_gettagi(rm);
		}
	}

	signa = getsign(a);
	signb = getsign(b);

	sign = signa ^ signb;

	dest = &st(deststnr);
	saved_sign = getsign(dest);

	if (!(taga | tagb)) {
		/* Both regs Valid, this should be the most common case. */
		reg_copy(a, &x);
		reg_copy(b, &y);
		setpositive(&x);
		setpositive(&y);
		tag = FPU_u_div(&x, &y, dest, control_w, sign);

		if (tag < 0)
			return tag;

		FPU_settagi(deststnr, tag);
		return tag;
	}

	if (taga == TAG_Special)
		taga = FPU_Special(a);
	if (tagb == TAG_Special)
		tagb = FPU_Special(b);

	if (((taga == TAG_Valid) && (tagb == TW_Denormal))
	    || ((taga == TW_Denormal) && (tagb == TAG_Valid))
	    || ((taga == TW_Denormal) && (tagb == TW_Denormal))) {
		if (denormal_operand() < 0)
			return FPU_Exception;

		FPU_to_exp16(a, &x);
		FPU_to_exp16(b, &y);
		tag = FPU_u_div(&x, &y, dest, control_w, sign);
		if (tag < 0)
			return tag;

		FPU_settagi(deststnr, tag);
		return tag;
	} else if ((taga <= TW_Denormal) && (tagb <= TW_Denormal)) {
		if (tagb != TAG_Zero) {
			/* Want to find Zero/Valid */
			if (tagb == TW_Denormal) {
				if (denormal_operand() < 0)
					return FPU_Exception;
			}

			/* The result is zero. */
			FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr);
			setsign(dest, sign);
			return TAG_Zero;
		}
		/* We have an exception condition, either 0/0 or Valid/Zero. */
		if (taga == TAG_Zero) {
			/* 0/0 */
			return arith_invalid(deststnr);
		}
		/* Valid/Zero */
		return FPU_divide_by_zero(deststnr, sign);
	}
	/* Must have infinities, NaNs, etc */
	else if ((taga == TW_NaN) || (tagb == TW_NaN)) {
		if (flags & LOADED)
			return real_2op_NaN((FPU_REG *) rm, flags & 0x0f, 0,
					    st0_ptr);

		if (flags & DEST_RM) {
			int tag;
			tag = FPU_gettag0();
			if (tag == TAG_Special)
				tag = FPU_Special(st0_ptr);
			return real_2op_NaN(st0_ptr, tag, rm,
					    (flags & REV) ? st0_ptr : &st(rm));
		} else {
			int tag;
			tag = FPU_gettagi(rm);
			if (tag == TAG_Special)
				tag = FPU_Special(&st(rm));
			return real_2op_NaN(&st(rm), tag, 0,
					    (flags & REV) ? st0_ptr : &st(rm));
		}
	} else if (taga == TW_Infinity) {
		if (tagb == TW_Infinity) {
			/* infinity/infinity */
			return arith_invalid(deststnr);
		} else {
			/* tagb must be Valid or Zero */
			if ((tagb == TW_Denormal) && (denormal_operand() < 0))
				return FPU_Exception;

			/* Infinity divided by Zero or Valid does
			   not raise and exception, but returns Infinity */
			FPU_copy_to_regi(a, TAG_Special, deststnr);
			setsign(dest, sign);
			return taga;
		}
	} else if (tagb == TW_Infinity) {
		if ((taga == TW_Denormal) && (denormal_operand() < 0))
			return FPU_Exception;

		/* The result is zero. */
		FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr);
		setsign(dest, sign);
		return TAG_Zero;
	}
#ifdef PARANOID
	else {
		EXCEPTION(EX_INTERNAL | 0x102);
		return FPU_Exception;
	}
#endif /* PARANOID */

	return 0;
}
Exemple #9
0
void FPU_copy_to_reg1(FPU_REG const *r, u_char tag)
{
    reg_copy(r, &st(1));
    FPU_settagi(1, tag);
}
Exemple #10
0
void FPU_copy_to_regi(FPU_REG const *r, u_char tag, int stnr)
{
    reg_copy(r, &st(stnr));
    FPU_settagi(stnr, tag);
}
Exemple #11
0
int FPU_div(int flags, int rm, int control_w)
{
	FPU_REG x, y;
	FPU_REG const *a, *b, *st0_ptr, *st_ptr;
	FPU_REG *dest;
	u_char taga, tagb, signa, signb, sign, saved_sign;
	int tag, deststnr;

	if (flags & DEST_RM)
		deststnr = rm;
	else
		deststnr = 0;

	if (flags & REV) {
		b = &st(0);
		st0_ptr = b;
		tagb = FPU_gettag0();
		if (flags & LOADED) {
			a = (FPU_REG *) rm;
			taga = flags & 0x0f;
		} else {
			a = &st(rm);
			st_ptr = a;
			taga = FPU_gettagi(rm);
		}
	} else {
		a = &st(0);
		st0_ptr = a;
		taga = FPU_gettag0();
		if (flags & LOADED) {
			b = (FPU_REG *) rm;
			tagb = flags & 0x0f;
		} else {
			b = &st(rm);
			st_ptr = b;
			tagb = FPU_gettagi(rm);
		}
	}

	signa = getsign(a);
	signb = getsign(b);

	sign = signa ^ signb;

	dest = &st(deststnr);
	saved_sign = getsign(dest);

	if (!(taga | tagb)) {
		
		reg_copy(a, &x);
		reg_copy(b, &y);
		setpositive(&x);
		setpositive(&y);
		tag = FPU_u_div(&x, &y, dest, control_w, sign);

		if (tag < 0)
			return tag;

		FPU_settagi(deststnr, tag);
		return tag;
	}

	if (taga == TAG_Special)
		taga = FPU_Special(a);
	if (tagb == TAG_Special)
		tagb = FPU_Special(b);

	if (((taga == TAG_Valid) && (tagb == TW_Denormal))
	    || ((taga == TW_Denormal) && (tagb == TAG_Valid))
	    || ((taga == TW_Denormal) && (tagb == TW_Denormal))) {
		if (denormal_operand() < 0)
			return FPU_Exception;

		FPU_to_exp16(a, &x);
		FPU_to_exp16(b, &y);
		tag = FPU_u_div(&x, &y, dest, control_w, sign);
		if (tag < 0)
			return tag;

		FPU_settagi(deststnr, tag);
		return tag;
	} else if ((taga <= TW_Denormal) && (tagb <= TW_Denormal)) {
		if (tagb != TAG_Zero) {
			
			if (tagb == TW_Denormal) {
				if (denormal_operand() < 0)
					return FPU_Exception;
			}

			
			FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr);
			setsign(dest, sign);
			return TAG_Zero;
		}
		
		if (taga == TAG_Zero) {
			
			return arith_invalid(deststnr);
		}
		
		return FPU_divide_by_zero(deststnr, sign);
	}
	
	else if ((taga == TW_NaN) || (tagb == TW_NaN)) {
		if (flags & LOADED)
			return real_2op_NaN((FPU_REG *) rm, flags & 0x0f, 0,
					    st0_ptr);

		if (flags & DEST_RM) {
			int tag;
			tag = FPU_gettag0();
			if (tag == TAG_Special)
				tag = FPU_Special(st0_ptr);
			return real_2op_NaN(st0_ptr, tag, rm,
					    (flags & REV) ? st0_ptr : &st(rm));
		} else {
			int tag;
			tag = FPU_gettagi(rm);
			if (tag == TAG_Special)
				tag = FPU_Special(&st(rm));
			return real_2op_NaN(&st(rm), tag, 0,
					    (flags & REV) ? st0_ptr : &st(rm));
		}
	} else if (taga == TW_Infinity) {
		if (tagb == TW_Infinity) {
			
			return arith_invalid(deststnr);
		} else {
			
			if ((tagb == TW_Denormal) && (denormal_operand() < 0))
				return FPU_Exception;

			
			FPU_copy_to_regi(a, TAG_Special, deststnr);
			setsign(dest, sign);
			return taga;
		}
	} else if (tagb == TW_Infinity) {
		if ((taga == TW_Denormal) && (denormal_operand() < 0))
			return FPU_Exception;

		
		FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr);
		setsign(dest, sign);
		return TAG_Zero;
	}
#ifdef PARANOID
	else {
		EXCEPTION(EX_INTERNAL | 0x102);
		return FPU_Exception;
	}
#endif 

	return 0;
}