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 $
64 /*---------------------------------------------------------------------------+
66 | The file contains code which accesses user memory. |
67 | Emulator static data may change when user memory is accessed, due to |
68 | other processes using the emulator while swapping is in progress. |
69 +---------------------------------------------------------------------------*/
70 #include <sys/param.h>
72 #include <sys/systm.h>
73 #include <machine/pcb.h>
75 #include <gnu/i386/fpemul/fpu_emu.h>
76 #include <gnu/i386/fpemul/fpu_system.h>
77 #include <gnu/i386/fpemul/exception.h>
78 #include <gnu/i386/fpemul/reg_constant.h>
79 #include <gnu/i386/fpemul/control_w.h>
80 #include <gnu/i386/fpemul/status_w.h>
83 #define EXTENDED_Emax 0x3fff /* largest valid exponent */
84 #define EXTENDED_Ebias 0x3fff
85 #define EXTENDED_Emin (-0x3ffe) /* smallest valid exponent */
87 #define DOUBLE_Emax 1023 /* largest valid exponent */
88 #define DOUBLE_Ebias 1023
89 #define DOUBLE_Emin (-1022) /* smallest valid exponent */
91 #define SINGLE_Emax 127 /* largest valid exponent */
92 #define SINGLE_Ebias 127
93 #define SINGLE_Emin (-126) /* smallest valid exponent */
95 #define LOST_UP (EX_Precision | SW_C1)
96 #define LOST_DOWN EX_Precision
98 FPU_REG FPU_loaded_data;
101 /* Get a long double from user memory */
103 reg_load_extended(void)
105 long double *s = (long double *) FPU_data_address;
106 unsigned long sigl, sigh, exp;
108 REENTRANT_CHECK(OFF);
109 /* Use temporary variables here because FPU_loaded data is static and
110 * hence re-entrancy problems can arise */
111 sigl = fuword((unsigned long *) s);
112 sigh = fuword(1 + (unsigned long *) s);
113 exp = fusword(4 + (unsigned short *) s);
116 FPU_loaded_data.sigl = sigl;
117 FPU_loaded_data.sigh = sigh;
118 FPU_loaded_data.exp = exp;
120 if (FPU_loaded_data.exp & 0x8000)
121 FPU_loaded_data.sign = SIGN_NEG;
123 FPU_loaded_data.sign = SIGN_POS;
124 if ((FPU_loaded_data.exp &= 0x7fff) == 0) {
125 if (!(FPU_loaded_data.sigl | FPU_loaded_data.sigh)) {
126 FPU_loaded_data.tag = TW_Zero;
129 /* The number is a de-normal or pseudodenormal. */
130 /* The 80486 doesn't regard pseudodenormals as denormals here. */
131 if (!(FPU_loaded_data.sigh & 0x80000000))
132 EXCEPTION(EX_Denormal);
133 FPU_loaded_data.exp++;
135 /* The default behaviour will now take care of it. */
137 if (FPU_loaded_data.exp == 0x7fff) {
138 FPU_loaded_data.exp = EXTENDED_Emax;
139 if ((FPU_loaded_data.sigh == 0x80000000)
140 && (FPU_loaded_data.sigl == 0)) {
141 FPU_loaded_data.tag = TW_Infinity;
144 if (!(FPU_loaded_data.sigh & 0x80000000)) {
145 /* Unsupported NaN data type */
146 EXCEPTION(EX_Invalid);
147 FPU_loaded_data.tag = TW_NaN;
150 FPU_loaded_data.tag = TW_NaN;
153 FPU_loaded_data.exp = (FPU_loaded_data.exp & 0x7fff) - EXTENDED_Ebias
155 FPU_loaded_data.tag = TW_Valid;
157 if (!(sigh & 0x80000000)) {
158 /* Unsupported data type */
159 EXCEPTION(EX_Invalid);
160 normalize_nuo(&FPU_loaded_data);
165 /* Get a double from user memory */
167 reg_load_double(void)
169 double *dfloat = (double *) FPU_data_address;
173 REENTRANT_CHECK(OFF);
174 m64 = fuword(1 + (unsigned long *) dfloat);
175 l64 = fuword((unsigned long *) dfloat);
178 if (m64 & 0x80000000)
179 FPU_loaded_data.sign = SIGN_NEG;
181 FPU_loaded_data.sign = SIGN_POS;
182 exp = ((m64 & 0x7ff00000) >> 20) - DOUBLE_Ebias;
184 if (exp > DOUBLE_Emax) {
185 /* Infinity or NaN */
186 if ((m64 == 0) && (l64 == 0)) {
188 FPU_loaded_data.exp = EXTENDED_Emax;
189 FPU_loaded_data.tag = TW_Infinity;
192 /* Must be a signaling or quiet NaN */
193 FPU_loaded_data.exp = EXTENDED_Emax;
194 FPU_loaded_data.tag = TW_NaN;
195 FPU_loaded_data.sigh = (m64 << 11) | 0x80000000;
196 FPU_loaded_data.sigh |= l64 >> 21;
197 FPU_loaded_data.sigl = l64 << 11;
201 if (exp < DOUBLE_Emin) {
202 /* Zero or de-normal */
203 if ((m64 == 0) && (l64 == 0)) {
205 int c = FPU_loaded_data.sign;
206 reg_move(&CONST_Z, &FPU_loaded_data);
207 FPU_loaded_data.sign = c;
211 EXCEPTION(EX_Denormal);
212 FPU_loaded_data.exp = DOUBLE_Emin + EXP_BIAS;
213 FPU_loaded_data.tag = TW_Valid;
214 FPU_loaded_data.sigh = m64 << 11;
215 FPU_loaded_data.sigh |= l64 >> 21;
216 FPU_loaded_data.sigl = l64 << 11;
217 normalize_nuo(&FPU_loaded_data);
221 FPU_loaded_data.exp = exp + EXP_BIAS;
222 FPU_loaded_data.tag = TW_Valid;
223 FPU_loaded_data.sigh = (m64 << 11) | 0x80000000;
224 FPU_loaded_data.sigh |= l64 >> 21;
225 FPU_loaded_data.sigl = l64 << 11;
232 /* Get a float from user memory */
234 reg_load_single(void)
236 float *single = (float *) FPU_data_address;
240 REENTRANT_CHECK(OFF);
241 m32 = fuword((unsigned long *) single);
244 if (m32 & 0x80000000)
245 FPU_loaded_data.sign = SIGN_NEG;
247 FPU_loaded_data.sign = SIGN_POS;
248 if (!(m32 & 0x7fffffff)) {
250 int c = FPU_loaded_data.sign;
251 reg_move(&CONST_Z, &FPU_loaded_data);
252 FPU_loaded_data.sign = c;
255 exp = ((m32 & 0x7f800000) >> 23) - SINGLE_Ebias;
256 m32 = (m32 & 0x7fffff) << 8;
257 if (exp < SINGLE_Emin) {
259 EXCEPTION(EX_Denormal);
260 FPU_loaded_data.exp = SINGLE_Emin + EXP_BIAS;
261 FPU_loaded_data.tag = TW_Valid;
262 FPU_loaded_data.sigh = m32;
263 FPU_loaded_data.sigl = 0;
264 normalize_nuo(&FPU_loaded_data);
267 if (exp > SINGLE_Emax) {
268 /* Infinity or NaN */
271 FPU_loaded_data.exp = EXTENDED_Emax;
272 FPU_loaded_data.tag = TW_Infinity;
275 /* Must be a signaling or quiet NaN */
276 FPU_loaded_data.exp = EXTENDED_Emax;
277 FPU_loaded_data.tag = TW_NaN;
278 FPU_loaded_data.sigh = m32 | 0x80000000;
279 FPU_loaded_data.sigl = 0;
283 FPU_loaded_data.exp = exp + EXP_BIAS;
284 FPU_loaded_data.sigh = m32 | 0x80000000;
285 FPU_loaded_data.sigl = 0;
286 FPU_loaded_data.tag = TW_Valid;
291 /* Get a long long from user memory */
295 long long *_s = (long long *) FPU_data_address;
299 REENTRANT_CHECK(OFF);
300 ((unsigned long *) &s)[0] = fuword((unsigned long *) _s);
301 ((unsigned long *) &s)[1] = fuword(1 + (unsigned long *) _s);
305 reg_move(&CONST_Z, &FPU_loaded_data);
309 FPU_loaded_data.sign = SIGN_POS;
312 FPU_loaded_data.sign = SIGN_NEG;
316 *((long long *) &FPU_loaded_data.sigl) = s;
317 FPU_loaded_data.exp = e;
318 FPU_loaded_data.tag = TW_Valid;
319 normalize_nuo(&FPU_loaded_data);
323 /* Get a long from user memory */
327 long *_s = (long *) FPU_data_address;
331 REENTRANT_CHECK(OFF);
332 s = (long) fuword((unsigned long *) _s);
336 reg_move(&CONST_Z, &FPU_loaded_data);
340 FPU_loaded_data.sign = SIGN_POS;
343 FPU_loaded_data.sign = SIGN_NEG;
347 FPU_loaded_data.sigh = s;
348 FPU_loaded_data.sigl = 0;
349 FPU_loaded_data.exp = e;
350 FPU_loaded_data.tag = TW_Valid;
351 normalize_nuo(&FPU_loaded_data);
355 /* Get a short from user memory */
359 short *_s = (short *) FPU_data_address;
362 REENTRANT_CHECK(OFF);
363 /* Cast as short to get the sign extended. */
364 s = (short) fusword((unsigned short *) _s);
368 reg_move(&CONST_Z, &FPU_loaded_data);
372 FPU_loaded_data.sign = SIGN_POS;
375 FPU_loaded_data.sign = SIGN_NEG;
379 FPU_loaded_data.sigh = s << 16;
381 FPU_loaded_data.sigl = 0;
382 FPU_loaded_data.exp = e;
383 FPU_loaded_data.tag = TW_Valid;
384 normalize_nuo(&FPU_loaded_data);
388 /* Get a packed bcd array from user memory */
392 char *s = (char *) FPU_data_address;
397 for (pos = 8; pos >= 0; pos--) {
399 REENTRANT_CHECK(OFF);
400 bcd = (unsigned char) fubyte((unsigned char *) s + pos);
407 /* Finish all access to user memory before putting stuff into the
408 * static FPU_loaded_data */
409 REENTRANT_CHECK(OFF);
410 FPU_loaded_data.sign =
411 ((unsigned char) fubyte((unsigned char *) s + 9)) & 0x80 ?
416 char sign = FPU_loaded_data.sign;
417 reg_move(&CONST_Z, &FPU_loaded_data);
418 FPU_loaded_data.sign = sign;
420 *((long long *) &FPU_loaded_data.sigl) = l;
421 FPU_loaded_data.exp = EXP_BIAS + 63;
422 FPU_loaded_data.tag = TW_Valid;
423 normalize_nuo(&FPU_loaded_data);
426 /*===========================================================================*/
428 /* Put a long double into user memory */
430 reg_store_extended(void)
432 long double *d = (long double *) FPU_data_address;
433 long e = FPU_st0_ptr->exp - EXP_BIAS + EXTENDED_Ebias;
434 unsigned short sign = FPU_st0_ptr->sign * 0x8000;
435 unsigned long ls, ms;
438 if (FPU_st0_tag == TW_Valid) {
440 EXCEPTION(EX_Overflow); /* Overflow */
441 /* This is a special case: see sec 16.2.5.1 of the
443 if (control_word & EX_Overflow) {
444 /* Overflow to infinity */
453 /* Correctly format the de-normal */
457 EXCEPTION(EX_Denormal);
458 reg_move(FPU_st0_ptr, &tmp);
459 tmp.exp += -EXTENDED_Emin + 63; /* largest exp to be 62 */
460 if ((precision_loss = round_to_int(&tmp))) {
461 EXCEPTION(EX_Underflow | precision_loss);
462 /* This is a special case: see
463 * sec 16.2.5.1 of the 80486
465 if (!(control_word & EX_Underflow))
472 /* ****** ??? This should not be
474 EXCEPTION(EX_Underflow); /* Underflow */
475 /* This is a special case: see sec
476 * 16.2.5.1 of the 80486 book */
477 if (control_word & EX_Underflow) {
478 /* Underflow to zero */
481 e = FPU_st0_ptr->sign == SIGN_POS ? 0x7fff : 0xffff;
486 ls = FPU_st0_ptr->sigl;
487 ms = FPU_st0_ptr->sigh;
490 if (FPU_st0_tag == TW_Zero) {
494 if (FPU_st0_tag == TW_Infinity) {
499 if (FPU_st0_tag == TW_NaN) {
500 ls = FPU_st0_ptr->sigl;
501 ms = FPU_st0_ptr->sigh;
504 if (FPU_st0_tag == TW_Empty) {
505 /* Empty register (stack
507 EXCEPTION(EX_StackUnder);
508 if (control_word & EX_Invalid) {
509 /* The masked response */
518 /* We don't use TW_Denormal
519 * yet ... perhaps never! */
520 EXCEPTION(EX_Invalid);
526 REENTRANT_CHECK(OFF);
527 /* verify_area(VERIFY_WRITE, d, 10); */
528 suword((unsigned long *) d, ls);
529 suword(1 + (unsigned long *) d, ms);
530 susword(4 + (short *) d, (unsigned short) e | sign);
538 /* Put a double into user memory */
540 reg_store_double(void)
542 double *dfloat = (double *) FPU_data_address;
544 if (FPU_st0_tag == TW_Valid) {
548 reg_move(FPU_st0_ptr, &tmp);
549 exp = tmp.exp - EXP_BIAS;
551 if (exp < DOUBLE_Emin) { /* It may be a denormal */
552 /* Make a de-normal */
555 if (exp <= -EXTENDED_Ebias)
556 EXCEPTION(EX_Denormal);
558 tmp.exp += -DOUBLE_Emin + 52; /* largest exp to be 51 */
560 if ((precision_loss = round_to_int(&tmp))) {
562 /* Did it round to a non-denormal ? */
563 /* This behaviour might be regarded as
564 * peculiar, it appears that the 80486 rounds
565 * to the dest precision, then converts to
566 * decide underflow. */
567 if ((tmp.sigh == 0x00100000) && (tmp.sigl == 0) &&
568 (FPU_st0_ptr->sigl & 0x000007ff))
569 EXCEPTION(precision_loss);
571 #endif /* PECULIAR_486 */
573 EXCEPTION(EX_Underflow | precision_loss);
574 /* This is a special case: see sec
575 * 16.2.5.1 of the 80486 book */
576 if (!(control_word & EX_Underflow))
583 if (tmp.sigl & 0x000007ff) {
584 unsigned long increment = 0; /* avoid gcc warnings */
586 switch (control_word & CW_RC) {
588 /* Rounding can get a little messy.. */
589 increment = ((tmp.sigl & 0x7ff) > 0x400) | /* nearest */
590 ((tmp.sigl & 0xc00) == 0xc00); /* odd -> even */
592 case RC_DOWN: /* towards -infinity */
593 increment = (tmp.sign == SIGN_POS) ? 0 : tmp.sigl & 0x7ff;
595 case RC_UP: /* towards +infinity */
596 increment = (tmp.sign == SIGN_POS) ? tmp.sigl & 0x7ff : 0;
603 /* Truncate the mantissa */
604 tmp.sigl &= 0xfffff800;
607 set_precision_flag_up();
609 if (tmp.sigl >= 0xfffff800) {
610 /* the sigl part overflows */
611 if (tmp.sigh == 0xffffffff) {
614 tmp.sigh = 0x80000000;
621 tmp.sigl = 0x00000000;
623 /* We only need to increment
625 tmp.sigl += 0x00000800;
628 set_precision_flag_down();
630 l[0] = (tmp.sigl >> 11) | (tmp.sigh << 21);
631 l[1] = ((tmp.sigh >> 11) & 0xfffff);
633 if (exp > DOUBLE_Emax) {
635 EXCEPTION(EX_Overflow);
636 /* This is a special case: see sec 16.2.5.1 of
638 if (control_word & EX_Overflow) {
639 /* Overflow to infinity */
640 l[0] = 0x00000000; /* Set to */
641 l[1] = 0x7ff00000; /* + INF */
645 /* Add the exponent */
646 l[1] |= (((exp + DOUBLE_Ebias) & 0x7ff) << 20);
650 if (FPU_st0_tag == TW_Zero) {
655 if (FPU_st0_tag == TW_Infinity) {
659 if (FPU_st0_tag == TW_NaN) {
660 /* See if we can get a valid NaN from
662 l[0] = (FPU_st0_ptr->sigl >> 11) | (FPU_st0_ptr->sigh << 21);
663 l[1] = ((FPU_st0_ptr->sigh >> 11) & 0xfffff);
664 if (!(l[0] | l[1])) {
665 /* This case does not seem to
666 * be handled by the 80486
668 EXCEPTION(EX_Invalid);
669 /* Make the quiet NaN "real
675 if (FPU_st0_tag == TW_Empty) {
676 /* Empty register (stack
678 EXCEPTION(EX_StackUnder);
679 if (control_word & EX_Invalid) {
680 /* The masked response */
684 REENTRANT_CHECK(OFF);
685 /* verify_area(VERIFY_W
688 suword((unsigned long *) dfloat, 0);
689 suword(1 + (unsigned long *) dfloat, 0xfff80000);
695 #if 0 /* TW_Denormal is not used yet, and probably
698 if (FPU_st0_tag == TW_Denormal) {
701 * always underflow */
703 EXCEPTION(EX_Underflow);
706 if (FPU_st0_ptr->sign)
709 REENTRANT_CHECK(OFF);
710 /* verify_area(VERIFY_WRITE, (void *) dfloat, 8);*/
711 suword((u_long *) dfloat, l[0]);
712 suword((u_long *) dfloat + 1, l[1]);
714 suword(l[0], (unsigned long *) dfloat);
715 suword(l[1], 1 + (unsigned long *) dfloat);*/
722 /* Put a float into user memory */
724 reg_store_single(void)
726 float *single = (float *) FPU_data_address;
729 if (FPU_st0_tag == TW_Valid) {
733 reg_move(FPU_st0_ptr, &tmp);
734 exp = tmp.exp - EXP_BIAS;
736 if (exp < SINGLE_Emin) {
737 /* Make a de-normal */
740 if (exp <= -EXTENDED_Ebias)
741 EXCEPTION(EX_Denormal);
743 tmp.exp += -SINGLE_Emin + 23; /* largest exp to be 22 */
745 if ((precision_loss = round_to_int(&tmp))) {
747 /* Did it round to a non-denormal ? */
748 /* This behaviour might be regarded as
749 * peculiar, it appears that the 80486 rounds
750 * to the dest precision, then converts to
751 * decide underflow. */
752 if ((tmp.sigl == 0x00800000) &&
753 ((FPU_st0_ptr->sigh & 0x000000ff) || FPU_st0_ptr->sigl))
754 EXCEPTION(precision_loss);
756 #endif /* PECULIAR_486 */
758 EXCEPTION(EX_Underflow | precision_loss);
759 /* This is a special case: see sec
760 * 16.2.5.1 of the 80486 book */
761 if (!(control_word & EX_Underflow))
767 if (tmp.sigl | (tmp.sigh & 0x000000ff)) {
768 unsigned long increment = 0; /* avoid gcc warnings */
769 unsigned long sigh = tmp.sigh;
770 unsigned long sigl = tmp.sigl;
772 switch (control_word & CW_RC) {
774 increment = ((sigh & 0xff) > 0x80) /* more than half */
775 ||(((sigh & 0xff) == 0x80) && sigl) /* more than half */
776 ||((sigh & 0x180) == 0x180); /* round to even */
778 case RC_DOWN: /* towards -infinity */
779 increment = (tmp.sign == SIGN_POS)
780 ? 0 : (sigl | (sigh & 0xff));
782 case RC_UP: /* towards +infinity */
783 increment = (tmp.sign == SIGN_POS)
784 ? (sigl | (sigh & 0xff)) : 0;
791 /* Truncate part of the mantissa */
795 set_precision_flag_up();
797 if (sigh >= 0xffffff00) {
798 /* The sigh part overflows */
799 tmp.sigh = 0x80000000;
804 tmp.sigh &= 0xffffff00;
808 set_precision_flag_down();
809 tmp.sigh &= 0xffffff00; /* Finish the truncation */
812 templ = (tmp.sigh >> 8) & 0x007fffff;
814 if (exp > SINGLE_Emax) {
816 EXCEPTION(EX_Overflow);
817 /* This is a special case: see sec 16.2.5.1 of
819 if (control_word & EX_Overflow) {
820 /* Overflow to infinity */
825 templ |= ((exp + SINGLE_Ebias) & 0xff) << 23;
828 if (FPU_st0_tag == TW_Zero) {
831 if (FPU_st0_tag == TW_Infinity) {
834 if (FPU_st0_tag == TW_NaN) {
835 /* See if we can get a valid NaN from
837 templ = FPU_st0_ptr->sigh >> 8;
838 if (!(templ & 0x3fffff)) {
839 /* This case does not seem to
840 * be handled by the 80486
842 EXCEPTION(EX_Invalid);
843 /* Make the quiet NaN "real
849 if (FPU_st0_tag == TW_Empty) {
850 /* Empty register (stack
852 EXCEPTION(EX_StackUnder);
853 if (control_word & EX_Invalid) {
854 /* The masked response */
858 REENTRANT_CHECK(OFF);
859 /* verify_area(VERIFY_WRITE, (void *) single, 4); */
860 suword((unsigned long *) single, 0xffc00000);
866 #if 0 /* TW_Denormal is not used yet, and probably
869 if (FPU_st0_tag == TW_Denormal) {
874 EXCEPTION(EX_Underflow);
879 EXCEPTION(EX_INTERNAL | 0x106);
883 if (FPU_st0_ptr->sign)
886 REENTRANT_CHECK(OFF);
887 /* verify_area(VERIFY_WRITE, (void *) single, 4); */
888 suword((unsigned long *) single, templ);
895 /* Put a long long into user memory */
897 reg_store_int64(void)
899 long long *d = (long long *) FPU_data_address;
903 if (FPU_st0_tag == TW_Empty) {
904 /* Empty register (stack underflow) */
905 EXCEPTION(EX_StackUnder);
906 if (control_word & EX_Invalid) {
907 /* The masked response */
908 /* Put out the QNaN indefinite */
913 reg_move(FPU_st0_ptr, &t);
915 ((long *) &tll)[0] = t.sigl;
916 ((long *) &tll)[1] = t.sigh;
917 if ((t.sigh & 0x80000000) &&
918 !((t.sigh == 0x80000000) && (t.sigl == 0) && (t.sign == SIGN_NEG))) {
919 EXCEPTION(EX_Invalid);
920 /* This is a special case: see sec 16.2.5.1 of the 80486 book */
921 if (control_word & EX_Invalid) {
922 /* Produce "indefinite" */
924 ((long *) &tll)[1] = 0x80000000;
925 ((long *) &tll)[0] = 0;
932 REENTRANT_CHECK(OFF);
933 /* verify_area(VERIFY_WRITE, (void *) d, 8); */
934 suword((unsigned long *) d, ((long *) &tll)[0]);
935 suword(1 + (unsigned long *) d, ((long *) &tll)[1]);
942 /* Put a long into user memory */
944 reg_store_int32(void)
946 long *d = (long *) FPU_data_address;
949 if (FPU_st0_tag == TW_Empty) {
950 /* Empty register (stack underflow) */
951 EXCEPTION(EX_StackUnder);
952 if (control_word & EX_Invalid) {
953 /* The masked response */
954 /* Put out the QNaN indefinite */
955 REENTRANT_CHECK(OFF);
956 /* verify_area(VERIFY_WRITE, d, 4);*/
957 suword((unsigned long *) d, 0x80000000);
963 reg_move(FPU_st0_ptr, &t);
966 ((t.sigl & 0x80000000) &&
967 !((t.sigl == 0x80000000) && (t.sign == SIGN_NEG)))) {
968 EXCEPTION(EX_Invalid);
969 /* This is a special case: see sec 16.2.5.1 of the 80486 book */
970 if (control_word & EX_Invalid) {
971 /* Produce "indefinite" */
977 t.sigl = -(long) t.sigl;
979 REENTRANT_CHECK(OFF);
980 /* verify_area(VERIFY_WRITE, d, 4); */
981 suword((unsigned long *) d, t.sigl);
988 /* Put a short into user memory */
990 reg_store_int16(void)
992 short *d = (short *) FPU_data_address;
996 if (FPU_st0_tag == TW_Empty) {
997 /* Empty register (stack underflow) */
998 EXCEPTION(EX_StackUnder);
999 if (control_word & EX_Invalid) {
1000 /* The masked response */
1001 /* Put out the QNaN indefinite */
1002 REENTRANT_CHECK(OFF);
1003 /* verify_area(VERIFY_WRITE, d, 2);*/
1004 susword((unsigned short *) d, 0x8000);
1005 REENTRANT_CHECK(ON);
1010 reg_move(FPU_st0_ptr, &t);
1013 ((t.sigl & 0xffff8000) &&
1014 !((t.sigl == 0x8000) && (t.sign == SIGN_NEG)))) {
1015 EXCEPTION(EX_Invalid);
1016 /* This is a special case: see sec 16.2.5.1 of the 80486 book */
1017 if (control_word & EX_Invalid) {
1018 /* Produce "indefinite" */
1026 REENTRANT_CHECK(OFF);
1027 /* verify_area(VERIFY_WRITE, d, 2); */
1028 susword((short *) d, (short) t.sigl);
1029 REENTRANT_CHECK(ON);
1035 /* Put a packed bcd array into user memory */
1039 char *d = (char *) FPU_data_address;
1044 unsigned char sign = (FPU_st0_ptr->sign == SIGN_NEG) ? 0x80 : 0;
1046 if (FPU_st0_tag == TW_Empty) {
1047 /* Empty register (stack underflow) */
1048 EXCEPTION(EX_StackUnder);
1049 if (control_word & EX_Invalid) {
1050 /* The masked response */
1051 /* Put out the QNaN indefinite */
1052 goto put_indefinite;
1056 reg_move(FPU_st0_ptr, &t);
1058 ll = *(long long *) (&t.sigl);
1060 /* Check for overflow, by comparing with 999999999999999999 decimal. */
1061 if ((t.sigh > 0x0de0b6b3) ||
1062 ((t.sigh == 0x0de0b6b3) && (t.sigl > 0xa763ffff))) {
1063 EXCEPTION(EX_Invalid);
1064 /* This is a special case: see sec 16.2.5.1 of the 80486 book */
1065 if (control_word & EX_Invalid) {
1067 /* Produce "indefinite" */
1068 REENTRANT_CHECK(OFF);
1069 /* verify_area(VERIFY_WRITE, d, 10);*/
1070 subyte((unsigned char *) d + 7, 0xff);
1071 subyte((unsigned char *) d + 8, 0xff);
1072 subyte((unsigned char *) d + 9, 0xff);
1073 REENTRANT_CHECK(ON);
1078 /* verify_area(VERIFY_WRITE, d, 10);*/
1079 for (i = 0; i < 9; i++) {
1080 b = div_small(&ll, 10);
1081 b |= (div_small(&ll, 10)) << 4;
1082 REENTRANT_CHECK(OFF);
1083 subyte((unsigned char *) d + i, b);
1084 REENTRANT_CHECK(ON);
1086 REENTRANT_CHECK(OFF);
1087 subyte((unsigned char *) d + 9, sign);
1088 REENTRANT_CHECK(ON);
1092 /*===========================================================================*/
1094 /* r gets mangled such that sig is int, sign:
1095 it is NOT normalized */
1096 /* The return value (in eax) is zero if the result is exact,
1097 if bits are changed due to rounding, truncation, etc, then
1098 a non-zero value is returned */
1099 /* Overflow is signalled by a non-zero return value (in eax).
1100 In the case of overflow, the returned significand always has the
1101 the largest possible value */
1102 /* The value returned in eax is never actually needed :-) */
1104 round_to_int(FPU_REG * r)
1109 if (r->tag == TW_Zero) {
1110 /* Make sure that zero is returned */
1111 *(long long *) &r->sigl = 0;
1112 return 0; /* o.k. */
1114 if (r->exp > EXP_BIAS + 63) {
1115 r->sigl = r->sigh = ~0; /* The largest representable number */
1116 return 1; /* overflow */
1118 eax = shrxs(&r->sigl, EXP_BIAS + 63 - r->exp);
1119 very_big = !(~(r->sigh) | ~(r->sigl)); /* test for 0xfff...fff */
1120 #define half_or_more (eax & 0x80000000)
1121 #define frac_part (eax)
1122 #define more_than_half ((eax & 0x80000001) == 0x80000001)
1123 switch (control_word & CW_RC) {
1125 if (more_than_half /* nearest */
1126 || (half_or_more && (r->sigl & 1))) { /* odd -> even */
1128 return 1; /* overflow */
1129 (*(long long *) (&r->sigl))++;
1134 if (frac_part && r->sign) {
1136 return 1; /* overflow */
1137 (*(long long *) (&r->sigl))++;
1142 if (frac_part && !r->sign) {
1144 return 1; /* overflow */
1145 (*(long long *) (&r->sigl))++;
1153 return eax ? LOST_DOWN : 0;
1156 /*===========================================================================*/
1161 char *s = (char *) FPU_data_address;
1162 unsigned short tag_word = 0;
1166 REENTRANT_CHECK(OFF);
1167 control_word = fusword((unsigned short *) s);
1168 status_word = fusword((unsigned short *) (s + 4));
1169 tag_word = fusword((unsigned short *) (s + 8));
1170 ip_offset = fuword((unsigned long *) (s + 0x0c));
1171 cs_selector = fuword((unsigned long *) (s + 0x10));
1172 data_operand_offset = fuword((unsigned long *) (s + 0x14));
1173 operand_selector = fuword((unsigned long *) (s + 0x18));
1174 REENTRANT_CHECK(ON);
1176 top = (status_word >> SW_Top_Shift) & 7;
1178 for (i = 0; i < 8; i++) {
1184 regs[i].tag = TW_Valid;
1187 regs[i].tag = TW_Zero;
1190 regs[i].tag = TW_NaN;
1193 regs[i].tag = TW_Empty;
1198 /* We want no net effect: */
1199 FPU_data_address = (void *) (intptr_t) data_operand_offset;
1200 FPU_entry_eip = ip_offset; /* We want no net effect */
1211 unsigned short saved_status, saved_control;
1212 char *s = (char *) fldenv();
1214 saved_status = status_word;
1215 saved_control = control_word;
1216 control_word = 0x037f; /* Mask all interrupts while we load. */
1217 for (i = 0; i < 8; i++) {
1218 /* load each register */
1219 FPU_data_address = (void *) (s + i * 10);
1220 reg_load_extended();
1221 stnr = (i + top) & 7;
1222 tag = regs[stnr].tag; /* derived from the loaded tag word */
1223 reg_move(&FPU_loaded_data, ®s[stnr]);
1224 if (tag == TW_NaN) {
1225 /* The current data is a special, i.e. NaN,
1226 * unsupported, infinity, or denormal */
1227 unsigned char t = regs[stnr].tag; /* derived from the new
1229 if ( /* (t == TW_Valid) || *** */ (t == TW_Zero))
1230 regs[stnr].tag = TW_NaN;
1232 regs[stnr].tag = tag;
1234 control_word = saved_control;
1235 status_word = saved_status;
1237 /* We want no net effect: */
1238 FPU_data_address = (void *) (intptr_t) data_operand_offset;
1245 unsigned short word = 0;
1249 for (i = 7; i >= 0; i--) {
1250 switch (tag = regs[i].tag) {
1251 #if 0 /* TW_Denormal is not used yet, and probably
1256 if (regs[i].exp <= (EXP_BIAS - EXTENDED_Ebias))
1266 /* TW_Valid and TW_Zero already have the correct value */
1278 char *d = (char *) FPU_data_address;
1280 /* verify_area(VERIFY_WRITE, d, 28);*/
1283 *(unsigned short *) &cs_selector = fpu_cs;
1284 *(unsigned short *) &operand_selector = fpu_os;
1287 REENTRANT_CHECK(OFF);
1288 susword((unsigned short *) d, control_word);
1289 susword((unsigned short *) (d + 4), (status_word & ~SW_Top) | ((top & 7) << SW_Top_Shift));
1290 susword((unsigned short *) (d + 8), tag_word());
1291 suword((unsigned long *) (d + 0x0c), ip_offset);
1292 suword((unsigned long *) (d + 0x10), cs_selector);
1293 suword((unsigned long *) (d + 0x14), data_operand_offset);
1294 suword((unsigned long *) (d + 0x18), operand_selector);
1295 REENTRANT_CHECK(ON);
1310 /* verify_area(VERIFY_WRITE, d, 80);*/
1311 for (i = 0; i < 8; i++) {
1312 /* Store each register in the order: st(0), st(1), ... */
1313 rp = ®s[(top + i) & 7];
1315 e = rp->exp - EXP_BIAS + EXTENDED_Ebias;
1317 if (rp->tag == TW_Valid) {
1319 /* Overflow to infinity */
1320 REENTRANT_CHECK(OFF);
1321 suword((unsigned long *) (d + i * 10), 0);
1322 suword((unsigned long *) (d + i * 10 + 4), 0);
1323 REENTRANT_CHECK(ON);
1328 /* Make a de-normal */
1330 tmp.exp += -EXTENDED_Emin + 63; /* largest exp to be 62 */
1332 REENTRANT_CHECK(OFF);
1333 suword((unsigned long *) (d + i * 10), tmp.sigl);
1334 suword((unsigned long *) (d + i * 10 + 4), tmp.sigh);
1335 REENTRANT_CHECK(ON);
1337 /* Underflow to zero */
1338 REENTRANT_CHECK(OFF);
1339 suword((unsigned long *) (d + i * 10), 0);
1340 suword((unsigned long *) (d + i * 10 + 4), 0);
1341 REENTRANT_CHECK(ON);
1345 REENTRANT_CHECK(OFF);
1346 suword((unsigned long *) (d + i * 10), rp->sigl);
1347 suword((unsigned long *) (d + i * 10 + 4), rp->sigh);
1348 REENTRANT_CHECK(ON);
1351 if (rp->tag == TW_Zero) {
1352 REENTRANT_CHECK(OFF);
1353 suword((unsigned long *) (d + i * 10), 0);
1354 suword((unsigned long *) (d + i * 10 + 4), 0);
1355 REENTRANT_CHECK(ON);
1358 if (rp->tag == TW_Infinity) {
1359 REENTRANT_CHECK(OFF);
1360 suword((unsigned long *) (d + i * 10), 0);
1361 suword((unsigned long *) (d + i * 10 + 4), 0x80000000);
1362 REENTRANT_CHECK(ON);
1365 if (rp->tag == TW_NaN) {
1366 REENTRANT_CHECK(OFF);
1367 suword((unsigned long *) (d + i * 10), rp->sigl);
1368 suword((unsigned long *) (d + i * 10 + 4), rp->sigh);
1369 REENTRANT_CHECK(ON);
1372 if (rp->tag == TW_Empty) {
1373 /* just copy the reg */
1374 REENTRANT_CHECK(OFF);
1375 suword((unsigned long *) (d + i * 10), rp->sigl);
1376 suword((unsigned long *) (d + i * 10 + 4), rp->sigh);
1377 REENTRANT_CHECK(ON);
1379 e |= rp->sign == SIGN_POS ? 0 : 0x8000;
1380 REENTRANT_CHECK(OFF);
1381 susword((unsigned short *) (d + i * 10 + 8), e);
1382 REENTRANT_CHECK(ON);
1388 /*===========================================================================*/