[POWERPC] Fix warning on UP
[linux-ginger.git] / arch / i386 / math-emu / reg_ld_str.c
blobe976caef64982849f3caa918ec5181bb3958b237
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 if (copy_from_user(&s,_s,8))
248 FPU_abort;
249 RE_ENTRANT_CHECK_ON;
251 if (s == 0)
253 reg_copy(&CONST_Z, st0_ptr);
254 return TAG_Zero;
257 if (s > 0)
258 sign = SIGN_Positive;
259 else
261 s = -s;
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)
274 long s;
275 int negative;
277 RE_ENTRANT_CHECK_OFF;
278 FPU_access_ok(VERIFY_READ, _s, 4);
279 FPU_get_user(s, _s);
280 RE_ENTRANT_CHECK_ON;
282 if (s == 0)
283 { reg_copy(&CONST_Z, loaded_data); return TAG_Zero; }
285 if (s > 0)
286 negative = SIGN_Positive;
287 else
289 s = -s;
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)
303 int s, negative;
305 RE_ENTRANT_CHECK_OFF;
306 FPU_access_ok(VERIFY_READ, _s, 2);
307 /* Cast as short to get the sign extended. */
308 FPU_get_user(s, _s);
309 RE_ENTRANT_CHECK_ON;
311 if (s == 0)
312 { reg_copy(&CONST_Z, loaded_data); return TAG_Zero; }
314 if (s > 0)
315 negative = SIGN_Positive;
316 else
318 s = -s;
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);
333 int pos;
334 u_char bcd;
335 long long l=0;
336 int sign;
338 RE_ENTRANT_CHECK_OFF;
339 FPU_access_ok(VERIFY_READ, s, 10);
340 RE_ENTRANT_CHECK_ON;
341 for ( pos = 8; pos >= 0; pos--)
343 l *= 10;
344 RE_ENTRANT_CHECK_OFF;
345 FPU_get_user(bcd, s+pos);
346 RE_ENTRANT_CHECK_ON;
347 l += bcd >> 4;
348 l *= 10;
349 l += bcd & 0x0f;
352 RE_ENTRANT_CHECK_OFF;
353 FPU_get_user(sign, s+9);
354 sign = sign & 0x80 ? SIGN_Negative : SIGN_Positive;
355 RE_ENTRANT_CHECK_ON;
357 if ( l == 0 )
359 reg_copy(&CONST_Z, st0_ptr);
360 addexponent(st0_ptr, sign); /* Set the sign. */
361 return TAG_Zero;
363 else
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));
389 RE_ENTRANT_CHECK_ON;
391 return 1;
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);
405 RE_ENTRANT_CHECK_ON;
406 return 1;
408 else
409 return 0;
414 /* Put a double into user memory */
415 int FPU_store_double(FPU_REG *st0_ptr, u_char st0_tag, double __user *dfloat)
417 unsigned long l[2];
418 unsigned long increment = 0; /* avoid gcc warnings */
419 int precision_loss;
420 int exp;
421 FPU_REG tmp;
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 */
432 denormal_arg:
434 if ( (precision_loss = FPU_round_to_int(&tmp, st0_tag)) )
436 #ifdef PECULIAR_486
437 /* Did it round to a non-denormal ? */
438 /* This behaviour might be regarded as peculiar, it appears
439 that the 80486 rounds to the dest precision, then
440 converts to decide underflow. */
441 if ( !((tmp.sigh == 0x00100000) && (tmp.sigl == 0) &&
442 (st0_ptr->sigl & 0x000007ff)) )
443 #endif /* PECULIAR_486 */
445 EXCEPTION(EX_Underflow);
446 /* This is a special case: see sec 16.2.5.1 of
447 the 80486 book */
448 if ( !(control_word & CW_Underflow) )
449 return 0;
451 EXCEPTION(precision_loss);
452 if ( !(control_word & CW_Precision) )
453 return 0;
455 l[0] = tmp.sigl;
456 l[1] = tmp.sigh;
458 else
460 if ( tmp.sigl & 0x000007ff )
462 precision_loss = 1;
463 switch (control_word & CW_RC)
465 case RC_RND:
466 /* Rounding can get a little messy.. */
467 increment = ((tmp.sigl & 0x7ff) > 0x400) | /* nearest */
468 ((tmp.sigl & 0xc00) == 0xc00); /* odd -> even */
469 break;
470 case RC_DOWN: /* towards -infinity */
471 increment = signpositive(&tmp) ? 0 : tmp.sigl & 0x7ff;
472 break;
473 case RC_UP: /* towards +infinity */
474 increment = signpositive(&tmp) ? tmp.sigl & 0x7ff : 0;
475 break;
476 case RC_CHOP:
477 increment = 0;
478 break;
481 /* Truncate the mantissa */
482 tmp.sigl &= 0xfffff800;
484 if ( increment )
486 if ( tmp.sigl >= 0xfffff800 )
488 /* the sigl part overflows */
489 if ( tmp.sigh == 0xffffffff )
491 /* The sigh part overflows */
492 tmp.sigh = 0x80000000;
493 exp++;
494 if (exp >= EXP_OVER)
495 goto overflow;
497 else
499 tmp.sigh ++;
501 tmp.sigl = 0x00000000;
503 else
505 /* We only need to increment sigl */
506 tmp.sigl += 0x00000800;
510 else
511 precision_loss = 0;
513 l[0] = (tmp.sigl >> 11) | (tmp.sigh << 21);
514 l[1] = ((tmp.sigh >> 11) & 0xfffff);
516 if ( exp > DOUBLE_Emax )
518 overflow:
519 EXCEPTION(EX_Overflow);
520 if ( !(control_word & CW_Overflow) )
521 return 0;
522 set_precision_flag_up();
523 if ( !(control_word & CW_Precision) )
524 return 0;
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 */
531 else
533 if ( precision_loss )
535 if ( increment )
536 set_precision_flag_up();
537 else
538 set_precision_flag_down();
540 /* Add the exponent */
541 l[1] |= (((exp+DOUBLE_Ebias) & 0x7ff) << 20);
545 else if (st0_tag == TAG_Zero)
547 /* Number is zero */
548 l[0] = 0;
549 l[1] = 0;
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. */
557 #ifndef PECULIAR_486
558 /* An 80486 is supposed to be able to generate
559 a denormal exception here, but... */
560 /* Underflow has priority. */
561 if ( control_word & CW_Underflow )
562 denormal_operand();
563 #endif /* PECULIAR_486 */
564 reg_copy(st0_ptr, &tmp);
565 goto denormal_arg;
567 else if (st0_tag == TW_Infinity)
569 l[0] = 0;
570 l[1] = 0x7ff00000;
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) )
586 return 0;
587 l[1] |= (0x40000000 >> 11);
589 l[1] |= 0x7ff00000;
591 else
593 /* It is an unsupported data type */
594 EXCEPTION(EX_Invalid);
595 if ( !(control_word & CW_Invalid) )
596 return 0;
597 l[0] = 0;
598 l[1] = 0xfff80000;
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);
614 RE_ENTRANT_CHECK_ON;
615 return 1;
617 else
618 return 0;
620 if ( getsign(st0_ptr) )
621 l[1] |= 0x80000000;
623 RE_ENTRANT_CHECK_OFF;
624 FPU_access_ok(VERIFY_WRITE,dfloat,8);
625 FPU_put_user(l[0], (unsigned long __user *)dfloat);
626 FPU_put_user(l[1], 1 + (unsigned long __user *)dfloat);
627 RE_ENTRANT_CHECK_ON;
629 return 1;
633 /* Put a float into user memory */
634 int FPU_store_single(FPU_REG *st0_ptr, u_char st0_tag, float __user *single)
636 long templ = 0;
637 unsigned long increment = 0; /* avoid gcc warnings */
638 int precision_loss;
639 int exp;
640 FPU_REG tmp;
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 */
652 denormal_arg:
654 if ( (precision_loss = FPU_round_to_int(&tmp, st0_tag)) )
656 #ifdef PECULIAR_486
657 /* Did it round to a non-denormal ? */
658 /* This behaviour might be regarded as peculiar, it appears
659 that the 80486 rounds to the dest precision, then
660 converts to decide underflow. */
661 if ( !((tmp.sigl == 0x00800000) &&
662 ((st0_ptr->sigh & 0x000000ff) || st0_ptr->sigl)) )
663 #endif /* PECULIAR_486 */
665 EXCEPTION(EX_Underflow);
666 /* This is a special case: see sec 16.2.5.1 of
667 the 80486 book */
668 if ( !(control_word & CW_Underflow) )
669 return 0;
671 EXCEPTION(precision_loss);
672 if ( !(control_word & CW_Precision) )
673 return 0;
675 templ = tmp.sigl;
677 else
679 if ( tmp.sigl | (tmp.sigh & 0x000000ff) )
681 unsigned long sigh = tmp.sigh;
682 unsigned long sigl = tmp.sigl;
684 precision_loss = 1;
685 switch (control_word & CW_RC)
687 case RC_RND:
688 increment = ((sigh & 0xff) > 0x80) /* more than half */
689 || (((sigh & 0xff) == 0x80) && sigl) /* more than half */
690 || ((sigh & 0x180) == 0x180); /* round to even */
691 break;
692 case RC_DOWN: /* towards -infinity */
693 increment = signpositive(&tmp)
694 ? 0 : (sigl | (sigh & 0xff));
695 break;
696 case RC_UP: /* towards +infinity */
697 increment = signpositive(&tmp)
698 ? (sigl | (sigh & 0xff)) : 0;
699 break;
700 case RC_CHOP:
701 increment = 0;
702 break;
705 /* Truncate part of the mantissa */
706 tmp.sigl = 0;
708 if (increment)
710 if ( sigh >= 0xffffff00 )
712 /* The sigh part overflows */
713 tmp.sigh = 0x80000000;
714 exp++;
715 if ( exp >= EXP_OVER )
716 goto overflow;
718 else
720 tmp.sigh &= 0xffffff00;
721 tmp.sigh += 0x100;
724 else
726 tmp.sigh &= 0xffffff00; /* Finish the truncation */
729 else
730 precision_loss = 0;
732 templ = (tmp.sigh >> 8) & 0x007fffff;
734 if ( exp > SINGLE_Emax )
736 overflow:
737 EXCEPTION(EX_Overflow);
738 if ( !(control_word & CW_Overflow) )
739 return 0;
740 set_precision_flag_up();
741 if ( !(control_word & CW_Precision) )
742 return 0;
744 /* This is a special case: see sec 16.2.5.1 of the 80486 book. */
745 /* Masked response is overflow to infinity. */
746 templ = 0x7f800000;
748 else
750 if ( precision_loss )
752 if ( increment )
753 set_precision_flag_up();
754 else
755 set_precision_flag_down();
757 /* Add the exponent */
758 templ |= ((exp+SINGLE_Ebias) & 0xff) << 23;
762 else if (st0_tag == TAG_Zero)
764 templ = 0;
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. */
774 #ifndef PECULIAR_486
775 /* An 80486 is supposed to be able to generate
776 a denormal exception here, but... */
777 /* Underflow has priority. */
778 if ( control_word & CW_Underflow )
779 denormal_operand();
780 #endif /* PECULIAR_486 */
781 goto denormal_arg;
783 else if (st0_tag == TW_Infinity)
785 templ = 0x7f800000;
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) )
799 return 0;
800 templ |= (0x40000000 >> 8);
802 templ |= 0x7f800000;
804 else
806 /* It is an unsupported data type */
807 EXCEPTION(EX_Invalid);
808 if ( !(control_word & CW_Invalid) )
809 return 0;
810 templ = 0xffc00000;
813 #ifdef PARANOID
814 else
816 EXCEPTION(EX_INTERNAL|0x164);
817 return 0;
819 #endif
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);
832 RE_ENTRANT_CHECK_ON;
833 return 1;
835 else
836 return 0;
838 #ifdef PARANOID
839 else
841 EXCEPTION(EX_INTERNAL|0x163);
842 return 0;
844 #endif
845 if ( getsign(st0_ptr) )
846 templ |= 0x80000000;
848 RE_ENTRANT_CHECK_OFF;
849 FPU_access_ok(VERIFY_WRITE,single,4);
850 FPU_put_user(templ,(unsigned long __user *) single);
851 RE_ENTRANT_CHECK_ON;
853 return 1;
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)
860 FPU_REG t;
861 long long tll;
862 int precision_loss;
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) &&
888 signnegative(&t))) )
890 EXCEPTION(EX_Invalid);
891 /* This is a special case: see sec 16.2.5.1 of the 80486 book */
892 invalid_operand:
893 if ( control_word & EX_Invalid )
895 /* Produce something like QNaN "indefinite" */
896 tll = 0x8000000000000000LL;
898 else
899 return 0;
901 else
903 if ( precision_loss )
904 set_precision_flag(precision_loss);
905 if ( signnegative(&t) )
906 tll = - tll;
909 RE_ENTRANT_CHECK_OFF;
910 FPU_access_ok(VERIFY_WRITE,d,8);
911 if (copy_to_user(d, &tll, 8))
912 FPU_abort;
913 RE_ENTRANT_CHECK_ON;
915 return 1;
919 /* Put a long into user memory */
920 int FPU_store_int32(FPU_REG *st0_ptr, u_char st0_tag, long __user *d)
922 FPU_REG t;
923 int precision_loss;
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);
944 if (t.sigh ||
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 */
950 invalid_operand:
951 if ( control_word & EX_Invalid )
953 /* Produce something like QNaN "indefinite" */
954 t.sigl = 0x80000000;
956 else
957 return 0;
959 else
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);
970 RE_ENTRANT_CHECK_ON;
972 return 1;
976 /* Put a short into user memory */
977 int FPU_store_int16(FPU_REG *st0_ptr, u_char st0_tag, short __user *d)
979 FPU_REG t;
980 int precision_loss;
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);
1001 if (t.sigh ||
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 */
1007 invalid_operand:
1008 if ( control_word & EX_Invalid )
1010 /* Produce something like QNaN "indefinite" */
1011 t.sigl = 0x8000;
1013 else
1014 return 0;
1016 else
1018 if ( precision_loss )
1019 set_precision_flag(precision_loss);
1020 if ( signnegative(&t) )
1021 t.sigl = -t.sigl;
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;
1029 return 1;
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)
1036 FPU_REG t;
1037 unsigned long long ll;
1038 u_char b;
1039 int i, precision_loss;
1040 u_char sign = (getsign(st0_ptr) == SIGN_NEG) ? 0x80 : 0;
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 */
1069 invalid_operand:
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;
1081 return 1;
1083 else
1084 return 0;
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;
1107 return 1;
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)
1122 u_char very_big;
1123 unsigned eax;
1125 if (tag == TAG_Zero)
1127 /* Make sure that zero is returned */
1128 significand(r) = 0;
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)
1145 case RC_RND:
1146 if ( more_than_half /* nearest */
1147 || (half_or_more && (r->sigl & 1)) ) /* odd -> even */
1149 if ( very_big ) return 1; /* overflow */
1150 significand(r) ++;
1151 return PRECISION_LOST_UP;
1153 break;
1154 case RC_DOWN:
1155 if (frac_part && getsign(r))
1157 if ( very_big ) return 1; /* overflow */
1158 significand(r) ++;
1159 return PRECISION_LOST_UP;
1161 break;
1162 case RC_UP:
1163 if (frac_part && !getsign(r))
1165 if ( very_big ) return 1; /* overflow */
1166 significand(r) ++;
1167 return PRECISION_LOST_UP;
1169 break;
1170 case RC_CHOP:
1171 break;
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;
1183 u_char tag;
1184 int i;
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;
1200 s += 0x0e;
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;
1208 else
1210 RE_ENTRANT_CHECK_OFF;
1211 FPU_access_ok(VERIFY_READ, s, 0x1c);
1212 FPU_get_user(control_word, (unsigned short __user *) s);
1213 FPU_get_user(partial_status, (unsigned short __user *) (s+4));
1214 FPU_get_user(tag_word, (unsigned short __user *) (s+8));
1215 FPU_get_user(instruction_address.offset, (unsigned long __user *) (s+0x0c));
1216 FPU_get_user(instruction_address.selector, (unsigned short __user *) (s+0x10));
1217 FPU_get_user(instruction_address.opcode, (unsigned short __user *) (s+0x12));
1218 FPU_get_user(operand_address.offset, (unsigned long __user *) (s+0x14));
1219 FPU_get_user(operand_address.selector, (unsigned long __user *) (s+0x18));
1220 RE_ENTRANT_CHECK_ON;
1221 s += 0x1c;
1224 #ifdef PECULIAR_486
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);
1232 else
1233 partial_status &= ~(SW_Summary | SW_Backward);
1235 for ( i = 0; i < 8; i++ )
1237 tag = tag_word & 3;
1238 tag_word >>= 2;
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);
1251 else
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);
1260 else
1261 FPU_settag(i, TAG_Special); /* An Un-normal */
1263 /* Else old tag is not empty and new tag is not empty. Old tag
1264 remains correct */
1267 return s;
1271 void frstor(fpu_addr_modes addr_modes, u_char __user *data_address)
1273 int i, regnr;
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);
1281 if ( offset )
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);
1304 #ifdef PECULIAR_486
1305 FPU_put_user(control_word & ~0xe080, (unsigned long __user *) d);
1306 #else
1307 FPU_put_user(control_word, (unsigned short __user *) d);
1308 #endif /* PECULIAR_486 */
1309 FPU_put_user(status_word(), (unsigned short __user *) (d+2));
1310 FPU_put_user(fpu_tag_word, (unsigned short __user *) (d+4));
1311 FPU_put_user(instruction_address.offset, (unsigned short __user *) (d+6));
1312 FPU_put_user(operand_address.offset, (unsigned short __user *) (d+0x0a));
1313 if ( addr_modes.default_mode == VM86 )
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));
1320 else
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;
1326 d += 0x0e;
1328 else
1330 RE_ENTRANT_CHECK_OFF;
1331 FPU_access_ok(VERIFY_WRITE, d, 7*4);
1332 #ifdef PECULIAR_486
1333 control_word &= ~0xe080;
1334 /* An 80486 sets nearly all of the reserved bits to 1. */
1335 control_word |= 0xffff0040;
1336 partial_status = status_word() | 0xffff0000;
1337 fpu_tag_word |= 0xffff0000;
1338 I387.soft.fcs &= ~0xf8000000;
1339 I387.soft.fos |= 0xffff0000;
1340 #endif /* PECULIAR_486 */
1341 if (__copy_to_user(d, &control_word, 7*4))
1342 FPU_abort;
1343 RE_ENTRANT_CHECK_ON;
1344 d += 0x1c;
1347 control_word |= CW_Exceptions;
1348 partial_status &= ~(SW_Summary | SW_Backward);
1350 return d;
1354 void fsave(fpu_addr_modes addr_modes, u_char __user *data_address)
1356 u_char __user *d;
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))
1366 FPU_abort;
1367 if ( offset )
1368 if (__copy_to_user(d+other, register_base, offset))
1369 FPU_abort;
1370 RE_ENTRANT_CHECK_ON;
1372 finit();
1375 /*===========================================================================*/