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