Linux-2.6.12-rc2
[linux-flexiantxendom0-natty.git] / 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 __user *s, int stnr)
90 {
91   FPU_REG *sti_ptr = &st(stnr);
92
93   RE_ENTRANT_CHECK_OFF;
94   FPU_access_ok(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 __user *dfloat, FPU_REG *loaded_data)
104 {
105   int exp, tag, negative;
106   unsigned m64, l64;
107
108   RE_ENTRANT_CHECK_OFF;
109   FPU_access_ok(VERIFY_READ, dfloat, 8);
110   FPU_get_user(m64, 1 + (unsigned long __user *) dfloat);
111   FPU_get_user(l64, (unsigned long __user *) 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 __user *single, FPU_REG *loaded_data)
176 {
177   unsigned m32;
178   int exp, tag, negative;
179
180   RE_ENTRANT_CHECK_OFF;
181   FPU_access_ok(VERIFY_READ, single, 4);
182   FPU_get_user(m32, (unsigned long __user *) 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 __user *_s)
240 {
241   long long s;
242   int sign;
243   FPU_REG *st0_ptr = &st(0);
244
245   RE_ENTRANT_CHECK_OFF;
246   FPU_access_ok(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 __user *_s, FPU_REG *loaded_data)
272 {
273   long s;
274   int negative;
275
276   RE_ENTRANT_CHECK_OFF;
277   FPU_access_ok(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 __user *_s, FPU_REG *loaded_data)
301 {
302   int s, negative;
303
304   RE_ENTRANT_CHECK_OFF;
305   FPU_access_ok(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 __user *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_access_ok(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, 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, 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 __user *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_access_ok(VERIFY_WRITE, d, 10);
384
385       FPU_put_user(st0_ptr->sigl, (unsigned long __user *) d);
386       FPU_put_user(st0_ptr->sigh, (unsigned long __user *) ((u_char __user *)d + 4));
387       FPU_put_user(exponent16(st0_ptr), (unsigned short __user *) ((u_char __user *)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_access_ok(VERIFY_WRITE,d,10);
401       FPU_put_user(0, (unsigned long __user *) d);
402       FPU_put_user(0xc0000000, 1 + (unsigned long __user *) d);
403       FPU_put_user(0xffff, 4 + (short __user *) 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 __user *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_access_ok(VERIFY_WRITE,dfloat,8);
611           FPU_put_user(0, (unsigned long __user *) dfloat);
612           FPU_put_user(0xfff80000, 1 + (unsigned long __user *) 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_access_ok(VERIFY_WRITE,dfloat,8);
624   FPU_put_user(l[0], (unsigned long __user *)dfloat);
625   FPU_put_user(l[1], 1 + (unsigned long __user *)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 __user *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_access_ok(VERIFY_WRITE,single,4);
830           FPU_put_user(0xffc00000, (unsigned long __user *) 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_access_ok(VERIFY_WRITE,single,4);
849   FPU_put_user(templ,(unsigned long __user *) 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 __user *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_access_ok(VERIFY_WRITE,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 __user *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_access_ok(VERIFY_WRITE,d,4);
967   FPU_put_user(t.sigl, (unsigned long __user *) 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 __user *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_access_ok(VERIFY_WRITE,d,2);
1024   FPU_put_user((short)t.sigl, 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 __user *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_access_ok(VERIFY_WRITE,d,10);
1073           for ( i = 0; i < 7; i++)
1074             FPU_put_user(0, d+i); /* These bytes "undefined" */
1075           FPU_put_user(0xc0, d+7); /* This byte "undefined" */
1076           FPU_put_user(0xff, d+8);
1077           FPU_put_user(0xff, 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_access_ok(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, d+i);
1099       RE_ENTRANT_CHECK_ON;
1100     }
1101   RE_ENTRANT_CHECK_OFF;
1102   FPU_put_user(sign, 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 __user *fldenv(fpu_addr_modes addr_modes, u_char __user *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_access_ok(VERIFY_READ, s, 0x0e);
1190       FPU_get_user(control_word, (unsigned short __user *) s);
1191       FPU_get_user(partial_status, (unsigned short __user *) (s+2));
1192       FPU_get_user(tag_word, (unsigned short __user *) (s+4));
1193       FPU_get_user(instruction_address.offset, (unsigned short __user *) (s+6));
1194       FPU_get_user(instruction_address.selector, (unsigned short __user *) (s+8));
1195       FPU_get_user(operand_address.offset, (unsigned short __user *) (s+0x0a));
1196       FPU_get_user(operand_address.selector, (unsigned short __user *) (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_access_ok(VERIFY_READ, s, 0x1c);
1210       FPU_get_user(control_word, (unsigned short __user *) s);
1211       FPU_get_user(partial_status, (unsigned short __user *) (s+4));
1212       FPU_get_user(tag_word, (unsigned short __user *) (s+8));
1213       FPU_get_user(instruction_address.offset, (unsigned long __user *) (s+0x0c));
1214       FPU_get_user(instruction_address.selector, (unsigned short __user *) (s+0x10));
1215       FPU_get_user(instruction_address.opcode, (unsigned short __user *) (s+0x12));
1216       FPU_get_user(operand_address.offset, (unsigned long __user *) (s+0x14));
1217       FPU_get_user(operand_address.selector, (unsigned long __user *) (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 __user *data_address)
1270 {
1271   int i, regnr;
1272   u_char __user *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_access_ok(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 __user *fstenv(fpu_addr_modes addr_modes, u_char __user *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_access_ok(VERIFY_WRITE,d,14);
1302 #ifdef PECULIAR_486
1303       FPU_put_user(control_word & ~0xe080, (unsigned long __user *) d);
1304 #else
1305       FPU_put_user(control_word, (unsigned short __user *) d);
1306 #endif /* PECULIAR_486 */
1307       FPU_put_user(status_word(), (unsigned short __user *) (d+2));
1308       FPU_put_user(fpu_tag_word, (unsigned short __user *) (d+4));
1309       FPU_put_user(instruction_address.offset, (unsigned short __user *) (d+6));
1310       FPU_put_user(operand_address.offset, (unsigned short __user *) (d+0x0a));
1311       if ( addr_modes.default_mode == VM86 )
1312         {
1313           FPU_put_user((instruction_address.offset & 0xf0000) >> 4,
1314                       (unsigned short __user *) (d+8));
1315           FPU_put_user((operand_address.offset & 0xf0000) >> 4,
1316                       (unsigned short __user *) (d+0x0c));
1317         }
1318       else
1319         {
1320           FPU_put_user(instruction_address.selector, (unsigned short __user *) (d+8));
1321           FPU_put_user(operand_address.selector, (unsigned short __user *) (d+0x0c));
1322         }
1323       RE_ENTRANT_CHECK_ON;
1324       d += 0x0e;
1325     }
1326   else
1327     {
1328       RE_ENTRANT_CHECK_OFF;
1329       FPU_access_ok(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 __user *data_address)
1352 {
1353   u_char __user *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_access_ok(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 /*===========================================================================*/