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