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 */
388 if (st0_tag == TAG_Valid) {
389 reg_copy(st0_ptr, &tmp);
390 exp = exponent(&tmp);
392 if (exp < DOUBLE_Emin) { /* It may be a denormal */
393 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[1] = 0x7ff00000; /* Set to + INF */
482 if (precision_loss) {
484 set_precision_flag_up();
486 set_precision_flag_down();
488 /* Add the exponent */
489 l[1] |= (((exp + DOUBLE_Ebias) & 0x7ff) << 20);
492 } else if (st0_tag == TAG_Zero) {
494 } else if (st0_tag == TAG_Special) {
495 st0_tag = FPU_Special(st0_ptr);
496 if (st0_tag == TW_Denormal) {
497 /* A denormal will always underflow. */
499 /* An 80486 is supposed to be able to generate
500 a denormal exception here, but... */
501 /* Underflow has priority. */
502 if (control_word & CW_Underflow)
504 #endif /* PECULIAR_486 */
505 reg_copy(st0_ptr, &tmp);
507 } else if (st0_tag == TW_Infinity) {
509 } else if (st0_tag == TW_NaN) {
510 /* Is it really a NaN ? */
511 if ((exponent(st0_ptr) == EXP_OVER)
512 && (st0_ptr->sigh & 0x80000000)) {
513 /* See if we can get a valid NaN from the FPU_REG */
515 (st0_ptr->sigl >> 11) | (st0_ptr->
517 l[1] = ((st0_ptr->sigh >> 11) & 0xfffff);
518 if (!(st0_ptr->sigh & 0x40000000)) {
519 /* It is a signalling NaN */
520 EXCEPTION(EX_Invalid);
521 if (!(control_word & CW_Invalid))
523 l[1] |= (0x40000000 >> 11);
527 /* It is an unsupported data type */
528 EXCEPTION(EX_Invalid);
529 if (!(control_word & CW_Invalid))
534 } else if (st0_tag == TAG_Empty) {
535 /* Empty register (stack underflow) */
536 EXCEPTION(EX_StackUnder);
537 if (control_word & CW_Invalid) {
538 /* The masked response */
539 /* Put out the QNaN indefinite */
540 RE_ENTRANT_CHECK_OFF;
541 FPU_access_ok(VERIFY_WRITE, dfloat, 8);
542 FPU_put_user(0, (unsigned long __user *)dfloat);
543 FPU_put_user(0xfff80000,
544 1 + (unsigned long __user *)dfloat);
550 if (getsign(st0_ptr))
553 RE_ENTRANT_CHECK_OFF;
554 FPU_access_ok(VERIFY_WRITE, dfloat, 8);
555 FPU_put_user(l[0], (unsigned long __user *)dfloat);
556 FPU_put_user(l[1], 1 + (unsigned long __user *)dfloat);
562 /* Put a float into user memory */
563 int FPU_store_single(FPU_REG *st0_ptr, u_char st0_tag, float __user *single)
566 unsigned long increment = 0; /* avoid gcc warnings */
571 if (st0_tag == TAG_Valid) {
573 reg_copy(st0_ptr, &tmp);
574 exp = exponent(&tmp);
576 if (exp < SINGLE_Emin) {
577 addexponent(&tmp, -SINGLE_Emin + 23); /* largest exp to be 22 */
581 if ((precision_loss = FPU_round_to_int(&tmp, st0_tag))) {
583 /* Did it round to a non-denormal ? */
584 /* This behaviour might be regarded as peculiar, it appears
585 that the 80486 rounds to the dest precision, then
586 converts to decide underflow. */
587 if (!((tmp.sigl == 0x00800000) &&
588 ((st0_ptr->sigh & 0x000000ff)
590 #endif /* PECULIAR_486 */
592 EXCEPTION(EX_Underflow);
593 /* This is a special case: see sec 16.2.5.1 of
595 if (!(control_word & CW_Underflow))
598 EXCEPTION(precision_loss);
599 if (!(control_word & CW_Precision))
604 if (tmp.sigl | (tmp.sigh & 0x000000ff)) {
605 unsigned long sigh = tmp.sigh;
606 unsigned long sigl = tmp.sigl;
609 switch (control_word & CW_RC) {
611 increment = ((sigh & 0xff) > 0x80) /* more than half */
612 ||(((sigh & 0xff) == 0x80) && sigl) /* more than half */
613 ||((sigh & 0x180) == 0x180); /* round to even */
615 case RC_DOWN: /* towards -infinity */
616 increment = signpositive(&tmp)
617 ? 0 : (sigl | (sigh & 0xff));
619 case RC_UP: /* towards +infinity */
620 increment = signpositive(&tmp)
621 ? (sigl | (sigh & 0xff)) : 0;
628 /* Truncate part of the mantissa */
632 if (sigh >= 0xffffff00) {
633 /* The sigh part overflows */
634 tmp.sigh = 0x80000000;
639 tmp.sigh &= 0xffffff00;
643 tmp.sigh &= 0xffffff00; /* Finish the truncation */
648 templ = (tmp.sigh >> 8) & 0x007fffff;
650 if (exp > SINGLE_Emax) {
652 EXCEPTION(EX_Overflow);
653 if (!(control_word & CW_Overflow))
655 set_precision_flag_up();
656 if (!(control_word & CW_Precision))
659 /* This is a special case: see sec 16.2.5.1 of the 80486 book. */
660 /* Masked response is overflow to infinity. */
663 if (precision_loss) {
665 set_precision_flag_up();
667 set_precision_flag_down();
669 /* Add the exponent */
670 templ |= ((exp + SINGLE_Ebias) & 0xff) << 23;
673 } else if (st0_tag == TAG_Zero) {
675 } else if (st0_tag == TAG_Special) {
676 st0_tag = FPU_Special(st0_ptr);
677 if (st0_tag == TW_Denormal) {
678 reg_copy(st0_ptr, &tmp);
680 /* A denormal will always underflow. */
682 /* An 80486 is supposed to be able to generate
683 a denormal exception here, but... */
684 /* Underflow has priority. */
685 if (control_word & CW_Underflow)
687 #endif /* PECULIAR_486 */
689 } else if (st0_tag == TW_Infinity) {
691 } else if (st0_tag == TW_NaN) {
692 /* Is it really a NaN ? */
693 if ((exponent(st0_ptr) == EXP_OVER)
694 && (st0_ptr->sigh & 0x80000000)) {
695 /* See if we can get a valid NaN from the FPU_REG */
696 templ = st0_ptr->sigh >> 8;
697 if (!(st0_ptr->sigh & 0x40000000)) {
698 /* It is a signalling NaN */
699 EXCEPTION(EX_Invalid);
700 if (!(control_word & CW_Invalid))
702 templ |= (0x40000000 >> 8);
706 /* It is an unsupported data type */
707 EXCEPTION(EX_Invalid);
708 if (!(control_word & CW_Invalid))
715 EXCEPTION(EX_INTERNAL | 0x164);
719 } else if (st0_tag == TAG_Empty) {
720 /* Empty register (stack underflow) */
721 EXCEPTION(EX_StackUnder);
722 if (control_word & EX_Invalid) {
723 /* The masked response */
724 /* Put out the QNaN indefinite */
725 RE_ENTRANT_CHECK_OFF;
726 FPU_access_ok(VERIFY_WRITE, single, 4);
727 FPU_put_user(0xffc00000,
728 (unsigned long __user *)single);
736 EXCEPTION(EX_INTERNAL | 0x163);
740 if (getsign(st0_ptr))
743 RE_ENTRANT_CHECK_OFF;
744 FPU_access_ok(VERIFY_WRITE, single, 4);
745 FPU_put_user(templ, (unsigned long __user *)single);
751 /* Put a long long into user memory */
752 int FPU_store_int64(FPU_REG *st0_ptr, u_char st0_tag, long long __user *d)
758 if (st0_tag == TAG_Empty) {
759 /* Empty register (stack underflow) */
760 EXCEPTION(EX_StackUnder);
761 goto invalid_operand;
762 } else if (st0_tag == TAG_Special) {
763 st0_tag = FPU_Special(st0_ptr);
764 if ((st0_tag == TW_Infinity) || (st0_tag == TW_NaN)) {
765 EXCEPTION(EX_Invalid);
766 goto invalid_operand;
770 reg_copy(st0_ptr, &t);
771 precision_loss = FPU_round_to_int(&t, st0_tag);
772 ((long *)&tll)[0] = t.sigl;
773 ((long *)&tll)[1] = t.sigh;
774 if ((precision_loss == 1) ||
775 ((t.sigh & 0x80000000) &&
776 !((t.sigh == 0x80000000) && (t.sigl == 0) && signnegative(&t)))) {
777 EXCEPTION(EX_Invalid);
778 /* This is a special case: see sec 16.2.5.1 of the 80486 book */
780 if (control_word & EX_Invalid) {
781 /* Produce something like QNaN "indefinite" */
782 tll = 0x8000000000000000LL;
787 set_precision_flag(precision_loss);
788 if (signnegative(&t))
792 RE_ENTRANT_CHECK_OFF;
793 FPU_access_ok(VERIFY_WRITE, d, 8);
794 if (copy_to_user(d, &tll, 8))
801 /* Put a long into user memory */
802 int FPU_store_int32(FPU_REG *st0_ptr, u_char st0_tag, long __user *d)
807 if (st0_tag == TAG_Empty) {
808 /* Empty register (stack underflow) */
809 EXCEPTION(EX_StackUnder);
810 goto invalid_operand;
811 } else if (st0_tag == TAG_Special) {
812 st0_tag = FPU_Special(st0_ptr);
813 if ((st0_tag == TW_Infinity) || (st0_tag == TW_NaN)) {
814 EXCEPTION(EX_Invalid);
815 goto invalid_operand;
819 reg_copy(st0_ptr, &t);
820 precision_loss = FPU_round_to_int(&t, st0_tag);
822 ((t.sigl & 0x80000000) &&
823 !((t.sigl == 0x80000000) && signnegative(&t)))) {
824 EXCEPTION(EX_Invalid);
825 /* This is a special case: see sec 16.2.5.1 of the 80486 book */
827 if (control_word & EX_Invalid) {
828 /* Produce something like QNaN "indefinite" */
834 set_precision_flag(precision_loss);
835 if (signnegative(&t))
836 t.sigl = -(long)t.sigl;
839 RE_ENTRANT_CHECK_OFF;
840 FPU_access_ok(VERIFY_WRITE, d, 4);
841 FPU_put_user(t.sigl, (unsigned long __user *)d);
847 /* Put a short into user memory */
848 int FPU_store_int16(FPU_REG *st0_ptr, u_char st0_tag, short __user *d)
853 if (st0_tag == TAG_Empty) {
854 /* Empty register (stack underflow) */
855 EXCEPTION(EX_StackUnder);
856 goto invalid_operand;
857 } else if (st0_tag == TAG_Special) {
858 st0_tag = FPU_Special(st0_ptr);
859 if ((st0_tag == TW_Infinity) || (st0_tag == TW_NaN)) {
860 EXCEPTION(EX_Invalid);
861 goto invalid_operand;
865 reg_copy(st0_ptr, &t);
866 precision_loss = FPU_round_to_int(&t, st0_tag);
868 ((t.sigl & 0xffff8000) &&
869 !((t.sigl == 0x8000) && signnegative(&t)))) {
870 EXCEPTION(EX_Invalid);
871 /* This is a special case: see sec 16.2.5.1 of the 80486 book */
873 if (control_word & EX_Invalid) {
874 /* Produce something like QNaN "indefinite" */
880 set_precision_flag(precision_loss);
881 if (signnegative(&t))
885 RE_ENTRANT_CHECK_OFF;
886 FPU_access_ok(VERIFY_WRITE, d, 2);
887 FPU_put_user((short)t.sigl, d);
893 /* Put a packed bcd array into user memory */
894 int FPU_store_bcd(FPU_REG *st0_ptr, u_char st0_tag, u_char __user *d)
897 unsigned long long ll;
899 int i, precision_loss;
900 u_char sign = (getsign(st0_ptr) == SIGN_NEG) ? 0x80 : 0;
902 if (st0_tag == TAG_Empty) {
903 /* Empty register (stack underflow) */
904 EXCEPTION(EX_StackUnder);
905 goto invalid_operand;
906 } else if (st0_tag == TAG_Special) {
907 st0_tag = FPU_Special(st0_ptr);
908 if ((st0_tag == TW_Infinity) || (st0_tag == TW_NaN)) {
909 EXCEPTION(EX_Invalid);
910 goto invalid_operand;
914 reg_copy(st0_ptr, &t);
915 precision_loss = FPU_round_to_int(&t, st0_tag);
916 ll = significand(&t);
918 /* Check for overflow, by comparing with 999999999999999999 decimal. */
919 if ((t.sigh > 0x0de0b6b3) ||
920 ((t.sigh == 0x0de0b6b3) && (t.sigl > 0xa763ffff))) {
921 EXCEPTION(EX_Invalid);
922 /* This is a special case: see sec 16.2.5.1 of the 80486 book */
924 if (control_word & CW_Invalid) {
925 /* Produce the QNaN "indefinite" */
926 RE_ENTRANT_CHECK_OFF;
927 FPU_access_ok(VERIFY_WRITE, d, 10);
928 for (i = 0; i < 7; i++)
929 FPU_put_user(0, d + i); /* These bytes "undefined" */
930 FPU_put_user(0xc0, d + 7); /* This byte "undefined" */
931 FPU_put_user(0xff, d + 8);
932 FPU_put_user(0xff, d + 9);
937 } else if (precision_loss) {
938 /* Precision loss doesn't stop the data transfer */
939 set_precision_flag(precision_loss);
942 RE_ENTRANT_CHECK_OFF;
943 FPU_access_ok(VERIFY_WRITE, d, 10);
945 for (i = 0; i < 9; i++) {
946 b = FPU_div_small(&ll, 10);
947 b |= (FPU_div_small(&ll, 10)) << 4;
948 RE_ENTRANT_CHECK_OFF;
949 FPU_put_user(b, d + i);
952 RE_ENTRANT_CHECK_OFF;
953 FPU_put_user(sign, d + 9);
959 /*===========================================================================*/
961 /* r gets mangled such that sig is int, sign:
962 it is NOT normalized */
963 /* The return value (in eax) is zero if the result is exact,
964 if bits are changed due to rounding, truncation, etc, then
965 a non-zero value is returned */
966 /* Overflow is signalled by a non-zero return value (in eax).
967 In the case of overflow, the returned significand always has the
968 largest possible value */
969 int FPU_round_to_int(FPU_REG *r, u_char tag)
974 if (tag == TAG_Zero) {
975 /* Make sure that zero is returned */
980 if (exponent(r) > 63) {
981 r->sigl = r->sigh = ~0; /* The largest representable number */
982 return 1; /* overflow */
985 eax = FPU_shrxs(&r->sigl, 63 - exponent(r));
986 very_big = !(~(r->sigh) | ~(r->sigl)); /* test for 0xfff...fff */
987 #define half_or_more (eax & 0x80000000)
988 #define frac_part (eax)
989 #define more_than_half ((eax & 0x80000001) == 0x80000001)
990 switch (control_word & CW_RC) {
992 if (more_than_half /* nearest */
993 || (half_or_more && (r->sigl & 1))) { /* odd -> even */
995 return 1; /* overflow */
997 return PRECISION_LOST_UP;
1001 if (frac_part && getsign(r)) {
1003 return 1; /* overflow */
1005 return PRECISION_LOST_UP;
1009 if (frac_part && !getsign(r)) {
1011 return 1; /* overflow */
1013 return PRECISION_LOST_UP;
1020 return eax ? PRECISION_LOST_DOWN : 0;
1024 /*===========================================================================*/
1026 u_char __user *fldenv(fpu_addr_modes addr_modes, u_char __user *s)
1028 unsigned short tag_word = 0;
1032 if ((addr_modes.default_mode == VM86) ||
1033 ((addr_modes.default_mode == PM16)
1034 ^ (addr_modes.override.operand_size == OP_SIZE_PREFIX))) {
1035 RE_ENTRANT_CHECK_OFF;
1036 FPU_access_ok(VERIFY_READ, s, 0x0e);
1037 FPU_get_user(control_word, (unsigned short __user *)s);
1038 FPU_get_user(partial_status, (unsigned short __user *)(s + 2));
1039 FPU_get_user(tag_word, (unsigned short __user *)(s + 4));
1040 FPU_get_user(instruction_address.offset,
1041 (unsigned short __user *)(s + 6));
1042 FPU_get_user(instruction_address.selector,
1043 (unsigned short __user *)(s + 8));
1044 FPU_get_user(operand_address.offset,
1045 (unsigned short __user *)(s + 0x0a));
1046 FPU_get_user(operand_address.selector,
1047 (unsigned short __user *)(s + 0x0c));
1048 RE_ENTRANT_CHECK_ON;
1050 if (addr_modes.default_mode == VM86) {
1051 instruction_address.offset
1052 += (instruction_address.selector & 0xf000) << 4;
1053 operand_address.offset +=
1054 (operand_address.selector & 0xf000) << 4;
1057 RE_ENTRANT_CHECK_OFF;
1058 FPU_access_ok(VERIFY_READ, s, 0x1c);
1059 FPU_get_user(control_word, (unsigned short __user *)s);
1060 FPU_get_user(partial_status, (unsigned short __user *)(s + 4));
1061 FPU_get_user(tag_word, (unsigned short __user *)(s + 8));
1062 FPU_get_user(instruction_address.offset,
1063 (unsigned long __user *)(s + 0x0c));
1064 FPU_get_user(instruction_address.selector,
1065 (unsigned short __user *)(s + 0x10));
1066 FPU_get_user(instruction_address.opcode,
1067 (unsigned short __user *)(s + 0x12));
1068 FPU_get_user(operand_address.offset,
1069 (unsigned long __user *)(s + 0x14));
1070 FPU_get_user(operand_address.selector,
1071 (unsigned long __user *)(s + 0x18));
1072 RE_ENTRANT_CHECK_ON;
1077 control_word &= ~0xe080;
1078 #endif /* PECULIAR_486 */
1080 top = (partial_status >> SW_Top_Shift) & 7;
1082 if (partial_status & ~control_word & CW_Exceptions)
1083 partial_status |= (SW_Summary | SW_Backward);
1085 partial_status &= ~(SW_Summary | SW_Backward);
1087 for (i = 0; i < 8; i++) {
1091 if (tag == TAG_Empty)
1092 /* New tag is empty. Accept it */
1093 FPU_settag(i, TAG_Empty);
1094 else if (FPU_gettag(i) == TAG_Empty) {
1095 /* Old tag is empty and new tag is not empty. New tag is determined
1096 by old reg contents */
1097 if (exponent(&fpu_register(i)) == -EXTENDED_Ebias) {
1099 (fpu_register(i).sigl | fpu_register(i).
1101 FPU_settag(i, TAG_Zero);
1103 FPU_settag(i, TAG_Special);
1104 } else if (exponent(&fpu_register(i)) ==
1105 0x7fff - EXTENDED_Ebias) {
1106 FPU_settag(i, TAG_Special);
1107 } else if (fpu_register(i).sigh & 0x80000000)
1108 FPU_settag(i, TAG_Valid);
1110 FPU_settag(i, TAG_Special); /* An Un-normal */
1112 /* Else old tag is not empty and new tag is not empty. Old tag
1119 void frstor(fpu_addr_modes addr_modes, u_char __user *data_address)
1122 u_char __user *s = fldenv(addr_modes, data_address);
1123 int offset = (top & 7) * 10, other = 80 - offset;
1125 /* Copy all registers in stack order. */
1126 RE_ENTRANT_CHECK_OFF;
1127 FPU_access_ok(VERIFY_READ, s, 80);
1128 __copy_from_user(register_base + offset, s, other);
1130 __copy_from_user(register_base, s + other, offset);
1131 RE_ENTRANT_CHECK_ON;
1133 for (i = 0; i < 8; i++) {
1134 regnr = (i + top) & 7;
1135 if (FPU_gettag(regnr) != TAG_Empty)
1136 /* The loaded data over-rides all other cases. */
1137 FPU_settag(regnr, FPU_tagof(&st(i)));
1142 u_char __user *fstenv(fpu_addr_modes addr_modes, u_char __user *d)
1144 if ((addr_modes.default_mode == VM86) ||
1145 ((addr_modes.default_mode == PM16)
1146 ^ (addr_modes.override.operand_size == OP_SIZE_PREFIX))) {
1147 RE_ENTRANT_CHECK_OFF;
1148 FPU_access_ok(VERIFY_WRITE, d, 14);
1150 FPU_put_user(control_word & ~0xe080, (unsigned long __user *)d);
1152 FPU_put_user(control_word, (unsigned short __user *)d);
1153 #endif /* PECULIAR_486 */
1154 FPU_put_user(status_word(), (unsigned short __user *)(d + 2));
1155 FPU_put_user(fpu_tag_word, (unsigned short __user *)(d + 4));
1156 FPU_put_user(instruction_address.offset,
1157 (unsigned short __user *)(d + 6));
1158 FPU_put_user(operand_address.offset,
1159 (unsigned short __user *)(d + 0x0a));
1160 if (addr_modes.default_mode == VM86) {
1161 FPU_put_user((instruction_address.
1162 offset & 0xf0000) >> 4,
1163 (unsigned short __user *)(d + 8));
1164 FPU_put_user((operand_address.offset & 0xf0000) >> 4,
1165 (unsigned short __user *)(d + 0x0c));
1167 FPU_put_user(instruction_address.selector,
1168 (unsigned short __user *)(d + 8));
1169 FPU_put_user(operand_address.selector,
1170 (unsigned short __user *)(d + 0x0c));
1172 RE_ENTRANT_CHECK_ON;
1175 RE_ENTRANT_CHECK_OFF;
1176 FPU_access_ok(VERIFY_WRITE, d, 7 * 4);
1178 control_word &= ~0xe080;
1179 /* An 80486 sets nearly all of the reserved bits to 1. */
1180 control_word |= 0xffff0040;
1181 partial_status = status_word() | 0xffff0000;
1182 fpu_tag_word |= 0xffff0000;
1183 I387->soft.fcs &= ~0xf8000000;
1184 I387->soft.fos |= 0xffff0000;
1185 #endif /* PECULIAR_486 */
1186 if (__copy_to_user(d, &control_word, 7 * 4))
1188 RE_ENTRANT_CHECK_ON;
1192 control_word |= CW_Exceptions;
1193 partial_status &= ~(SW_Summary | SW_Backward);
1198 void fsave(fpu_addr_modes addr_modes, u_char __user *data_address)
1201 int offset = (top & 7) * 10, other = 80 - offset;
1203 d = fstenv(addr_modes, data_address);
1205 RE_ENTRANT_CHECK_OFF;
1206 FPU_access_ok(VERIFY_WRITE, d, 80);
1208 /* Copy all registers in stack order. */
1209 if (__copy_to_user(d, register_base + offset, other))
1212 if (__copy_to_user(d + other, register_base, offset))
1214 RE_ENTRANT_CHECK_ON;
1219 /*===========================================================================*/