reg_ld_str.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:33k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*---------------------------------------------------------------------------+
  2.  |  reg_ld_str.c                                                             |
  3.  |                                                                           |
  4.  | All of the functions which transfer data between user memory and FPU_REGs.|
  5.  |                                                                           |
  6.  | Copyright (C) 1992,1993,1994,1996,1997                                    |
  7.  |                  W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
  8.  |                  E-mail   billm@suburbia.net                              |
  9.  |                                                                           |
  10.  |                                                                           |
  11.  +---------------------------------------------------------------------------*/
  12. /*---------------------------------------------------------------------------+
  13.  | Note:                                                                     |
  14.  |    The file contains code which accesses user memory.                     |
  15.  |    Emulator static data may change when user memory is accessed, due to   |
  16.  |    other processes using the emulator while swapping is in progress.      |
  17.  +---------------------------------------------------------------------------*/
  18. #include "fpu_emu.h"
  19. #include <asm/uaccess.h>
  20. #include "fpu_system.h"
  21. #include "exception.h"
  22. #include "reg_constant.h"
  23. #include "control_w.h"
  24. #include "status_w.h"
  25. #define DOUBLE_Emax 1023         /* largest valid exponent */
  26. #define DOUBLE_Ebias 1023
  27. #define DOUBLE_Emin (-1022)      /* smallest valid exponent */
  28. #define SINGLE_Emax 127          /* largest valid exponent */
  29. #define SINGLE_Ebias 127
  30. #define SINGLE_Emin (-126)       /* smallest valid exponent */
  31. static u_char normalize_no_excep(FPU_REG *r, int exp, int sign)
  32. {
  33.   u_char tag;
  34.   setexponent16(r, exp);
  35.   tag = FPU_normalize_nuo(r);
  36.   stdexp(r);
  37.   if ( sign )
  38.     setnegative(r);
  39.   return tag;
  40. }
  41. int FPU_tagof(FPU_REG *ptr)
  42. {
  43.   int exp;
  44.   exp = exponent16(ptr) & 0x7fff;
  45.   if ( exp == 0 )
  46.     {
  47.       if ( !(ptr->sigh | ptr->sigl) )
  48. {
  49.   return TAG_Zero;
  50. }
  51.       /* The number is a de-normal or pseudodenormal. */
  52.       return TAG_Special;
  53.     }
  54.   if ( exp == 0x7fff )
  55.     {
  56.       /* Is an Infinity, a NaN, or an unsupported data type. */
  57.       return TAG_Special;
  58.     }
  59.   if ( !(ptr->sigh & 0x80000000) )
  60.     {
  61.       /* Unsupported data type. */
  62.       /* Valid numbers have the ms bit set to 1. */
  63.       /* Unnormal. */
  64.       return TAG_Special;
  65.     }
  66.   return TAG_Valid;
  67. }
  68. /* Get a long double from user memory */
  69. int FPU_load_extended(long double *s, int stnr)
  70. {
  71.   FPU_REG *sti_ptr = &st(stnr);
  72.   RE_ENTRANT_CHECK_OFF;
  73.   FPU_verify_area(VERIFY_READ, s, 10);
  74.   __copy_from_user(sti_ptr, s, 10);
  75.   RE_ENTRANT_CHECK_ON;
  76.   return FPU_tagof(sti_ptr);
  77. }
  78. /* Get a double from user memory */
  79. int FPU_load_double(double *dfloat, FPU_REG *loaded_data)
  80. {
  81.   int exp, tag, negative;
  82.   unsigned m64, l64;
  83.   RE_ENTRANT_CHECK_OFF;
  84.   FPU_verify_area(VERIFY_READ, dfloat, 8);
  85.   FPU_get_user(m64, 1 + (unsigned long *) dfloat);
  86.   FPU_get_user(l64, (unsigned long *) dfloat);
  87.   RE_ENTRANT_CHECK_ON;
  88.   negative = (m64 & 0x80000000) ? SIGN_Negative : SIGN_Positive;
  89.   exp = ((m64 & 0x7ff00000) >> 20) - DOUBLE_Ebias + EXTENDED_Ebias;
  90.   m64 &= 0xfffff;
  91.   if ( exp > DOUBLE_Emax + EXTENDED_Ebias )
  92.     {
  93.       /* Infinity or NaN */
  94.       if ((m64 == 0) && (l64 == 0))
  95. {
  96.   /* +- infinity */
  97.   loaded_data->sigh = 0x80000000;
  98.   loaded_data->sigl = 0x00000000;
  99.   exp = EXP_Infinity + EXTENDED_Ebias;
  100.   tag = TAG_Special;
  101. }
  102.       else
  103. {
  104.   /* Must be a signaling or quiet NaN */
  105.   exp = EXP_NaN + EXTENDED_Ebias;
  106.   loaded_data->sigh = (m64 << 11) | 0x80000000;
  107.   loaded_data->sigh |= l64 >> 21;
  108.   loaded_data->sigl = l64 << 11;
  109.   tag = TAG_Special;    /* The calling function must look for NaNs */
  110. }
  111.     }
  112.   else if ( exp < DOUBLE_Emin + EXTENDED_Ebias )
  113.     {
  114.       /* Zero or de-normal */
  115.       if ((m64 == 0) && (l64 == 0))
  116. {
  117.   /* Zero */
  118.   reg_copy(&CONST_Z, loaded_data);
  119.   exp = 0;
  120.   tag = TAG_Zero;
  121. }
  122.       else
  123. {
  124.   /* De-normal */
  125.   loaded_data->sigh = m64 << 11;
  126.   loaded_data->sigh |= l64 >> 21;
  127.   loaded_data->sigl = l64 << 11;
  128.   return normalize_no_excep(loaded_data, DOUBLE_Emin, negative)
  129.     | (denormal_operand() < 0 ? FPU_Exception : 0);
  130. }
  131.     }
  132.   else
  133.     {
  134.       loaded_data->sigh = (m64 << 11) | 0x80000000;
  135.       loaded_data->sigh |= l64 >> 21;
  136.       loaded_data->sigl = l64 << 11;
  137.       tag = TAG_Valid;
  138.     }
  139.   setexponent16(loaded_data, exp | negative);
  140.   return tag;
  141. }
  142. /* Get a float from user memory */
  143. int FPU_load_single(float *single, FPU_REG *loaded_data)
  144. {
  145.   unsigned m32;
  146.   int exp, tag, negative;
  147.   RE_ENTRANT_CHECK_OFF;
  148.   FPU_verify_area(VERIFY_READ, single, 4);
  149.   FPU_get_user(m32, (unsigned long *) single);
  150.   RE_ENTRANT_CHECK_ON;
  151.   negative = (m32 & 0x80000000) ? SIGN_Negative : SIGN_Positive;
  152.   if (!(m32 & 0x7fffffff))
  153.     {
  154.       /* Zero */
  155.       reg_copy(&CONST_Z, loaded_data);
  156.       addexponent(loaded_data, negative);
  157.       return TAG_Zero;
  158.     }
  159.   exp = ((m32 & 0x7f800000) >> 23) - SINGLE_Ebias + EXTENDED_Ebias;
  160.   m32 = (m32 & 0x7fffff) << 8;
  161.   if ( exp < SINGLE_Emin + EXTENDED_Ebias )
  162.     {
  163.       /* De-normals */
  164.       loaded_data->sigh = m32;
  165.       loaded_data->sigl = 0;
  166.       return normalize_no_excep(loaded_data, SINGLE_Emin, negative)
  167. | (denormal_operand() < 0 ? FPU_Exception : 0);
  168.     }
  169.   else if ( exp > SINGLE_Emax + EXTENDED_Ebias )
  170.     {
  171.     /* Infinity or NaN */
  172.       if ( m32 == 0 )
  173. {
  174.   /* +- infinity */
  175.   loaded_data->sigh = 0x80000000;
  176.   loaded_data->sigl = 0x00000000;
  177.   exp = EXP_Infinity + EXTENDED_Ebias;
  178.   tag = TAG_Special;
  179. }
  180.       else
  181. {
  182.   /* Must be a signaling or quiet NaN */
  183.   exp = EXP_NaN + EXTENDED_Ebias;
  184.   loaded_data->sigh = m32 | 0x80000000;
  185.   loaded_data->sigl = 0;
  186.   tag = TAG_Special;  /* The calling function must look for NaNs */
  187. }
  188.     }
  189.   else
  190.     {
  191.       loaded_data->sigh = m32 | 0x80000000;
  192.       loaded_data->sigl = 0;
  193.       tag = TAG_Valid;
  194.     }
  195.   setexponent16(loaded_data, exp | negative);  /* Set the sign. */
  196.   return tag;
  197. }
  198. /* Get a long long from user memory */
  199. int FPU_load_int64(long long *_s)
  200. {
  201.   long long s;
  202.   int sign;
  203.   FPU_REG *st0_ptr = &st(0);
  204.   RE_ENTRANT_CHECK_OFF;
  205.   FPU_verify_area(VERIFY_READ, _s, 8);
  206.   copy_from_user(&s,_s,8);
  207.   RE_ENTRANT_CHECK_ON;
  208.   if (s == 0)
  209.     {
  210.       reg_copy(&CONST_Z, st0_ptr);
  211.       return TAG_Zero;
  212.     }
  213.   if (s > 0)
  214.     sign = SIGN_Positive;
  215.   else
  216.   {
  217.     s = -s;
  218.     sign = SIGN_Negative;
  219.   }
  220.   significand(st0_ptr) = s;
  221.   return normalize_no_excep(st0_ptr, 63, sign);
  222. }
  223. /* Get a long from user memory */
  224. int FPU_load_int32(long *_s, FPU_REG *loaded_data)
  225. {
  226.   long s;
  227.   int negative;
  228.   RE_ENTRANT_CHECK_OFF;
  229.   FPU_verify_area(VERIFY_READ, _s, 4);
  230.   FPU_get_user(s, _s);
  231.   RE_ENTRANT_CHECK_ON;
  232.   if (s == 0)
  233.     { reg_copy(&CONST_Z, loaded_data); return TAG_Zero; }
  234.   if (s > 0)
  235.     negative = SIGN_Positive;
  236.   else
  237.     {
  238.       s = -s;
  239.       negative = SIGN_Negative;
  240.     }
  241.   loaded_data->sigh = s;
  242.   loaded_data->sigl = 0;
  243.   return normalize_no_excep(loaded_data, 31, negative);
  244. }
  245. /* Get a short from user memory */
  246. int FPU_load_int16(short *_s, FPU_REG *loaded_data)
  247. {
  248.   int s, negative;
  249.   RE_ENTRANT_CHECK_OFF;
  250.   FPU_verify_area(VERIFY_READ, _s, 2);
  251.   /* Cast as short to get the sign extended. */
  252.   FPU_get_user(s, _s);
  253.   RE_ENTRANT_CHECK_ON;
  254.   if (s == 0)
  255.     { reg_copy(&CONST_Z, loaded_data); return TAG_Zero; }
  256.   if (s > 0)
  257.     negative = SIGN_Positive;
  258.   else
  259.     {
  260.       s = -s;
  261.       negative = SIGN_Negative;
  262.     }
  263.   loaded_data->sigh = s << 16;
  264.   loaded_data->sigl = 0;
  265.   return normalize_no_excep(loaded_data, 15, negative);
  266. }
  267. /* Get a packed bcd array from user memory */
  268. int FPU_load_bcd(u_char *s)
  269. {
  270.   FPU_REG *st0_ptr = &st(0);
  271.   int pos;
  272.   u_char bcd;
  273.   long long l=0;
  274.   int sign;
  275.   RE_ENTRANT_CHECK_OFF;
  276.   FPU_verify_area(VERIFY_READ, s, 10);
  277.   RE_ENTRANT_CHECK_ON;
  278.   for ( pos = 8; pos >= 0; pos--)
  279.     {
  280.       l *= 10;
  281.       RE_ENTRANT_CHECK_OFF;
  282.       FPU_get_user(bcd, (u_char *) s+pos);
  283.       RE_ENTRANT_CHECK_ON;
  284.       l += bcd >> 4;
  285.       l *= 10;
  286.       l += bcd & 0x0f;
  287.     }
  288.  
  289.   RE_ENTRANT_CHECK_OFF;
  290.   FPU_get_user(sign, (u_char *) s+9);
  291.   sign = sign & 0x80 ? SIGN_Negative : SIGN_Positive;
  292.   RE_ENTRANT_CHECK_ON;
  293.   if ( l == 0 )
  294.     {
  295.       reg_copy(&CONST_Z, st0_ptr);
  296.       addexponent(st0_ptr, sign);   /* Set the sign. */
  297.       return TAG_Zero;
  298.     }
  299.   else
  300.     {
  301.       significand(st0_ptr) = l;
  302.       return normalize_no_excep(st0_ptr, 63, sign);
  303.     }
  304. }
  305. /*===========================================================================*/
  306. /* Put a long double into user memory */
  307. int FPU_store_extended(FPU_REG *st0_ptr, u_char st0_tag, long double *d)
  308. {
  309.   /*
  310.     The only exception raised by an attempt to store to an
  311.     extended format is the Invalid Stack exception, i.e.
  312.     attempting to store from an empty register.
  313.    */
  314.   if ( st0_tag != TAG_Empty )
  315.     {
  316.       RE_ENTRANT_CHECK_OFF;
  317.       FPU_verify_area(VERIFY_WRITE, d, 10);
  318.       FPU_put_user(st0_ptr->sigl, (unsigned long *) d);
  319.       FPU_put_user(st0_ptr->sigh, (unsigned long *) ((u_char *)d + 4));
  320.       FPU_put_user(exponent16(st0_ptr), (unsigned short *) ((u_char *)d + 8));
  321.       RE_ENTRANT_CHECK_ON;
  322.       return 1;
  323.     }
  324.   /* Empty register (stack underflow) */
  325.   EXCEPTION(EX_StackUnder);
  326.   if ( control_word & CW_Invalid )
  327.     {
  328.       /* The masked response */
  329.       /* Put out the QNaN indefinite */
  330.       RE_ENTRANT_CHECK_OFF;
  331.       FPU_verify_area(VERIFY_WRITE,d,10);
  332.       FPU_put_user(0, (unsigned long *) d);
  333.       FPU_put_user(0xc0000000, 1 + (unsigned long *) d);
  334.       FPU_put_user(0xffff, 4 + (short *) d);
  335.       RE_ENTRANT_CHECK_ON;
  336.       return 1;
  337.     }
  338.   else
  339.     return 0;
  340. }
  341. /* Put a double into user memory */
  342. int FPU_store_double(FPU_REG *st0_ptr, u_char st0_tag, double *dfloat)
  343. {
  344.   unsigned long l[2];
  345.   unsigned long increment = 0; /* avoid gcc warnings */
  346.   int precision_loss;
  347.   int exp;
  348.   FPU_REG tmp;
  349.   if ( st0_tag == TAG_Valid )
  350.     {
  351.       reg_copy(st0_ptr, &tmp);
  352.       exp = exponent(&tmp);
  353.       if ( exp < DOUBLE_Emin )     /* It may be a denormal */
  354. {
  355.   addexponent(&tmp, -DOUBLE_Emin + 52);  /* largest exp to be 51 */
  356. denormal_arg:
  357.   if ( (precision_loss = FPU_round_to_int(&tmp, st0_tag)) )
  358.     {
  359. #ifdef PECULIAR_486
  360.       /* Did it round to a non-denormal ? */
  361.       /* This behaviour might be regarded as peculiar, it appears
  362.  that the 80486 rounds to the dest precision, then
  363.  converts to decide underflow. */
  364.       if ( !((tmp.sigh == 0x00100000) && (tmp.sigl == 0) &&
  365.   (st0_ptr->sigl & 0x000007ff)) )
  366. #endif /* PECULIAR_486 */
  367. {
  368.   EXCEPTION(EX_Underflow);
  369.   /* This is a special case: see sec 16.2.5.1 of
  370.      the 80486 book */
  371.   if ( !(control_word & CW_Underflow) )
  372.     return 0;
  373. }
  374.       EXCEPTION(precision_loss);
  375.       if ( !(control_word & CW_Precision) )
  376. return 0;
  377.     }
  378.   l[0] = tmp.sigl;
  379.   l[1] = tmp.sigh;
  380. }
  381.       else
  382. {
  383.   if ( tmp.sigl & 0x000007ff )
  384.     {
  385.       precision_loss = 1;
  386.       switch (control_word & CW_RC)
  387. {
  388. case RC_RND:
  389.   /* Rounding can get a little messy.. */
  390.   increment = ((tmp.sigl & 0x7ff) > 0x400) |  /* nearest */
  391.     ((tmp.sigl & 0xc00) == 0xc00);            /* odd -> even */
  392.   break;
  393. case RC_DOWN:   /* towards -infinity */
  394.   increment = signpositive(&tmp) ? 0 : tmp.sigl & 0x7ff;
  395.   break;
  396. case RC_UP:     /* towards +infinity */
  397.   increment = signpositive(&tmp) ? tmp.sigl & 0x7ff : 0;
  398.   break;
  399. case RC_CHOP:
  400.   increment = 0;
  401.   break;
  402. }
  403.   
  404.       /* Truncate the mantissa */
  405.       tmp.sigl &= 0xfffff800;
  406.   
  407.       if ( increment )
  408. {
  409.   if ( tmp.sigl >= 0xfffff800 )
  410.     {
  411.       /* the sigl part overflows */
  412.       if ( tmp.sigh == 0xffffffff )
  413. {
  414.   /* The sigh part overflows */
  415.   tmp.sigh = 0x80000000;
  416.   exp++;
  417.   if (exp >= EXP_OVER)
  418.     goto overflow;
  419. }
  420.       else
  421. {
  422.   tmp.sigh ++;
  423. }
  424.       tmp.sigl = 0x00000000;
  425.     }
  426.   else
  427.     {
  428.       /* We only need to increment sigl */
  429.       tmp.sigl += 0x00000800;
  430.     }
  431. }
  432.     }
  433.   else
  434.     precision_loss = 0;
  435.   
  436.   l[0] = (tmp.sigl >> 11) | (tmp.sigh << 21);
  437.   l[1] = ((tmp.sigh >> 11) & 0xfffff);
  438.   if ( exp > DOUBLE_Emax )
  439.     {
  440.     overflow:
  441.       EXCEPTION(EX_Overflow);
  442.       if ( !(control_word & CW_Overflow) )
  443. return 0;
  444.       set_precision_flag_up();
  445.       if ( !(control_word & CW_Precision) )
  446. return 0;
  447.       /* This is a special case: see sec 16.2.5.1 of the 80486 book */
  448.       /* Overflow to infinity */
  449.       l[0] = 0x00000000; /* Set to */
  450.       l[1] = 0x7ff00000; /* + INF */
  451.     }
  452.   else
  453.     {
  454.       if ( precision_loss )
  455. {
  456.   if ( increment )
  457.     set_precision_flag_up();
  458.   else
  459.     set_precision_flag_down();
  460. }
  461.       /* Add the exponent */
  462.       l[1] |= (((exp+DOUBLE_Ebias) & 0x7ff) << 20);
  463.     }
  464. }
  465.     }
  466.   else if (st0_tag == TAG_Zero)
  467.     {
  468.       /* Number is zero */
  469.       l[0] = 0;
  470.       l[1] = 0;
  471.     }
  472.   else if ( st0_tag == TAG_Special )
  473.     {
  474.       st0_tag = FPU_Special(st0_ptr);
  475.       if ( st0_tag == TW_Denormal )
  476. {
  477.   /* A denormal will always underflow. */
  478. #ifndef PECULIAR_486
  479.   /* An 80486 is supposed to be able to generate
  480.      a denormal exception here, but... */
  481.   /* Underflow has priority. */
  482.   if ( control_word & CW_Underflow )
  483.     denormal_operand();
  484. #endif /* PECULIAR_486 */
  485.   reg_copy(st0_ptr, &tmp);
  486.   goto denormal_arg;
  487. }
  488.       else if (st0_tag == TW_Infinity)
  489. {
  490.   l[0] = 0;
  491.   l[1] = 0x7ff00000;
  492. }
  493.       else if (st0_tag == TW_NaN)
  494. {
  495.   /* Is it really a NaN ? */
  496.   if ( (exponent(st0_ptr) == EXP_OVER)
  497.        && (st0_ptr->sigh & 0x80000000) )
  498.     {
  499.       /* See if we can get a valid NaN from the FPU_REG */
  500.       l[0] = (st0_ptr->sigl >> 11) | (st0_ptr->sigh << 21);
  501.       l[1] = ((st0_ptr->sigh >> 11) & 0xfffff);
  502.       if ( !(st0_ptr->sigh & 0x40000000) )
  503. {
  504.   /* It is a signalling NaN */
  505.   EXCEPTION(EX_Invalid);
  506.   if ( !(control_word & CW_Invalid) )
  507.     return 0;
  508.   l[1] |= (0x40000000 >> 11);
  509. }
  510.       l[1] |= 0x7ff00000;
  511.     }
  512.   else
  513.     {
  514.       /* It is an unsupported data type */
  515.       EXCEPTION(EX_Invalid);
  516.       if ( !(control_word & CW_Invalid) )
  517. return 0;
  518.       l[0] = 0;
  519.       l[1] = 0xfff80000;
  520.     }
  521. }
  522.     }
  523.   else if ( st0_tag == TAG_Empty )
  524.     {
  525.       /* Empty register (stack underflow) */
  526.       EXCEPTION(EX_StackUnder);
  527.       if ( control_word & CW_Invalid )
  528. {
  529.   /* The masked response */
  530.   /* Put out the QNaN indefinite */
  531.   RE_ENTRANT_CHECK_OFF;
  532.   FPU_verify_area(VERIFY_WRITE,(void *)dfloat,8);
  533.   FPU_put_user(0, (unsigned long *) dfloat);
  534.   FPU_put_user(0xfff80000, 1 + (unsigned long *) dfloat);
  535.   RE_ENTRANT_CHECK_ON;
  536.   return 1;
  537. }
  538.       else
  539. return 0;
  540.     }
  541.   if ( getsign(st0_ptr) )
  542.     l[1] |= 0x80000000;
  543.   RE_ENTRANT_CHECK_OFF;
  544.   FPU_verify_area(VERIFY_WRITE,(void *)dfloat,8);
  545.   FPU_put_user(l[0], (unsigned long *)dfloat);
  546.   FPU_put_user(l[1], 1 + (unsigned long *)dfloat);
  547.   RE_ENTRANT_CHECK_ON;
  548.   return 1;
  549. }
  550. /* Put a float into user memory */
  551. int FPU_store_single(FPU_REG *st0_ptr, u_char st0_tag, float *single)
  552. {
  553.   long templ;
  554.   unsigned long increment = 0;      /* avoid gcc warnings */
  555.   int precision_loss;
  556.   int exp;
  557.   FPU_REG tmp;
  558.   if ( st0_tag == TAG_Valid )
  559.     {
  560.       reg_copy(st0_ptr, &tmp);
  561.       exp = exponent(&tmp);
  562.       if ( exp < SINGLE_Emin )
  563. {
  564.   addexponent(&tmp, -SINGLE_Emin + 23);  /* largest exp to be 22 */
  565. denormal_arg:
  566.   if ( (precision_loss = FPU_round_to_int(&tmp, st0_tag)) )
  567.     {
  568. #ifdef PECULIAR_486
  569.       /* Did it round to a non-denormal ? */
  570.       /* This behaviour might be regarded as peculiar, it appears
  571.  that the 80486 rounds to the dest precision, then
  572.  converts to decide underflow. */
  573.       if ( !((tmp.sigl == 0x00800000) &&
  574.   ((st0_ptr->sigh & 0x000000ff) || st0_ptr->sigl)) )
  575. #endif /* PECULIAR_486 */
  576. {
  577.   EXCEPTION(EX_Underflow);
  578.   /* This is a special case: see sec 16.2.5.1 of
  579.      the 80486 book */
  580.   if ( !(control_word & CW_Underflow) )
  581.     return 0;
  582. }
  583.       EXCEPTION(precision_loss);
  584.       if ( !(control_word & CW_Precision) )
  585. return 0;
  586.     }
  587.   templ = tmp.sigl;
  588.       }
  589.       else
  590. {
  591.   if ( tmp.sigl | (tmp.sigh & 0x000000ff) )
  592.     {
  593.       unsigned long sigh = tmp.sigh;
  594.       unsigned long sigl = tmp.sigl;
  595.       
  596.       precision_loss = 1;
  597.       switch (control_word & CW_RC)
  598. {
  599. case RC_RND:
  600.   increment = ((sigh & 0xff) > 0x80)       /* more than half */
  601.     || (((sigh & 0xff) == 0x80) && sigl)   /* more than half */
  602.     || ((sigh & 0x180) == 0x180);        /* round to even */
  603.   break;
  604. case RC_DOWN:   /* towards -infinity */
  605.   increment = signpositive(&tmp)
  606.     ? 0 : (sigl | (sigh & 0xff));
  607.   break;
  608. case RC_UP:     /* towards +infinity */
  609.   increment = signpositive(&tmp)
  610.     ? (sigl | (sigh & 0xff)) : 0;
  611.   break;
  612. case RC_CHOP:
  613.   increment = 0;
  614.   break;
  615. }
  616.   
  617.       /* Truncate part of the mantissa */
  618.       tmp.sigl = 0;
  619.   
  620.       if (increment)
  621. {
  622.   if ( sigh >= 0xffffff00 )
  623.     {
  624.       /* The sigh part overflows */
  625.       tmp.sigh = 0x80000000;
  626.       exp++;
  627.       if ( exp >= EXP_OVER )
  628. goto overflow;
  629.     }
  630.   else
  631.     {
  632.       tmp.sigh &= 0xffffff00;
  633.       tmp.sigh += 0x100;
  634.     }
  635. }
  636.       else
  637. {
  638.   tmp.sigh &= 0xffffff00;  /* Finish the truncation */
  639. }
  640.     }
  641.   else
  642.     precision_loss = 0;
  643.       
  644.   templ = (tmp.sigh >> 8) & 0x007fffff;
  645.   if ( exp > SINGLE_Emax )
  646.     {
  647.     overflow:
  648.       EXCEPTION(EX_Overflow);
  649.       if ( !(control_word & CW_Overflow) )
  650. return 0;
  651.       set_precision_flag_up();
  652.       if ( !(control_word & CW_Precision) )
  653. return 0;
  654.       /* This is a special case: see sec 16.2.5.1 of the 80486 book. */
  655.       /* Masked response is overflow to infinity. */
  656.       templ = 0x7f800000;
  657.     }
  658.   else
  659.     {
  660.       if ( precision_loss )
  661. {
  662.   if ( increment )
  663.     set_precision_flag_up();
  664.   else
  665.     set_precision_flag_down();
  666. }
  667.       /* Add the exponent */
  668.       templ |= ((exp+SINGLE_Ebias) & 0xff) << 23;
  669.     }
  670. }
  671.     }
  672.   else if (st0_tag == TAG_Zero)
  673.     {
  674.       templ = 0;
  675.     }
  676.   else if ( st0_tag == TAG_Special )
  677.     {
  678.       st0_tag = FPU_Special(st0_ptr);
  679.       if (st0_tag == TW_Denormal)
  680. {
  681.   reg_copy(st0_ptr, &tmp);
  682.   /* A denormal will always underflow. */
  683. #ifndef PECULIAR_486
  684.   /* An 80486 is supposed to be able to generate
  685.      a denormal exception here, but... */
  686.   /* Underflow has priority. */
  687.   if ( control_word & CW_Underflow )
  688.     denormal_operand();
  689. #endif /* PECULIAR_486 */ 
  690.   goto denormal_arg;
  691. }
  692.       else if (st0_tag == TW_Infinity)
  693. {
  694.   templ = 0x7f800000;
  695. }
  696.       else if (st0_tag == TW_NaN)
  697. {
  698.   /* Is it really a NaN ? */
  699.   if ( (exponent(st0_ptr) == EXP_OVER) && (st0_ptr->sigh & 0x80000000) )
  700.     {
  701.       /* See if we can get a valid NaN from the FPU_REG */
  702.       templ = st0_ptr->sigh >> 8;
  703.       if ( !(st0_ptr->sigh & 0x40000000) )
  704. {
  705.   /* It is a signalling NaN */
  706.   EXCEPTION(EX_Invalid);
  707.   if ( !(control_word & CW_Invalid) )
  708.     return 0;
  709.   templ |= (0x40000000 >> 8);
  710. }
  711.       templ |= 0x7f800000;
  712.     }
  713.   else
  714.     {
  715.       /* It is an unsupported data type */
  716.       EXCEPTION(EX_Invalid);
  717.       if ( !(control_word & CW_Invalid) )
  718. return 0;
  719.       templ = 0xffc00000;
  720.     }
  721. }
  722. #ifdef PARANOID
  723.       else
  724. {
  725.   EXCEPTION(EX_INTERNAL|0x164);
  726.   return 0;
  727. }
  728. #endif
  729.     }
  730.   else if ( st0_tag == TAG_Empty )
  731.     {
  732.       /* Empty register (stack underflow) */
  733.       EXCEPTION(EX_StackUnder);
  734.       if ( control_word & EX_Invalid )
  735. {
  736.   /* The masked response */
  737.   /* Put out the QNaN indefinite */
  738.   RE_ENTRANT_CHECK_OFF;
  739.   FPU_verify_area(VERIFY_WRITE,(void *)single,4);
  740.   FPU_put_user(0xffc00000, (unsigned long *) single);
  741.   RE_ENTRANT_CHECK_ON;
  742.   return 1;
  743. }
  744.       else
  745. return 0;
  746.     }
  747. #ifdef PARANOID
  748.   else
  749.     {
  750.       EXCEPTION(EX_INTERNAL|0x163);
  751.       return 0;
  752.     }
  753. #endif
  754.   if ( getsign(st0_ptr) )
  755.     templ |= 0x80000000;
  756.   RE_ENTRANT_CHECK_OFF;
  757.   FPU_verify_area(VERIFY_WRITE,(void *)single,4);
  758.   FPU_put_user(templ,(unsigned long *) single);
  759.   RE_ENTRANT_CHECK_ON;
  760.   return 1;
  761. }
  762. /* Put a long long into user memory */
  763. int FPU_store_int64(FPU_REG *st0_ptr, u_char st0_tag, long long *d)
  764. {
  765.   FPU_REG t;
  766.   long long tll;
  767.   int precision_loss;
  768.   if ( st0_tag == TAG_Empty )
  769.     {
  770.       /* Empty register (stack underflow) */
  771.       EXCEPTION(EX_StackUnder);
  772.       goto invalid_operand;
  773.     }
  774.   else if ( st0_tag == TAG_Special )
  775.     {
  776.       st0_tag = FPU_Special(st0_ptr);
  777.       if ( (st0_tag == TW_Infinity) ||
  778.    (st0_tag == TW_NaN) )
  779. {
  780.   EXCEPTION(EX_Invalid);
  781.   goto invalid_operand;
  782. }
  783.     }
  784.   reg_copy(st0_ptr, &t);
  785.   precision_loss = FPU_round_to_int(&t, st0_tag);
  786.   ((long *)&tll)[0] = t.sigl;
  787.   ((long *)&tll)[1] = t.sigh;
  788.   if ( (precision_loss == 1) ||
  789.       ((t.sigh & 0x80000000) &&
  790.        !((t.sigh == 0x80000000) && (t.sigl == 0) &&
  791.  signnegative(&t))) )
  792.     {
  793.       EXCEPTION(EX_Invalid);
  794.       /* This is a special case: see sec 16.2.5.1 of the 80486 book */
  795.     invalid_operand:
  796.       if ( control_word & EX_Invalid )
  797. {
  798.   /* Produce something like QNaN "indefinite" */
  799.   tll = 0x8000000000000000LL;
  800. }
  801.       else
  802. return 0;
  803.     }
  804.   else
  805.     {
  806.       if ( precision_loss )
  807. set_precision_flag(precision_loss);
  808.       if ( signnegative(&t) )
  809. tll = - tll;
  810.     }
  811.   RE_ENTRANT_CHECK_OFF;
  812.   FPU_verify_area(VERIFY_WRITE,(void *)d,8);
  813.   copy_to_user(d, &tll, 8);
  814.   RE_ENTRANT_CHECK_ON;
  815.   return 1;
  816. }
  817. /* Put a long into user memory */
  818. int FPU_store_int32(FPU_REG *st0_ptr, u_char st0_tag, long *d)
  819. {
  820.   FPU_REG t;
  821.   int precision_loss;
  822.   if ( st0_tag == TAG_Empty )
  823.     {
  824.       /* Empty register (stack underflow) */
  825.       EXCEPTION(EX_StackUnder);
  826.       goto invalid_operand;
  827.     }
  828.   else if ( st0_tag == TAG_Special )
  829.     {
  830.       st0_tag = FPU_Special(st0_ptr);
  831.       if ( (st0_tag == TW_Infinity) ||
  832.    (st0_tag == TW_NaN) )
  833. {
  834.   EXCEPTION(EX_Invalid);
  835.   goto invalid_operand;
  836. }
  837.     }
  838.   reg_copy(st0_ptr, &t);
  839.   precision_loss = FPU_round_to_int(&t, st0_tag);
  840.   if (t.sigh ||
  841.       ((t.sigl & 0x80000000) &&
  842.        !((t.sigl == 0x80000000) && signnegative(&t))) )
  843.     {
  844.       EXCEPTION(EX_Invalid);
  845.       /* This is a special case: see sec 16.2.5.1 of the 80486 book */
  846.     invalid_operand:
  847.       if ( control_word & EX_Invalid )
  848. {
  849.   /* Produce something like QNaN "indefinite" */
  850.   t.sigl = 0x80000000;
  851. }
  852.       else
  853. return 0;
  854.     }
  855.   else
  856.     {
  857.       if ( precision_loss )
  858. set_precision_flag(precision_loss);
  859.       if ( signnegative(&t) )
  860. t.sigl = -(long)t.sigl;
  861.     }
  862.   RE_ENTRANT_CHECK_OFF;
  863.   FPU_verify_area(VERIFY_WRITE,d,4);
  864.   FPU_put_user(t.sigl, (unsigned long *) d);
  865.   RE_ENTRANT_CHECK_ON;
  866.   return 1;
  867. }
  868. /* Put a short into user memory */
  869. int FPU_store_int16(FPU_REG *st0_ptr, u_char st0_tag, short *d)
  870. {
  871.   FPU_REG t;
  872.   int precision_loss;
  873.   if ( st0_tag == TAG_Empty )
  874.     {
  875.       /* Empty register (stack underflow) */
  876.       EXCEPTION(EX_StackUnder);
  877.       goto invalid_operand;
  878.     }
  879.   else if ( st0_tag == TAG_Special )
  880.     {
  881.       st0_tag = FPU_Special(st0_ptr);
  882.       if ( (st0_tag == TW_Infinity) ||
  883.    (st0_tag == TW_NaN) )
  884. {
  885.   EXCEPTION(EX_Invalid);
  886.   goto invalid_operand;
  887. }
  888.     }
  889.   reg_copy(st0_ptr, &t);
  890.   precision_loss = FPU_round_to_int(&t, st0_tag);
  891.   if (t.sigh ||
  892.       ((t.sigl & 0xffff8000) &&
  893.        !((t.sigl == 0x8000) && signnegative(&t))) )
  894.     {
  895.       EXCEPTION(EX_Invalid);
  896.       /* This is a special case: see sec 16.2.5.1 of the 80486 book */
  897.     invalid_operand:
  898.       if ( control_word & EX_Invalid )
  899. {
  900.   /* Produce something like QNaN "indefinite" */
  901.   t.sigl = 0x8000;
  902. }
  903.       else
  904. return 0;
  905.     }
  906.   else
  907.     {
  908.       if ( precision_loss )
  909. set_precision_flag(precision_loss);
  910.       if ( signnegative(&t) )
  911. t.sigl = -t.sigl;
  912.     }
  913.   RE_ENTRANT_CHECK_OFF;
  914.   FPU_verify_area(VERIFY_WRITE,d,2);
  915.   FPU_put_user((short)t.sigl,(short *) d);
  916.   RE_ENTRANT_CHECK_ON;
  917.   return 1;
  918. }
  919. /* Put a packed bcd array into user memory */
  920. int FPU_store_bcd(FPU_REG *st0_ptr, u_char st0_tag, u_char *d)
  921. {
  922.   FPU_REG t;
  923.   unsigned long long ll;
  924.   u_char b;
  925.   int i, precision_loss;
  926.   u_char sign = (getsign(st0_ptr) == SIGN_NEG) ? 0x80 : 0;
  927.   if ( st0_tag == TAG_Empty )
  928.     {
  929.       /* Empty register (stack underflow) */
  930.       EXCEPTION(EX_StackUnder);
  931.       goto invalid_operand;
  932.     }
  933.   else if ( st0_tag == TAG_Special )
  934.     {
  935.       st0_tag = FPU_Special(st0_ptr);
  936.       if ( (st0_tag == TW_Infinity) ||
  937.    (st0_tag == TW_NaN) )
  938. {
  939.   EXCEPTION(EX_Invalid);
  940.   goto invalid_operand;
  941. }
  942.     }
  943.   reg_copy(st0_ptr, &t);
  944.   precision_loss = FPU_round_to_int(&t, st0_tag);
  945.   ll = significand(&t);
  946.   /* Check for overflow, by comparing with 999999999999999999 decimal. */
  947.   if ( (t.sigh > 0x0de0b6b3) ||
  948.       ((t.sigh == 0x0de0b6b3) && (t.sigl > 0xa763ffff)) )
  949.     {
  950.       EXCEPTION(EX_Invalid);
  951.       /* This is a special case: see sec 16.2.5.1 of the 80486 book */
  952.     invalid_operand:
  953.       if ( control_word & CW_Invalid )
  954. {
  955.   /* Produce the QNaN "indefinite" */
  956.   RE_ENTRANT_CHECK_OFF;
  957.   FPU_verify_area(VERIFY_WRITE,d,10);
  958.   for ( i = 0; i < 7; i++)
  959.     FPU_put_user(0, (u_char *) d+i); /* These bytes "undefined" */
  960.   FPU_put_user(0xc0, (u_char *) d+7); /* This byte "undefined" */
  961.   FPU_put_user(0xff, (u_char *) d+8);
  962.   FPU_put_user(0xff, (u_char *) d+9);
  963.   RE_ENTRANT_CHECK_ON;
  964.   return 1;
  965. }
  966.       else
  967. return 0;
  968.     }
  969.   else if ( precision_loss )
  970.     {
  971.       /* Precision loss doesn't stop the data transfer */
  972.       set_precision_flag(precision_loss);
  973.     }
  974.   RE_ENTRANT_CHECK_OFF;
  975.   FPU_verify_area(VERIFY_WRITE,d,10);
  976.   RE_ENTRANT_CHECK_ON;
  977.   for ( i = 0; i < 9; i++)
  978.     {
  979.       b = FPU_div_small(&ll, 10);
  980.       b |= (FPU_div_small(&ll, 10)) << 4;
  981.       RE_ENTRANT_CHECK_OFF;
  982.       FPU_put_user(b,(u_char *) d+i);
  983.       RE_ENTRANT_CHECK_ON;
  984.     }
  985.   RE_ENTRANT_CHECK_OFF;
  986.   FPU_put_user(sign,(u_char *) d+9);
  987.   RE_ENTRANT_CHECK_ON;
  988.   return 1;
  989. }
  990. /*===========================================================================*/
  991. /* r gets mangled such that sig is int, sign: 
  992.    it is NOT normalized */
  993. /* The return value (in eax) is zero if the result is exact,
  994.    if bits are changed due to rounding, truncation, etc, then
  995.    a non-zero value is returned */
  996. /* Overflow is signalled by a non-zero return value (in eax).
  997.    In the case of overflow, the returned significand always has the
  998.    largest possible value */
  999. int FPU_round_to_int(FPU_REG *r, u_char tag)
  1000. {
  1001.   u_char     very_big;
  1002.   unsigned eax;
  1003.   if (tag == TAG_Zero)
  1004.     {
  1005.       /* Make sure that zero is returned */
  1006.       significand(r) = 0;
  1007.       return 0;        /* o.k. */
  1008.     }
  1009.   if (exponent(r) > 63)
  1010.     {
  1011.       r->sigl = r->sigh = ~0;      /* The largest representable number */
  1012.       return 1;        /* overflow */
  1013.     }
  1014.   eax = FPU_shrxs(&r->sigl, 63 - exponent(r));
  1015.   very_big = !(~(r->sigh) | ~(r->sigl));  /* test for 0xfff...fff */
  1016. #define half_or_more (eax & 0x80000000)
  1017. #define frac_part (eax)
  1018. #define more_than_half  ((eax & 0x80000001) == 0x80000001)
  1019.   switch (control_word & CW_RC)
  1020.     {
  1021.     case RC_RND:
  1022.       if ( more_than_half                /* nearest */
  1023.   || (half_or_more && (r->sigl & 1)) ) /* odd -> even */
  1024. {
  1025.   if ( very_big ) return 1;        /* overflow */
  1026.   significand(r) ++;
  1027.   return PRECISION_LOST_UP;
  1028. }
  1029.       break;
  1030.     case RC_DOWN:
  1031.       if (frac_part && getsign(r))
  1032. {
  1033.   if ( very_big ) return 1;        /* overflow */
  1034.   significand(r) ++;
  1035.   return PRECISION_LOST_UP;
  1036. }
  1037.       break;
  1038.     case RC_UP:
  1039.       if (frac_part && !getsign(r))
  1040. {
  1041.   if ( very_big ) return 1;        /* overflow */
  1042.   significand(r) ++;
  1043.   return PRECISION_LOST_UP;
  1044. }
  1045.       break;
  1046.     case RC_CHOP:
  1047.       break;
  1048.     }
  1049.   return eax ? PRECISION_LOST_DOWN : 0;
  1050. }
  1051. /*===========================================================================*/
  1052. u_char *fldenv(fpu_addr_modes addr_modes, u_char *s)
  1053. {
  1054.   unsigned short tag_word = 0;
  1055.   u_char tag;
  1056.   int i;
  1057.   if ( (addr_modes.default_mode == VM86) ||
  1058.       ((addr_modes.default_mode == PM16)
  1059.       ^ (addr_modes.override.operand_size == OP_SIZE_PREFIX)) )
  1060.     {
  1061.       RE_ENTRANT_CHECK_OFF;
  1062.       FPU_verify_area(VERIFY_READ, s, 0x0e);
  1063.       FPU_get_user(control_word, (unsigned short *) s);
  1064.       FPU_get_user(partial_status, (unsigned short *) (s+2));
  1065.       FPU_get_user(tag_word, (unsigned short *) (s+4));
  1066.       FPU_get_user(instruction_address.offset, (unsigned short *) (s+6));
  1067.       FPU_get_user(instruction_address.selector, (unsigned short *) (s+8));
  1068.       FPU_get_user(operand_address.offset, (unsigned short *) (s+0x0a));
  1069.       FPU_get_user(operand_address.selector, (unsigned short *) (s+0x0c));
  1070.       RE_ENTRANT_CHECK_ON;
  1071.       s += 0x0e;
  1072.       if ( addr_modes.default_mode == VM86 )
  1073. {
  1074.   instruction_address.offset
  1075.     += (instruction_address.selector & 0xf000) << 4;
  1076.   operand_address.offset += (operand_address.selector & 0xf000) << 4;
  1077. }
  1078.     }
  1079.   else
  1080.     {
  1081.       RE_ENTRANT_CHECK_OFF;
  1082.       FPU_verify_area(VERIFY_READ, s, 0x1c);
  1083.       FPU_get_user(control_word, (unsigned short *) s);
  1084.       FPU_get_user(partial_status, (unsigned short *) (s+4));
  1085.       FPU_get_user(tag_word, (unsigned short *) (s+8));
  1086.       FPU_get_user(instruction_address.offset, (unsigned long *) (s+0x0c));
  1087.       FPU_get_user(instruction_address.selector, (unsigned short *) (s+0x10));
  1088.       FPU_get_user(instruction_address.opcode, (unsigned short *) (s+0x12));
  1089.       FPU_get_user(operand_address.offset, (unsigned long *) (s+0x14));
  1090.       FPU_get_user(operand_address.selector, (unsigned long *) (s+0x18));
  1091.       RE_ENTRANT_CHECK_ON;
  1092.       s += 0x1c;
  1093.     }
  1094. #ifdef PECULIAR_486
  1095.   control_word &= ~0xe080;
  1096. #endif /* PECULIAR_486 */ 
  1097.   top = (partial_status >> SW_Top_Shift) & 7;
  1098.   if ( partial_status & ~control_word & CW_Exceptions )
  1099.     partial_status |= (SW_Summary | SW_Backward);
  1100.   else
  1101.     partial_status &= ~(SW_Summary | SW_Backward);
  1102.   for ( i = 0; i < 8; i++ )
  1103.     {
  1104.       tag = tag_word & 3;
  1105.       tag_word >>= 2;
  1106.       if ( tag == TAG_Empty )
  1107. /* New tag is empty.  Accept it */
  1108. FPU_settag(i, TAG_Empty);
  1109.       else if ( FPU_gettag(i) == TAG_Empty )
  1110. {
  1111.   /* Old tag is empty and new tag is not empty.  New tag is determined
  1112.      by old reg contents */
  1113.   if ( exponent(&fpu_register(i)) == - EXTENDED_Ebias )
  1114.     {
  1115.       if ( !(fpu_register(i).sigl | fpu_register(i).sigh) )
  1116. FPU_settag(i, TAG_Zero);
  1117.       else
  1118. FPU_settag(i, TAG_Special);
  1119.     }
  1120.   else if ( exponent(&fpu_register(i)) == 0x7fff - EXTENDED_Ebias )
  1121.     {
  1122.       FPU_settag(i, TAG_Special);
  1123.     }
  1124.   else if ( fpu_register(i).sigh & 0x80000000 )
  1125.     FPU_settag(i, TAG_Valid);
  1126.   else
  1127.     FPU_settag(i, TAG_Special);   /* An Un-normal */
  1128.    }
  1129.       /* Else old tag is not empty and new tag is not empty.  Old tag
  1130.  remains correct */
  1131.     }
  1132.   return s;
  1133. }
  1134. void frstor(fpu_addr_modes addr_modes, u_char *data_address)
  1135. {
  1136.   int i, regnr;
  1137.   u_char *s = fldenv(addr_modes, data_address);
  1138.   int offset = (top & 7) * 10, other = 80 - offset;
  1139.   /* Copy all registers in stack order. */
  1140.   RE_ENTRANT_CHECK_OFF;
  1141.   FPU_verify_area(VERIFY_READ,s,80);
  1142.   __copy_from_user(register_base+offset, s, other);
  1143.   if ( offset )
  1144.     __copy_from_user(register_base, s+other, offset);
  1145.   RE_ENTRANT_CHECK_ON;
  1146.   for ( i = 0; i < 8; i++ )
  1147.     {
  1148.       regnr = (i+top) & 7;
  1149.       if ( FPU_gettag(regnr) != TAG_Empty )
  1150. /* The loaded data over-rides all other cases. */
  1151. FPU_settag(regnr, FPU_tagof(&st(i)));
  1152.     }
  1153. }
  1154. u_char *fstenv(fpu_addr_modes addr_modes, u_char *d)
  1155. {
  1156.   if ( (addr_modes.default_mode == VM86) ||
  1157.       ((addr_modes.default_mode == PM16)
  1158.       ^ (addr_modes.override.operand_size == OP_SIZE_PREFIX)) )
  1159.     {
  1160.       RE_ENTRANT_CHECK_OFF;
  1161.       FPU_verify_area(VERIFY_WRITE,d,14);
  1162. #ifdef PECULIAR_486
  1163.       FPU_put_user(control_word & ~0xe080, (unsigned long *) d);
  1164. #else
  1165.       FPU_put_user(control_word, (unsigned short *) d);
  1166. #endif /* PECULIAR_486 */
  1167.       FPU_put_user(status_word(), (unsigned short *) (d+2));
  1168.       FPU_put_user(fpu_tag_word, (unsigned short *) (d+4));
  1169.       FPU_put_user(instruction_address.offset, (unsigned short *) (d+6));
  1170.       FPU_put_user(operand_address.offset, (unsigned short *) (d+0x0a));
  1171.       if ( addr_modes.default_mode == VM86 )
  1172. {
  1173.   FPU_put_user((instruction_address.offset & 0xf0000) >> 4,
  1174.       (unsigned short *) (d+8));
  1175.   FPU_put_user((operand_address.offset & 0xf0000) >> 4,
  1176.       (unsigned short *) (d+0x0c));
  1177. }
  1178.       else
  1179. {
  1180.   FPU_put_user(instruction_address.selector, (unsigned short *) (d+8));
  1181.   FPU_put_user(operand_address.selector, (unsigned short *) (d+0x0c));
  1182. }
  1183.       RE_ENTRANT_CHECK_ON;
  1184.       d += 0x0e;
  1185.     }
  1186.   else
  1187.     {
  1188.       RE_ENTRANT_CHECK_OFF;
  1189.       FPU_verify_area(VERIFY_WRITE, d, 7*4);
  1190. #ifdef PECULIAR_486
  1191.       control_word &= ~0xe080;
  1192.       /* An 80486 sets nearly all of the reserved bits to 1. */
  1193.       control_word |= 0xffff0040;
  1194.       partial_status = status_word() | 0xffff0000;
  1195.       fpu_tag_word |= 0xffff0000;
  1196.       I387.soft.fcs &= ~0xf8000000;
  1197.       I387.soft.fos |= 0xffff0000;
  1198. #endif /* PECULIAR_486 */
  1199.       __copy_to_user(d, &control_word, 7*4);
  1200.       RE_ENTRANT_CHECK_ON;
  1201.       d += 0x1c;
  1202.     }
  1203.   
  1204.   control_word |= CW_Exceptions;
  1205.   partial_status &= ~(SW_Summary | SW_Backward);
  1206.   return d;
  1207. }
  1208. void fsave(fpu_addr_modes addr_modes, u_char *data_address)
  1209. {
  1210.   u_char *d;
  1211.   int offset = (top & 7) * 10, other = 80 - offset;
  1212.   d = fstenv(addr_modes, data_address);
  1213.   RE_ENTRANT_CHECK_OFF;
  1214.   FPU_verify_area(VERIFY_WRITE,d,80);
  1215.   /* Copy all registers in stack order. */
  1216.   __copy_to_user(d, register_base+offset, other);
  1217.   if ( offset )
  1218.     __copy_to_user(d+other, register_base, offset);
  1219.   RE_ENTRANT_CHECK_ON;
  1220.   finit();
  1221. }
  1222. /*===========================================================================*/