1 /*---------------------------------------------------------------------------+
4 | All of the functions which transfer data between user memory and FPU_REGs.|
6 | Copyright (C) 1992,1993,1994,1996,1997 |
7 | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
8 | E-mail billm@suburbia.net |
11 +---------------------------------------------------------------------------*/
13 /*---------------------------------------------------------------------------+
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 +---------------------------------------------------------------------------*/
22 #include <asm/uaccess.h>
24 #include "fpu_system.h"
25 #include "exception.h"
26 #include "reg_constant.h"
27 #include "control_w.h"
30 #define DOUBLE_Emax 1023 /* largest valid exponent */
31 #define DOUBLE_Ebias 1023
32 #define DOUBLE_Emin (-1022) /* smallest valid exponent */
34 #define SINGLE_Emax 127 /* largest valid exponent */
35 #define SINGLE_Ebias 127
36 #define SINGLE_Emin (-126) /* smallest valid exponent */
38 static u_char normalize_no_excep(FPU_REG *r, int exp, int sign)
42 setexponent16(r, exp);
44 tag = FPU_normalize_nuo(r);
52 int FPU_tagof(FPU_REG *ptr)
56 exp = exponent16(ptr) & 0x7fff;
58 if (!(ptr->sigh | ptr->sigl)) {
61 /* The number is a de-normal or pseudodenormal. */
66 /* Is an Infinity, a NaN, or an unsupported data type. */
70 if (!(ptr->sigh & 0x80000000)) {
71 /* Unsupported data type. */
72 /* Valid numbers have the ms bit set to 1. */
80 /* Get a long double from user memory */
81 int FPU_load_extended(long double __user *s, int stnr)
83 FPU_REG *sti_ptr = &st(stnr);
86 FPU_access_ok(VERIFY_READ, s, 10);
87 __copy_from_user(sti_ptr, s, 10);
90 return FPU_tagof(sti_ptr);
93 /* Get a double from user memory */
94 int FPU_load_double(double __user *dfloat, FPU_REG *loaded_data)
96 int exp, tag, negative;
100 FPU_access_ok(VERIFY_READ, dfloat, 8);
101 FPU_get_user(m64, 1 + (unsigned long __user *)dfloat);
102 FPU_get_user(l64, (unsigned long __user *)dfloat);
105 negative = (m64 & 0x80000000) ? SIGN_Negative : SIGN_Positive;
106 exp = ((m64 & 0x7ff00000) >> 20) - DOUBLE_Ebias + EXTENDED_Ebias;
108 if (exp > DOUBLE_Emax + EXTENDED_Ebias) {
109 /* Infinity or NaN */
110 if ((m64 == 0) && (l64 == 0)) {
112 loaded_data->sigh = 0x80000000;
113 loaded_data->sigl = 0x00000000;
114 exp = EXP_Infinity + EXTENDED_Ebias;
117 /* Must be a signaling or quiet NaN */
118 exp = EXP_NaN + EXTENDED_Ebias;
119 loaded_data->sigh = (m64 << 11) | 0x80000000;
120 loaded_data->sigh |= l64 >> 21;
121 loaded_data->sigl = l64 << 11;
122 tag = TAG_Special; /* The calling function must look for NaNs */
124 } else if (exp < DOUBLE_Emin + EXTENDED_Ebias) {
125 /* Zero or de-normal */
126 if ((m64 == 0) && (l64 == 0)) {
128 reg_copy(&CONST_Z, loaded_data);
133 loaded_data->sigh = m64 << 11;
134 loaded_data->sigh |= l64 >> 21;
135 loaded_data->sigl = l64 << 11;
137 return normalize_no_excep(loaded_data, DOUBLE_Emin,
139 | (denormal_operand() < 0 ? FPU_Exception : 0);
142 loaded_data->sigh = (m64 << 11) | 0x80000000;
143 loaded_data->sigh |= l64 >> 21;
144 loaded_data->sigl = l64 << 11;
149 setexponent16(loaded_data, exp | negative);
154 /* Get a float from user memory */
155 int FPU_load_single(float __user *single, FPU_REG *loaded_data)
158 int exp, tag, negative;
160 RE_ENTRANT_CHECK_OFF;
161 FPU_access_ok(VERIFY_READ, single, 4);
162 FPU_get_user(m32, (unsigned long __user *)single);
165 negative = (m32 & 0x80000000) ? SIGN_Negative : SIGN_Positive;
167 if (!(m32 & 0x7fffffff)) {
169 reg_copy(&CONST_Z, loaded_data);
170 addexponent(loaded_data, negative);
173 exp = ((m32 & 0x7f800000) >> 23) - SINGLE_Ebias + EXTENDED_Ebias;
174 m32 = (m32 & 0x7fffff) << 8;
175 if (exp < SINGLE_Emin + EXTENDED_Ebias) {
177 loaded_data->sigh = m32;
178 loaded_data->sigl = 0;
180 return normalize_no_excep(loaded_data, SINGLE_Emin, negative)
181 | (denormal_operand() < 0 ? FPU_Exception : 0);
182 } else if (exp > SINGLE_Emax + EXTENDED_Ebias) {
183 /* Infinity or NaN */
186 loaded_data->sigh = 0x80000000;
187 loaded_data->sigl = 0x00000000;
188 exp = EXP_Infinity + EXTENDED_Ebias;
191 /* Must be a signaling or quiet NaN */
192 exp = EXP_NaN + EXTENDED_Ebias;
193 loaded_data->sigh = m32 | 0x80000000;
194 loaded_data->sigl = 0;
195 tag = TAG_Special; /* The calling function must look for NaNs */
198 loaded_data->sigh = m32 | 0x80000000;
199 loaded_data->sigl = 0;
203 setexponent16(loaded_data, exp | negative); /* Set the sign. */
208 /* Get a long long from user memory */
209 int FPU_load_int64(long long __user *_s)
213 FPU_REG *st0_ptr = &st(0);
215 RE_ENTRANT_CHECK_OFF;
216 FPU_access_ok(VERIFY_READ, _s, 8);
217 if (copy_from_user(&s, _s, 8))
222 reg_copy(&CONST_Z, st0_ptr);
227 sign = SIGN_Positive;
230 sign = SIGN_Negative;
233 significand(st0_ptr) = s;
235 return normalize_no_excep(st0_ptr, 63, sign);
238 /* Get a long from user memory */
239 int FPU_load_int32(long __user *_s, FPU_REG *loaded_data)
244 RE_ENTRANT_CHECK_OFF;
245 FPU_access_ok(VERIFY_READ, _s, 4);
250 reg_copy(&CONST_Z, loaded_data);
255 negative = SIGN_Positive;
258 negative = SIGN_Negative;
261 loaded_data->sigh = s;
262 loaded_data->sigl = 0;
264 return normalize_no_excep(loaded_data, 31, negative);
267 /* Get a short from user memory */
268 int FPU_load_int16(short __user *_s, FPU_REG *loaded_data)
272 RE_ENTRANT_CHECK_OFF;
273 FPU_access_ok(VERIFY_READ, _s, 2);
274 /* Cast as short to get the sign extended. */
279 reg_copy(&CONST_Z, loaded_data);
284 negative = SIGN_Positive;
287 negative = SIGN_Negative;
290 loaded_data->sigh = s << 16;
291 loaded_data->sigl = 0;
293 return normalize_no_excep(loaded_data, 15, negative);
296 /* Get a packed bcd array from user memory */
297 int FPU_load_bcd(u_char __user *s)
299 FPU_REG *st0_ptr = &st(0);
305 RE_ENTRANT_CHECK_OFF;
306 FPU_access_ok(VERIFY_READ, s, 10);
308 for (pos = 8; pos >= 0; pos--) {
310 RE_ENTRANT_CHECK_OFF;
311 FPU_get_user(bcd, s + pos);
318 RE_ENTRANT_CHECK_OFF;
319 FPU_get_user(sign, s + 9);
320 sign = sign & 0x80 ? SIGN_Negative : SIGN_Positive;
324 reg_copy(&CONST_Z, st0_ptr);
325 addexponent(st0_ptr, sign); /* Set the sign. */
328 significand(st0_ptr) = l;
329 return normalize_no_excep(st0_ptr, 63, sign);
333 /*===========================================================================*/
335 /* Put a long double into user memory */
336 int FPU_store_extended(FPU_REG *st0_ptr, u_char st0_tag,
337 long double __user * d)
340 The only exception raised by an attempt to store to an
341 extended format is the Invalid Stack exception, i.e.
342 attempting to store from an empty register.
345 if (st0_tag != TAG_Empty) {
346 RE_ENTRANT_CHECK_OFF;
347 FPU_access_ok(VERIFY_WRITE, d, 10);
349 FPU_put_user(st0_ptr->sigl, (unsigned long __user *)d);
350 FPU_put_user(st0_ptr->sigh,
351 (unsigned long __user *)((u_char __user *) d + 4));
352 FPU_put_user(exponent16(st0_ptr),
353 (unsigned short __user *)((u_char __user *) d +
360 /* Empty register (stack underflow) */
361 EXCEPTION(EX_StackUnder);
362 if (control_word & CW_Invalid) {
363 /* The masked response */
364 /* Put out the QNaN indefinite */
365 RE_ENTRANT_CHECK_OFF;
366 FPU_access_ok(VERIFY_WRITE, d, 10);
367 FPU_put_user(0, (unsigned long __user *)d);
368 FPU_put_user(0xc0000000, 1 + (unsigned long __user *)d);
369 FPU_put_user(0xffff, 4 + (short __user *)d);
377 /* Put a double into user memory */
378 int FPU_store_double(FPU_REG *st0_ptr, u_char st0_tag, double __user *dfloat)
381 unsigned long increment = 0; /* avoid gcc warnings */
386 if (st0_tag == TAG_Valid) {
387 reg_copy(st0_ptr, &tmp);
388 exp = exponent(&tmp);
390 if (exp < DOUBLE_Emin) { /* It may be a denormal */
391 addexponent(&tmp, -DOUBLE_Emin + 52); /* largest exp to be 51 */
395 if ((precision_loss = FPU_round_to_int(&tmp, st0_tag))) {
397 /* Did it round to a non-denormal ? */
398 /* This behaviour might be regarded as peculiar, it appears
399 that the 80486 rounds to the dest precision, then
400 converts to decide underflow. */
402 ((tmp.sigh == 0x00100000) && (tmp.sigl == 0)
403 && (st0_ptr->sigl & 0x000007ff)))
404 #endif /* PECULIAR_486 */
406 EXCEPTION(EX_Underflow);
407 /* This is a special case: see sec 16.2.5.1 of
409 if (!(control_word & CW_Underflow))
412 EXCEPTION(precision_loss);
413 if (!(control_word & CW_Precision))
419 if (tmp.sigl & 0x000007ff) {
421 switch (control_word & CW_RC) {
423 /* Rounding can get a little messy.. */
424 increment = ((tmp.sigl & 0x7ff) > 0x400) | /* nearest */
425 ((tmp.sigl & 0xc00) == 0xc00); /* odd -> even */
427 case RC_DOWN: /* towards -infinity */
429 signpositive(&tmp) ? 0 : tmp.
432 case RC_UP: /* towards +infinity */
434 signpositive(&tmp) ? tmp.
442 /* Truncate the mantissa */
443 tmp.sigl &= 0xfffff800;
446 if (tmp.sigl >= 0xfffff800) {
447 /* the sigl part overflows */
448 if (tmp.sigh == 0xffffffff) {
449 /* The sigh part overflows */
450 tmp.sigh = 0x80000000;
457 tmp.sigl = 0x00000000;
459 /* We only need to increment sigl */
460 tmp.sigl += 0x00000800;
466 l[0] = (tmp.sigl >> 11) | (tmp.sigh << 21);
467 l[1] = ((tmp.sigh >> 11) & 0xfffff);
469 if (exp > DOUBLE_Emax) {
471 EXCEPTION(EX_Overflow);
472 if (!(control_word & CW_Overflow))
474 set_precision_flag_up();
475 if (!(control_word & CW_Precision))
478 /* This is a special case: see sec 16.2.5.1 of the 80486 book */
479 /* Overflow to infinity */
480 l[0] = 0x00000000; /* Set to */
481 l[1] = 0x7ff00000; /* + INF */
483 if (precision_loss) {
485 set_precision_flag_up();
487 set_precision_flag_down();
489 /* Add the exponent */
490 l[1] |= (((exp + DOUBLE_Ebias) & 0x7ff) << 20);
493 } else if (st0_tag == TAG_Zero) {
497 } else if (st0_tag == TAG_Special) {
498 st0_tag = FPU_Special(st0_ptr);
499 if (st0_tag == TW_Denormal) {
500 /* A denormal will always underflow. */
502 /* An 80486 is supposed to be able to generate
503 a denormal exception here, but... */
504 /* Underflow has priority. */
505 if (control_word & CW_Underflow)
507 #endif /* PECULIAR_486 */
508 reg_copy(st0_ptr, &tmp);
510 } else if (st0_tag == TW_Infinity) {
513 } else if (st0_tag == TW_NaN) {
514 /* Is it really a NaN ? */
515 if ((exponent(st0_ptr) == EXP_OVER)
516 && (st0_ptr->sigh & 0x80000000)) {
517 /* See if we can get a valid NaN from the FPU_REG */
519 (st0_ptr->sigl >> 11) | (st0_ptr->
521 l[1] = ((st0_ptr->sigh >> 11) & 0xfffff);
522 if (!(st0_ptr->sigh & 0x40000000)) {
523 /* It is a signalling NaN */
524 EXCEPTION(EX_Invalid);
525 if (!(control_word & CW_Invalid))
527 l[1] |= (0x40000000 >> 11);
531 /* It is an unsupported data type */
532 EXCEPTION(EX_Invalid);
533 if (!(control_word & CW_Invalid))
539 } else if (st0_tag == TAG_Empty) {
540 /* Empty register (stack underflow) */
541 EXCEPTION(EX_StackUnder);
542 if (control_word & CW_Invalid) {
543 /* The masked response */
544 /* Put out the QNaN indefinite */
545 RE_ENTRANT_CHECK_OFF;
546 FPU_access_ok(VERIFY_WRITE, dfloat, 8);
547 FPU_put_user(0, (unsigned long __user *)dfloat);
548 FPU_put_user(0xfff80000,
549 1 + (unsigned long __user *)dfloat);
555 if (getsign(st0_ptr))
558 RE_ENTRANT_CHECK_OFF;
559 FPU_access_ok(VERIFY_WRITE, dfloat, 8);
560 FPU_put_user(l[0], (unsigned long __user *)dfloat);
561 FPU_put_user(l[1], 1 + (unsigned long __user *)dfloat);
567 /* Put a float into user memory */
568 int FPU_store_single(FPU_REG *st0_ptr, u_char st0_tag, float __user *single)
571 unsigned long increment = 0; /* avoid gcc warnings */
576 if (st0_tag == TAG_Valid) {
578 reg_copy(st0_ptr, &tmp);
579 exp = exponent(&tmp);
581 if (exp < SINGLE_Emin) {
582 addexponent(&tmp, -SINGLE_Emin + 23); /* largest exp to be 22 */
586 if ((precision_loss = FPU_round_to_int(&tmp, st0_tag))) {
588 /* Did it round to a non-denormal ? */
589 /* This behaviour might be regarded as peculiar, it appears
590 that the 80486 rounds to the dest precision, then
591 converts to decide underflow. */
592 if (!((tmp.sigl == 0x00800000) &&
593 ((st0_ptr->sigh & 0x000000ff)
595 #endif /* PECULIAR_486 */
597 EXCEPTION(EX_Underflow);
598 /* This is a special case: see sec 16.2.5.1 of
600 if (!(control_word & CW_Underflow))
603 EXCEPTION(precision_loss);
604 if (!(control_word & CW_Precision))
609 if (tmp.sigl | (tmp.sigh & 0x000000ff)) {
610 unsigned long sigh = tmp.sigh;
611 unsigned long sigl = tmp.sigl;
614 switch (control_word & CW_RC) {
616 increment = ((sigh & 0xff) > 0x80) /* more than half */
617 ||(((sigh & 0xff) == 0x80) && sigl) /* more than half */
618 ||((sigh & 0x180) == 0x180); /* round to even */
620 case RC_DOWN: /* towards -infinity */
621 increment = signpositive(&tmp)
622 ? 0 : (sigl | (sigh & 0xff));
624 case RC_UP: /* towards +infinity */
625 increment = signpositive(&tmp)
626 ? (sigl | (sigh & 0xff)) : 0;
633 /* Truncate part of the mantissa */
637 if (sigh >= 0xffffff00) {
638 /* The sigh part overflows */
639 tmp.sigh = 0x80000000;
644 tmp.sigh &= 0xffffff00;
648 tmp.sigh &= 0xffffff00; /* Finish the truncation */
653 templ = (tmp.sigh >> 8) & 0x007fffff;
655 if (exp > SINGLE_Emax) {
657 EXCEPTION(EX_Overflow);
658 if (!(control_word & CW_Overflow))
660 set_precision_flag_up();
661 if (!(control_word & CW_Precision))
664 /* This is a special case: see sec 16.2.5.1 of the 80486 book. */
665 /* Masked response is overflow to infinity. */
668 if (precision_loss) {
670 set_precision_flag_up();
672 set_precision_flag_down();
674 /* Add the exponent */
675 templ |= ((exp + SINGLE_Ebias) & 0xff) << 23;
678 } else if (st0_tag == TAG_Zero) {
680 } else if (st0_tag == TAG_Special) {
681 st0_tag = FPU_Special(st0_ptr);
682 if (st0_tag == TW_Denormal) {
683 reg_copy(st0_ptr, &tmp);
685 /* A denormal will always underflow. */
687 /* An 80486 is supposed to be able to generate
688 a denormal exception here, but... */
689 /* Underflow has priority. */
690 if (control_word & CW_Underflow)
692 #endif /* PECULIAR_486 */
694 } else if (st0_tag == TW_Infinity) {
696 } else if (st0_tag == TW_NaN) {
697 /* Is it really a NaN ? */
698 if ((exponent(st0_ptr) == EXP_OVER)
699 && (st0_ptr->sigh & 0x80000000)) {
700 /* See if we can get a valid NaN from the FPU_REG */
701 templ = st0_ptr->sigh >> 8;
702 if (!(st0_ptr->sigh & 0x40000000)) {
703 /* It is a signalling NaN */
704 EXCEPTION(EX_Invalid);
705 if (!(control_word & CW_Invalid))
707 templ |= (0x40000000 >> 8);
711 /* It is an unsupported data type */
712 EXCEPTION(EX_Invalid);
713 if (!(control_word & CW_Invalid))
720 EXCEPTION(EX_INTERNAL | 0x164);
724 } else if (st0_tag == TAG_Empty) {
725 /* Empty register (stack underflow) */
726 EXCEPTION(EX_StackUnder);
727 if (control_word & EX_Invalid) {
728 /* The masked response */
729 /* Put out the QNaN indefinite */
730 RE_ENTRANT_CHECK_OFF;
731 FPU_access_ok(VERIFY_WRITE, single, 4);
732 FPU_put_user(0xffc00000,
733 (unsigned long __user *)single);
741 EXCEPTION(EX_INTERNAL | 0x163);
745 if (getsign(st0_ptr))
748 RE_ENTRANT_CHECK_OFF;
749 FPU_access_ok(VERIFY_WRITE, single, 4);
750 FPU_put_user(templ, (unsigned long __user *)single);
756 /* Put a long long into user memory */
757 int FPU_store_int64(FPU_REG *st0_ptr, u_char st0_tag, long long __user *d)
763 if (st0_tag == TAG_Empty) {
764 /* Empty register (stack underflow) */
765 EXCEPTION(EX_StackUnder);
766 goto invalid_operand;
767 } else if (st0_tag == TAG_Special) {
768 st0_tag = FPU_Special(st0_ptr);
769 if ((st0_tag == TW_Infinity) || (st0_tag == TW_NaN)) {
770 EXCEPTION(EX_Invalid);
771 goto invalid_operand;
775 reg_copy(st0_ptr, &t);
776 precision_loss = FPU_round_to_int(&t, st0_tag);
777 ((long *)&tll)[0] = t.sigl;
778 ((long *)&tll)[1] = t.sigh;
779 if ((precision_loss == 1) ||
780 ((t.sigh & 0x80000000) &&
781 !((t.sigh == 0x80000000) && (t.sigl == 0) && signnegative(&t)))) {
782 EXCEPTION(EX_Invalid);
783 /* This is a special case: see sec 16.2.5.1 of the 80486 book */
785 if (control_word & EX_Invalid) {
786 /* Produce something like QNaN "indefinite" */
787 tll = 0x8000000000000000LL;
792 set_precision_flag(precision_loss);
793 if (signnegative(&t))
797 RE_ENTRANT_CHECK_OFF;
798 FPU_access_ok(VERIFY_WRITE, d, 8);
799 if (copy_to_user(d, &tll, 8))
806 /* Put a long into user memory */
807 int FPU_store_int32(FPU_REG *st0_ptr, u_char st0_tag, long __user *d)
812 if (st0_tag == TAG_Empty) {
813 /* Empty register (stack underflow) */
814 EXCEPTION(EX_StackUnder);
815 goto invalid_operand;
816 } else if (st0_tag == TAG_Special) {
817 st0_tag = FPU_Special(st0_ptr);
818 if ((st0_tag == TW_Infinity) || (st0_tag == TW_NaN)) {
819 EXCEPTION(EX_Invalid);
820 goto invalid_operand;
824 reg_copy(st0_ptr, &t);
825 precision_loss = FPU_round_to_int(&t, st0_tag);
827 ((t.sigl & 0x80000000) &&
828 !((t.sigl == 0x80000000) && signnegative(&t)))) {
829 EXCEPTION(EX_Invalid);
830 /* This is a special case: see sec 16.2.5.1 of the 80486 book */
832 if (control_word & EX_Invalid) {
833 /* Produce something like QNaN "indefinite" */
839 set_precision_flag(precision_loss);
840 if (signnegative(&t))
841 t.sigl = -(long)t.sigl;
844 RE_ENTRANT_CHECK_OFF;
845 FPU_access_ok(VERIFY_WRITE, d, 4);
846 FPU_put_user(t.sigl, (unsigned long __user *)d);
852 /* Put a short into user memory */
853 int FPU_store_int16(FPU_REG *st0_ptr, u_char st0_tag, short __user *d)
858 if (st0_tag == TAG_Empty) {
859 /* Empty register (stack underflow) */
860 EXCEPTION(EX_StackUnder);
861 goto invalid_operand;
862 } else if (st0_tag == TAG_Special) {
863 st0_tag = FPU_Special(st0_ptr);
864 if ((st0_tag == TW_Infinity) || (st0_tag == TW_NaN)) {
865 EXCEPTION(EX_Invalid);
866 goto invalid_operand;
870 reg_copy(st0_ptr, &t);
871 precision_loss = FPU_round_to_int(&t, st0_tag);
873 ((t.sigl & 0xffff8000) &&
874 !((t.sigl == 0x8000) && signnegative(&t)))) {
875 EXCEPTION(EX_Invalid);
876 /* This is a special case: see sec 16.2.5.1 of the 80486 book */
878 if (control_word & EX_Invalid) {
879 /* Produce something like QNaN "indefinite" */
885 set_precision_flag(precision_loss);
886 if (signnegative(&t))
890 RE_ENTRANT_CHECK_OFF;
891 FPU_access_ok(VERIFY_WRITE, d, 2);
892 FPU_put_user((short)t.sigl, d);
898 /* Put a packed bcd array into user memory */
899 int FPU_store_bcd(FPU_REG *st0_ptr, u_char st0_tag, u_char __user *d)
902 unsigned long long ll;
904 int i, precision_loss;
905 u_char sign = (getsign(st0_ptr) == SIGN_NEG) ? 0x80 : 0;
907 if (st0_tag == TAG_Empty) {
908 /* Empty register (stack underflow) */
909 EXCEPTION(EX_StackUnder);
910 goto invalid_operand;
911 } else if (st0_tag == TAG_Special) {
912 st0_tag = FPU_Special(st0_ptr);
913 if ((st0_tag == TW_Infinity) || (st0_tag == TW_NaN)) {
914 EXCEPTION(EX_Invalid);
915 goto invalid_operand;
919 reg_copy(st0_ptr, &t);
920 precision_loss = FPU_round_to_int(&t, st0_tag);
921 ll = significand(&t);
923 /* Check for overflow, by comparing with 999999999999999999 decimal. */
924 if ((t.sigh > 0x0de0b6b3) ||
925 ((t.sigh == 0x0de0b6b3) && (t.sigl > 0xa763ffff))) {
926 EXCEPTION(EX_Invalid);
927 /* This is a special case: see sec 16.2.5.1 of the 80486 book */
929 if (control_word & CW_Invalid) {
930 /* Produce the QNaN "indefinite" */
931 RE_ENTRANT_CHECK_OFF;
932 FPU_access_ok(VERIFY_WRITE, d, 10);
933 for (i = 0; i < 7; i++)
934 FPU_put_user(0, d + i); /* These bytes "undefined" */
935 FPU_put_user(0xc0, d + 7); /* This byte "undefined" */
936 FPU_put_user(0xff, d + 8);
937 FPU_put_user(0xff, d + 9);
942 } else if (precision_loss) {
943 /* Precision loss doesn't stop the data transfer */
944 set_precision_flag(precision_loss);
947 RE_ENTRANT_CHECK_OFF;
948 FPU_access_ok(VERIFY_WRITE, d, 10);
950 for (i = 0; i < 9; i++) {
951 b = FPU_div_small(&ll, 10);
952 b |= (FPU_div_small(&ll, 10)) << 4;
953 RE_ENTRANT_CHECK_OFF;
954 FPU_put_user(b, d + i);
957 RE_ENTRANT_CHECK_OFF;
958 FPU_put_user(sign, d + 9);
964 /*===========================================================================*/
966 /* r gets mangled such that sig is int, sign:
967 it is NOT normalized */
968 /* The return value (in eax) is zero if the result is exact,
969 if bits are changed due to rounding, truncation, etc, then
970 a non-zero value is returned */
971 /* Overflow is signalled by a non-zero return value (in eax).
972 In the case of overflow, the returned significand always has the
973 largest possible value */
974 int FPU_round_to_int(FPU_REG *r, u_char tag)
979 if (tag == TAG_Zero) {
980 /* Make sure that zero is returned */
985 if (exponent(r) > 63) {
986 r->sigl = r->sigh = ~0; /* The largest representable number */
987 return 1; /* overflow */
990 eax = FPU_shrxs(&r->sigl, 63 - exponent(r));
991 very_big = !(~(r->sigh) | ~(r->sigl)); /* test for 0xfff...fff */
992 #define half_or_more (eax & 0x80000000)
993 #define frac_part (eax)
994 #define more_than_half ((eax & 0x80000001) == 0x80000001)
995 switch (control_word & CW_RC) {
997 if (more_than_half /* nearest */
998 || (half_or_more && (r->sigl & 1))) { /* odd -> even */
1000 return 1; /* overflow */
1002 return PRECISION_LOST_UP;
1006 if (frac_part && getsign(r)) {
1008 return 1; /* overflow */
1010 return PRECISION_LOST_UP;
1014 if (frac_part && !getsign(r)) {
1016 return 1; /* overflow */
1018 return PRECISION_LOST_UP;
1025 return eax ? PRECISION_LOST_DOWN : 0;
1029 /*===========================================================================*/
1031 u_char __user *fldenv(fpu_addr_modes addr_modes, u_char __user *s)
1033 unsigned short tag_word = 0;
1037 if ((addr_modes.default_mode == VM86) ||
1038 ((addr_modes.default_mode == PM16)
1039 ^ (addr_modes.override.operand_size == OP_SIZE_PREFIX))) {
1040 RE_ENTRANT_CHECK_OFF;
1041 FPU_access_ok(VERIFY_READ, s, 0x0e);
1042 FPU_get_user(control_word, (unsigned short __user *)s);
1043 FPU_get_user(partial_status, (unsigned short __user *)(s + 2));
1044 FPU_get_user(tag_word, (unsigned short __user *)(s + 4));
1045 FPU_get_user(instruction_address.offset,
1046 (unsigned short __user *)(s + 6));
1047 FPU_get_user(instruction_address.selector,
1048 (unsigned short __user *)(s + 8));
1049 FPU_get_user(operand_address.offset,
1050 (unsigned short __user *)(s + 0x0a));
1051 FPU_get_user(operand_address.selector,
1052 (unsigned short __user *)(s + 0x0c));
1053 RE_ENTRANT_CHECK_ON;
1055 if (addr_modes.default_mode == VM86) {
1056 instruction_address.offset
1057 += (instruction_address.selector & 0xf000) << 4;
1058 operand_address.offset +=
1059 (operand_address.selector & 0xf000) << 4;
1062 RE_ENTRANT_CHECK_OFF;
1063 FPU_access_ok(VERIFY_READ, s, 0x1c);
1064 FPU_get_user(control_word, (unsigned short __user *)s);
1065 FPU_get_user(partial_status, (unsigned short __user *)(s + 4));
1066 FPU_get_user(tag_word, (unsigned short __user *)(s + 8));
1067 FPU_get_user(instruction_address.offset,
1068 (unsigned long __user *)(s + 0x0c));
1069 FPU_get_user(instruction_address.selector,
1070 (unsigned short __user *)(s + 0x10));
1071 FPU_get_user(instruction_address.opcode,
1072 (unsigned short __user *)(s + 0x12));
1073 FPU_get_user(operand_address.offset,
1074 (unsigned long __user *)(s + 0x14));
1075 FPU_get_user(operand_address.selector,
1076 (unsigned long __user *)(s + 0x18));
1077 RE_ENTRANT_CHECK_ON;
1082 control_word &= ~0xe080;
1083 #endif /* PECULIAR_486 */
1085 top = (partial_status >> SW_Top_Shift) & 7;
1087 if (partial_status & ~control_word & CW_Exceptions)
1088 partial_status |= (SW_Summary | SW_Backward);
1090 partial_status &= ~(SW_Summary | SW_Backward);
1092 for (i = 0; i < 8; i++) {
1096 if (tag == TAG_Empty)
1097 /* New tag is empty. Accept it */
1098 FPU_settag(i, TAG_Empty);
1099 else if (FPU_gettag(i) == TAG_Empty) {
1100 /* Old tag is empty and new tag is not empty. New tag is determined
1101 by old reg contents */
1102 if (exponent(&fpu_register(i)) == -EXTENDED_Ebias) {
1104 (fpu_register(i).sigl | fpu_register(i).
1106 FPU_settag(i, TAG_Zero);
1108 FPU_settag(i, TAG_Special);
1109 } else if (exponent(&fpu_register(i)) ==
1110 0x7fff - EXTENDED_Ebias) {
1111 FPU_settag(i, TAG_Special);
1112 } else if (fpu_register(i).sigh & 0x80000000)
1113 FPU_settag(i, TAG_Valid);
1115 FPU_settag(i, TAG_Special); /* An Un-normal */
1117 /* Else old tag is not empty and new tag is not empty. Old tag
1124 void frstor(fpu_addr_modes addr_modes, u_char __user *data_address)
1127 u_char __user *s = fldenv(addr_modes, data_address);
1128 int offset = (top & 7) * 10, other = 80 - offset;
1130 /* Copy all registers in stack order. */
1131 RE_ENTRANT_CHECK_OFF;
1132 FPU_access_ok(VERIFY_READ, s, 80);
1133 __copy_from_user(register_base + offset, s, other);
1135 __copy_from_user(register_base, s + other, offset);
1136 RE_ENTRANT_CHECK_ON;
1138 for (i = 0; i < 8; i++) {
1139 regnr = (i + top) & 7;
1140 if (FPU_gettag(regnr) != TAG_Empty)
1141 /* The loaded data over-rides all other cases. */
1142 FPU_settag(regnr, FPU_tagof(&st(i)));
1147 u_char __user *fstenv(fpu_addr_modes addr_modes, u_char __user *d)
1149 if ((addr_modes.default_mode == VM86) ||
1150 ((addr_modes.default_mode == PM16)
1151 ^ (addr_modes.override.operand_size == OP_SIZE_PREFIX))) {
1152 RE_ENTRANT_CHECK_OFF;
1153 FPU_access_ok(VERIFY_WRITE, d, 14);
1155 FPU_put_user(control_word & ~0xe080, (unsigned long __user *)d);
1157 FPU_put_user(control_word, (unsigned short __user *)d);
1158 #endif /* PECULIAR_486 */
1159 FPU_put_user(status_word(), (unsigned short __user *)(d + 2));
1160 FPU_put_user(fpu_tag_word, (unsigned short __user *)(d + 4));
1161 FPU_put_user(instruction_address.offset,
1162 (unsigned short __user *)(d + 6));
1163 FPU_put_user(operand_address.offset,
1164 (unsigned short __user *)(d + 0x0a));
1165 if (addr_modes.default_mode == VM86) {
1166 FPU_put_user((instruction_address.
1167 offset & 0xf0000) >> 4,
1168 (unsigned short __user *)(d + 8));
1169 FPU_put_user((operand_address.offset & 0xf0000) >> 4,
1170 (unsigned short __user *)(d + 0x0c));
1172 FPU_put_user(instruction_address.selector,
1173 (unsigned short __user *)(d + 8));
1174 FPU_put_user(operand_address.selector,
1175 (unsigned short __user *)(d + 0x0c));
1177 RE_ENTRANT_CHECK_ON;
1180 RE_ENTRANT_CHECK_OFF;
1181 FPU_access_ok(VERIFY_WRITE, d, 7 * 4);
1183 control_word &= ~0xe080;
1184 /* An 80486 sets nearly all of the reserved bits to 1. */
1185 control_word |= 0xffff0040;
1186 partial_status = status_word() | 0xffff0000;
1187 fpu_tag_word |= 0xffff0000;
1188 I387.soft.fcs &= ~0xf8000000;
1189 I387.soft.fos |= 0xffff0000;
1190 #endif /* PECULIAR_486 */
1191 if (__copy_to_user(d, &control_word, 7 * 4))
1193 RE_ENTRANT_CHECK_ON;
1197 control_word |= CW_Exceptions;
1198 partial_status &= ~(SW_Summary | SW_Backward);
1203 void fsave(fpu_addr_modes addr_modes, u_char __user *data_address)
1206 int offset = (top & 7) * 10, other = 80 - offset;
1208 d = fstenv(addr_modes, data_address);
1210 RE_ENTRANT_CHECK_OFF;
1211 FPU_access_ok(VERIFY_WRITE, d, 80);
1213 /* Copy all registers in stack order. */
1214 if (__copy_to_user(d, register_base + offset, other))
1217 if (__copy_to_user(d + other, register_base, offset))
1219 RE_ENTRANT_CHECK_ON;
1224 /*===========================================================================*/