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"
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
)
44 setexponent16(r
, exp
);
46 tag
= FPU_normalize_nuo(r
);
55 int FPU_tagof(FPU_REG
*ptr
)
59 exp
= exponent16(ptr
) & 0x7fff;
62 if ( !(ptr
->sigh
| ptr
->sigl
) )
66 /* The number is a de-normal or pseudodenormal. */
72 /* Is an Infinity, a NaN, or an unsupported data type. */
76 if ( !(ptr
->sigh
& 0x80000000) )
78 /* Unsupported data type. */
79 /* Valid numbers have the ms bit set to 1. */
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
);
94 FPU_access_ok(VERIFY_READ
, s
, 10);
95 __copy_from_user(sti_ptr
, s
, 10);
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
;
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
);
114 negative
= (m64
& 0x80000000) ? SIGN_Negative
: SIGN_Positive
;
115 exp
= ((m64
& 0x7ff00000) >> 20) - DOUBLE_Ebias
+ EXTENDED_Ebias
;
117 if ( exp
> DOUBLE_Emax
+ EXTENDED_Ebias
)
119 /* Infinity or NaN */
120 if ((m64
== 0) && (l64
== 0))
123 loaded_data
->sigh
= 0x80000000;
124 loaded_data
->sigl
= 0x00000000;
125 exp
= EXP_Infinity
+ EXTENDED_Ebias
;
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))
144 reg_copy(&CONST_Z
, loaded_data
);
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);
161 loaded_data
->sigh
= (m64
<< 11) | 0x80000000;
162 loaded_data
->sigh
|= l64
>> 21;
163 loaded_data
->sigl
= l64
<< 11;
168 setexponent16(loaded_data
, exp
| negative
);
174 /* Get a float from user memory */
175 int FPU_load_single(float __user
*single
, FPU_REG
*loaded_data
)
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
);
185 negative
= (m32
& 0x80000000) ? SIGN_Negative
: SIGN_Positive
;
187 if (!(m32
& 0x7fffffff))
190 reg_copy(&CONST_Z
, loaded_data
);
191 addexponent(loaded_data
, negative
);
194 exp
= ((m32
& 0x7f800000) >> 23) - SINGLE_Ebias
+ EXTENDED_Ebias
;
195 m32
= (m32
& 0x7fffff) << 8;
196 if ( exp
< SINGLE_Emin
+ EXTENDED_Ebias
)
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 */
211 loaded_data
->sigh
= 0x80000000;
212 loaded_data
->sigl
= 0x00000000;
213 exp
= EXP_Infinity
+ EXTENDED_Ebias
;
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 */
227 loaded_data
->sigh
= m32
| 0x80000000;
228 loaded_data
->sigl
= 0;
232 setexponent16(loaded_data
, exp
| negative
); /* Set the sign. */
238 /* Get a long long from user memory */
239 int FPU_load_int64(long long __user
*_s
)
243 FPU_REG
*st0_ptr
= &st(0);
245 RE_ENTRANT_CHECK_OFF
;
246 FPU_access_ok(VERIFY_READ
, _s
, 8);
247 if (copy_from_user(&s
,_s
,8))
253 reg_copy(&CONST_Z
, st0_ptr
);
258 sign
= SIGN_Positive
;
262 sign
= SIGN_Negative
;
265 significand(st0_ptr
) = s
;
267 return normalize_no_excep(st0_ptr
, 63, sign
);
271 /* Get a long from user memory */
272 int FPU_load_int32(long __user
*_s
, FPU_REG
*loaded_data
)
277 RE_ENTRANT_CHECK_OFF
;
278 FPU_access_ok(VERIFY_READ
, _s
, 4);
283 { reg_copy(&CONST_Z
, loaded_data
); return TAG_Zero
; }
286 negative
= SIGN_Positive
;
290 negative
= SIGN_Negative
;
293 loaded_data
->sigh
= s
;
294 loaded_data
->sigl
= 0;
296 return normalize_no_excep(loaded_data
, 31, negative
);
300 /* Get a short from user memory */
301 int FPU_load_int16(short __user
*_s
, FPU_REG
*loaded_data
)
305 RE_ENTRANT_CHECK_OFF
;
306 FPU_access_ok(VERIFY_READ
, _s
, 2);
307 /* Cast as short to get the sign extended. */
312 { reg_copy(&CONST_Z
, loaded_data
); return TAG_Zero
; }
315 negative
= SIGN_Positive
;
319 negative
= SIGN_Negative
;
322 loaded_data
->sigh
= s
<< 16;
323 loaded_data
->sigl
= 0;
325 return normalize_no_excep(loaded_data
, 15, negative
);
329 /* Get a packed bcd array from user memory */
330 int FPU_load_bcd(u_char __user
*s
)
332 FPU_REG
*st0_ptr
= &st(0);
338 RE_ENTRANT_CHECK_OFF
;
339 FPU_access_ok(VERIFY_READ
, s
, 10);
341 for ( pos
= 8; pos
>= 0; pos
--)
344 RE_ENTRANT_CHECK_OFF
;
345 FPU_get_user(bcd
, s
+pos
);
352 RE_ENTRANT_CHECK_OFF
;
353 FPU_get_user(sign
, s
+9);
354 sign
= sign
& 0x80 ? SIGN_Negative
: SIGN_Positive
;
359 reg_copy(&CONST_Z
, st0_ptr
);
360 addexponent(st0_ptr
, sign
); /* Set the sign. */
365 significand(st0_ptr
) = l
;
366 return normalize_no_excep(st0_ptr
, 63, sign
);
370 /*===========================================================================*/
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
)
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.
381 if ( st0_tag
!= TAG_Empty
)
383 RE_ENTRANT_CHECK_OFF
;
384 FPU_access_ok(VERIFY_WRITE
, d
, 10);
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));
394 /* Empty register (stack underflow) */
395 EXCEPTION(EX_StackUnder
);
396 if ( control_word
& CW_Invalid
)
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
);
414 /* Put a double into user memory */
415 int FPU_store_double(FPU_REG
*st0_ptr
, u_char st0_tag
, double __user
*dfloat
)
418 unsigned long increment
= 0; /* avoid gcc warnings */
423 if ( st0_tag
== TAG_Valid
)
425 reg_copy(st0_ptr
, &tmp
);
426 exp
= exponent(&tmp
);
428 if ( exp
< DOUBLE_Emin
) /* It may be a denormal */
430 addexponent(&tmp
, -DOUBLE_Emin
+ 52); /* largest exp to be 51 */
434 if ( (precision_loss
= FPU_round_to_int(&tmp
, st0_tag
)) )
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 */
445 EXCEPTION(EX_Underflow
);
446 /* This is a special case: see sec 16.2.5.1 of
448 if ( !(control_word
& CW_Underflow
) )
451 EXCEPTION(precision_loss
);
452 if ( !(control_word
& CW_Precision
) )
460 if ( tmp
.sigl
& 0x000007ff )
463 switch (control_word
& CW_RC
)
466 /* Rounding can get a little messy.. */
467 increment
= ((tmp
.sigl
& 0x7ff) > 0x400) | /* nearest */
468 ((tmp
.sigl
& 0xc00) == 0xc00); /* odd -> even */
470 case RC_DOWN
: /* towards -infinity */
471 increment
= signpositive(&tmp
) ? 0 : tmp
.sigl
& 0x7ff;
473 case RC_UP
: /* towards +infinity */
474 increment
= signpositive(&tmp
) ? tmp
.sigl
& 0x7ff : 0;
481 /* Truncate the mantissa */
482 tmp
.sigl
&= 0xfffff800;
486 if ( tmp
.sigl
>= 0xfffff800 )
488 /* the sigl part overflows */
489 if ( tmp
.sigh
== 0xffffffff )
491 /* The sigh part overflows */
492 tmp
.sigh
= 0x80000000;
501 tmp
.sigl
= 0x00000000;
505 /* We only need to increment sigl */
506 tmp
.sigl
+= 0x00000800;
513 l
[0] = (tmp
.sigl
>> 11) | (tmp
.sigh
<< 21);
514 l
[1] = ((tmp
.sigh
>> 11) & 0xfffff);
516 if ( exp
> DOUBLE_Emax
)
519 EXCEPTION(EX_Overflow
);
520 if ( !(control_word
& CW_Overflow
) )
522 set_precision_flag_up();
523 if ( !(control_word
& CW_Precision
) )
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 */
533 if ( precision_loss
)
536 set_precision_flag_up();
538 set_precision_flag_down();
540 /* Add the exponent */
541 l
[1] |= (((exp
+DOUBLE_Ebias
) & 0x7ff) << 20);
545 else if (st0_tag
== TAG_Zero
)
551 else if ( st0_tag
== TAG_Special
)
553 st0_tag
= FPU_Special(st0_ptr
);
554 if ( st0_tag
== TW_Denormal
)
556 /* A denormal will always underflow. */
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
)
563 #endif /* PECULIAR_486 */
564 reg_copy(st0_ptr
, &tmp
);
567 else if (st0_tag
== TW_Infinity
)
572 else if (st0_tag
== TW_NaN
)
574 /* Is it really a NaN ? */
575 if ( (exponent(st0_ptr
) == EXP_OVER
)
576 && (st0_ptr
->sigh
& 0x80000000) )
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) )
583 /* It is a signalling NaN */
584 EXCEPTION(EX_Invalid
);
585 if ( !(control_word
& CW_Invalid
) )
587 l
[1] |= (0x40000000 >> 11);
593 /* It is an unsupported data type */
594 EXCEPTION(EX_Invalid
);
595 if ( !(control_word
& CW_Invalid
) )
602 else if ( st0_tag
== TAG_Empty
)
604 /* Empty register (stack underflow) */
605 EXCEPTION(EX_StackUnder
);
606 if ( control_word
& CW_Invalid
)
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
);
620 if ( getsign(st0_ptr
) )
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
);
633 /* Put a float into user memory */
634 int FPU_store_single(FPU_REG
*st0_ptr
, u_char st0_tag
, float __user
*single
)
637 unsigned long increment
= 0; /* avoid gcc warnings */
642 if ( st0_tag
== TAG_Valid
)
645 reg_copy(st0_ptr
, &tmp
);
646 exp
= exponent(&tmp
);
648 if ( exp
< SINGLE_Emin
)
650 addexponent(&tmp
, -SINGLE_Emin
+ 23); /* largest exp to be 22 */
654 if ( (precision_loss
= FPU_round_to_int(&tmp
, st0_tag
)) )
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 */
665 EXCEPTION(EX_Underflow
);
666 /* This is a special case: see sec 16.2.5.1 of
668 if ( !(control_word
& CW_Underflow
) )
671 EXCEPTION(precision_loss
);
672 if ( !(control_word
& CW_Precision
) )
679 if ( tmp
.sigl
| (tmp
.sigh
& 0x000000ff) )
681 unsigned long sigh
= tmp
.sigh
;
682 unsigned long sigl
= tmp
.sigl
;
685 switch (control_word
& CW_RC
)
688 increment
= ((sigh
& 0xff) > 0x80) /* more than half */
689 || (((sigh
& 0xff) == 0x80) && sigl
) /* more than half */
690 || ((sigh
& 0x180) == 0x180); /* round to even */
692 case RC_DOWN
: /* towards -infinity */
693 increment
= signpositive(&tmp
)
694 ? 0 : (sigl
| (sigh
& 0xff));
696 case RC_UP
: /* towards +infinity */
697 increment
= signpositive(&tmp
)
698 ? (sigl
| (sigh
& 0xff)) : 0;
705 /* Truncate part of the mantissa */
710 if ( sigh
>= 0xffffff00 )
712 /* The sigh part overflows */
713 tmp
.sigh
= 0x80000000;
715 if ( exp
>= EXP_OVER
)
720 tmp
.sigh
&= 0xffffff00;
726 tmp
.sigh
&= 0xffffff00; /* Finish the truncation */
732 templ
= (tmp
.sigh
>> 8) & 0x007fffff;
734 if ( exp
> SINGLE_Emax
)
737 EXCEPTION(EX_Overflow
);
738 if ( !(control_word
& CW_Overflow
) )
740 set_precision_flag_up();
741 if ( !(control_word
& CW_Precision
) )
744 /* This is a special case: see sec 16.2.5.1 of the 80486 book. */
745 /* Masked response is overflow to infinity. */
750 if ( precision_loss
)
753 set_precision_flag_up();
755 set_precision_flag_down();
757 /* Add the exponent */
758 templ
|= ((exp
+SINGLE_Ebias
) & 0xff) << 23;
762 else if (st0_tag
== TAG_Zero
)
766 else if ( st0_tag
== TAG_Special
)
768 st0_tag
= FPU_Special(st0_ptr
);
769 if (st0_tag
== TW_Denormal
)
771 reg_copy(st0_ptr
, &tmp
);
773 /* A denormal will always underflow. */
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
)
780 #endif /* PECULIAR_486 */
783 else if (st0_tag
== TW_Infinity
)
787 else if (st0_tag
== TW_NaN
)
789 /* Is it really a NaN ? */
790 if ( (exponent(st0_ptr
) == EXP_OVER
) && (st0_ptr
->sigh
& 0x80000000) )
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) )
796 /* It is a signalling NaN */
797 EXCEPTION(EX_Invalid
);
798 if ( !(control_word
& CW_Invalid
) )
800 templ
|= (0x40000000 >> 8);
806 /* It is an unsupported data type */
807 EXCEPTION(EX_Invalid
);
808 if ( !(control_word
& CW_Invalid
) )
816 EXCEPTION(EX_INTERNAL
|0x164);
821 else if ( st0_tag
== TAG_Empty
)
823 /* Empty register (stack underflow) */
824 EXCEPTION(EX_StackUnder
);
825 if ( control_word
& EX_Invalid
)
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
);
841 EXCEPTION(EX_INTERNAL
|0x163);
845 if ( getsign(st0_ptr
) )
848 RE_ENTRANT_CHECK_OFF
;
849 FPU_access_ok(VERIFY_WRITE
,single
,4);
850 FPU_put_user(templ
,(unsigned long __user
*) single
);
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
)
864 if ( st0_tag
== TAG_Empty
)
866 /* Empty register (stack underflow) */
867 EXCEPTION(EX_StackUnder
);
868 goto invalid_operand
;
870 else if ( st0_tag
== TAG_Special
)
872 st0_tag
= FPU_Special(st0_ptr
);
873 if ( (st0_tag
== TW_Infinity
) ||
874 (st0_tag
== TW_NaN
) )
876 EXCEPTION(EX_Invalid
);
877 goto invalid_operand
;
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) &&
890 EXCEPTION(EX_Invalid
);
891 /* This is a special case: see sec 16.2.5.1 of the 80486 book */
893 if ( control_word
& EX_Invalid
)
895 /* Produce something like QNaN "indefinite" */
896 tll
= 0x8000000000000000LL
;
903 if ( precision_loss
)
904 set_precision_flag(precision_loss
);
905 if ( signnegative(&t
) )
909 RE_ENTRANT_CHECK_OFF
;
910 FPU_access_ok(VERIFY_WRITE
,d
,8);
911 if (copy_to_user(d
, &tll
, 8))
919 /* Put a long into user memory */
920 int FPU_store_int32(FPU_REG
*st0_ptr
, u_char st0_tag
, long __user
*d
)
925 if ( st0_tag
== TAG_Empty
)
927 /* Empty register (stack underflow) */
928 EXCEPTION(EX_StackUnder
);
929 goto invalid_operand
;
931 else if ( st0_tag
== TAG_Special
)
933 st0_tag
= FPU_Special(st0_ptr
);
934 if ( (st0_tag
== TW_Infinity
) ||
935 (st0_tag
== TW_NaN
) )
937 EXCEPTION(EX_Invalid
);
938 goto invalid_operand
;
942 reg_copy(st0_ptr
, &t
);
943 precision_loss
= FPU_round_to_int(&t
, st0_tag
);
945 ((t
.sigl
& 0x80000000) &&
946 !((t
.sigl
== 0x80000000) && signnegative(&t
))) )
948 EXCEPTION(EX_Invalid
);
949 /* This is a special case: see sec 16.2.5.1 of the 80486 book */
951 if ( control_word
& EX_Invalid
)
953 /* Produce something like QNaN "indefinite" */
961 if ( precision_loss
)
962 set_precision_flag(precision_loss
);
963 if ( signnegative(&t
) )
964 t
.sigl
= -(long)t
.sigl
;
967 RE_ENTRANT_CHECK_OFF
;
968 FPU_access_ok(VERIFY_WRITE
,d
,4);
969 FPU_put_user(t
.sigl
, (unsigned long __user
*) d
);
976 /* Put a short into user memory */
977 int FPU_store_int16(FPU_REG
*st0_ptr
, u_char st0_tag
, short __user
*d
)
982 if ( st0_tag
== TAG_Empty
)
984 /* Empty register (stack underflow) */
985 EXCEPTION(EX_StackUnder
);
986 goto invalid_operand
;
988 else if ( st0_tag
== TAG_Special
)
990 st0_tag
= FPU_Special(st0_ptr
);
991 if ( (st0_tag
== TW_Infinity
) ||
992 (st0_tag
== TW_NaN
) )
994 EXCEPTION(EX_Invalid
);
995 goto invalid_operand
;
999 reg_copy(st0_ptr
, &t
);
1000 precision_loss
= FPU_round_to_int(&t
, st0_tag
);
1002 ((t
.sigl
& 0xffff8000) &&
1003 !((t
.sigl
== 0x8000) && signnegative(&t
))) )
1005 EXCEPTION(EX_Invalid
);
1006 /* This is a special case: see sec 16.2.5.1 of the 80486 book */
1008 if ( control_word
& EX_Invalid
)
1010 /* Produce something like QNaN "indefinite" */
1018 if ( precision_loss
)
1019 set_precision_flag(precision_loss
);
1020 if ( signnegative(&t
) )
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
;
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
)
1037 unsigned long long ll
;
1039 int i
, precision_loss
;
1040 u_char sign
= (getsign(st0_ptr
) == SIGN_NEG
) ? 0x80 : 0;
1042 if ( st0_tag
== TAG_Empty
)
1044 /* Empty register (stack underflow) */
1045 EXCEPTION(EX_StackUnder
);
1046 goto invalid_operand
;
1048 else if ( st0_tag
== TAG_Special
)
1050 st0_tag
= FPU_Special(st0_ptr
);
1051 if ( (st0_tag
== TW_Infinity
) ||
1052 (st0_tag
== TW_NaN
) )
1054 EXCEPTION(EX_Invalid
);
1055 goto invalid_operand
;
1059 reg_copy(st0_ptr
, &t
);
1060 precision_loss
= FPU_round_to_int(&t
, st0_tag
);
1061 ll
= significand(&t
);
1063 /* Check for overflow, by comparing with 999999999999999999 decimal. */
1064 if ( (t
.sigh
> 0x0de0b6b3) ||
1065 ((t
.sigh
== 0x0de0b6b3) && (t
.sigl
> 0xa763ffff)) )
1067 EXCEPTION(EX_Invalid
);
1068 /* This is a special case: see sec 16.2.5.1 of the 80486 book */
1070 if ( control_word
& CW_Invalid
)
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
;
1086 else if ( precision_loss
)
1088 /* Precision loss doesn't stop the data transfer */
1089 set_precision_flag(precision_loss
);
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
++)
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
;
1103 RE_ENTRANT_CHECK_OFF
;
1104 FPU_put_user(sign
, d
+9);
1105 RE_ENTRANT_CHECK_ON
;
1110 /*===========================================================================*/
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
)
1125 if (tag
== TAG_Zero
)
1127 /* Make sure that zero is returned */
1129 return 0; /* o.k. */
1132 if (exponent(r
) > 63)
1134 r
->sigl
= r
->sigh
= ~0; /* The largest representable number */
1135 return 1; /* overflow */
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
)
1146 if ( more_than_half
/* nearest */
1147 || (half_or_more
&& (r
->sigl
& 1)) ) /* odd -> even */
1149 if ( very_big
) return 1; /* overflow */
1151 return PRECISION_LOST_UP
;
1155 if (frac_part
&& getsign(r
))
1157 if ( very_big
) return 1; /* overflow */
1159 return PRECISION_LOST_UP
;
1163 if (frac_part
&& !getsign(r
))
1165 if ( very_big
) return 1; /* overflow */
1167 return PRECISION_LOST_UP
;
1174 return eax
? PRECISION_LOST_DOWN
: 0;
1178 /*===========================================================================*/
1180 u_char __user
*fldenv(fpu_addr_modes addr_modes
, u_char __user
*s
)
1182 unsigned short tag_word
= 0;
1186 if ( (addr_modes
.default_mode
== VM86
) ||
1187 ((addr_modes
.default_mode
== PM16
)
1188 ^ (addr_modes
.override
.operand_size
== OP_SIZE_PREFIX
)) )
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
;
1201 if ( addr_modes
.default_mode
== VM86
)
1203 instruction_address
.offset
1204 += (instruction_address
.selector
& 0xf000) << 4;
1205 operand_address
.offset
+= (operand_address
.selector
& 0xf000) << 4;
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
;
1225 control_word
&= ~0xe080;
1226 #endif /* PECULIAR_486 */
1228 top
= (partial_status
>> SW_Top_Shift
) & 7;
1230 if ( partial_status
& ~control_word
& CW_Exceptions
)
1231 partial_status
|= (SW_Summary
| SW_Backward
);
1233 partial_status
&= ~(SW_Summary
| SW_Backward
);
1235 for ( i
= 0; i
< 8; i
++ )
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
)
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
)
1249 if ( !(fpu_register(i
).sigl
| fpu_register(i
).sigh
) )
1250 FPU_settag(i
, TAG_Zero
);
1252 FPU_settag(i
, TAG_Special
);
1254 else if ( exponent(&fpu_register(i
)) == 0x7fff - EXTENDED_Ebias
)
1256 FPU_settag(i
, TAG_Special
);
1258 else if ( fpu_register(i
).sigh
& 0x80000000 )
1259 FPU_settag(i
, TAG_Valid
);
1261 FPU_settag(i
, TAG_Special
); /* An Un-normal */
1263 /* Else old tag is not empty and new tag is not empty. Old tag
1271 void frstor(fpu_addr_modes addr_modes
, u_char __user
*data_address
)
1274 u_char __user
*s
= fldenv(addr_modes
, data_address
);
1275 int offset
= (top
& 7) * 10, other
= 80 - offset
;
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
);
1282 __copy_from_user(register_base
, s
+other
, offset
);
1283 RE_ENTRANT_CHECK_ON
;
1285 for ( i
= 0; i
< 8; i
++ )
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
)));
1296 u_char __user
*fstenv(fpu_addr_modes addr_modes
, u_char __user
*d
)
1298 if ( (addr_modes
.default_mode
== VM86
) ||
1299 ((addr_modes
.default_mode
== PM16
)
1300 ^ (addr_modes
.override
.operand_size
== OP_SIZE_PREFIX
)) )
1302 RE_ENTRANT_CHECK_OFF
;
1303 FPU_access_ok(VERIFY_WRITE
,d
,14);
1305 FPU_put_user(control_word
& ~0xe080, (unsigned long __user
*) d
);
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
)
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));
1322 FPU_put_user(instruction_address
.selector
, (unsigned short __user
*) (d
+8));
1323 FPU_put_user(operand_address
.selector
, (unsigned short __user
*) (d
+0x0c));
1325 RE_ENTRANT_CHECK_ON
;
1330 RE_ENTRANT_CHECK_OFF
;
1331 FPU_access_ok(VERIFY_WRITE
, d
, 7*4);
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))
1343 RE_ENTRANT_CHECK_ON
;
1347 control_word
|= CW_Exceptions
;
1348 partial_status
&= ~(SW_Summary
| SW_Backward
);
1354 void fsave(fpu_addr_modes addr_modes
, u_char __user
*data_address
)
1357 int offset
= (top
& 7) * 10, other
= 80 - offset
;
1359 d
= fstenv(addr_modes
, data_address
);
1361 RE_ENTRANT_CHECK_OFF
;
1362 FPU_access_ok(VERIFY_WRITE
,d
,80);
1364 /* Copy all registers in stack order. */
1365 if (__copy_to_user(d
, register_base
+offset
, other
))
1368 if (__copy_to_user(d
+other
, register_base
, offset
))
1370 RE_ENTRANT_CHECK_ON
;
1375 /*===========================================================================*/