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 {
810 EXCEPTION(EX_Invalid);
811
812 if ( control_word & EX_Invalid )
813 {
814
815 put_indefinite:
816 ((long *)&tll)[1] = 0x80000000;
817 ((long *)&tll)[0] = 0;
818 }
819 else
820 return 0;
821 }
822 else if (t.sign)
823 tll = - tll;
824
825 RE_ENTRANT_CHECK_OFF
826 verify_area((void *)d,8);
827 put_fs_long(((long *)&tll)[0],(unsigned long *) d);
828 put_fs_long(((long *)&tll)[1],1 + (unsigned long *) d);
829 RE_ENTRANT_CHECK_ON
830
831 return 1;
832 }
833
834
835
836 int reg_store_int32(void)
837 {
838 long *d = (long *)FPU_data_address;
839 FPU_REG t;
840 long tl;
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 || (t.sigl & 0x80000000))
863 {
864 EXCEPTION(EX_Invalid);
865
866 if ( control_word & EX_Invalid )
867 {
868
869 tl = 0x80000000;
870 }
871 else
872 return 0;
873 }
874 else
875 tl = FPU_st0_ptr->sign ? -t.sigl : t.sigl;
876
877 RE_ENTRANT_CHECK_OFF
878 verify_area(d,4);
879 put_fs_long(tl, (unsigned long *) d);
880 RE_ENTRANT_CHECK_ON
881
882 return 1;
883 }
884
885
886
887 int reg_store_int16(void)
888 {
889 short *d = (short *)FPU_data_address;
890 FPU_REG t;
891 short ts;
892
893 if ( FPU_st0_tag == TW_Empty )
894 {
895
896 EXCEPTION(EX_StackUnder);
897 if ( control_word & EX_Invalid )
898 {
899
900
901 RE_ENTRANT_CHECK_OFF
902 verify_area(d,2);
903 put_fs_word(0x8000, (unsigned short *) d);
904 RE_ENTRANT_CHECK_ON
905 return 1;
906 }
907 else
908 return 0;
909 }
910
911 reg_move(FPU_st0_ptr, &t);
912 round_to_int(&t);
913 if (t.sigh || (t.sigl & 0xFFFF8000))
914 {
915 EXCEPTION(EX_Invalid);
916
917 if ( control_word & EX_Invalid )
918 {
919
920 ts = 0x8000;
921 }
922 else
923 return 0;
924 }
925 else
926 ts = FPU_st0_ptr->sign ? -t.sigl : t.sigl;
927
928 RE_ENTRANT_CHECK_OFF
929 verify_area(d,2);
930 put_fs_word(ts,(short *) d);
931 RE_ENTRANT_CHECK_ON
932
933 return 1;
934 }
935
936
937
938 int reg_store_bcd(void)
939 {
940 char *d = (char *)FPU_data_address;
941 FPU_REG t;
942 long long ll;
943 unsigned char b;
944 int i;
945 unsigned char sign = (FPU_st0_ptr->sign == SIGN_NEG) ? 0x80 : 0;
946
947 if ( FPU_st0_tag == TW_Empty )
948 {
949
950 EXCEPTION(EX_StackUnder);
951 if ( control_word & EX_Invalid )
952 {
953
954
955 goto put_indefinite;
956 }
957 else
958 return 0;
959 }
960
961 reg_move(FPU_st0_ptr, &t);
962 round_to_int(&t);
963 ll = *(long long *)(&t.sigl);
964
965
966 if ( (t.sigh > 0x0de0b6b3) ||
967 ((t.sigh == 0x0de0b6b3) && (t.sigl > 0xa763ffff)) )
968 {
969 EXCEPTION(EX_Invalid);
970
971 if ( control_word & EX_Invalid )
972 {
973 put_indefinite:
974
975 RE_ENTRANT_CHECK_OFF
976 verify_area(d,10);
977 put_fs_byte(0xff,(unsigned char *) d+7);
978 put_fs_byte(0xff,(unsigned char *) d+8);
979 put_fs_byte(0xff,(unsigned char *) d+9);
980 RE_ENTRANT_CHECK_ON
981 return 1;
982 }
983 else
984 return 0;
985 }
986
987 verify_area(d,10);
988 for ( i = 0; i < 9; i++)
989 {
990 b = div_small(&ll, 10);
991 b |= (div_small(&ll, 10)) << 4;
992 RE_ENTRANT_CHECK_OFF
993 put_fs_byte(b,(unsigned char *) d+i);
994 RE_ENTRANT_CHECK_ON
995 }
996 RE_ENTRANT_CHECK_OFF
997 put_fs_byte(sign,(unsigned char *) d+9);
998 RE_ENTRANT_CHECK_ON
999
1000 return 1;
1001 }
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011 int round_to_int(FPU_REG *r)
1012 {
1013 char very_big;
1014 unsigned eax;
1015
1016 if (r->tag == TW_Zero)
1017 {
1018
1019 *(long long *)&r->sigl = 0;
1020 return 0;
1021 }
1022
1023 if (r->exp > EXP_BIAS + 63)
1024 {
1025 r->sigl = r->sigh = ~0;
1026 return 1;
1027 }
1028
1029 eax = shrxs(&r->sigl, EXP_BIAS + 63 - r->exp);
1030 very_big = !(~(r->sigh) | ~(r->sigl));
1031 #define half_or_more (eax & 0x80000000)
1032 #define frac_part (eax)
1033 #define more_than_half ((eax & 0x80000001) == 0x80000001)
1034 switch (control_word & CW_RC)
1035 {
1036 case RC_RND:
1037 if ( more_than_half
1038 || (half_or_more && (r->sigl & 1)) )
1039 {
1040 if ( very_big ) return 1;
1041 (*(long long *)(&r->sigl)) ++;
1042 }
1043 break;
1044 case RC_DOWN:
1045 if (frac_part && r->sign)
1046 {
1047 if ( very_big ) return 1;
1048 (*(long long *)(&r->sigl)) ++;
1049 }
1050 break;
1051 case RC_UP:
1052 if (frac_part && !r->sign)
1053 {
1054 if ( very_big ) return 1;
1055 (*(long long *)(&r->sigl)) ++;
1056 }
1057 break;
1058 case RC_CHOP:
1059 break;
1060 }
1061
1062 return 0;
1063 }
1064
1065
1066
1067 char *fldenv(void)
1068 {
1069 char *s = (char *)FPU_data_address;
1070 unsigned short tag_word = 0;
1071 unsigned char tag;
1072 int i;
1073
1074 RE_ENTRANT_CHECK_OFF
1075 control_word = get_fs_word((unsigned short *) s);
1076 status_word = get_fs_word((unsigned short *) (s+4));
1077 tag_word = get_fs_word((unsigned short *) (s+8));
1078 ip_offset = get_fs_long((unsigned long *) (s+0x0c));
1079 cs_selector = get_fs_long((unsigned long *) (s+0x10));
1080 data_operand_offset = get_fs_long((unsigned long *) (s+0x14));
1081 operand_selector = get_fs_long((unsigned long *) (s+0x18));
1082 RE_ENTRANT_CHECK_ON
1083
1084
1085 for ( i = 7; i >= 0; i-- )
1086 {
1087 tag = tag_word & 3;
1088 tag_word <<= 2;
1089
1090 switch ( tag )
1091 {
1092 case 0:
1093 regs[i].tag = TW_Valid;
1094 break;
1095 case 1:
1096 regs[i].tag = TW_Zero;
1097 break;
1098 case 2:
1099 regs[i].tag = TW_NaN;
1100 break;
1101 case 3:
1102 regs[i].tag = TW_Empty;
1103 break;
1104 }
1105 }
1106
1107 FPU_data_address = (void *)data_operand_offset;
1108 FPU_entry_eip = ip_offset;
1109
1110 return s + 0x1c;
1111 }
1112
1113
1114 void frstor(void)
1115 {
1116 int i;
1117 unsigned char tag;
1118 FPU_REG *s = (FPU_REG *)fldenv();
1119
1120 for ( i = 0; i < 8; i++ )
1121 {
1122
1123 FPU_data_address = (void *)&(s[i]);
1124 reg_load_extended();
1125 tag = regs[i].tag;
1126 reg_move(&FPU_loaded_data, ®s[i]);
1127 if ( tag == TW_NaN )
1128 {
1129 unsigned char t = regs[i].tag;
1130 if ( (t == TW_Valid) || (t == TW_Zero) )
1131 regs[i].tag = TW_NaN;
1132 }
1133 else
1134 regs[i].tag = tag;
1135 }
1136
1137 FPU_data_address = (void *)data_operand_offset;
1138 }
1139
1140
1141 char *fstenv(void)
1142 {
1143 char *d = (char *)FPU_data_address;
1144 unsigned short tag_word = 0;
1145 unsigned char tag;
1146 int i;
1147
1148 verify_area(d,28);
1149
1150 for ( i = 7; i >= 0; i-- )
1151 {
1152 switch ( tag = regs[i].tag )
1153 {
1154 case TW_Denormal:
1155 case TW_Infinity:
1156 case TW_NaN:
1157 tag = 2;
1158 break;
1159 case TW_Empty:
1160 tag = 3;
1161 break;
1162
1163 }
1164 tag_word <<= 2;
1165 tag_word |= tag;
1166 }
1167
1168
1169 *(unsigned short *)&cs_selector = FPU_CS;
1170 *(unsigned short *)&operand_selector = FPU_DS;
1171
1172 RE_ENTRANT_CHECK_OFF
1173 put_fs_word(control_word, (unsigned short *) d);
1174 put_fs_word(status_word, (unsigned short *) (d+4));
1175 put_fs_word(tag_word, (unsigned short *) (d+8));
1176 put_fs_long(ip_offset, (unsigned long *) (d+0x0c));
1177 put_fs_long(cs_selector, (unsigned long *) (d+0x10));
1178 put_fs_long(data_operand_offset, (unsigned long *) (d+0x14));
1179 put_fs_long(operand_selector, (unsigned long *) (d+0x18));
1180 RE_ENTRANT_CHECK_ON
1181
1182 return d + 0x1c;
1183 }
1184
1185
1186 void fsave(void)
1187 {
1188 char *d;
1189 FPU_REG tmp, *rp;
1190 int i;
1191 short e;
1192
1193 d = fstenv();
1194 verify_area(d,80);
1195 for ( i = 0; i < 8; i++ )
1196 {
1197
1198 rp = ®s[i];
1199
1200 e = rp->exp - EXP_BIAS + EXTENDED_Ebias;
1201
1202 if ( rp->tag == TW_Valid )
1203 {
1204 if ( e >= 0x7fff )
1205 {
1206
1207 RE_ENTRANT_CHECK_OFF
1208 put_fs_long(0, (unsigned long *) (d+i*10+2));
1209 put_fs_long(0x80000000, (unsigned long *) (d+i*10+6));
1210 RE_ENTRANT_CHECK_ON
1211 e = 0x7fff;
1212 }
1213 else if ( e <= 0 )
1214 {
1215 if ( e == 0 )
1216 {
1217
1218 RE_ENTRANT_CHECK_OFF
1219 put_fs_long(rp->sigl, (unsigned long *) (d+i*10+2));
1220 put_fs_long(rp->sigh, (unsigned long *) (d+i*10+6));
1221 RE_ENTRANT_CHECK_ON
1222 }
1223 else if ( e > -64 )
1224 {
1225
1226 reg_move(rp, &tmp);
1227 tmp.exp += -EXTENDED_Emin + 64;
1228 round_to_int(&tmp);
1229 e = 0;
1230 RE_ENTRANT_CHECK_OFF
1231 put_fs_long(tmp.sigl, (unsigned long *) (d+i*10+2));
1232 put_fs_long(tmp.sigh, (unsigned long *) (d+i*10+6));
1233 RE_ENTRANT_CHECK_ON
1234 }
1235 else
1236 {
1237
1238 RE_ENTRANT_CHECK_OFF
1239 put_fs_long(0, (unsigned long *) (d+i*10+2));
1240 put_fs_long(0, (unsigned long *) (d+i*10+6));
1241 RE_ENTRANT_CHECK_ON
1242 e = 0;
1243 }
1244 }
1245 else
1246 {
1247 RE_ENTRANT_CHECK_OFF
1248 put_fs_long(rp->sigl, (unsigned long *) (d+i*10+2));
1249 put_fs_long(rp->sigh, (unsigned long *) (d+i*10+6));
1250 RE_ENTRANT_CHECK_ON
1251 }
1252 }
1253 else if ( rp->tag == TW_Zero )
1254 {
1255 RE_ENTRANT_CHECK_OFF
1256 put_fs_long(0, (unsigned long *) (d+i*10+2));
1257 put_fs_long(0, (unsigned long *) (d+i*10+6));
1258 RE_ENTRANT_CHECK_ON
1259 e = 0;
1260 }
1261 else if ( rp->tag == TW_Infinity )
1262 {
1263 RE_ENTRANT_CHECK_OFF
1264 put_fs_long(0, (unsigned long *) (d+i*10+2));
1265 put_fs_long(0x80000000, (unsigned long *) (d+i*10+6));
1266 RE_ENTRANT_CHECK_ON
1267 e = 0x7fff;
1268 }
1269 else if ( rp->tag == TW_NaN )
1270 {
1271 RE_ENTRANT_CHECK_OFF
1272 put_fs_long(rp->sigl, (unsigned long *) (d+i*10+2));
1273 put_fs_long(rp->sigh, (unsigned long *) (d+i*10+6));
1274 RE_ENTRANT_CHECK_ON
1275 e = 0x7fff;
1276 }
1277 else if ( rp->tag == TW_Empty )
1278 {
1279
1280 RE_ENTRANT_CHECK_OFF
1281 put_fs_long(rp->sigl, (unsigned long *) (d+i*10+2));
1282 put_fs_long(rp->sigh, (unsigned long *) (d+i*10+6));
1283 RE_ENTRANT_CHECK_ON
1284 }
1285 RE_ENTRANT_CHECK_OFF
1286 put_fs_word(e, (unsigned short *) (d+i*10));
1287 RE_ENTRANT_CHECK_ON
1288 }
1289
1290 }
1291
1292