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