4 * All of the functions which transfer data between user memory and FPU_REGs.
7 * Copyright (C) 1992,1993,1994
8 * W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
9 * Australia. E-mail billm@vaxc.cc.monash.edu.au
10 * All rights reserved.
12 * This copyright notice covers the redistribution and use of the
13 * FPU emulator developed by W. Metzenthen. It covers only its use
14 * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
15 * use is not permitted under this copyright.
17 * Redistribution and use in source and binary forms, with or without
18 * modification, are permitted provided that the following conditions
20 * 1. Redistributions of source code must retain the above copyright
21 * notice, this list of conditions and the following disclaimer.
22 * 2. Redistributions in binary form must include information specifying
23 * that source code for the emulator is freely available and include
25 * a) an offer to provide the source code for a nominal distribution
27 * b) list at least two alternative methods whereby the source
28 * can be obtained, e.g. a publically accessible bulletin board
29 * and an anonymous ftp site from which the software can be
31 * 3. All advertising materials specifically mentioning features or use of
32 * this emulator must acknowledge that it was developed by W. Metzenthen.
33 * 4. The name of W. Metzenthen may not be used to endorse or promote
34 * products derived from this software without specific prior written
37 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
38 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
39 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
40 * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
41 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
42 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
43 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
44 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
45 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
46 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
49 * The purpose of this copyright, based upon the Berkeley copyright, is to
50 * ensure that the covered software remains freely available to everyone.
52 * The software (with necessary differences) is also available, but under
53 * the terms of the GNU copyleft, for the Linux operating system and for
54 * the djgpp ms-dos extender.
56 * W. Metzenthen June 1994.
59 * $FreeBSD: src/sys/gnu/i386/fpemul/reg_ld_str.c,v 1.13 1999/08/28 00:42:56 peter Exp $
60 * $DragonFly: src/sys/i386/gnu/fpemul/Attic/reg_ld_str.c,v 1.2 2003/06/17 04:28:34 dillon Exp $
65 /*---------------------------------------------------------------------------+
67 | The file contains code which accesses user memory. |
68 | Emulator static data may change when user memory is accessed, due to |
69 | other processes using the emulator while swapping is in progress. |
70 +---------------------------------------------------------------------------*/
71 #include <sys/param.h>
73 #include <sys/systm.h>
74 #include <machine/pcb.h>
76 #include <gnu/i386/fpemul/fpu_emu.h>
77 #include <gnu/i386/fpemul/fpu_system.h>
78 #include <gnu/i386/fpemul/exception.h>
79 #include <gnu/i386/fpemul/reg_constant.h>
80 #include <gnu/i386/fpemul/control_w.h>
81 #include <gnu/i386/fpemul/status_w.h>
84 #define EXTENDED_Emax 0x3fff /* largest valid exponent */
85 #define EXTENDED_Ebias 0x3fff
86 #define EXTENDED_Emin (-0x3ffe) /* smallest valid exponent */
88 #define DOUBLE_Emax 1023 /* largest valid exponent */
89 #define DOUBLE_Ebias 1023
90 #define DOUBLE_Emin (-1022) /* smallest valid exponent */
92 #define SINGLE_Emax 127 /* largest valid exponent */
93 #define SINGLE_Ebias 127
94 #define SINGLE_Emin (-126) /* smallest valid exponent */
96 #define LOST_UP (EX_Precision | SW_C1)
97 #define LOST_DOWN EX_Precision
99 FPU_REG FPU_loaded_data;
102 /* Get a long double from user memory */
104 reg_load_extended(void)
106 long double *s = (long double *) FPU_data_address;
107 unsigned long sigl, sigh, exp;
109 REENTRANT_CHECK(OFF);
110 /* Use temporary variables here because FPU_loaded data is static and
111 * hence re-entrancy problems can arise */
112 sigl = fuword((unsigned long *) s);
113 sigh = fuword(1 + (unsigned long *) s);
114 exp = fusword(4 + (unsigned short *) s);
117 FPU_loaded_data.sigl = sigl;
118 FPU_loaded_data.sigh = sigh;
119 FPU_loaded_data.exp = exp;
121 if (FPU_loaded_data.exp & 0x8000)
122 FPU_loaded_data.sign = SIGN_NEG;
124 FPU_loaded_data.sign = SIGN_POS;
125 if ((FPU_loaded_data.exp &= 0x7fff) == 0) {
126 if (!(FPU_loaded_data.sigl | FPU_loaded_data.sigh)) {
127 FPU_loaded_data.tag = TW_Zero;
130 /* The number is a de-normal or pseudodenormal. */
131 /* The 80486 doesn't regard pseudodenormals as denormals here. */
132 if (!(FPU_loaded_data.sigh & 0x80000000))
133 EXCEPTION(EX_Denormal);
134 FPU_loaded_data.exp++;
136 /* The default behaviour will now take care of it. */
138 if (FPU_loaded_data.exp == 0x7fff) {
139 FPU_loaded_data.exp = EXTENDED_Emax;
140 if ((FPU_loaded_data.sigh == 0x80000000)
141 && (FPU_loaded_data.sigl == 0)) {
142 FPU_loaded_data.tag = TW_Infinity;
145 if (!(FPU_loaded_data.sigh & 0x80000000)) {
146 /* Unsupported NaN data type */
147 EXCEPTION(EX_Invalid);
148 FPU_loaded_data.tag = TW_NaN;
151 FPU_loaded_data.tag = TW_NaN;
154 FPU_loaded_data.exp = (FPU_loaded_data.exp & 0x7fff) - EXTENDED_Ebias
156 FPU_loaded_data.tag = TW_Valid;
158 if (!(sigh & 0x80000000)) {
159 /* Unsupported data type */
160 EXCEPTION(EX_Invalid);
161 normalize_nuo(&FPU_loaded_data);
166 /* Get a double from user memory */
168 reg_load_double(void)
170 double *dfloat = (double *) FPU_data_address;
174 REENTRANT_CHECK(OFF);
175 m64 = fuword(1 + (unsigned long *) dfloat);
176 l64 = fuword((unsigned long *) dfloat);
179 if (m64 & 0x80000000)
180 FPU_loaded_data.sign = SIGN_NEG;
182 FPU_loaded_data.sign = SIGN_POS;
183 exp = ((m64 & 0x7ff00000) >> 20) - DOUBLE_Ebias;
185 if (exp > DOUBLE_Emax) {
186 /* Infinity or NaN */
187 if ((m64 == 0) && (l64 == 0)) {
189 FPU_loaded_data.exp = EXTENDED_Emax;
190 FPU_loaded_data.tag = TW_Infinity;
193 /* Must be a signaling or quiet NaN */
194 FPU_loaded_data.exp = EXTENDED_Emax;
195 FPU_loaded_data.tag = TW_NaN;
196 FPU_loaded_data.sigh = (m64 << 11) | 0x80000000;
197 FPU_loaded_data.sigh |= l64 >> 21;
198 FPU_loaded_data.sigl = l64 << 11;
202 if (exp < DOUBLE_Emin) {
203 /* Zero or de-normal */
204 if ((m64 == 0) && (l64 == 0)) {
206 int c = FPU_loaded_data.sign;
207 reg_move(&CONST_Z, &FPU_loaded_data);
208 FPU_loaded_data.sign = c;
212 EXCEPTION(EX_Denormal);
213 FPU_loaded_data.exp = DOUBLE_Emin + EXP_BIAS;
214 FPU_loaded_data.tag = TW_Valid;
215 FPU_loaded_data.sigh = m64 << 11;
216 FPU_loaded_data.sigh |= l64 >> 21;
217 FPU_loaded_data.sigl = l64 << 11;
218 normalize_nuo(&FPU_loaded_data);
222 FPU_loaded_data.exp = exp + EXP_BIAS;
223 FPU_loaded_data.tag = TW_Valid;
224 FPU_loaded_data.sigh = (m64 << 11) | 0x80000000;
225 FPU_loaded_data.sigh |= l64 >> 21;
226 FPU_loaded_data.sigl = l64 << 11;
233 /* Get a float from user memory */
235 reg_load_single(void)
237 float *single = (float *) FPU_data_address;
241 REENTRANT_CHECK(OFF);
242 m32 = fuword((unsigned long *) single);
245 if (m32 & 0x80000000)
246 FPU_loaded_data.sign = SIGN_NEG;
248 FPU_loaded_data.sign = SIGN_POS;
249 if (!(m32 & 0x7fffffff)) {
251 int c = FPU_loaded_data.sign;
252 reg_move(&CONST_Z, &FPU_loaded_data);
253 FPU_loaded_data.sign = c;
256 exp = ((m32 & 0x7f800000) >> 23) - SINGLE_Ebias;
257 m32 = (m32 & 0x7fffff) << 8;
258 if (exp < SINGLE_Emin) {
260 EXCEPTION(EX_Denormal);
261 FPU_loaded_data.exp = SINGLE_Emin + EXP_BIAS;
262 FPU_loaded_data.tag = TW_Valid;
263 FPU_loaded_data.sigh = m32;
264 FPU_loaded_data.sigl = 0;
265 normalize_nuo(&FPU_loaded_data);
268 if (exp > SINGLE_Emax) {
269 /* Infinity or NaN */
272 FPU_loaded_data.exp = EXTENDED_Emax;
273 FPU_loaded_data.tag = TW_Infinity;
276 /* Must be a signaling or quiet NaN */
277 FPU_loaded_data.exp = EXTENDED_Emax;
278 FPU_loaded_data.tag = TW_NaN;
279 FPU_loaded_data.sigh = m32 | 0x80000000;
280 FPU_loaded_data.sigl = 0;
284 FPU_loaded_data.exp = exp + EXP_BIAS;
285 FPU_loaded_data.sigh = m32 | 0x80000000;
286 FPU_loaded_data.sigl = 0;
287 FPU_loaded_data.tag = TW_Valid;
292 /* Get a long long from user memory */
296 long long *_s = (long long *) FPU_data_address;
300 REENTRANT_CHECK(OFF);
301 ((unsigned long *) &s)[0] = fuword((unsigned long *) _s);
302 ((unsigned long *) &s)[1] = fuword(1 + (unsigned long *) _s);
306 reg_move(&CONST_Z, &FPU_loaded_data);
310 FPU_loaded_data.sign = SIGN_POS;
313 FPU_loaded_data.sign = SIGN_NEG;
317 *((long long *) &FPU_loaded_data.sigl) = s;
318 FPU_loaded_data.exp = e;
319 FPU_loaded_data.tag = TW_Valid;
320 normalize_nuo(&FPU_loaded_data);
324 /* Get a long from user memory */
328 long *_s = (long *) FPU_data_address;
332 REENTRANT_CHECK(OFF);
333 s = (long) fuword((unsigned long *) _s);
337 reg_move(&CONST_Z, &FPU_loaded_data);
341 FPU_loaded_data.sign = SIGN_POS;
344 FPU_loaded_data.sign = SIGN_NEG;
348 FPU_loaded_data.sigh = s;
349 FPU_loaded_data.sigl = 0;
350 FPU_loaded_data.exp = e;
351 FPU_loaded_data.tag = TW_Valid;
352 normalize_nuo(&FPU_loaded_data);
356 /* Get a short from user memory */
360 short *_s = (short *) FPU_data_address;
363 REENTRANT_CHECK(OFF);
364 /* Cast as short to get the sign extended. */
365 s = (short) fusword((unsigned short *) _s);
369 reg_move(&CONST_Z, &FPU_loaded_data);
373 FPU_loaded_data.sign = SIGN_POS;
376 FPU_loaded_data.sign = SIGN_NEG;
380 FPU_loaded_data.sigh = s << 16;
382 FPU_loaded_data.sigl = 0;
383 FPU_loaded_data.exp = e;
384 FPU_loaded_data.tag = TW_Valid;
385 normalize_nuo(&FPU_loaded_data);
389 /* Get a packed bcd array from user memory */
393 char *s = (char *) FPU_data_address;
398 for (pos = 8; pos >= 0; pos--) {
400 REENTRANT_CHECK(OFF);
401 bcd = (unsigned char) fubyte((unsigned char *) s + pos);
408 /* Finish all access to user memory before putting stuff into the
409 * static FPU_loaded_data */
410 REENTRANT_CHECK(OFF);
411 FPU_loaded_data.sign =
412 ((unsigned char) fubyte((unsigned char *) s + 9)) & 0x80 ?
417 char sign = FPU_loaded_data.sign;
418 reg_move(&CONST_Z, &FPU_loaded_data);
419 FPU_loaded_data.sign = sign;
421 *((long long *) &FPU_loaded_data.sigl) = l;
422 FPU_loaded_data.exp = EXP_BIAS + 63;
423 FPU_loaded_data.tag = TW_Valid;
424 normalize_nuo(&FPU_loaded_data);
427 /*===========================================================================*/
429 /* Put a long double into user memory */
431 reg_store_extended(void)
433 long double *d = (long double *) FPU_data_address;
434 long e = FPU_st0_ptr->exp - EXP_BIAS + EXTENDED_Ebias;
435 unsigned short sign = FPU_st0_ptr->sign * 0x8000;
436 unsigned long ls, ms;
439 if (FPU_st0_tag == TW_Valid) {
441 EXCEPTION(EX_Overflow); /* Overflow */
442 /* This is a special case: see sec 16.2.5.1 of the
444 if (control_word & EX_Overflow) {
445 /* Overflow to infinity */
454 /* Correctly format the de-normal */
458 EXCEPTION(EX_Denormal);
459 reg_move(FPU_st0_ptr, &tmp);
460 tmp.exp += -EXTENDED_Emin + 63; /* largest exp to be 62 */
461 if ((precision_loss = round_to_int(&tmp))) {
462 EXCEPTION(EX_Underflow | precision_loss);
463 /* This is a special case: see
464 * sec 16.2.5.1 of the 80486
466 if (!(control_word & EX_Underflow))
473 /* ****** ??? This should not be
475 EXCEPTION(EX_Underflow); /* Underflow */
476 /* This is a special case: see sec
477 * 16.2.5.1 of the 80486 book */
478 if (control_word & EX_Underflow) {
479 /* Underflow to zero */
482 e = FPU_st0_ptr->sign == SIGN_POS ? 0x7fff : 0xffff;
487 ls = FPU_st0_ptr->sigl;
488 ms = FPU_st0_ptr->sigh;
491 if (FPU_st0_tag == TW_Zero) {
495 if (FPU_st0_tag == TW_Infinity) {
500 if (FPU_st0_tag == TW_NaN) {
501 ls = FPU_st0_ptr->sigl;
502 ms = FPU_st0_ptr->sigh;
505 if (FPU_st0_tag == TW_Empty) {
506 /* Empty register (stack
508 EXCEPTION(EX_StackUnder);
509 if (control_word & EX_Invalid) {
510 /* The masked response */
519 /* We don't use TW_Denormal
520 * yet ... perhaps never! */
521 EXCEPTION(EX_Invalid);
527 REENTRANT_CHECK(OFF);
528 /* verify_area(VERIFY_WRITE, d, 10); */
529 suword((unsigned long *) d, ls);
530 suword(1 + (unsigned long *) d, ms);
531 susword(4 + (short *) d, (unsigned short) e | sign);
539 /* Put a double into user memory */
541 reg_store_double(void)
543 double *dfloat = (double *) FPU_data_address;
545 if (FPU_st0_tag == TW_Valid) {
549 reg_move(FPU_st0_ptr, &tmp);
550 exp = tmp.exp - EXP_BIAS;
552 if (exp < DOUBLE_Emin) { /* It may be a denormal */
553 /* Make a de-normal */
556 if (exp <= -EXTENDED_Ebias)
557 EXCEPTION(EX_Denormal);
559 tmp.exp += -DOUBLE_Emin + 52; /* largest exp to be 51 */
561 if ((precision_loss = round_to_int(&tmp))) {
563 /* Did it round to a non-denormal ? */
564 /* This behaviour might be regarded as
565 * peculiar, it appears that the 80486 rounds
566 * to the dest precision, then converts to
567 * decide underflow. */
568 if ((tmp.sigh == 0x00100000) && (tmp.sigl == 0) &&
569 (FPU_st0_ptr->sigl & 0x000007ff))
570 EXCEPTION(precision_loss);
572 #endif /* PECULIAR_486 */
574 EXCEPTION(EX_Underflow | precision_loss);
575 /* This is a special case: see sec
576 * 16.2.5.1 of the 80486 book */
577 if (!(control_word & EX_Underflow))
584 if (tmp.sigl & 0x000007ff) {
585 unsigned long increment = 0; /* avoid gcc warnings */
587 switch (control_word & CW_RC) {
589 /* Rounding can get a little messy.. */
590 increment = ((tmp.sigl & 0x7ff) > 0x400) | /* nearest */
591 ((tmp.sigl & 0xc00) == 0xc00); /* odd -> even */
593 case RC_DOWN: /* towards -infinity */
594 increment = (tmp.sign == SIGN_POS) ? 0 : tmp.sigl & 0x7ff;
596 case RC_UP: /* towards +infinity */
597 increment = (tmp.sign == SIGN_POS) ? tmp.sigl & 0x7ff : 0;
604 /* Truncate the mantissa */
605 tmp.sigl &= 0xfffff800;
608 set_precision_flag_up();
610 if (tmp.sigl >= 0xfffff800) {
611 /* the sigl part overflows */
612 if (tmp.sigh == 0xffffffff) {
615 tmp.sigh = 0x80000000;
622 tmp.sigl = 0x00000000;
624 /* We only need to increment
626 tmp.sigl += 0x00000800;
629 set_precision_flag_down();
631 l[0] = (tmp.sigl >> 11) | (tmp.sigh << 21);
632 l[1] = ((tmp.sigh >> 11) & 0xfffff);
634 if (exp > DOUBLE_Emax) {
636 EXCEPTION(EX_Overflow);
637 /* This is a special case: see sec 16.2.5.1 of
639 if (control_word & EX_Overflow) {
640 /* Overflow to infinity */
641 l[0] = 0x00000000; /* Set to */
642 l[1] = 0x7ff00000; /* + INF */
646 /* Add the exponent */
647 l[1] |= (((exp + DOUBLE_Ebias) & 0x7ff) << 20);
651 if (FPU_st0_tag == TW_Zero) {
656 if (FPU_st0_tag == TW_Infinity) {
660 if (FPU_st0_tag == TW_NaN) {
661 /* See if we can get a valid NaN from
663 l[0] = (FPU_st0_ptr->sigl >> 11) | (FPU_st0_ptr->sigh << 21);
664 l[1] = ((FPU_st0_ptr->sigh >> 11) & 0xfffff);
665 if (!(l[0] | l[1])) {
666 /* This case does not seem to
667 * be handled by the 80486
669 EXCEPTION(EX_Invalid);
670 /* Make the quiet NaN "real
676 if (FPU_st0_tag == TW_Empty) {
677 /* Empty register (stack
679 EXCEPTION(EX_StackUnder);
680 if (control_word & EX_Invalid) {
681 /* The masked response */
685 REENTRANT_CHECK(OFF);
686 /* verify_area(VERIFY_W
689 suword((unsigned long *) dfloat, 0);
690 suword(1 + (unsigned long *) dfloat, 0xfff80000);
696 #if 0 /* TW_Denormal is not used yet, and probably
699 if (FPU_st0_tag == TW_Denormal) {
702 * always underflow */
704 EXCEPTION(EX_Underflow);
707 if (FPU_st0_ptr->sign)
710 REENTRANT_CHECK(OFF);
711 /* verify_area(VERIFY_WRITE, (void *) dfloat, 8);*/
712 suword((u_long *) dfloat, l[0]);
713 suword((u_long *) dfloat + 1, l[1]);
715 suword(l[0], (unsigned long *) dfloat);
716 suword(l[1], 1 + (unsigned long *) dfloat);*/
723 /* Put a float into user memory */
725 reg_store_single(void)
727 float *single = (float *) FPU_data_address;
730 if (FPU_st0_tag == TW_Valid) {
734 reg_move(FPU_st0_ptr, &tmp);
735 exp = tmp.exp - EXP_BIAS;
737 if (exp < SINGLE_Emin) {
738 /* Make a de-normal */
741 if (exp <= -EXTENDED_Ebias)
742 EXCEPTION(EX_Denormal);
744 tmp.exp += -SINGLE_Emin + 23; /* largest exp to be 22 */
746 if ((precision_loss = round_to_int(&tmp))) {
748 /* Did it round to a non-denormal ? */
749 /* This behaviour might be regarded as
750 * peculiar, it appears that the 80486 rounds
751 * to the dest precision, then converts to
752 * decide underflow. */
753 if ((tmp.sigl == 0x00800000) &&
754 ((FPU_st0_ptr->sigh & 0x000000ff) || FPU_st0_ptr->sigl))
755 EXCEPTION(precision_loss);
757 #endif /* PECULIAR_486 */
759 EXCEPTION(EX_Underflow | precision_loss);
760 /* This is a special case: see sec
761 * 16.2.5.1 of the 80486 book */
762 if (!(control_word & EX_Underflow))
768 if (tmp.sigl | (tmp.sigh & 0x000000ff)) {
769 unsigned long increment = 0; /* avoid gcc warnings */
770 unsigned long sigh = tmp.sigh;
771 unsigned long sigl = tmp.sigl;
773 switch (control_word & CW_RC) {
775 increment = ((sigh & 0xff) > 0x80) /* more than half */
776 ||(((sigh & 0xff) == 0x80) && sigl) /* more than half */
777 ||((sigh & 0x180) == 0x180); /* round to even */
779 case RC_DOWN: /* towards -infinity */
780 increment = (tmp.sign == SIGN_POS)
781 ? 0 : (sigl | (sigh & 0xff));
783 case RC_UP: /* towards +infinity */
784 increment = (tmp.sign == SIGN_POS)
785 ? (sigl | (sigh & 0xff)) : 0;
792 /* Truncate part of the mantissa */
796 set_precision_flag_up();
798 if (sigh >= 0xffffff00) {
799 /* The sigh part overflows */
800 tmp.sigh = 0x80000000;
805 tmp.sigh &= 0xffffff00;
809 set_precision_flag_down();
810 tmp.sigh &= 0xffffff00; /* Finish the truncation */
813 templ = (tmp.sigh >> 8) & 0x007fffff;
815 if (exp > SINGLE_Emax) {
817 EXCEPTION(EX_Overflow);
818 /* This is a special case: see sec 16.2.5.1 of
820 if (control_word & EX_Overflow) {
821 /* Overflow to infinity */
826 templ |= ((exp + SINGLE_Ebias) & 0xff) << 23;
829 if (FPU_st0_tag == TW_Zero) {
832 if (FPU_st0_tag == TW_Infinity) {
835 if (FPU_st0_tag == TW_NaN) {
836 /* See if we can get a valid NaN from
838 templ = FPU_st0_ptr->sigh >> 8;
839 if (!(templ & 0x3fffff)) {
840 /* This case does not seem to
841 * be handled by the 80486
843 EXCEPTION(EX_Invalid);
844 /* Make the quiet NaN "real
850 if (FPU_st0_tag == TW_Empty) {
851 /* Empty register (stack
853 EXCEPTION(EX_StackUnder);
854 if (control_word & EX_Invalid) {
855 /* The masked response */
859 REENTRANT_CHECK(OFF);
860 /* verify_area(VERIFY_WRITE, (void *) single, 4); */
861 suword((unsigned long *) single, 0xffc00000);
867 #if 0 /* TW_Denormal is not used yet, and probably
870 if (FPU_st0_tag == TW_Denormal) {
875 EXCEPTION(EX_Underflow);
880 EXCEPTION(EX_INTERNAL | 0x106);
884 if (FPU_st0_ptr->sign)
887 REENTRANT_CHECK(OFF);
888 /* verify_area(VERIFY_WRITE, (void *) single, 4); */
889 suword((unsigned long *) single, templ);
896 /* Put a long long into user memory */
898 reg_store_int64(void)
900 long long *d = (long long *) FPU_data_address;
904 if (FPU_st0_tag == TW_Empty) {
905 /* Empty register (stack underflow) */
906 EXCEPTION(EX_StackUnder);
907 if (control_word & EX_Invalid) {
908 /* The masked response */
909 /* Put out the QNaN indefinite */
914 reg_move(FPU_st0_ptr, &t);
916 ((long *) &tll)[0] = t.sigl;
917 ((long *) &tll)[1] = t.sigh;
918 if ((t.sigh & 0x80000000) &&
919 !((t.sigh == 0x80000000) && (t.sigl == 0) && (t.sign == SIGN_NEG))) {
920 EXCEPTION(EX_Invalid);
921 /* This is a special case: see sec 16.2.5.1 of the 80486 book */
922 if (control_word & EX_Invalid) {
923 /* Produce "indefinite" */
925 ((long *) &tll)[1] = 0x80000000;
926 ((long *) &tll)[0] = 0;
933 REENTRANT_CHECK(OFF);
934 /* verify_area(VERIFY_WRITE, (void *) d, 8); */
935 suword((unsigned long *) d, ((long *) &tll)[0]);
936 suword(1 + (unsigned long *) d, ((long *) &tll)[1]);
943 /* Put a long into user memory */
945 reg_store_int32(void)
947 long *d = (long *) FPU_data_address;
950 if (FPU_st0_tag == TW_Empty) {
951 /* Empty register (stack underflow) */
952 EXCEPTION(EX_StackUnder);
953 if (control_word & EX_Invalid) {
954 /* The masked response */
955 /* Put out the QNaN indefinite */
956 REENTRANT_CHECK(OFF);
957 /* verify_area(VERIFY_WRITE, d, 4);*/
958 suword((unsigned long *) d, 0x80000000);
964 reg_move(FPU_st0_ptr, &t);
967 ((t.sigl & 0x80000000) &&
968 !((t.sigl == 0x80000000) && (t.sign == SIGN_NEG)))) {
969 EXCEPTION(EX_Invalid);
970 /* This is a special case: see sec 16.2.5.1 of the 80486 book */
971 if (control_word & EX_Invalid) {
972 /* Produce "indefinite" */
978 t.sigl = -(long) t.sigl;
980 REENTRANT_CHECK(OFF);
981 /* verify_area(VERIFY_WRITE, d, 4); */
982 suword((unsigned long *) d, t.sigl);
989 /* Put a short into user memory */
991 reg_store_int16(void)
993 short *d = (short *) FPU_data_address;
997 if (FPU_st0_tag == TW_Empty) {
998 /* Empty register (stack underflow) */
999 EXCEPTION(EX_StackUnder);
1000 if (control_word & EX_Invalid) {
1001 /* The masked response */
1002 /* Put out the QNaN indefinite */
1003 REENTRANT_CHECK(OFF);
1004 /* verify_area(VERIFY_WRITE, d, 2);*/
1005 susword((unsigned short *) d, 0x8000);
1006 REENTRANT_CHECK(ON);
1011 reg_move(FPU_st0_ptr, &t);
1014 ((t.sigl & 0xffff8000) &&
1015 !((t.sigl == 0x8000) && (t.sign == SIGN_NEG)))) {
1016 EXCEPTION(EX_Invalid);
1017 /* This is a special case: see sec 16.2.5.1 of the 80486 book */
1018 if (control_word & EX_Invalid) {
1019 /* Produce "indefinite" */
1027 REENTRANT_CHECK(OFF);
1028 /* verify_area(VERIFY_WRITE, d, 2); */
1029 susword((short *) d, (short) t.sigl);
1030 REENTRANT_CHECK(ON);
1036 /* Put a packed bcd array into user memory */
1040 char *d = (char *) FPU_data_address;
1045 unsigned char sign = (FPU_st0_ptr->sign == SIGN_NEG) ? 0x80 : 0;
1047 if (FPU_st0_tag == TW_Empty) {
1048 /* Empty register (stack underflow) */
1049 EXCEPTION(EX_StackUnder);
1050 if (control_word & EX_Invalid) {
1051 /* The masked response */
1052 /* Put out the QNaN indefinite */
1053 goto put_indefinite;
1057 reg_move(FPU_st0_ptr, &t);
1059 ll = *(long long *) (&t.sigl);
1061 /* Check for overflow, by comparing with 999999999999999999 decimal. */
1062 if ((t.sigh > 0x0de0b6b3) ||
1063 ((t.sigh == 0x0de0b6b3) && (t.sigl > 0xa763ffff))) {
1064 EXCEPTION(EX_Invalid);
1065 /* This is a special case: see sec 16.2.5.1 of the 80486 book */
1066 if (control_word & EX_Invalid) {
1068 /* Produce "indefinite" */
1069 REENTRANT_CHECK(OFF);
1070 /* verify_area(VERIFY_WRITE, d, 10);*/
1071 subyte((unsigned char *) d + 7, 0xff);
1072 subyte((unsigned char *) d + 8, 0xff);
1073 subyte((unsigned char *) d + 9, 0xff);
1074 REENTRANT_CHECK(ON);
1079 /* verify_area(VERIFY_WRITE, d, 10);*/
1080 for (i = 0; i < 9; i++) {
1081 b = div_small(&ll, 10);
1082 b |= (div_small(&ll, 10)) << 4;
1083 REENTRANT_CHECK(OFF);
1084 subyte((unsigned char *) d + i, b);
1085 REENTRANT_CHECK(ON);
1087 REENTRANT_CHECK(OFF);
1088 subyte((unsigned char *) d + 9, sign);
1089 REENTRANT_CHECK(ON);
1093 /*===========================================================================*/
1095 /* r gets mangled such that sig is int, sign:
1096 it is NOT normalized */
1097 /* The return value (in eax) is zero if the result is exact,
1098 if bits are changed due to rounding, truncation, etc, then
1099 a non-zero value is returned */
1100 /* Overflow is signalled by a non-zero return value (in eax).
1101 In the case of overflow, the returned significand always has the
1102 the largest possible value */
1103 /* The value returned in eax is never actually needed :-) */
1105 round_to_int(FPU_REG * r)
1110 if (r->tag == TW_Zero) {
1111 /* Make sure that zero is returned */
1112 *(long long *) &r->sigl = 0;
1113 return 0; /* o.k. */
1115 if (r->exp > EXP_BIAS + 63) {
1116 r->sigl = r->sigh = ~0; /* The largest representable number */
1117 return 1; /* overflow */
1119 eax = shrxs(&r->sigl, EXP_BIAS + 63 - r->exp);
1120 very_big = !(~(r->sigh) | ~(r->sigl)); /* test for 0xfff...fff */
1121 #define half_or_more (eax & 0x80000000)
1122 #define frac_part (eax)
1123 #define more_than_half ((eax & 0x80000001) == 0x80000001)
1124 switch (control_word & CW_RC) {
1126 if (more_than_half /* nearest */
1127 || (half_or_more && (r->sigl & 1))) { /* odd -> even */
1129 return 1; /* overflow */
1130 (*(long long *) (&r->sigl))++;
1135 if (frac_part && r->sign) {
1137 return 1; /* overflow */
1138 (*(long long *) (&r->sigl))++;
1143 if (frac_part && !r->sign) {
1145 return 1; /* overflow */
1146 (*(long long *) (&r->sigl))++;
1154 return eax ? LOST_DOWN : 0;
1157 /*===========================================================================*/
1162 char *s = (char *) FPU_data_address;
1163 unsigned short tag_word = 0;
1167 REENTRANT_CHECK(OFF);
1168 control_word = fusword((unsigned short *) s);
1169 status_word = fusword((unsigned short *) (s + 4));
1170 tag_word = fusword((unsigned short *) (s + 8));
1171 ip_offset = fuword((unsigned long *) (s + 0x0c));
1172 cs_selector = fuword((unsigned long *) (s + 0x10));
1173 data_operand_offset = fuword((unsigned long *) (s + 0x14));
1174 operand_selector = fuword((unsigned long *) (s + 0x18));
1175 REENTRANT_CHECK(ON);
1177 top = (status_word >> SW_Top_Shift) & 7;
1179 for (i = 0; i < 8; i++) {
1185 regs[i].tag = TW_Valid;
1188 regs[i].tag = TW_Zero;
1191 regs[i].tag = TW_NaN;
1194 regs[i].tag = TW_Empty;
1199 /* We want no net effect: */
1200 FPU_data_address = (void *) (intptr_t) data_operand_offset;
1201 FPU_entry_eip = ip_offset; /* We want no net effect */
1212 unsigned short saved_status, saved_control;
1213 char *s = (char *) fldenv();
1215 saved_status = status_word;
1216 saved_control = control_word;
1217 control_word = 0x037f; /* Mask all interrupts while we load. */
1218 for (i = 0; i < 8; i++) {
1219 /* load each register */
1220 FPU_data_address = (void *) (s + i * 10);
1221 reg_load_extended();
1222 stnr = (i + top) & 7;
1223 tag = regs[stnr].tag; /* derived from the loaded tag word */
1224 reg_move(&FPU_loaded_data, ®s[stnr]);
1225 if (tag == TW_NaN) {
1226 /* The current data is a special, i.e. NaN,
1227 * unsupported, infinity, or denormal */
1228 unsigned char t = regs[stnr].tag; /* derived from the new
1230 if ( /* (t == TW_Valid) || *** */ (t == TW_Zero))
1231 regs[stnr].tag = TW_NaN;
1233 regs[stnr].tag = tag;
1235 control_word = saved_control;
1236 status_word = saved_status;
1238 /* We want no net effect: */
1239 FPU_data_address = (void *) (intptr_t) data_operand_offset;
1246 unsigned short word = 0;
1250 for (i = 7; i >= 0; i--) {
1251 switch (tag = regs[i].tag) {
1252 #if 0 /* TW_Denormal is not used yet, and probably
1257 if (regs[i].exp <= (EXP_BIAS - EXTENDED_Ebias))
1267 /* TW_Valid and TW_Zero already have the correct value */
1279 char *d = (char *) FPU_data_address;
1281 /* verify_area(VERIFY_WRITE, d, 28);*/
1284 *(unsigned short *) &cs_selector = fpu_cs;
1285 *(unsigned short *) &operand_selector = fpu_os;
1288 REENTRANT_CHECK(OFF);
1289 susword((unsigned short *) d, control_word);
1290 susword((unsigned short *) (d + 4), (status_word & ~SW_Top) | ((top & 7) << SW_Top_Shift));
1291 susword((unsigned short *) (d + 8), tag_word());
1292 suword((unsigned long *) (d + 0x0c), ip_offset);
1293 suword((unsigned long *) (d + 0x10), cs_selector);
1294 suword((unsigned long *) (d + 0x14), data_operand_offset);
1295 suword((unsigned long *) (d + 0x18), operand_selector);
1296 REENTRANT_CHECK(ON);
1311 /* verify_area(VERIFY_WRITE, d, 80);*/
1312 for (i = 0; i < 8; i++) {
1313 /* Store each register in the order: st(0), st(1), ... */
1314 rp = ®s[(top + i) & 7];
1316 e = rp->exp - EXP_BIAS + EXTENDED_Ebias;
1318 if (rp->tag == TW_Valid) {
1320 /* Overflow to infinity */
1321 REENTRANT_CHECK(OFF);
1322 suword((unsigned long *) (d + i * 10), 0);
1323 suword((unsigned long *) (d + i * 10 + 4), 0);
1324 REENTRANT_CHECK(ON);
1329 /* Make a de-normal */
1331 tmp.exp += -EXTENDED_Emin + 63; /* largest exp to be 62 */
1333 REENTRANT_CHECK(OFF);
1334 suword((unsigned long *) (d + i * 10), tmp.sigl);
1335 suword((unsigned long *) (d + i * 10 + 4), tmp.sigh);
1336 REENTRANT_CHECK(ON);
1338 /* Underflow to zero */
1339 REENTRANT_CHECK(OFF);
1340 suword((unsigned long *) (d + i * 10), 0);
1341 suword((unsigned long *) (d + i * 10 + 4), 0);
1342 REENTRANT_CHECK(ON);
1346 REENTRANT_CHECK(OFF);
1347 suword((unsigned long *) (d + i * 10), rp->sigl);
1348 suword((unsigned long *) (d + i * 10 + 4), rp->sigh);
1349 REENTRANT_CHECK(ON);
1352 if (rp->tag == TW_Zero) {
1353 REENTRANT_CHECK(OFF);
1354 suword((unsigned long *) (d + i * 10), 0);
1355 suword((unsigned long *) (d + i * 10 + 4), 0);
1356 REENTRANT_CHECK(ON);
1359 if (rp->tag == TW_Infinity) {
1360 REENTRANT_CHECK(OFF);
1361 suword((unsigned long *) (d + i * 10), 0);
1362 suword((unsigned long *) (d + i * 10 + 4), 0x80000000);
1363 REENTRANT_CHECK(ON);
1366 if (rp->tag == TW_NaN) {
1367 REENTRANT_CHECK(OFF);
1368 suword((unsigned long *) (d + i * 10), rp->sigl);
1369 suword((unsigned long *) (d + i * 10 + 4), rp->sigh);
1370 REENTRANT_CHECK(ON);
1373 if (rp->tag == TW_Empty) {
1374 /* just copy the reg */
1375 REENTRANT_CHECK(OFF);
1376 suword((unsigned long *) (d + i * 10), rp->sigl);
1377 suword((unsigned long *) (d + i * 10 + 4), rp->sigh);
1378 REENTRANT_CHECK(ON);
1380 e |= rp->sign == SIGN_POS ? 0 : 0x8000;
1381 REENTRANT_CHECK(OFF);
1382 susword((unsigned short *) (d + i * 10 + 8), e);
1383 REENTRANT_CHECK(ON);
1389 /*===========================================================================*/