This source file includes following definitions.
- reg_load_extended
- reg_load_double
- reg_load_single
- reg_load_int64
- reg_load_int32
- reg_load_int16
- reg_load_bcd
- reg_store_extended
- reg_store_double
- reg_store_single
- reg_store_int64
- reg_store_int32
- reg_store_int16
- reg_store_bcd
- round_to_int
- fldenv
- frstor
- fstenv
- fsave
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 #include <asm/segment.h>
21
22 #include "fpu_system.h"
23 #include "exception.h"
24 #include "reg_constant.h"
25 #include "fpu_emu.h"
26 #include "control_w.h"
27
28
29 #define EXTENDED_Emax 0x3fff
30 #define EXTENDED_Ebias 0x3fff
31 #define EXTENDED_Emin (-0x3ffe)
32
33 #define DOUBLE_Emax 1023
34 #define DOUBLE_Ebias 1023
35 #define DOUBLE_Emin (-1022)
36
37 #define SINGLE_Emax 127
38 #define SINGLE_Ebias 127
39 #define SINGLE_Emin (-126)
40
41
42 FPU_REG FPU_loaded_data;
43
44
45
46 void reg_load_extended(void)
47 {
48 long double *s = (long double *)FPU_data_address;
49 unsigned long sigl, sigh, exp;
50
51 RE_ENTRANT_CHECK_OFF
52
53
54 sigl = get_fs_long((unsigned long *) s);
55 sigh = get_fs_long(1 + (unsigned long *) s);
56 exp = get_fs_word(4 + (unsigned short *) s);
57 RE_ENTRANT_CHECK_ON
58
59 FPU_loaded_data.sigl = sigl;
60 FPU_loaded_data.sigh = sigh;
61 FPU_loaded_data.exp = exp;
62
63 if (FPU_loaded_data.exp & 0x8000)
64 FPU_loaded_data.sign = SIGN_NEG;
65 else
66 FPU_loaded_data.sign = SIGN_POS;
67 if ( (FPU_loaded_data.exp &= 0x7fff) == 0 )
68 {
69 if ( !(FPU_loaded_data.sigl | FPU_loaded_data.sigh) )
70 {
71 FPU_loaded_data.tag = TW_Zero;
72 return;
73 }
74
75
76 }
77 else if ( FPU_loaded_data.exp == 0x7fff )
78 {
79 FPU_loaded_data.exp = EXTENDED_Emax;
80 if ( (FPU_loaded_data.sigh == 0x80000000)
81 && (FPU_loaded_data.sigl == 0) )
82 {
83 FPU_loaded_data.tag = TW_Infinity;
84 return;
85 }
86 if ( !(FPU_loaded_data.sigh & 0x80000000) )
87 {
88
89 EXCEPTION(EX_Invalid);
90 FPU_loaded_data.tag = TW_NaN;
91 return;
92 }
93 FPU_loaded_data.tag = TW_NaN;
94 return;
95 }
96 FPU_loaded_data.exp = (FPU_loaded_data.exp & 0x7fff) - EXTENDED_Ebias
97 + EXP_BIAS;
98 FPU_loaded_data.tag = TW_Valid;
99
100 normalize(&FPU_loaded_data);
101 }
102
103
104
105 void reg_load_double(void)
106 {
107 double *dfloat = (double *)FPU_data_address;
108 int exp;
109 unsigned m64, l64;
110
111 RE_ENTRANT_CHECK_OFF
112 m64 = get_fs_long(1 + (unsigned long *) dfloat);
113 l64 = get_fs_long((unsigned long *) dfloat);
114 RE_ENTRANT_CHECK_ON
115
116 if (m64 & 0x80000000)
117 FPU_loaded_data.sign = SIGN_NEG;
118 else
119 FPU_loaded_data.sign = SIGN_POS;
120 exp = ((m64 & 0x7ff00000) >> 20) - DOUBLE_Ebias;
121 m64 &= 0xfffff;
122 if (exp > DOUBLE_Emax)
123 {
124
125 if ((m64 == 0) && (l64 == 0))
126 {
127
128 FPU_loaded_data.exp = EXTENDED_Emax;
129 FPU_loaded_data.tag = TW_Infinity;
130 return;
131 }
132 else
133 {
134
135 FPU_loaded_data.exp = EXTENDED_Emax;
136 FPU_loaded_data.tag = TW_NaN;
137 FPU_loaded_data.sigh = (m64 << 11) | 0x80000000;
138 FPU_loaded_data.sigh |= l64 >> 21;
139 FPU_loaded_data.sigl = l64 << 11;
140 return;
141 }
142 }
143 else if ( exp < DOUBLE_Emin )
144 {
145
146 if ((m64 == 0) && (l64 == 0))
147 {
148
149 int c = FPU_loaded_data.sign;
150 reg_move(&CONST_Z, &FPU_loaded_data);
151 FPU_loaded_data.sign = c;
152 return;
153 }
154 else
155 {
156
157 FPU_loaded_data.exp = DOUBLE_Emin + EXP_BIAS;
158 FPU_loaded_data.tag = TW_Valid;
159 FPU_loaded_data.sigh = m64 << 11;
160 FPU_loaded_data.sigh |= l64 >> 21;
161 FPU_loaded_data.sigl = l64 << 11;
162 normalize(&FPU_loaded_data);
163 return;
164 }
165 }
166 else
167 {
168 FPU_loaded_data.exp = exp + EXP_BIAS;
169 FPU_loaded_data.tag = TW_Valid;
170 FPU_loaded_data.sigh = (m64 << 11) | 0x80000000;
171 FPU_loaded_data.sigh |= l64 >> 21;
172 FPU_loaded_data.sigl = l64 << 11;
173
174 return;
175 }
176 }
177
178
179
180 void reg_load_single(void)
181 {
182 float *single = (float *)FPU_data_address;
183 unsigned m32;
184 int exp;
185
186 RE_ENTRANT_CHECK_OFF
187 m32 = get_fs_long((unsigned long *) single);
188 RE_ENTRANT_CHECK_ON
189
190 if (m32 & 0x80000000)
191 FPU_loaded_data.sign = SIGN_NEG;
192 else
193 FPU_loaded_data.sign = SIGN_POS;
194 if (!(m32 & 0x7fffffff))
195 {
196
197 int c = FPU_loaded_data.sign;
198 reg_move(&CONST_Z, &FPU_loaded_data);
199 FPU_loaded_data.sign = c;
200 return;
201 }
202 exp = ((m32 & 0x7f800000) >> 23) - SINGLE_Ebias;
203 m32 = (m32 & 0x7fffff) << 8;
204 if ( exp < SINGLE_Emin )
205 {
206
207 FPU_loaded_data.exp = SINGLE_Emin + EXP_BIAS;
208 FPU_loaded_data.tag = TW_Valid;
209 FPU_loaded_data.sigh = m32;
210 FPU_loaded_data.sigl = 0;
211 normalize(&FPU_loaded_data);
212 return;
213 }
214 else if ( exp > SINGLE_Emax )
215 {
216
217 if ( m32 == 0 )
218 {
219
220 FPU_loaded_data.exp = EXTENDED_Emax;
221 FPU_loaded_data.tag = TW_Infinity;
222 return;
223 }
224 else
225 {
226
227 FPU_loaded_data.exp = EXTENDED_Emax;
228 FPU_loaded_data.tag = TW_NaN;
229 FPU_loaded_data.sigh = m32 | 0x80000000;
230 FPU_loaded_data.sigl = 0;
231 return;
232 }
233 }
234 else
235 {
236 FPU_loaded_data.exp = exp + EXP_BIAS;
237 FPU_loaded_data.sigh = m32 | 0x80000000;
238 FPU_loaded_data.sigl = 0;
239 FPU_loaded_data.tag = TW_Valid;
240 }
241 }
242
243
244
245 void reg_load_int64(void)
246 {
247 long long *_s = (long long *)FPU_data_address;
248 int e;
249 long long s;
250
251 RE_ENTRANT_CHECK_OFF
252 ((unsigned long *)&s)[0] = get_fs_long((unsigned long *) _s);
253 ((unsigned long *)&s)[1] = get_fs_long(1 + (unsigned long *) _s);
254 RE_ENTRANT_CHECK_ON
255
256 if (s == 0)
257 { reg_move(&CONST_Z, &FPU_loaded_data); return; }
258
259 if (s > 0)
260 FPU_loaded_data.sign = SIGN_POS;
261 else
262 {
263 s = -s;
264 FPU_loaded_data.sign = SIGN_NEG;
265 }
266
267 e = EXP_BIAS + 63;
268 *((long long *)&FPU_loaded_data.sigl) = s;
269 FPU_loaded_data.exp = e;
270 FPU_loaded_data.tag = TW_Valid;
271 normalize(&FPU_loaded_data);
272 }
273
274
275
276 void reg_load_int32(void)
277 {
278 long *_s = (long *)FPU_data_address;
279 long s;
280 int e;
281
282 RE_ENTRANT_CHECK_OFF
283 s = (long)get_fs_long((unsigned long *) _s);
284 RE_ENTRANT_CHECK_ON
285
286 if (s == 0)
287 { reg_move(&CONST_Z, &FPU_loaded_data); return; }
288
289 if (s > 0)
290 FPU_loaded_data.sign = SIGN_POS;
291 else
292 {
293 s = -s;
294 FPU_loaded_data.sign = SIGN_NEG;
295 }
296
297 e = EXP_BIAS + 31;
298 FPU_loaded_data.sigh = s;
299 FPU_loaded_data.sigl = 0;
300 FPU_loaded_data.exp = e;
301 FPU_loaded_data.tag = TW_Valid;
302 normalize(&FPU_loaded_data);
303 }
304
305
306
307 void reg_load_int16(void)
308 {
309 short *_s = (short *)FPU_data_address;
310 int s, e;
311
312 RE_ENTRANT_CHECK_OFF
313 s = (int)get_fs_word((unsigned short *) _s);
314 RE_ENTRANT_CHECK_ON
315
316 if (s == 0)
317 { reg_move(&CONST_Z, &FPU_loaded_data); return; }
318
319 if (s > 0)
320 FPU_loaded_data.sign = SIGN_POS;
321 else
322 {
323 s = -s;
324 FPU_loaded_data.sign = SIGN_NEG;
325 }
326
327 e = EXP_BIAS + 15;
328 FPU_loaded_data.sigh = s << 16;
329
330 FPU_loaded_data.sigl = 0;
331 FPU_loaded_data.exp = e;
332 FPU_loaded_data.tag = TW_Valid;
333 normalize(&FPU_loaded_data);
334 }
335
336
337
338 void reg_load_bcd(void)
339 {
340 char *s = (char *)FPU_data_address;
341 int pos;
342 unsigned char bcd;
343 long long l=0;
344
345 for ( pos = 8; pos >= 0; pos--)
346 {
347 l *= 10;
348 RE_ENTRANT_CHECK_OFF
349 bcd = (unsigned char)get_fs_byte((unsigned char *) s+pos);
350 RE_ENTRANT_CHECK_ON
351 l += bcd >> 4;
352 l *= 10;
353 l += bcd & 0x0f;
354 }
355
356
357
358 RE_ENTRANT_CHECK_OFF
359 FPU_loaded_data.sign =
360 ((unsigned char)get_fs_byte((unsigned char *) s+9)) & 0x80 ?
361 SIGN_NEG : SIGN_POS;
362 RE_ENTRANT_CHECK_ON
363
364 if (l == 0)
365 {
366 char sign = FPU_loaded_data.sign;
367 reg_move(&CONST_Z, &FPU_loaded_data);
368 FPU_loaded_data.sign = sign;
369 }
370 else
371 {
372 *((long long *)&FPU_loaded_data.sigl) = l;
373 FPU_loaded_data.exp = EXP_BIAS + 63;
374 FPU_loaded_data.tag = TW_Valid;
375 normalize(&FPU_loaded_data);
376 }
377 }
378
379
380
381
382 int reg_store_extended(void)
383 {
384 long double *d = (long double *)FPU_data_address;
385 long e = FPU_st0_ptr->exp - EXP_BIAS + EXTENDED_Ebias;
386 unsigned short sign = FPU_st0_ptr->sign*0x8000;
387 unsigned long ls, ms;
388
389
390 if ( FPU_st0_tag == TW_Valid )
391 {
392 if ( e >= 0x7fff )
393 {
394 EXCEPTION(EX_Overflow);
395
396 if ( control_word & EX_Overflow )
397 {
398
399 ls = 0;
400 ms = 0x80000000;
401 e = 0x7fff;
402 }
403 else
404 return 0;
405 }
406 else if ( e <= 0 )
407 {
408 if ( e == 0 )
409 {
410 EXCEPTION(EX_Denormal);
411 ls = FPU_st0_ptr->sigl;
412 ms = FPU_st0_ptr->sigh;
413 }
414 else if ( e > -64 )
415 {
416
417 FPU_REG tmp;
418 EXCEPTION(EX_Denormal);
419 reg_move(FPU_st0_ptr, &tmp);
420 tmp.exp += -EXTENDED_Emin + 64;
421 round_to_int(&tmp);
422 e = 0;
423 ls = tmp.sigl;
424 ms = tmp.sigh;
425 }
426 else
427 {
428 EXCEPTION(EX_Underflow);
429
430 if ( control_word & EX_Underflow )
431 {
432
433 ls = 0;
434 ms = 0;
435 e = 0;
436 }
437 else
438 return 0;
439 }
440 }
441 else
442 {
443 ls = FPU_st0_ptr->sigl;
444 ms = FPU_st0_ptr->sigh;
445 }
446 }
447 else if ( FPU_st0_tag == TW_Zero )
448 {
449 ls = ms = 0;
450 e = 0;
451 }
452 else if ( FPU_st0_tag == TW_Infinity )
453 {
454 ls = 0;
455 ms = 0x80000000;
456 e = 0x7fff;
457 }
458 else if ( FPU_st0_tag == TW_NaN )
459 {
460 ls = FPU_st0_ptr->sigl;
461 ms = FPU_st0_ptr->sigh;
462 e = 0x7fff;
463 }
464 else if ( FPU_st0_tag == TW_Empty )
465 {
466
467 EXCEPTION(EX_StackUnder);
468 if ( control_word & EX_Invalid )
469 {
470
471
472 ls = 0;
473 ms = 0xc0000000;
474 e = 0xffff;
475 }
476 else
477 return 0;
478 }
479 else
480 {
481
482 EXCEPTION(EX_Invalid);
483
484 e = 0x7fff;
485 ls = 1;
486 ms = 0x80000000;
487 }
488 RE_ENTRANT_CHECK_OFF
489 verify_area(VERIFY_WRITE,d,10);
490 put_fs_long(ls, (unsigned long *) d);
491 put_fs_long(ms, 1 + (unsigned long *) d);
492 put_fs_word((unsigned short)e | sign, 4 + (short *) d);
493 RE_ENTRANT_CHECK_ON
494
495 return 1;
496
497 }
498
499
500
501 int reg_store_double(void)
502 {
503 double *dfloat = (double *)FPU_data_address;
504 unsigned long l[2];
505
506 if (FPU_st0_tag == TW_Valid)
507 {
508 int exp;
509 FPU_REG tmp;
510
511 reg_move(FPU_st0_ptr, &tmp);
512
513 if ( tmp.sigl & 0x000007ff )
514 {
515 unsigned long increment = 0;
516
517 switch (control_word & CW_RC)
518 {
519 case RC_RND:
520
521 increment = ((tmp.sigl & 0x7ff) > 0x400) |
522 ((tmp.sigl & 0xc00) == 0xc00);
523 break;
524 case RC_DOWN:
525 increment = (tmp.sign == SIGN_POS) ? 0 : tmp.sigl & 0x7ff;
526 break;
527 case RC_UP:
528 increment = (tmp.sign == SIGN_POS) ? tmp.sigl & 0x7ff : 0;
529 break;
530 case RC_CHOP:
531 increment = 0;
532 break;
533 }
534
535
536 tmp.sigl &= 0xfffff800;
537
538 if ( increment )
539 {
540 if ( tmp.sigl >= 0xfffff800 )
541 {
542
543 if ( tmp.sigh == 0xffffffff )
544 {
545
546 tmp.sigh = 0x80000000;
547 tmp.exp++;
548 if (tmp.exp >= EXP_OVER)
549 goto overflow;
550 }
551 else
552 {
553 tmp.sigh ++;
554 }
555 tmp.sigl = 0x00000000;
556 }
557 else
558 {
559
560 tmp.sigl += 0x00000800;
561 }
562 }
563 }
564
565 l[0] = (tmp.sigl >> 11) | (tmp.sigh << 21);
566 l[1] = ((tmp.sigh >> 11) & 0xfffff);
567 exp = tmp.exp - EXP_BIAS;
568
569 if ( exp > DOUBLE_Emax )
570 {
571 overflow:
572 EXCEPTION(EX_Overflow);
573
574 if ( control_word & EX_Overflow )
575 {
576
577 l[0] = 0x00000000;
578 l[1] = 0x7ff00000;
579 }
580 else
581 return 0;
582 }
583 else if ( exp < DOUBLE_Emin )
584 {
585 if ( exp > DOUBLE_Emin-53 )
586 {
587
588 FPU_REG tmp;
589 EXCEPTION(EX_Denormal);
590 reg_move(FPU_st0_ptr, &tmp);
591 tmp.exp += -DOUBLE_Emin + 52;
592 round_to_int(&tmp);
593 l[0] = tmp.sigl;
594 l[1] = tmp.sigh;
595 }
596 else
597 {
598 EXCEPTION(EX_Underflow);
599
600 if ( control_word & EX_Underflow )
601 {
602
603 l[0] = l[1] = 0;
604 }
605 else
606 return 0;
607 }
608 }
609 else
610 {
611
612 l[1] |= (((exp+DOUBLE_Ebias) & 0x7ff) << 20);
613 }
614 }
615 else if (FPU_st0_tag == TW_Zero)
616 {
617
618 l[0] = l[1] = 0;
619 }
620 else if (FPU_st0_tag == TW_Infinity)
621 {
622 l[0] = 0;
623 l[1] = 0x7ff00000;
624 }
625 else if (FPU_st0_tag == TW_NaN)
626 {
627
628 l[0] = (FPU_st0_ptr->sigl >> 11) | (FPU_st0_ptr->sigh << 21);
629 l[1] = ((FPU_st0_ptr->sigh >> 11) & 0xfffff);
630 if ( !(l[0] | l[1]) )
631 {
632
633 EXCEPTION(EX_Invalid);
634
635 goto put_indefinite;
636 }
637 l[1] |= 0x7ff00000;
638 }
639 else if ( FPU_st0_tag == TW_Empty )
640 {
641
642 EXCEPTION(EX_StackUnder);
643 if ( control_word & EX_Invalid )
644 {
645
646
647 put_indefinite:
648 RE_ENTRANT_CHECK_OFF
649 verify_area(VERIFY_WRITE,(void *)dfloat,8);
650 put_fs_long(0, (unsigned long *) dfloat);
651 put_fs_long(0xfff80000, 1 + (unsigned long *) dfloat);
652 RE_ENTRANT_CHECK_ON
653 return 1;
654 }
655 else
656 return 0;
657 }
658 else if (FPU_st0_tag == TW_Denormal)
659 {
660
661 l[0] = l[1] = 0;
662 EXCEPTION(EX_Underflow);
663 }
664 if (FPU_st0_ptr->sign)
665 l[1] |= 0x80000000;
666
667 RE_ENTRANT_CHECK_OFF
668 verify_area(VERIFY_WRITE,(void *)dfloat,8);
669 put_fs_long(l[0], (unsigned long *)dfloat);
670 put_fs_long(l[1], 1 + (unsigned long *)dfloat);
671 RE_ENTRANT_CHECK_ON
672
673 return 1;
674 }
675
676
677
678 int reg_store_single(void)
679 {
680 float *single = (float *)FPU_data_address;
681 long templ;
682
683 if (FPU_st0_tag == TW_Valid)
684 {
685 int exp;
686 FPU_REG tmp;
687
688 reg_move(FPU_st0_ptr, &tmp);
689
690 if ( tmp.sigl | (tmp.sigh & 0x000000ff) )
691 {
692 unsigned long increment = 0;
693 unsigned long sigh = tmp.sigh;
694 unsigned long sigl = tmp.sigl;
695
696 switch (control_word & CW_RC)
697 {
698 case RC_RND:
699 increment = ((sigh & 0xff) > 0x80)
700 || (((sigh & 0xff) == 0x80) && sigl)
701 || ((sigh & 0x180) == 0x180);
702 break;
703 case RC_DOWN:
704 increment = (tmp.sign == SIGN_POS) ? 0 : (sigl | (sigh & 0xff));
705 break;
706 case RC_UP:
707 increment = (tmp.sign == SIGN_POS) ? (sigl | (sigh & 0xff)) : 0;
708 break;
709 case RC_CHOP:
710 increment = 0;
711 break;
712 }
713
714
715 tmp.sigl = 0;
716
717 if (increment)
718 {
719 if ( sigh >= 0xffffff00 )
720 {
721
722 tmp.sigh = 0x80000000;
723 tmp.exp++;
724 if (tmp.exp >= EXP_OVER)
725 goto overflow;
726 }
727 else
728 {
729 tmp.sigh &= 0xffffff00;
730 tmp.sigh += 0x100;
731 }
732 }
733 else
734 tmp.sigh &= 0xffffff00;
735 }
736
737 templ = (tmp.sigh >> 8) & 0x007fffff;
738 exp = tmp.exp - EXP_BIAS;
739
740 if ( exp > SINGLE_Emax )
741 {
742 overflow:
743 EXCEPTION(EX_Overflow);
744
745 if ( control_word & EX_Overflow )
746 {
747
748 templ = 0x7f800000;
749 }
750 else
751 return 0;
752 }
753 else if ( exp < SINGLE_Emin )
754 {
755 if ( exp > SINGLE_Emin-24 )
756 {
757
758 FPU_REG tmp;
759 EXCEPTION(EX_Denormal);
760 reg_move(FPU_st0_ptr, &tmp);
761 tmp.exp += -SINGLE_Emin + 23;
762 round_to_int(&tmp);
763 templ = tmp.sigl;
764 }
765 else
766 {
767 EXCEPTION(EX_Underflow);
768
769 if ( control_word & EX_Underflow )
770 {
771
772 templ = 0;
773 }
774 else
775 return 0;
776 }
777 }
778 else
779 templ |= ((exp+SINGLE_Ebias) & 0xff) << 23;
780 }
781 else if (FPU_st0_tag == TW_Zero)
782 {
783 templ = 0;
784 }
785 else if (FPU_st0_tag == TW_Infinity)
786 {
787 templ = 0x7f800000;
788 }
789 else if (FPU_st0_tag == TW_NaN)
790 {
791
792 templ = FPU_st0_ptr->sigh >> 8;
793 if ( !(templ & 0x3fffff) )
794 {
795
796 EXCEPTION(EX_Invalid);
797
798 goto put_indefinite;
799 }
800 templ |= 0x7f800000;
801 }
802 else if ( FPU_st0_tag == TW_Empty )
803 {
804
805 EXCEPTION(EX_StackUnder);
806 if ( control_word & EX_Invalid )
807 {
808
809
810 put_indefinite:
811 RE_ENTRANT_CHECK_OFF
812 verify_area(VERIFY_WRITE,(void *)single,4);
813 put_fs_long(0xffc00000, (unsigned long *) single);
814 RE_ENTRANT_CHECK_ON
815 return 1;
816 }
817 else
818 return 0;
819 }
820 else if (FPU_st0_tag == TW_Denormal)
821 {
822
823 templ = 0;
824 EXCEPTION(EX_Underflow);
825 }
826 #ifdef PARANOID
827 else
828 {
829 EXCEPTION(EX_INTERNAL|0x106);
830 return 0;
831 }
832 #endif
833 if (FPU_st0_ptr->sign)
834 templ |= 0x80000000;
835
836 RE_ENTRANT_CHECK_OFF
837 verify_area(VERIFY_WRITE,(void *)single,4);
838 put_fs_long(templ,(unsigned long *) single);
839 RE_ENTRANT_CHECK_ON
840
841 return 1;
842 }
843
844
845
846 int reg_store_int64(void)
847 {
848 long long *d = (long long *)FPU_data_address;
849 FPU_REG t;
850 long long tll;
851
852 if ( FPU_st0_tag == TW_Empty )
853 {
854
855 EXCEPTION(EX_StackUnder);
856 if ( control_word & EX_Invalid )
857 {
858
859
860 goto put_indefinite;
861 }
862 else
863 return 0;
864 }
865
866 reg_move(FPU_st0_ptr, &t);
867 round_to_int(&t);
868 ((long *)&tll)[0] = t.sigl;
869 ((long *)&tll)[1] = t.sigh;
870 if ( (t.sigh & 0x80000000) &&
871 !((t.sigh == 0x80000000) && (t.sigl == 0) && (t.sign == SIGN_NEG)) )
872 {
873 EXCEPTION(EX_Invalid);
874
875 if ( control_word & EX_Invalid )
876 {
877
878 put_indefinite:
879 ((long *)&tll)[1] = 0x80000000;
880 ((long *)&tll)[0] = 0;
881 }
882 else
883 return 0;
884 }
885 else if ( t.sign )
886 tll = - tll;
887
888 RE_ENTRANT_CHECK_OFF
889 verify_area(VERIFY_WRITE,(void *)d,8);
890 put_fs_long(((long *)&tll)[0],(unsigned long *) d);
891 put_fs_long(((long *)&tll)[1],1 + (unsigned long *) d);
892 RE_ENTRANT_CHECK_ON
893
894 return 1;
895 }
896
897
898
899 int reg_store_int32(void)
900 {
901 long *d = (long *)FPU_data_address;
902 FPU_REG t;
903
904 if ( FPU_st0_tag == TW_Empty )
905 {
906
907 EXCEPTION(EX_StackUnder);
908 if ( control_word & EX_Invalid )
909 {
910
911
912 RE_ENTRANT_CHECK_OFF
913 verify_area(VERIFY_WRITE,d,4);
914 put_fs_long(0x80000000, (unsigned long *) d);
915 RE_ENTRANT_CHECK_ON
916 return 1;
917 }
918 else
919 return 0;
920 }
921
922 reg_move(FPU_st0_ptr, &t);
923 round_to_int(&t);
924 if (t.sigh ||
925 ((t.sigl & 0x80000000) &&
926 !((t.sigl == 0x80000000) && (t.sign == SIGN_NEG))) )
927 {
928 EXCEPTION(EX_Invalid);
929
930 if ( control_word & EX_Invalid )
931 {
932
933 t.sigl = 0x80000000;
934 }
935 else
936 return 0;
937 }
938 else if ( t.sign )
939 t.sigl = -(long)t.sigl;
940
941 RE_ENTRANT_CHECK_OFF
942 verify_area(VERIFY_WRITE,d,4);
943 put_fs_long(t.sigl, (unsigned long *) d);
944 RE_ENTRANT_CHECK_ON
945
946 return 1;
947 }
948
949
950
951 int reg_store_int16(void)
952 {
953 short *d = (short *)FPU_data_address;
954 FPU_REG t;
955 short ts;
956
957 if ( FPU_st0_tag == TW_Empty )
958 {
959
960 EXCEPTION(EX_StackUnder);
961 if ( control_word & EX_Invalid )
962 {
963
964
965 RE_ENTRANT_CHECK_OFF
966 verify_area(VERIFY_WRITE,d,2);
967 put_fs_word(0x8000, (unsigned short *) d);
968 RE_ENTRANT_CHECK_ON
969 return 1;
970 }
971 else
972 return 0;
973 }
974
975 reg_move(FPU_st0_ptr, &t);
976 round_to_int(&t);
977 if (t.sigh ||
978 ((t.sigl & 0xffff8000) &&
979 !((t.sigl == 0x8000) && (t.sign == SIGN_NEG))) )
980 {
981 EXCEPTION(EX_Invalid);
982
983 if ( control_word & EX_Invalid )
984 {
985
986 ts = 0x8000;
987 }
988 else
989 return 0;
990 }
991 else if ( t.sign )
992 t.sigl = -t.sigl;
993
994 RE_ENTRANT_CHECK_OFF
995 verify_area(VERIFY_WRITE,d,2);
996 put_fs_word((short)t.sigl,(short *) d);
997 RE_ENTRANT_CHECK_ON
998
999 return 1;
1000 }
1001
1002
1003
1004 int reg_store_bcd(void)
1005 {
1006 char *d = (char *)FPU_data_address;
1007 FPU_REG t;
1008 long long ll;
1009 unsigned char b;
1010 int i;
1011 unsigned char sign = (FPU_st0_ptr->sign == SIGN_NEG) ? 0x80 : 0;
1012
1013 if ( FPU_st0_tag == TW_Empty )
1014 {
1015
1016 EXCEPTION(EX_StackUnder);
1017 if ( control_word & EX_Invalid )
1018 {
1019
1020
1021 goto put_indefinite;
1022 }
1023 else
1024 return 0;
1025 }
1026
1027 reg_move(FPU_st0_ptr, &t);
1028 round_to_int(&t);
1029 ll = *(long long *)(&t.sigl);
1030
1031
1032 if ( (t.sigh > 0x0de0b6b3) ||
1033 ((t.sigh == 0x0de0b6b3) && (t.sigl > 0xa763ffff)) )
1034 {
1035 EXCEPTION(EX_Invalid);
1036
1037 if ( control_word & EX_Invalid )
1038 {
1039 put_indefinite:
1040
1041 RE_ENTRANT_CHECK_OFF
1042 verify_area(VERIFY_WRITE,d,10);
1043 put_fs_byte(0xff,(unsigned char *) d+7);
1044 put_fs_byte(0xff,(unsigned char *) d+8);
1045 put_fs_byte(0xff,(unsigned char *) d+9);
1046 RE_ENTRANT_CHECK_ON
1047 return 1;
1048 }
1049 else
1050 return 0;
1051 }
1052
1053 verify_area(VERIFY_WRITE,d,10);
1054 for ( i = 0; i < 9; i++)
1055 {
1056 b = div_small(&ll, 10);
1057 b |= (div_small(&ll, 10)) << 4;
1058 RE_ENTRANT_CHECK_OFF
1059 put_fs_byte(b,(unsigned char *) d+i);
1060 RE_ENTRANT_CHECK_ON
1061 }
1062 RE_ENTRANT_CHECK_OFF
1063 put_fs_byte(sign,(unsigned char *) d+9);
1064 RE_ENTRANT_CHECK_ON
1065
1066 return 1;
1067 }
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077 int round_to_int(FPU_REG *r)
1078 {
1079 char very_big;
1080 unsigned eax;
1081
1082 if (r->tag == TW_Zero)
1083 {
1084
1085 *(long long *)&r->sigl = 0;
1086 return 0;
1087 }
1088
1089 if (r->exp > EXP_BIAS + 63)
1090 {
1091 r->sigl = r->sigh = ~0;
1092 return 1;
1093 }
1094
1095 eax = shrxs(&r->sigl, EXP_BIAS + 63 - r->exp);
1096 very_big = !(~(r->sigh) | ~(r->sigl));
1097 #define half_or_more (eax & 0x80000000)
1098 #define frac_part (eax)
1099 #define more_than_half ((eax & 0x80000001) == 0x80000001)
1100 switch (control_word & CW_RC)
1101 {
1102 case RC_RND:
1103 if ( more_than_half
1104 || (half_or_more && (r->sigl & 1)) )
1105 {
1106 if ( very_big ) return 1;
1107 (*(long long *)(&r->sigl)) ++;
1108 }
1109 break;
1110 case RC_DOWN:
1111 if (frac_part && r->sign)
1112 {
1113 if ( very_big ) return 1;
1114 (*(long long *)(&r->sigl)) ++;
1115 }
1116 break;
1117 case RC_UP:
1118 if (frac_part && !r->sign)
1119 {
1120 if ( very_big ) return 1;
1121 (*(long long *)(&r->sigl)) ++;
1122 }
1123 break;
1124 case RC_CHOP:
1125 break;
1126 }
1127
1128 return 0;
1129 }
1130
1131
1132
1133 char *fldenv(void)
1134 {
1135 char *s = (char *)FPU_data_address;
1136 unsigned short tag_word = 0;
1137 unsigned char tag;
1138 int i;
1139
1140 RE_ENTRANT_CHECK_OFF
1141 control_word = get_fs_word((unsigned short *) s);
1142 status_word = get_fs_word((unsigned short *) (s+4));
1143 tag_word = get_fs_word((unsigned short *) (s+8));
1144 ip_offset = get_fs_long((unsigned long *) (s+0x0c));
1145 cs_selector = get_fs_long((unsigned long *) (s+0x10));
1146 data_operand_offset = get_fs_long((unsigned long *) (s+0x14));
1147 operand_selector = get_fs_long((unsigned long *) (s+0x18));
1148 RE_ENTRANT_CHECK_ON
1149
1150
1151 for ( i = 7; i >= 0; i-- )
1152 {
1153 tag = tag_word & 3;
1154 tag_word <<= 2;
1155
1156 switch ( tag )
1157 {
1158 case 0:
1159 regs[i].tag = TW_Valid;
1160 break;
1161 case 1:
1162 regs[i].tag = TW_Zero;
1163 break;
1164 case 2:
1165 regs[i].tag = TW_NaN;
1166 break;
1167 case 3:
1168 regs[i].tag = TW_Empty;
1169 break;
1170 }
1171 }
1172
1173 FPU_data_address = (void *)data_operand_offset;
1174 FPU_entry_eip = ip_offset;
1175
1176 return s + 0x1c;
1177 }
1178
1179
1180 void frstor(void)
1181 {
1182 int i;
1183 unsigned char tag;
1184 FPU_REG *s = (FPU_REG *)fldenv();
1185
1186 for ( i = 0; i < 8; i++ )
1187 {
1188
1189 FPU_data_address = (void *)&(s[i]);
1190 reg_load_extended();
1191 tag = regs[i].tag;
1192 reg_move(&FPU_loaded_data, ®s[i]);
1193 if ( tag == TW_NaN )
1194 {
1195 unsigned char t = regs[i].tag;
1196 if ( (t == TW_Valid) || (t == TW_Zero) )
1197 regs[i].tag = TW_NaN;
1198 }
1199 else
1200 regs[i].tag = tag;
1201 }
1202
1203 FPU_data_address = (void *)data_operand_offset;
1204 }
1205
1206
1207 char *fstenv(void)
1208 {
1209 char *d = (char *)FPU_data_address;
1210 unsigned short tag_word = 0;
1211 unsigned char tag;
1212 int i;
1213
1214 verify_area(VERIFY_WRITE,d,28);
1215
1216 for ( i = 7; i >= 0; i-- )
1217 {
1218 switch ( tag = regs[i].tag )
1219 {
1220 case TW_Denormal:
1221 case TW_Infinity:
1222 case TW_NaN:
1223 tag = 2;
1224 break;
1225 case TW_Empty:
1226 tag = 3;
1227 break;
1228
1229 }
1230 tag_word <<= 2;
1231 tag_word |= tag;
1232 }
1233
1234
1235 *(unsigned short *)&cs_selector = FPU_CS;
1236 *(unsigned short *)&operand_selector = FPU_DS;
1237
1238 RE_ENTRANT_CHECK_OFF
1239 put_fs_word(control_word, (unsigned short *) d);
1240 put_fs_word(status_word, (unsigned short *) (d+4));
1241 put_fs_word(tag_word, (unsigned short *) (d+8));
1242 put_fs_long(ip_offset, (unsigned long *) (d+0x0c));
1243 put_fs_long(cs_selector, (unsigned long *) (d+0x10));
1244 put_fs_long(data_operand_offset, (unsigned long *) (d+0x14));
1245 put_fs_long(operand_selector, (unsigned long *) (d+0x18));
1246 RE_ENTRANT_CHECK_ON
1247
1248 return d + 0x1c;
1249 }
1250
1251
1252 void fsave(void)
1253 {
1254 char *d;
1255 FPU_REG tmp, *rp;
1256 int i;
1257 short e;
1258
1259 d = fstenv();
1260 verify_area(VERIFY_WRITE,d,80);
1261 for ( i = 0; i < 8; i++ )
1262 {
1263
1264 rp = ®s[i];
1265
1266 e = rp->exp - EXP_BIAS + EXTENDED_Ebias;
1267
1268 if ( rp->tag == TW_Valid )
1269 {
1270 if ( e >= 0x7fff )
1271 {
1272
1273 RE_ENTRANT_CHECK_OFF
1274 put_fs_long(0, (unsigned long *) (d+i*10+2));
1275 put_fs_long(0x80000000, (unsigned long *) (d+i*10+6));
1276 RE_ENTRANT_CHECK_ON
1277 e = 0x7fff;
1278 }
1279 else if ( e <= 0 )
1280 {
1281 if ( e == 0 )
1282 {
1283
1284 RE_ENTRANT_CHECK_OFF
1285 put_fs_long(rp->sigl, (unsigned long *) (d+i*10+2));
1286 put_fs_long(rp->sigh, (unsigned long *) (d+i*10+6));
1287 RE_ENTRANT_CHECK_ON
1288 }
1289 else if ( e > -64 )
1290 {
1291
1292 reg_move(rp, &tmp);
1293 tmp.exp += -EXTENDED_Emin + 64;
1294 round_to_int(&tmp);
1295 e = 0;
1296 RE_ENTRANT_CHECK_OFF
1297 put_fs_long(tmp.sigl, (unsigned long *) (d+i*10+2));
1298 put_fs_long(tmp.sigh, (unsigned long *) (d+i*10+6));
1299 RE_ENTRANT_CHECK_ON
1300 }
1301 else
1302 {
1303
1304 RE_ENTRANT_CHECK_OFF
1305 put_fs_long(0, (unsigned long *) (d+i*10+2));
1306 put_fs_long(0, (unsigned long *) (d+i*10+6));
1307 RE_ENTRANT_CHECK_ON
1308 e = 0;
1309 }
1310 }
1311 else
1312 {
1313 RE_ENTRANT_CHECK_OFF
1314 put_fs_long(rp->sigl, (unsigned long *) (d+i*10+2));
1315 put_fs_long(rp->sigh, (unsigned long *) (d+i*10+6));
1316 RE_ENTRANT_CHECK_ON
1317 }
1318 }
1319 else if ( rp->tag == TW_Zero )
1320 {
1321 RE_ENTRANT_CHECK_OFF
1322 put_fs_long(0, (unsigned long *) (d+i*10+2));
1323 put_fs_long(0, (unsigned long *) (d+i*10+6));
1324 RE_ENTRANT_CHECK_ON
1325 e = 0;
1326 }
1327 else if ( rp->tag == TW_Infinity )
1328 {
1329 RE_ENTRANT_CHECK_OFF
1330 put_fs_long(0, (unsigned long *) (d+i*10+2));
1331 put_fs_long(0x80000000, (unsigned long *) (d+i*10+6));
1332 RE_ENTRANT_CHECK_ON
1333 e = 0x7fff;
1334 }
1335 else if ( rp->tag == TW_NaN )
1336 {
1337 RE_ENTRANT_CHECK_OFF
1338 put_fs_long(rp->sigl, (unsigned long *) (d+i*10+2));
1339 put_fs_long(rp->sigh, (unsigned long *) (d+i*10+6));
1340 RE_ENTRANT_CHECK_ON
1341 e = 0x7fff;
1342 }
1343 else if ( rp->tag == TW_Empty )
1344 {
1345
1346 RE_ENTRANT_CHECK_OFF
1347 put_fs_long(rp->sigl, (unsigned long *) (d+i*10+2));
1348 put_fs_long(rp->sigh, (unsigned long *) (d+i*10+6));
1349 RE_ENTRANT_CHECK_ON
1350 }
1351 RE_ENTRANT_CHECK_OFF
1352 put_fs_word(e, (unsigned short *) (d+i*10));
1353 RE_ENTRANT_CHECK_ON
1354 }
1355
1356 }
1357
1358