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