File: /usr/src/linux/arch/i386/math-emu/reg_ld_str.c

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     
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     
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
633     int FPU_store_single(FPU_REG *st0_ptr, u_char st0_tag, float *single)
634     {
635       long templ;
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 */
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 */
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 */
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 */
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 */
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     
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     
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     
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     
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