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