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