Linux-2.6.12-rc2
[linux-2.6/next.git] / arch / i386 / math-emu / reg_ld_str.c
blobf06ed41d191d53f5496c295bfaf1ca3b07179b69
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 +---------------------------------------------------------------------------*/
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 +---------------------------------------------------------------------------*/
20 #include "fpu_emu.h"
22 #include <asm/uaccess.h>
24 #include "fpu_system.h"
25 #include "exception.h"
26 #include "reg_constant.h"
27 #include "control_w.h"
28 #include "status_w.h"
31 #define DOUBLE_Emax 1023 /* largest valid exponent */
32 #define DOUBLE_Ebias 1023
33 #define DOUBLE_Emin (-1022) /* smallest valid exponent */
35 #define SINGLE_Emax 127 /* largest valid exponent */
36 #define SINGLE_Ebias 127
37 #define SINGLE_Emin (-126) /* smallest valid exponent */
40 static u_char normalize_no_excep(FPU_REG *r, int exp, int sign)
42 u_char tag;
44 setexponent16(r, exp);
46 tag = FPU_normalize_nuo(r);
47 stdexp(r);
48 if ( sign )
49 setnegative(r);
51 return tag;
55 int FPU_tagof(FPU_REG *ptr)
57 int exp;
59 exp = exponent16(ptr) & 0x7fff;
60 if ( exp == 0 )
62 if ( !(ptr->sigh | ptr->sigl) )
64 return TAG_Zero;
66 /* The number is a de-normal or pseudodenormal. */
67 return TAG_Special;
70 if ( exp == 0x7fff )
72 /* Is an Infinity, a NaN, or an unsupported data type. */
73 return TAG_Special;
76 if ( !(ptr->sigh & 0x80000000) )
78 /* Unsupported data type. */
79 /* Valid numbers have the ms bit set to 1. */
80 /* Unnormal. */
81 return TAG_Special;
84 return TAG_Valid;
88 /* Get a long double from user memory */
89 int FPU_load_extended(long double __user *s, int stnr)
91 FPU_REG *sti_ptr = &st(stnr);
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;
98 return FPU_tagof(sti_ptr);
102 /* Get a double from user memory */
103 int FPU_load_double(double __user *dfloat, FPU_REG *loaded_data)
105 int exp, tag, negative;
106 unsigned m64, l64;
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;
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 )
119 /* Infinity or NaN */
120 if ((m64 == 0) && (l64 == 0))
122 /* +- infinity */
123 loaded_data->sigh = 0x80000000;
124 loaded_data->sigl = 0x00000000;
125 exp = EXP_Infinity + EXTENDED_Ebias;
126 tag = TAG_Special;
128 else
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 */
138 else if ( exp < DOUBLE_Emin + EXTENDED_Ebias )
140 /* Zero or de-normal */
141 if ((m64 == 0) && (l64 == 0))
143 /* Zero */
144 reg_copy(&CONST_Z, loaded_data);
145 exp = 0;
146 tag = TAG_Zero;
148 else
150 /* De-normal */
151 loaded_data->sigh = m64 << 11;
152 loaded_data->sigh |= l64 >> 21;
153 loaded_data->sigl = l64 << 11;
155 return normalize_no_excep(loaded_data, DOUBLE_Emin, negative)
156 | (denormal_operand() < 0 ? FPU_Exception : 0);
159 else
161 loaded_data->sigh = (m64 << 11) | 0x80000000;
162 loaded_data->sigh |= l64 >> 21;
163 loaded_data->sigl = l64 << 11;
165 tag = TAG_Valid;
168 setexponent16(loaded_data, exp | negative);
170 return tag;
174 /* Get a float from user memory */
175 int FPU_load_single(float __user *single, FPU_REG *loaded_data)
177 unsigned m32;
178 int exp, tag, negative;
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;
185 negative = (m32 & 0x80000000) ? SIGN_Negative : SIGN_Positive;
187 if (!(m32 & 0x7fffffff))
189 /* Zero */
190 reg_copy(&CONST_Z, loaded_data);
191 addexponent(loaded_data, negative);
192 return TAG_Zero;
194 exp = ((m32 & 0x7f800000) >> 23) - SINGLE_Ebias + EXTENDED_Ebias;
195 m32 = (m32 & 0x7fffff) << 8;
196 if ( exp < SINGLE_Emin + EXTENDED_Ebias )
198 /* De-normals */
199 loaded_data->sigh = m32;
200 loaded_data->sigl = 0;
202 return normalize_no_excep(loaded_data, SINGLE_Emin, negative)
203 | (denormal_operand() < 0 ? FPU_Exception : 0);
205 else if ( exp > SINGLE_Emax + EXTENDED_Ebias )
207 /* Infinity or NaN */
208 if ( m32 == 0 )
210 /* +- infinity */
211 loaded_data->sigh = 0x80000000;
212 loaded_data->sigl = 0x00000000;
213 exp = EXP_Infinity + EXTENDED_Ebias;
214 tag = TAG_Special;
216 else
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 */
225 else
227 loaded_data->sigh = m32 | 0x80000000;
228 loaded_data->sigl = 0;
229 tag = TAG_Valid;
232 setexponent16(loaded_data, exp | negative); /* Set the sign. */
234 return tag;
238 /* Get a long long from user memory */
239 int FPU_load_int64(long long __user *_s)
241 long long s;
242 int sign;
243 FPU_REG *st0_ptr = &st(0);
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;
250 if (s == 0)
252 reg_copy(&CONST_Z, st0_ptr);
253 return TAG_Zero;
256 if (s > 0)
257 sign = SIGN_Positive;
258 else
260 s = -s;
261 sign = SIGN_Negative;
264 significand(st0_ptr) = s;
266 return normalize_no_excep(st0_ptr, 63, sign);
270 /* Get a long from user memory */
271 int FPU_load_int32(long __user *_s, FPU_REG *loaded_data)
273 long s;
274 int negative;
276 RE_ENTRANT_CHECK_OFF;
277 FPU_access_ok(VERIFY_READ, _s, 4);
278 FPU_get_user(s, _s);
279 RE_ENTRANT_CHECK_ON;
281 if (s == 0)
282 { reg_copy(&CONST_Z, loaded_data); return TAG_Zero; }
284 if (s > 0)
285 negative = SIGN_Positive;
286 else
288 s = -s;
289 negative = SIGN_Negative;
292 loaded_data->sigh = s;
293 loaded_data->sigl = 0;
295 return normalize_no_excep(loaded_data, 31, negative);
299 /* Get a short from user memory */
300 int FPU_load_int16(short __user *_s, FPU_REG *loaded_data)
302 int s, negative;
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;
310 if (s == 0)
311 { reg_copy(&CONST_Z, loaded_data); return TAG_Zero; }
313 if (s > 0)
314 negative = SIGN_Positive;
315 else
317 s = -s;
318 negative = SIGN_Negative;
321 loaded_data->sigh = s << 16;
322 loaded_data->sigl = 0;
324 return normalize_no_excep(loaded_data, 15, negative);
328 /* Get a packed bcd array from user memory */
329 int FPU_load_bcd(u_char __user *s)
331 FPU_REG *st0_ptr = &st(0);
332 int pos;
333 u_char bcd;
334 long long l=0;
335 int sign;
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--)
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;
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;
356 if ( l == 0 )
358 reg_copy(&CONST_Z, st0_ptr);
359 addexponent(st0_ptr, sign); /* Set the sign. */
360 return TAG_Zero;
362 else
364 significand(st0_ptr) = l;
365 return normalize_no_excep(st0_ptr, 63, sign);
369 /*===========================================================================*/
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)
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.
380 if ( st0_tag != TAG_Empty )
382 RE_ENTRANT_CHECK_OFF;
383 FPU_access_ok(VERIFY_WRITE, d, 10);
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;
390 return 1;
393 /* Empty register (stack underflow) */
394 EXCEPTION(EX_StackUnder);
395 if ( control_word & CW_Invalid )
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;
407 else
408 return 0;
413 /* Put a double into user memory */
414 int FPU_store_double(FPU_REG *st0_ptr, u_char st0_tag, double __user *dfloat)
416 unsigned long l[2];
417 unsigned long increment = 0; /* avoid gcc warnings */
418 int precision_loss;
419 int exp;
420 FPU_REG tmp;
422 if ( st0_tag == TAG_Valid )
424 reg_copy(st0_ptr, &tmp);
425 exp = exponent(&tmp);
427 if ( exp < DOUBLE_Emin ) /* It may be a denormal */
429 addexponent(&tmp, -DOUBLE_Emin + 52); /* largest exp to be 51 */
431 denormal_arg:
433 if ( (precision_loss = FPU_round_to_int(&tmp, st0_tag)) )
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 */
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;
450 EXCEPTION(precision_loss);
451 if ( !(control_word & CW_Precision) )
452 return 0;
454 l[0] = tmp.sigl;
455 l[1] = tmp.sigh;
457 else
459 if ( tmp.sigl & 0x000007ff )
461 precision_loss = 1;
462 switch (control_word & CW_RC)
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;
480 /* Truncate the mantissa */
481 tmp.sigl &= 0xfffff800;
483 if ( increment )
485 if ( tmp.sigl >= 0xfffff800 )
487 /* the sigl part overflows */
488 if ( tmp.sigh == 0xffffffff )
490 /* The sigh part overflows */
491 tmp.sigh = 0x80000000;
492 exp++;
493 if (exp >= EXP_OVER)
494 goto overflow;
496 else
498 tmp.sigh ++;
500 tmp.sigl = 0x00000000;
502 else
504 /* We only need to increment sigl */
505 tmp.sigl += 0x00000800;
509 else
510 precision_loss = 0;
512 l[0] = (tmp.sigl >> 11) | (tmp.sigh << 21);
513 l[1] = ((tmp.sigh >> 11) & 0xfffff);
515 if ( exp > DOUBLE_Emax )
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;
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 */
530 else
532 if ( precision_loss )
534 if ( increment )
535 set_precision_flag_up();
536 else
537 set_precision_flag_down();
539 /* Add the exponent */
540 l[1] |= (((exp+DOUBLE_Ebias) & 0x7ff) << 20);
544 else if (st0_tag == TAG_Zero)
546 /* Number is zero */
547 l[0] = 0;
548 l[1] = 0;
550 else if ( st0_tag == TAG_Special )
552 st0_tag = FPU_Special(st0_ptr);
553 if ( st0_tag == TW_Denormal )
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;
566 else if (st0_tag == TW_Infinity)
568 l[0] = 0;
569 l[1] = 0x7ff00000;
571 else if (st0_tag == TW_NaN)
573 /* Is it really a NaN ? */
574 if ( (exponent(st0_ptr) == EXP_OVER)
575 && (st0_ptr->sigh & 0x80000000) )
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) )
582 /* It is a signalling NaN */
583 EXCEPTION(EX_Invalid);
584 if ( !(control_word & CW_Invalid) )
585 return 0;
586 l[1] |= (0x40000000 >> 11);
588 l[1] |= 0x7ff00000;
590 else
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;
601 else if ( st0_tag == TAG_Empty )
603 /* Empty register (stack underflow) */
604 EXCEPTION(EX_StackUnder);
605 if ( control_word & CW_Invalid )
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;
616 else
617 return 0;
619 if ( getsign(st0_ptr) )
620 l[1] |= 0x80000000;
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;
628 return 1;
632 /* Put a float into user memory */
633 int FPU_store_single(FPU_REG *st0_ptr, u_char st0_tag, float __user *single)
635 long templ = 0;
636 unsigned long increment = 0; /* avoid gcc warnings */
637 int precision_loss;
638 int exp;
639 FPU_REG tmp;
641 if ( st0_tag == TAG_Valid )
644 reg_copy(st0_ptr, &tmp);
645 exp = exponent(&tmp);
647 if ( exp < SINGLE_Emin )
649 addexponent(&tmp, -SINGLE_Emin + 23); /* largest exp to be 22 */
651 denormal_arg:
653 if ( (precision_loss = FPU_round_to_int(&tmp, st0_tag)) )
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 */
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;
670 EXCEPTION(precision_loss);
671 if ( !(control_word & CW_Precision) )
672 return 0;
674 templ = tmp.sigl;
676 else
678 if ( tmp.sigl | (tmp.sigh & 0x000000ff) )
680 unsigned long sigh = tmp.sigh;
681 unsigned long sigl = tmp.sigl;
683 precision_loss = 1;
684 switch (control_word & CW_RC)
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;
704 /* Truncate part of the mantissa */
705 tmp.sigl = 0;
707 if (increment)
709 if ( sigh >= 0xffffff00 )
711 /* The sigh part overflows */
712 tmp.sigh = 0x80000000;
713 exp++;
714 if ( exp >= EXP_OVER )
715 goto overflow;
717 else
719 tmp.sigh &= 0xffffff00;
720 tmp.sigh += 0x100;
723 else
725 tmp.sigh &= 0xffffff00; /* Finish the truncation */
728 else
729 precision_loss = 0;
731 templ = (tmp.sigh >> 8) & 0x007fffff;
733 if ( exp > SINGLE_Emax )
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;
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;
747 else
749 if ( precision_loss )
751 if ( increment )
752 set_precision_flag_up();
753 else
754 set_precision_flag_down();
756 /* Add the exponent */
757 templ |= ((exp+SINGLE_Ebias) & 0xff) << 23;
761 else if (st0_tag == TAG_Zero)
763 templ = 0;
765 else if ( st0_tag == TAG_Special )
767 st0_tag = FPU_Special(st0_ptr);
768 if (st0_tag == TW_Denormal)
770 reg_copy(st0_ptr, &tmp);
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;
782 else if (st0_tag == TW_Infinity)
784 templ = 0x7f800000;
786 else if (st0_tag == TW_NaN)
788 /* Is it really a NaN ? */
789 if ( (exponent(st0_ptr) == EXP_OVER) && (st0_ptr->sigh & 0x80000000) )
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) )
795 /* It is a signalling NaN */
796 EXCEPTION(EX_Invalid);
797 if ( !(control_word & CW_Invalid) )
798 return 0;
799 templ |= (0x40000000 >> 8);
801 templ |= 0x7f800000;
803 else
805 /* It is an unsupported data type */
806 EXCEPTION(EX_Invalid);
807 if ( !(control_word & CW_Invalid) )
808 return 0;
809 templ = 0xffc00000;
812 #ifdef PARANOID
813 else
815 EXCEPTION(EX_INTERNAL|0x164);
816 return 0;
818 #endif
820 else if ( st0_tag == TAG_Empty )
822 /* Empty register (stack underflow) */
823 EXCEPTION(EX_StackUnder);
824 if ( control_word & EX_Invalid )
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;
834 else
835 return 0;
837 #ifdef PARANOID
838 else
840 EXCEPTION(EX_INTERNAL|0x163);
841 return 0;
843 #endif
844 if ( getsign(st0_ptr) )
845 templ |= 0x80000000;
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;
852 return 1;
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)
859 FPU_REG t;
860 long long tll;
861 int precision_loss;
863 if ( st0_tag == TAG_Empty )
865 /* Empty register (stack underflow) */
866 EXCEPTION(EX_StackUnder);
867 goto invalid_operand;
869 else if ( st0_tag == TAG_Special )
871 st0_tag = FPU_Special(st0_ptr);
872 if ( (st0_tag == TW_Infinity) ||
873 (st0_tag == TW_NaN) )
875 EXCEPTION(EX_Invalid);
876 goto invalid_operand;
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))) )
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 )
894 /* Produce something like QNaN "indefinite" */
895 tll = 0x8000000000000000LL;
897 else
898 return 0;
900 else
902 if ( precision_loss )
903 set_precision_flag(precision_loss);
904 if ( signnegative(&t) )
905 tll = - tll;
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;
913 return 1;
917 /* Put a long into user memory */
918 int FPU_store_int32(FPU_REG *st0_ptr, u_char st0_tag, long __user *d)
920 FPU_REG t;
921 int precision_loss;
923 if ( st0_tag == TAG_Empty )
925 /* Empty register (stack underflow) */
926 EXCEPTION(EX_StackUnder);
927 goto invalid_operand;
929 else if ( st0_tag == TAG_Special )
931 st0_tag = FPU_Special(st0_ptr);
932 if ( (st0_tag == TW_Infinity) ||
933 (st0_tag == TW_NaN) )
935 EXCEPTION(EX_Invalid);
936 goto invalid_operand;
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))) )
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 )
951 /* Produce something like QNaN "indefinite" */
952 t.sigl = 0x80000000;
954 else
955 return 0;
957 else
959 if ( precision_loss )
960 set_precision_flag(precision_loss);
961 if ( signnegative(&t) )
962 t.sigl = -(long)t.sigl;
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;
970 return 1;
974 /* Put a short into user memory */
975 int FPU_store_int16(FPU_REG *st0_ptr, u_char st0_tag, short __user *d)
977 FPU_REG t;
978 int precision_loss;
980 if ( st0_tag == TAG_Empty )
982 /* Empty register (stack underflow) */
983 EXCEPTION(EX_StackUnder);
984 goto invalid_operand;
986 else if ( st0_tag == TAG_Special )
988 st0_tag = FPU_Special(st0_ptr);
989 if ( (st0_tag == TW_Infinity) ||
990 (st0_tag == TW_NaN) )
992 EXCEPTION(EX_Invalid);
993 goto invalid_operand;
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))) )
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 )
1008 /* Produce something like QNaN "indefinite" */
1009 t.sigl = 0x8000;
1011 else
1012 return 0;
1014 else
1016 if ( precision_loss )
1017 set_precision_flag(precision_loss);
1018 if ( signnegative(&t) )
1019 t.sigl = -t.sigl;
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;
1027 return 1;
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)
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;
1040 if ( st0_tag == TAG_Empty )
1042 /* Empty register (stack underflow) */
1043 EXCEPTION(EX_StackUnder);
1044 goto invalid_operand;
1046 else if ( st0_tag == TAG_Special )
1048 st0_tag = FPU_Special(st0_ptr);
1049 if ( (st0_tag == TW_Infinity) ||
1050 (st0_tag == TW_NaN) )
1052 EXCEPTION(EX_Invalid);
1053 goto invalid_operand;
1057 reg_copy(st0_ptr, &t);
1058 precision_loss = FPU_round_to_int(&t, st0_tag);
1059 ll = significand(&t);
1061 /* Check for overflow, by comparing with 999999999999999999 decimal. */
1062 if ( (t.sigh > 0x0de0b6b3) ||
1063 ((t.sigh == 0x0de0b6b3) && (t.sigl > 0xa763ffff)) )
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 )
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;
1081 else
1082 return 0;
1084 else if ( precision_loss )
1086 /* Precision loss doesn't stop the data transfer */
1087 set_precision_flag(precision_loss);
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++)
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;
1101 RE_ENTRANT_CHECK_OFF;
1102 FPU_put_user(sign, d+9);
1103 RE_ENTRANT_CHECK_ON;
1105 return 1;
1108 /*===========================================================================*/
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)
1120 u_char very_big;
1121 unsigned eax;
1123 if (tag == TAG_Zero)
1125 /* Make sure that zero is returned */
1126 significand(r) = 0;
1127 return 0; /* o.k. */
1130 if (exponent(r) > 63)
1132 r->sigl = r->sigh = ~0; /* The largest representable number */
1133 return 1; /* overflow */
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)
1143 case RC_RND:
1144 if ( more_than_half /* nearest */
1145 || (half_or_more && (r->sigl & 1)) ) /* odd -> even */
1147 if ( very_big ) return 1; /* overflow */
1148 significand(r) ++;
1149 return PRECISION_LOST_UP;
1151 break;
1152 case RC_DOWN:
1153 if (frac_part && getsign(r))
1155 if ( very_big ) return 1; /* overflow */
1156 significand(r) ++;
1157 return PRECISION_LOST_UP;
1159 break;
1160 case RC_UP:
1161 if (frac_part && !getsign(r))
1163 if ( very_big ) return 1; /* overflow */
1164 significand(r) ++;
1165 return PRECISION_LOST_UP;
1167 break;
1168 case RC_CHOP:
1169 break;
1172 return eax ? PRECISION_LOST_DOWN : 0;
1176 /*===========================================================================*/
1178 u_char __user *fldenv(fpu_addr_modes addr_modes, u_char __user *s)
1180 unsigned short tag_word = 0;
1181 u_char tag;
1182 int i;
1184 if ( (addr_modes.default_mode == VM86) ||
1185 ((addr_modes.default_mode == PM16)
1186 ^ (addr_modes.override.operand_size == OP_SIZE_PREFIX)) )
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 )
1201 instruction_address.offset
1202 += (instruction_address.selector & 0xf000) << 4;
1203 operand_address.offset += (operand_address.selector & 0xf000) << 4;
1206 else
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;
1222 #ifdef PECULIAR_486
1223 control_word &= ~0xe080;
1224 #endif /* PECULIAR_486 */
1226 top = (partial_status >> SW_Top_Shift) & 7;
1228 if ( partial_status & ~control_word & CW_Exceptions )
1229 partial_status |= (SW_Summary | SW_Backward);
1230 else
1231 partial_status &= ~(SW_Summary | SW_Backward);
1233 for ( i = 0; i < 8; i++ )
1235 tag = tag_word & 3;
1236 tag_word >>= 2;
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 )
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 )
1247 if ( !(fpu_register(i).sigl | fpu_register(i).sigh) )
1248 FPU_settag(i, TAG_Zero);
1249 else
1250 FPU_settag(i, TAG_Special);
1252 else if ( exponent(&fpu_register(i)) == 0x7fff - EXTENDED_Ebias )
1254 FPU_settag(i, TAG_Special);
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 */
1261 /* Else old tag is not empty and new tag is not empty. Old tag
1262 remains correct */
1265 return s;
1269 void frstor(fpu_addr_modes addr_modes, u_char __user *data_address)
1271 int i, regnr;
1272 u_char __user *s = fldenv(addr_modes, data_address);
1273 int offset = (top & 7) * 10, other = 80 - offset;
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;
1283 for ( i = 0; i < 8; i++ )
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)));
1294 u_char __user *fstenv(fpu_addr_modes addr_modes, u_char __user *d)
1296 if ( (addr_modes.default_mode == VM86) ||
1297 ((addr_modes.default_mode == PM16)
1298 ^ (addr_modes.override.operand_size == OP_SIZE_PREFIX)) )
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 )
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));
1318 else
1320 FPU_put_user(instruction_address.selector, (unsigned short __user *) (d+8));
1321 FPU_put_user(operand_address.selector, (unsigned short __user *) (d+0x0c));
1323 RE_ENTRANT_CHECK_ON;
1324 d += 0x0e;
1326 else
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;
1344 control_word |= CW_Exceptions;
1345 partial_status &= ~(SW_Summary | SW_Backward);
1347 return d;
1351 void fsave(fpu_addr_modes addr_modes, u_char __user *data_address)
1353 u_char __user *d;
1354 int offset = (top & 7) * 10, other = 80 - offset;
1356 d = fstenv(addr_modes, data_address);
1358 RE_ENTRANT_CHECK_OFF;
1359 FPU_access_ok(VERIFY_WRITE,d,80);
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;
1367 finit();
1370 /*===========================================================================*/