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
507 if (FPU_st0_tag == TW_Valid)
508 {
509 int exp;
510 FPU_REG tmp;
511
512 reg_move(FPU_st0_ptr, &tmp);
513 if (round_to_53_bits(&tmp)) goto overflow;
514 l[0] = (tmp.sigl >> 11) | (tmp.sigh << 21);
515 l[1] = ((tmp.sigh >> 11) & 0xfffff);
516 exp = tmp.exp - EXP_BIAS;
517
518 if ( exp > DOUBLE_Emax )
519 {
520 EXCEPTION(EX_Overflow);
521 overflow:
522
523 if ( control_word & EX_Overflow )
524 {
525
526 l[0] = 0x00000000;
527 l[1] = 0x7ff00000;
528 }
529 else
530 return 0;
531 }
532 else if ( exp < DOUBLE_Emin )
533 {
534 if ( exp > DOUBLE_Emin-53 )
535 {
536
537 FPU_REG tmp;
538 EXCEPTION(EX_Denormal);
539 reg_move(FPU_st0_ptr, &tmp);
540 tmp.exp += -DOUBLE_Emin + 52;
541 round_to_int(&tmp);
542 l[0] = tmp.sigl;
543 l[1] = tmp.sigh;
544 }
545 else
546 {
547 EXCEPTION(EX_Underflow);
548
549 if ( control_word & EX_Underflow )
550 {
551
552 l[0] = l[1] = 0;
553 }
554 else
555 return 0;
556 }
557 }
558 else
559 {
560
561 l[1] |= (((exp+DOUBLE_Ebias) & 0x7ff) << 20);
562 }
563 }
564 else if (FPU_st0_tag == TW_Zero)
565 {
566
567 l[0] = l[1] = 0;
568 }
569 else if (FPU_st0_tag == TW_Infinity)
570 {
571 l[0] = 0;
572 l[1] = 0x7ff00000;
573 }
574 else if (FPU_st0_tag == TW_NaN)
575 {
576
577 l[0] = (FPU_st0_ptr->sigl >> 11) | (FPU_st0_ptr->sigh << 21);
578 l[1] = ((FPU_st0_ptr->sigh >> 11) & 0xfffff);
579 if ( !(l[0] | l[1]) )
580 {
581
582 EXCEPTION(EX_Invalid);
583
584 goto put_indefinite;
585 }
586 l[1] |= 0x7ff00000;
587 }
588 else if ( FPU_st0_tag == TW_Empty )
589 {
590
591 EXCEPTION(EX_StackUnder);
592 if ( control_word & EX_Invalid )
593 {
594
595
596 put_indefinite:
597 RE_ENTRANT_CHECK_OFF
598 verify_area(VERIFY_WRITE,(void *)dfloat,8);
599 put_fs_long(0, (unsigned long *) dfloat);
600 put_fs_long(0xfff80000, 1 + (unsigned long *) dfloat);
601 RE_ENTRANT_CHECK_ON
602 return 1;
603 }
604 else
605 return 0;
606 }
607 else if (FPU_st0_tag == TW_Denormal)
608 {
609
610 l[0] = l[1] = 0;
611 EXCEPTION(EX_Underflow);
612 }
613 if (FPU_st0_ptr->sign)
614 l[1] |= 0x80000000;
615
616 RE_ENTRANT_CHECK_OFF
617 verify_area(VERIFY_WRITE,(void *)dfloat,8);
618 put_fs_long(l[0], (unsigned long *)dfloat);
619 put_fs_long(l[1], 1 + (unsigned long *)dfloat);
620 RE_ENTRANT_CHECK_ON
621
622 return 1;
623 }
624
625
626
627 int reg_store_single(void)
628 {
629 float *single = (float *)FPU_data_address;
630 long templ;
631
632 if (FPU_st0_tag == TW_Valid)
633 {
634 int exp;
635 FPU_REG tmp;
636
637 reg_move(FPU_st0_ptr, &tmp);
638 if (round_to_24_bits(&tmp)) goto overflow;
639 templ = (tmp.sigh >> 8) & 0x007fffff;
640 exp = tmp.exp - EXP_BIAS;
641
642 if ( exp > SINGLE_Emax )
643 {
644 EXCEPTION(EX_Overflow);
645 overflow:
646
647 if ( control_word & EX_Overflow )
648 {
649
650 templ = 0x7f800000;
651 }
652 else
653 return 0;
654 }
655 else if ( exp < SINGLE_Emin )
656 {
657 if ( exp > SINGLE_Emin-24 )
658 {
659
660 FPU_REG tmp;
661 EXCEPTION(EX_Denormal);
662 reg_move(FPU_st0_ptr, &tmp);
663 tmp.exp += -SINGLE_Emin + 23;
664 round_to_int(&tmp);
665 templ = tmp.sigl;
666 }
667 else
668 {
669 EXCEPTION(EX_Underflow);
670
671 if ( control_word & EX_Underflow )
672 {
673
674 templ = 0;
675 }
676 else
677 return 0;
678 }
679 }
680 else
681 templ |= ((exp+SINGLE_Ebias) & 0xff) << 23;
682 }
683 else if (FPU_st0_tag == TW_Zero)
684 {
685 templ = 0;
686 }
687 else if (FPU_st0_tag == TW_Infinity)
688 {
689 templ = 0x7f800000;
690 }
691 else if (FPU_st0_tag == TW_NaN)
692 {
693
694 templ = FPU_st0_ptr->sigh >> 8;
695 if ( !(templ & 0x3fffff) )
696 {
697
698 EXCEPTION(EX_Invalid);
699
700 goto put_indefinite;
701 }
702 templ |= 0x7f800000;
703 }
704 else if ( FPU_st0_tag == TW_Empty )
705 {
706
707 EXCEPTION(EX_StackUnder);
708 if ( control_word & EX_Invalid )
709 {
710
711
712 put_indefinite:
713 RE_ENTRANT_CHECK_OFF
714 verify_area(VERIFY_WRITE,(void *)single,4);
715 put_fs_long(0xffc00000, (unsigned long *) single);
716 RE_ENTRANT_CHECK_ON
717 return 1;
718 }
719 else
720 return 0;
721 }
722 else if (FPU_st0_tag == TW_Denormal)
723 {
724
725 templ = 0;
726 EXCEPTION(EX_Underflow);
727 }
728 #ifdef PARANOID
729 else
730 {
731 EXCEPTION(EX_INTERNAL|0x106);
732 return 0;
733 }
734 #endif
735 if (FPU_st0_ptr->sign)
736 templ |= 0x80000000;
737
738 RE_ENTRANT_CHECK_OFF
739 verify_area(VERIFY_WRITE,(void *)single,4);
740 put_fs_long(templ,(unsigned long *) single);
741 RE_ENTRANT_CHECK_ON
742
743 return 1;
744 }
745
746
747
748 int reg_store_int64(void)
749 {
750 long long *d = (long long *)FPU_data_address;
751 FPU_REG t;
752 long long tll;
753
754 if ( FPU_st0_tag == TW_Empty )
755 {
756
757 EXCEPTION(EX_StackUnder);
758 if ( control_word & EX_Invalid )
759 {
760
761
762 goto put_indefinite;
763 }
764 else
765 return 0;
766 }
767
768 reg_move(FPU_st0_ptr, &t);
769 round_to_int(&t);
770 ((long *)&tll)[0] = t.sigl;
771 ((long *)&tll)[1] = t.sigh;
772 if ( (t.sigh & 0x80000000) &&
773 !((t.sigh == 0x80000000) && (t.sigl == 0) && (t.sign == SIGN_NEG)) )
774 {
775 EXCEPTION(EX_Invalid);
776
777 if ( control_word & EX_Invalid )
778 {
779
780 put_indefinite:
781 ((long *)&tll)[1] = 0x80000000;
782 ((long *)&tll)[0] = 0;
783 }
784 else
785 return 0;
786 }
787 else if ( t.sign )
788 tll = - tll;
789
790 RE_ENTRANT_CHECK_OFF
791 verify_area(VERIFY_WRITE,(void *)d,8);
792 put_fs_long(((long *)&tll)[0],(unsigned long *) d);
793 put_fs_long(((long *)&tll)[1],1 + (unsigned long *) d);
794 RE_ENTRANT_CHECK_ON
795
796 return 1;
797 }
798
799
800
801 int reg_store_int32(void)
802 {
803 long *d = (long *)FPU_data_address;
804 FPU_REG t;
805
806 if ( FPU_st0_tag == TW_Empty )
807 {
808
809 EXCEPTION(EX_StackUnder);
810 if ( control_word & EX_Invalid )
811 {
812
813
814 RE_ENTRANT_CHECK_OFF
815 verify_area(VERIFY_WRITE,d,4);
816 put_fs_long(0x80000000, (unsigned long *) d);
817 RE_ENTRANT_CHECK_ON
818 return 1;
819 }
820 else
821 return 0;
822 }
823
824 reg_move(FPU_st0_ptr, &t);
825 round_to_int(&t);
826 if (t.sigh ||
827 ((t.sigl & 0x80000000) &&
828 !((t.sigl == 0x80000000) && (t.sign == SIGN_NEG))) )
829 {
830 EXCEPTION(EX_Invalid);
831
832 if ( control_word & EX_Invalid )
833 {
834
835 t.sigl = 0x80000000;
836 }
837 else
838 return 0;
839 }
840 else if ( t.sign )
841 t.sigl = -(long)t.sigl;
842
843 RE_ENTRANT_CHECK_OFF
844 verify_area(VERIFY_WRITE,d,4);
845 put_fs_long(t.sigl, (unsigned long *) d);
846 RE_ENTRANT_CHECK_ON
847
848 return 1;
849 }
850
851
852
853 int reg_store_int16(void)
854 {
855 short *d = (short *)FPU_data_address;
856 FPU_REG t;
857 short ts;
858
859 if ( FPU_st0_tag == TW_Empty )
860 {
861
862 EXCEPTION(EX_StackUnder);
863 if ( control_word & EX_Invalid )
864 {
865
866
867 RE_ENTRANT_CHECK_OFF
868 verify_area(VERIFY_WRITE,d,2);
869 put_fs_word(0x8000, (unsigned short *) d);
870 RE_ENTRANT_CHECK_ON
871 return 1;
872 }
873 else
874 return 0;
875 }
876
877 reg_move(FPU_st0_ptr, &t);
878 round_to_int(&t);
879 if (t.sigh ||
880 ((t.sigl & 0xffff8000) &&
881 !((t.sigl == 0x8000) && (t.sign == SIGN_NEG))) )
882 {
883 EXCEPTION(EX_Invalid);
884
885 if ( control_word & EX_Invalid )
886 {
887
888 ts = 0x8000;
889 }
890 else
891 return 0;
892 }
893 else if ( t.sign )
894 t.sigl = -t.sigl;
895
896 RE_ENTRANT_CHECK_OFF
897 verify_area(VERIFY_WRITE,d,2);
898 put_fs_word((short)t.sigl,(short *) d);
899 RE_ENTRANT_CHECK_ON
900
901 return 1;
902 }
903
904
905
906 int reg_store_bcd(void)
907 {
908 char *d = (char *)FPU_data_address;
909 FPU_REG t;
910 long long ll;
911 unsigned char b;
912 int i;
913 unsigned char sign = (FPU_st0_ptr->sign == SIGN_NEG) ? 0x80 : 0;
914
915 if ( FPU_st0_tag == TW_Empty )
916 {
917
918 EXCEPTION(EX_StackUnder);
919 if ( control_word & EX_Invalid )
920 {
921
922
923 goto put_indefinite;
924 }
925 else
926 return 0;
927 }
928
929 reg_move(FPU_st0_ptr, &t);
930 round_to_int(&t);
931 ll = *(long long *)(&t.sigl);
932
933
934 if ( (t.sigh > 0x0de0b6b3) ||
935 ((t.sigh == 0x0de0b6b3) && (t.sigl > 0xa763ffff)) )
936 {
937 EXCEPTION(EX_Invalid);
938
939 if ( control_word & EX_Invalid )
940 {
941 put_indefinite:
942
943 RE_ENTRANT_CHECK_OFF
944 verify_area(VERIFY_WRITE,d,10);
945 put_fs_byte(0xff,(unsigned char *) d+7);
946 put_fs_byte(0xff,(unsigned char *) d+8);
947 put_fs_byte(0xff,(unsigned char *) d+9);
948 RE_ENTRANT_CHECK_ON
949 return 1;
950 }
951 else
952 return 0;
953 }
954
955 verify_area(VERIFY_WRITE,d,10);
956 for ( i = 0; i < 9; i++)
957 {
958 b = div_small(&ll, 10);
959 b |= (div_small(&ll, 10)) << 4;
960 RE_ENTRANT_CHECK_OFF
961 put_fs_byte(b,(unsigned char *) d+i);
962 RE_ENTRANT_CHECK_ON
963 }
964 RE_ENTRANT_CHECK_OFF
965 put_fs_byte(sign,(unsigned char *) d+9);
966 RE_ENTRANT_CHECK_ON
967
968 return 1;
969 }
970
971
972
973
974
975
976
977
978
979 int round_to_int(FPU_REG *r)
980 {
981 char very_big;
982 unsigned eax;
983
984 if (r->tag == TW_Zero)
985 {
986
987 *(long long *)&r->sigl = 0;
988 return 0;
989 }
990
991 if (r->exp > EXP_BIAS + 63)
992 {
993 r->sigl = r->sigh = ~0;
994 return 1;
995 }
996
997 eax = shrxs(&r->sigl, EXP_BIAS + 63 - r->exp);
998 very_big = !(~(r->sigh) | ~(r->sigl));
999 #define half_or_more (eax & 0x80000000)
1000 #define frac_part (eax)
1001 #define more_than_half ((eax & 0x80000001) == 0x80000001)
1002 switch (control_word & CW_RC)
1003 {
1004 case RC_RND:
1005 if ( more_than_half
1006 || (half_or_more && (r->sigl & 1)) )
1007 {
1008 if ( very_big ) return 1;
1009 (*(long long *)(&r->sigl)) ++;
1010 }
1011 break;
1012 case RC_DOWN:
1013 if (frac_part && r->sign)
1014 {
1015 if ( very_big ) return 1;
1016 (*(long long *)(&r->sigl)) ++;
1017 }
1018 break;
1019 case RC_UP:
1020 if (frac_part && !r->sign)
1021 {
1022 if ( very_big ) return 1;
1023 (*(long long *)(&r->sigl)) ++;
1024 }
1025 break;
1026 case RC_CHOP:
1027 break;
1028 }
1029
1030 return 0;
1031 }
1032
1033
1034
1035 char *fldenv(void)
1036 {
1037 char *s = (char *)FPU_data_address;
1038 unsigned short tag_word = 0;
1039 unsigned char tag;
1040 int i;
1041
1042 RE_ENTRANT_CHECK_OFF
1043 control_word = get_fs_word((unsigned short *) s);
1044 status_word = get_fs_word((unsigned short *) (s+4));
1045 tag_word = get_fs_word((unsigned short *) (s+8));
1046 ip_offset = get_fs_long((unsigned long *) (s+0x0c));
1047 cs_selector = get_fs_long((unsigned long *) (s+0x10));
1048 data_operand_offset = get_fs_long((unsigned long *) (s+0x14));
1049 operand_selector = get_fs_long((unsigned long *) (s+0x18));
1050 RE_ENTRANT_CHECK_ON
1051
1052
1053 for ( i = 7; i >= 0; i-- )
1054 {
1055 tag = tag_word & 3;
1056 tag_word <<= 2;
1057
1058 switch ( tag )
1059 {
1060 case 0:
1061 regs[i].tag = TW_Valid;
1062 break;
1063 case 1:
1064 regs[i].tag = TW_Zero;
1065 break;
1066 case 2:
1067 regs[i].tag = TW_NaN;
1068 break;
1069 case 3:
1070 regs[i].tag = TW_Empty;
1071 break;
1072 }
1073 }
1074
1075 FPU_data_address = (void *)data_operand_offset;
1076 FPU_entry_eip = ip_offset;
1077
1078 return s + 0x1c;
1079 }
1080
1081
1082 void frstor(void)
1083 {
1084 int i;
1085 unsigned char tag;
1086 FPU_REG *s = (FPU_REG *)fldenv();
1087
1088 for ( i = 0; i < 8; i++ )
1089 {
1090
1091 FPU_data_address = (void *)&(s[i]);
1092 reg_load_extended();
1093 tag = regs[i].tag;
1094 reg_move(&FPU_loaded_data, ®s[i]);
1095 if ( tag == TW_NaN )
1096 {
1097 unsigned char t = regs[i].tag;
1098 if ( (t == TW_Valid) || (t == TW_Zero) )
1099 regs[i].tag = TW_NaN;
1100 }
1101 else
1102 regs[i].tag = tag;
1103 }
1104
1105 FPU_data_address = (void *)data_operand_offset;
1106 }
1107
1108
1109 char *fstenv(void)
1110 {
1111 char *d = (char *)FPU_data_address;
1112 unsigned short tag_word = 0;
1113 unsigned char tag;
1114 int i;
1115
1116 verify_area(VERIFY_WRITE,d,28);
1117
1118 for ( i = 7; i >= 0; i-- )
1119 {
1120 switch ( tag = regs[i].tag )
1121 {
1122 case TW_Denormal:
1123 case TW_Infinity:
1124 case TW_NaN:
1125 tag = 2;
1126 break;
1127 case TW_Empty:
1128 tag = 3;
1129 break;
1130
1131 }
1132 tag_word <<= 2;
1133 tag_word |= tag;
1134 }
1135
1136
1137 *(unsigned short *)&cs_selector = FPU_CS;
1138 *(unsigned short *)&operand_selector = FPU_DS;
1139
1140 RE_ENTRANT_CHECK_OFF
1141 put_fs_word(control_word, (unsigned short *) d);
1142 put_fs_word(status_word, (unsigned short *) (d+4));
1143 put_fs_word(tag_word, (unsigned short *) (d+8));
1144 put_fs_long(ip_offset, (unsigned long *) (d+0x0c));
1145 put_fs_long(cs_selector, (unsigned long *) (d+0x10));
1146 put_fs_long(data_operand_offset, (unsigned long *) (d+0x14));
1147 put_fs_long(operand_selector, (unsigned long *) (d+0x18));
1148 RE_ENTRANT_CHECK_ON
1149
1150 return d + 0x1c;
1151 }
1152
1153
1154 void fsave(void)
1155 {
1156 char *d;
1157 FPU_REG tmp, *rp;
1158 int i;
1159 short e;
1160
1161 d = fstenv();
1162 verify_area(VERIFY_WRITE,d,80);
1163 for ( i = 0; i < 8; i++ )
1164 {
1165
1166 rp = ®s[i];
1167
1168 e = rp->exp - EXP_BIAS + EXTENDED_Ebias;
1169
1170 if ( rp->tag == TW_Valid )
1171 {
1172 if ( e >= 0x7fff )
1173 {
1174
1175 RE_ENTRANT_CHECK_OFF
1176 put_fs_long(0, (unsigned long *) (d+i*10+2));
1177 put_fs_long(0x80000000, (unsigned long *) (d+i*10+6));
1178 RE_ENTRANT_CHECK_ON
1179 e = 0x7fff;
1180 }
1181 else if ( e <= 0 )
1182 {
1183 if ( e == 0 )
1184 {
1185
1186 RE_ENTRANT_CHECK_OFF
1187 put_fs_long(rp->sigl, (unsigned long *) (d+i*10+2));
1188 put_fs_long(rp->sigh, (unsigned long *) (d+i*10+6));
1189 RE_ENTRANT_CHECK_ON
1190 }
1191 else if ( e > -64 )
1192 {
1193
1194 reg_move(rp, &tmp);
1195 tmp.exp += -EXTENDED_Emin + 64;
1196 round_to_int(&tmp);
1197 e = 0;
1198 RE_ENTRANT_CHECK_OFF
1199 put_fs_long(tmp.sigl, (unsigned long *) (d+i*10+2));
1200 put_fs_long(tmp.sigh, (unsigned long *) (d+i*10+6));
1201 RE_ENTRANT_CHECK_ON
1202 }
1203 else
1204 {
1205
1206 RE_ENTRANT_CHECK_OFF
1207 put_fs_long(0, (unsigned long *) (d+i*10+2));
1208 put_fs_long(0, (unsigned long *) (d+i*10+6));
1209 RE_ENTRANT_CHECK_ON
1210 e = 0;
1211 }
1212 }
1213 else
1214 {
1215 RE_ENTRANT_CHECK_OFF
1216 put_fs_long(rp->sigl, (unsigned long *) (d+i*10+2));
1217 put_fs_long(rp->sigh, (unsigned long *) (d+i*10+6));
1218 RE_ENTRANT_CHECK_ON
1219 }
1220 }
1221 else if ( rp->tag == TW_Zero )
1222 {
1223 RE_ENTRANT_CHECK_OFF
1224 put_fs_long(0, (unsigned long *) (d+i*10+2));
1225 put_fs_long(0, (unsigned long *) (d+i*10+6));
1226 RE_ENTRANT_CHECK_ON
1227 e = 0;
1228 }
1229 else if ( rp->tag == TW_Infinity )
1230 {
1231 RE_ENTRANT_CHECK_OFF
1232 put_fs_long(0, (unsigned long *) (d+i*10+2));
1233 put_fs_long(0x80000000, (unsigned long *) (d+i*10+6));
1234 RE_ENTRANT_CHECK_ON
1235 e = 0x7fff;
1236 }
1237 else if ( rp->tag == TW_NaN )
1238 {
1239 RE_ENTRANT_CHECK_OFF
1240 put_fs_long(rp->sigl, (unsigned long *) (d+i*10+2));
1241 put_fs_long(rp->sigh, (unsigned long *) (d+i*10+6));
1242 RE_ENTRANT_CHECK_ON
1243 e = 0x7fff;
1244 }
1245 else if ( rp->tag == TW_Empty )
1246 {
1247
1248 RE_ENTRANT_CHECK_OFF
1249 put_fs_long(rp->sigl, (unsigned long *) (d+i*10+2));
1250 put_fs_long(rp->sigh, (unsigned long *) (d+i*10+6));
1251 RE_ENTRANT_CHECK_ON
1252 }
1253 RE_ENTRANT_CHECK_OFF
1254 put_fs_word(e, (unsigned short *) (d+i*10));
1255 RE_ENTRANT_CHECK_ON
1256 }
1257
1258 }
1259
1260