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

📄 reg_ld_str.c

📁 LINUX 1.0 内核c源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
      reg_move(FPU_st0_ptr, &tmp);
      exp = tmp.exp - EXP_BIAS;

      if ( exp < DOUBLE_Emin )     /* It may be a denormal */
	{
	  int precision_loss;

	  /* A denormal will always underflow. */
#ifndef PECULIAR_486
	  /* An 80486 is supposed to be able to generate
	     a denormal exception here, but... */
	  if ( FPU_st0_ptr->exp <= EXP_UNDER )
	    {
	      /* Underflow has priority. */
	      if ( control_word & CW_Underflow )
		denormal_operand();
	    }
#endif PECULIAR_486

	  tmp.exp += -DOUBLE_Emin + 52;  /* largest exp to be 51 */

	  if ( (precision_loss = round_to_int(&tmp)) )
	    {
#ifdef PECULIAR_486
	      /* Did it round to a non-denormal ? */
	      /* This behaviour might be regarded as peculiar, it appears
		 that the 80486 rounds to the dest precision, then
		 converts to decide underflow. */
	      if ( !((tmp.sigh == 0x00100000) && (tmp.sigl == 0) &&
		  (FPU_st0_ptr->sigl & 0x000007ff)) )
#endif PECULIAR_486
		{
		  EXCEPTION(EX_Underflow);
		  /* This is a special case: see sec 16.2.5.1 of
		     the 80486 book */
		  if ( !(control_word & CW_Underflow) )
		    return 0;
		}
	      EXCEPTION(precision_loss);
	      if ( !(control_word & CW_Precision) )
		return 0;
	    }
	  l[0] = tmp.sigl;
	  l[1] = tmp.sigh;
	}
      else
	{
	  if ( tmp.sigl & 0x000007ff )
	    {
	      switch (control_word & CW_RC)
		{
		case RC_RND:
		  /* Rounding can get a little messy.. */
		  increment = ((tmp.sigl & 0x7ff) > 0x400) |  /* nearest */
		    ((tmp.sigl & 0xc00) == 0xc00);            /* odd -> even */
		  break;
		case RC_DOWN:   /* towards -infinity */
		  increment = (tmp.sign == SIGN_POS) ? 0 : tmp.sigl & 0x7ff;
		  break;
		case RC_UP:     /* towards +infinity */
		  increment = (tmp.sign == SIGN_POS) ? tmp.sigl & 0x7ff : 0;
		  break;
		case RC_CHOP:
		  increment = 0;
		  break;
		}
	  
	      /* Truncate the mantissa */
	      tmp.sigl &= 0xfffff800;
	  
	      if ( increment )
		{
		  set_precision_flag_up();

		  if ( tmp.sigl >= 0xfffff800 )
		    {
		      /* the sigl part overflows */
		      if ( tmp.sigh == 0xffffffff )
			{
			  /* The sigh part overflows */
			  tmp.sigh = 0x80000000;
			  exp++;
			  if (exp >= EXP_OVER)
			    goto overflow;
			}
		      else
			{
			  tmp.sigh ++;
			}
		      tmp.sigl = 0x00000000;
		    }
		  else
		    {
		      /* We only need to increment sigl */
		      tmp.sigl += 0x00000800;
		    }
		}
	      else
		set_precision_flag_down();
	    }
	  
	  l[0] = (tmp.sigl >> 11) | (tmp.sigh << 21);
	  l[1] = ((tmp.sigh >> 11) & 0xfffff);

	  if ( exp > DOUBLE_Emax )
	    {
	    overflow:
	      EXCEPTION(EX_Overflow);
	      if ( !(control_word & CW_Overflow) )
		return 0;
	      set_precision_flag_up();
	      if ( !(control_word & CW_Precision) )
		return 0;

	      /* This is a special case: see sec 16.2.5.1 of the 80486 book */
	      /* Overflow to infinity */
	      l[0] = 0x00000000;	/* Set to */
	      l[1] = 0x7ff00000;	/* + INF */
	    }
	  else
	    {
	      /* Add the exponent */
	      l[1] |= (((exp+DOUBLE_Ebias) & 0x7ff) << 20);
	    }
	}
    }
  else if (FPU_st0_tag == TW_Zero)
    {
      /* Number is zero */
      l[0] = 0;
      l[1] = 0;
    }
  else if (FPU_st0_tag == TW_Infinity)
    {
      l[0] = 0;
      l[1] = 0x7ff00000;
    }
  else if (FPU_st0_tag == TW_NaN)
    {
      /* See if we can get a valid NaN from the FPU_REG */
      l[0] = (FPU_st0_ptr->sigl >> 11) | (FPU_st0_ptr->sigh << 21);
      l[1] = ((FPU_st0_ptr->sigh >> 11) & 0xfffff);
      if ( !(FPU_st0_ptr->sigh & 0x40000000) )
	{
	  /* It is a signalling NaN */
	  EXCEPTION(EX_Invalid);
	  if ( !(control_word & CW_Invalid) )
	    return 0;
	  l[1] |= (0x40000000 >> 11);
	}
      l[1] |= 0x7ff00000;
    }
  else if ( FPU_st0_tag == TW_Empty )
    {
      /* Empty register (stack underflow) */
      EXCEPTION(EX_StackUnder);
      if ( control_word & CW_Invalid )
	{
	  /* The masked response */
	  /* Put out the QNaN indefinite */
	  RE_ENTRANT_CHECK_OFF;
	  FPU_verify_area(VERIFY_WRITE,(void *)dfloat,8);
	  put_fs_long(0, (unsigned long *) dfloat);
	  put_fs_long(0xfff80000, 1 + (unsigned long *) dfloat);
	  RE_ENTRANT_CHECK_ON;
	  return 1;
	}
      else
	return 0;
    }
  if (FPU_st0_ptr->sign)
    l[1] |= 0x80000000;

  RE_ENTRANT_CHECK_OFF;
  FPU_verify_area(VERIFY_WRITE,(void *)dfloat,8);
  put_fs_long(l[0], (unsigned long *)dfloat);
  put_fs_long(l[1], 1 + (unsigned long *)dfloat);
  RE_ENTRANT_CHECK_ON;

  return 1;
}


/* Put a float into user memory */
int reg_store_single(void)
{
  float *single = (float *)FPU_data_address;
  long templ;
  unsigned long increment = 0;     	/* avoid gcc warnings */

  if (FPU_st0_tag == TW_Valid)
    {
      int exp;
      FPU_REG tmp;

      reg_move(FPU_st0_ptr, &tmp);
      exp = tmp.exp - EXP_BIAS;

      if ( exp < SINGLE_Emin )
	{
	  int precision_loss;

	  /* A denormal will always underflow. */
#ifndef PECULIAR_486
	  /* An 80486 is supposed to be able to generate
	     a denormal exception here, but... */
	  if ( FPU_st0_ptr->exp <= EXP_UNDER )
	    {
	      /* Underflow has priority. */
	      if ( control_word & CW_Underflow )
		denormal_operand();
	    }
#endif PECULIAR_486

	  tmp.exp += -SINGLE_Emin + 23;  /* largest exp to be 22 */

	  if ( (precision_loss = round_to_int(&tmp)) )
	    {
#ifdef PECULIAR_486
	      /* Did it round to a non-denormal ? */
	      /* This behaviour might be regarded as peculiar, it appears
		 that the 80486 rounds to the dest precision, then
		 converts to decide underflow. */
	      if ( !((tmp.sigl == 0x00800000) &&
		  ((FPU_st0_ptr->sigh & 0x000000ff) || FPU_st0_ptr->sigl)) )
#endif PECULIAR_486
		{
		  EXCEPTION(EX_Underflow);
		  /* This is a special case: see sec 16.2.5.1 of
		     the 80486 book */
		  if ( !(control_word & EX_Underflow) )
		    return 0;
		}
	      EXCEPTION(precision_loss);
	      if ( !(control_word & EX_Precision) )
		return 0;
	    }
	  templ = tmp.sigl;
	}
      else
	{
	  if ( tmp.sigl | (tmp.sigh & 0x000000ff) )
	    {
	      unsigned long sigh = tmp.sigh;
	      unsigned long sigl = tmp.sigl;
	      
	      switch (control_word & CW_RC)
		{
		case RC_RND:
		  increment = ((sigh & 0xff) > 0x80)       /* more than half */
		    || (((sigh & 0xff) == 0x80) && sigl)   /* more than half */
		      || ((sigh & 0x180) == 0x180);        /* round to even */
		  break;
		case RC_DOWN:   /* towards -infinity */
		  increment = (tmp.sign == SIGN_POS)
		              ? 0 : (sigl | (sigh & 0xff));
		  break;
		case RC_UP:     /* towards +infinity */
		  increment = (tmp.sign == SIGN_POS)
		              ? (sigl | (sigh & 0xff)) : 0;
		  break;
		case RC_CHOP:
		  increment = 0;
		  break;
		}
	  
	      /* Truncate part of the mantissa */
	      tmp.sigl = 0;
	  
	      if (increment)
		{
		  set_precision_flag_up();

		  if ( sigh >= 0xffffff00 )
		    {
		      /* The sigh part overflows */
		      tmp.sigh = 0x80000000;
		      exp++;
		      if ( exp >= EXP_OVER )
			goto overflow;
		    }
		  else
		    {
		      tmp.sigh &= 0xffffff00;
		      tmp.sigh += 0x100;
		    }
		}
	      else
		{
		  set_precision_flag_down();
		  tmp.sigh &= 0xffffff00;  /* Finish the truncation */
		}
	    }

	  templ = (tmp.sigh >> 8) & 0x007fffff;

	  if ( exp > SINGLE_Emax )
	    {
	    overflow:
	      EXCEPTION(EX_Overflow);
	      if ( !(control_word & CW_Overflow) )
		return 0;
	      set_precision_flag_up();
	      if ( !(control_word & CW_Precision) )
		return 0;

	      /* This is a special case: see sec 16.2.5.1 of the 80486 book. */
	      /* Masked respose is overflow to infinity. */
	      templ = 0x7f800000;
	    }
	  else
	    templ |= ((exp+SINGLE_Ebias) & 0xff) << 23;
	}
    }
  else if (FPU_st0_tag == TW_Zero)
    {
      templ = 0;
    }
  else if (FPU_st0_tag == TW_Infinity)
    {
      templ = 0x7f800000;
    }
  else if (FPU_st0_tag == TW_NaN)
    {
      /* See if we can get a valid NaN from the FPU_REG */
      templ = FPU_st0_ptr->sigh >> 8;
      if ( !(FPU_st0_ptr->sigh & 0x40000000) )
	{
	  /* It is a signalling NaN */
	  EXCEPTION(EX_Invalid);
	  if ( !(control_word & CW_Invalid) )
	    return 0;
	  templ |= (0x40000000 >> 8);
	}
      templ |= 0x7f800000;
    }
  else if ( FPU_st0_tag == TW_Empty )
    {
      /* Empty register (stack underflow) */
      EXCEPTION(EX_StackUnder);
      if ( control_word & EX_Invalid )
	{
	  /* The masked response */
	  /* Put out the QNaN indefinite */
	  RE_ENTRANT_CHECK_OFF;
	  FPU_verify_area(VERIFY_WRITE,(void *)single,4);
	  put_fs_long(0xffc00000, (unsigned long *) single);
	  RE_ENTRANT_CHECK_ON;
	  return 1;
	}
      else
	return 0;
    }
#ifdef PARANOID
  else
    {
      EXCEPTION(EX_INTERNAL|0x106);
      return 0;
    }
#endif
  if (FPU_st0_ptr->sign)
    templ |= 0x80000000;

  RE_ENTRANT_CHECK_OFF;
  FPU_verify_area(VERIFY_WRITE,(void *)single,4);
  put_fs_long(templ,(unsigned long *) single);
  RE_ENTRANT_CHECK_ON;

  return 1;
}


/* Put a long long into user memory */
int reg_store_int64(void)
{
  long long *d = (long long *)FPU_data_address;
  FPU_REG t;
  long long tll;
  int precision_loss;

  if ( FPU_st0_tag == TW_Empty )
    {
      /* Empty register (stack underflow) */
      EXCEPTION(EX_StackUnder);
      goto invalid_operand;
    }
  else if ( (FPU_st0_tag == TW_Infinity) ||
	   (FPU_st0_tag == TW_NaN) )
    {
      EXCEPTION(EX_Invalid);
      goto invalid_operand;
    }

  reg_move(FPU_st0_ptr, &t);
  precision_loss = round_to_int(&t);
  ((long *)&tll)[0] = t.sigl;
  ((long *)&tll)[1] = t.sigh;
  if ( (precision_loss == 1) ||
      ((t.sigh & 0x80000000) &&
       !((t.sigh == 0x80000000) && (t.sigl == 0) &&
	 (t.sign == SIGN_NEG))) )
    {
      EXCEPTION(EX_Invalid);
      /* This is a special case: see sec 16.2.5.1 of the 80486 book */
    invalid_operand:
      if ( control_word & EX_Invalid )
	{
	  /* Produce something like QNaN "indefinite" */
	  tll = 0x8000000000000000LL;
	}
      else
	return 0;
    }
  else
    {
      if ( precision_loss )
	set_precision_flag(precision_loss);
      if ( t.sign )
	tll = - tll;
    }

  RE_ENTRANT_CHECK_OFF;
  FPU_verify_area(VERIFY_WRITE,(void *)d,8);
  put_fs_long(((long *)&tll)[0],(unsigned long *) d);
  put_fs_long(((long *)&tll)[1],1 + (unsigned long *) d);
  RE_ENTRANT_CHECK_ON;

  return 1;
}


/* Put a long into user memory */
int reg_store_int32(void)
{
  long *d = (long *)FPU_data_address;
  FPU_REG t;
  int precision_loss;

  if ( FPU_st0_tag == TW_Empty )
    {
      /* Empty register (stack underflow) */
      EXCEPTION(EX_StackUnder);
      goto invalid_operand;
    }
  else if ( (FPU_st0_tag == TW_Infinity) ||
	   (FPU_st0_tag == TW_NaN) )
    {
      EXCEPTION(EX_Invalid);
      goto invalid_operand;
    }

  reg_move(FPU_st0_ptr, &t);
  precision_loss = round_to_int(&t);
  if (t.sigh ||
      ((t.sigl & 0x80000000) &&
       !((t.sigl == 0x80000000) && (t.sign == SIGN_NEG))) )
    {
      EXCEPTION(EX_Invalid);
      /* This is a special case: see sec 16.2.5.1 of the 80486 book */
    invalid_operand:
      if ( control_word & EX_Invalid )
	{
	  /* Produce something like QNaN "indefinite" */
	  t.sigl = 0x80000000;
	}
      else
	return 0;
    }
  else
    {
      if ( precision_loss )
	set_precision_flag(precision_loss);
      if ( t.sign )
	t.sigl = -(long)t.sigl;
    }

  RE_ENTRANT_CHECK_OFF;
  FPU_verify_area(VERIFY_WRITE,d,4);
  put_fs_long(t.sigl, (unsigned long *) d);
  RE_ENTRANT_CHECK_ON;

  return 1;
}


/* Put a short into user memory */
int reg_store_int16(void)
{

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -