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 exp;
470 FPU_REG tmp;
471
472 reg_move(st0_ptr, &tmp);
473 exp = tmp.exp - EXP_BIAS;
474
475 if ( exp < DOUBLE_Emin )
476 {
477 int precision_loss;
478
479
480 #ifndef PECULIAR_486
481
482
483 if ( st0_ptr->exp <= EXP_UNDER )
484 {
485
486 if ( control_word & CW_Underflow )
487 denormal_operand();
488 }
489 #endif PECULIAR_486
490
491 tmp.exp += -DOUBLE_Emin + 52;
492
493 if ( (precision_loss = round_to_int(&tmp)) )
494 {
495 #ifdef PECULIAR_486
496
497
498
499
500 if ( !((tmp.sigh == 0x00100000) && (tmp.sigl == 0) &&
501 (st0_ptr->sigl & 0x000007ff)) )
502 #endif PECULIAR_486
503 {
504 EXCEPTION(EX_Underflow);
505
506
507 if ( !(control_word & CW_Underflow) )
508 return 0;
509 }
510 EXCEPTION(precision_loss);
511 if ( !(control_word & CW_Precision) )
512 return 0;
513 }
514 l[0] = tmp.sigl;
515 l[1] = tmp.sigh;
516 }
517 else
518 {
519 if ( tmp.sigl & 0x000007ff )
520 {
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 set_precision_flag_up();
545
546 if ( tmp.sigl >= 0xfffff800 )
547 {
548
549 if ( tmp.sigh == 0xffffffff )
550 {
551
552 tmp.sigh = 0x80000000;
553 exp++;
554 if (exp >= EXP_OVER)
555 goto overflow;
556 }
557 else
558 {
559 tmp.sigh ++;
560 }
561 tmp.sigl = 0x00000000;
562 }
563 else
564 {
565
566 tmp.sigl += 0x00000800;
567 }
568 }
569 else
570 set_precision_flag_down();
571 }
572
573 l[0] = (tmp.sigl >> 11) | (tmp.sigh << 21);
574 l[1] = ((tmp.sigh >> 11) & 0xfffff);
575
576 if ( exp > DOUBLE_Emax )
577 {
578 overflow:
579 EXCEPTION(EX_Overflow);
580 if ( !(control_word & CW_Overflow) )
581 return 0;
582 set_precision_flag_up();
583 if ( !(control_word & CW_Precision) )
584 return 0;
585
586
587
588 l[0] = 0x00000000;
589 l[1] = 0x7ff00000;
590 }
591 else
592 {
593
594 l[1] |= (((exp+DOUBLE_Ebias) & 0x7ff) << 20);
595 }
596 }
597 }
598 else if (st0_tag == TW_Zero)
599 {
600
601 l[0] = 0;
602 l[1] = 0;
603 }
604 else if (st0_tag == TW_Infinity)
605 {
606 l[0] = 0;
607 l[1] = 0x7ff00000;
608 }
609 else if (st0_tag == TW_NaN)
610 {
611
612 l[0] = (st0_ptr->sigl >> 11) | (st0_ptr->sigh << 21);
613 l[1] = ((st0_ptr->sigh >> 11) & 0xfffff);
614 if ( !(st0_ptr->sigh & 0x40000000) )
615 {
616
617 EXCEPTION(EX_Invalid);
618 if ( !(control_word & CW_Invalid) )
619 return 0;
620 l[1] |= (0x40000000 >> 11);
621 }
622 l[1] |= 0x7ff00000;
623 }
624 else if ( st0_tag == TW_Empty )
625 {
626
627 EXCEPTION(EX_StackUnder);
628 if ( control_word & CW_Invalid )
629 {
630
631
632 RE_ENTRANT_CHECK_OFF;
633 FPU_verify_area(VERIFY_WRITE,(void *)dfloat,8);
634 put_fs_long(0, (unsigned long *) dfloat);
635 put_fs_long(0xfff80000, 1 + (unsigned long *) dfloat);
636 RE_ENTRANT_CHECK_ON;
637 return 1;
638 }
639 else
640 return 0;
641 }
642 if ( st0_ptr->sign )
643 l[1] |= 0x80000000;
644
645 RE_ENTRANT_CHECK_OFF;
646 FPU_verify_area(VERIFY_WRITE,(void *)dfloat,8);
647 put_fs_long(l[0], (unsigned long *)dfloat);
648 put_fs_long(l[1], 1 + (unsigned long *)dfloat);
649 RE_ENTRANT_CHECK_ON;
650
651 return 1;
652 }
653
654
655
656 int reg_store_single(float *single, FPU_REG *st0_ptr)
657 {
658 long templ;
659 unsigned long increment = 0;
660 char st0_tag = st0_ptr->tag;
661
662 if (st0_tag == TW_Valid)
663 {
664 int exp;
665 FPU_REG tmp;
666
667 reg_move(st0_ptr, &tmp);
668 exp = tmp.exp - EXP_BIAS;
669
670 if ( exp < SINGLE_Emin )
671 {
672 int precision_loss;
673
674
675 #ifndef PECULIAR_486
676
677
678 if ( st0_ptr->exp <= EXP_UNDER )
679 {
680
681 if ( control_word & CW_Underflow )
682 denormal_operand();
683 }
684 #endif PECULIAR_486
685
686 tmp.exp += -SINGLE_Emin + 23;
687
688 if ( (precision_loss = round_to_int(&tmp)) )
689 {
690 #ifdef PECULIAR_486
691
692
693
694
695 if ( !((tmp.sigl == 0x00800000) &&
696 ((st0_ptr->sigh & 0x000000ff) || st0_ptr->sigl)) )
697 #endif PECULIAR_486
698 {
699 EXCEPTION(EX_Underflow);
700
701
702 if ( !(control_word & EX_Underflow) )
703 return 0;
704 }
705 EXCEPTION(precision_loss);
706 if ( !(control_word & EX_Precision) )
707 return 0;
708 }
709 templ = tmp.sigl;
710 }
711 else
712 {
713 if ( tmp.sigl | (tmp.sigh & 0x000000ff) )
714 {
715 unsigned long sigh = tmp.sigh;
716 unsigned long sigl = tmp.sigl;
717
718 switch (control_word & CW_RC)
719 {
720 case RC_RND:
721 increment = ((sigh & 0xff) > 0x80)
722 || (((sigh & 0xff) == 0x80) && sigl)
723 || ((sigh & 0x180) == 0x180);
724 break;
725 case RC_DOWN:
726 increment = (tmp.sign == SIGN_POS)
727 ? 0 : (sigl | (sigh & 0xff));
728 break;
729 case RC_UP:
730 increment = (tmp.sign == SIGN_POS)
731 ? (sigl | (sigh & 0xff)) : 0;
732 break;
733 case RC_CHOP:
734 increment = 0;
735 break;
736 }
737
738
739 tmp.sigl = 0;
740
741 if (increment)
742 {
743 set_precision_flag_up();
744
745 if ( sigh >= 0xffffff00 )
746 {
747
748 tmp.sigh = 0x80000000;
749 exp++;
750 if ( exp >= EXP_OVER )
751 goto overflow;
752 }
753 else
754 {
755 tmp.sigh &= 0xffffff00;
756 tmp.sigh += 0x100;
757 }
758 }
759 else
760 {
761 set_precision_flag_down();
762 tmp.sigh &= 0xffffff00;
763 }
764 }
765
766 templ = (tmp.sigh >> 8) & 0x007fffff;
767
768 if ( exp > SINGLE_Emax )
769 {
770 overflow:
771 EXCEPTION(EX_Overflow);
772 if ( !(control_word & CW_Overflow) )
773 return 0;
774 set_precision_flag_up();
775 if ( !(control_word & CW_Precision) )
776 return 0;
777
778
779
780 templ = 0x7f800000;
781 }
782 else
783 templ |= ((exp+SINGLE_Ebias) & 0xff) << 23;
784 }
785 }
786 else if (st0_tag == TW_Zero)
787 {
788 templ = 0;
789 }
790 else if (st0_tag == TW_Infinity)
791 {
792 templ = 0x7f800000;
793 }
794 else if (st0_tag == TW_NaN)
795 {
796
797 templ = st0_ptr->sigh >> 8;
798 if ( !(st0_ptr->sigh & 0x40000000) )
799 {
800
801 EXCEPTION(EX_Invalid);
802 if ( !(control_word & CW_Invalid) )
803 return 0;
804 templ |= (0x40000000 >> 8);
805 }
806 templ |= 0x7f800000;
807 }
808 else if ( st0_tag == TW_Empty )
809 {
810
811 EXCEPTION(EX_StackUnder);
812 if ( control_word & EX_Invalid )
813 {
814
815
816 RE_ENTRANT_CHECK_OFF;
817 FPU_verify_area(VERIFY_WRITE,(void *)single,4);
818 put_fs_long(0xffc00000, (unsigned long *) single);
819 RE_ENTRANT_CHECK_ON;
820 return 1;
821 }
822 else
823 return 0;
824 }
825 #ifdef PARANOID
826 else
827 {
828 EXCEPTION(EX_INTERNAL|0x163);
829 return 0;
830 }
831 #endif
832 if (st0_ptr->sign)
833 templ |= 0x80000000;
834
835 RE_ENTRANT_CHECK_OFF;
836 FPU_verify_area(VERIFY_WRITE,(void *)single,4);
837 put_fs_long(templ,(unsigned long *) single);
838 RE_ENTRANT_CHECK_ON;
839
840 return 1;
841 }
842
843
844
845 int reg_store_int64(long long *d, FPU_REG *st0_ptr)
846 {
847 FPU_REG t;
848 long long tll;
849 int precision_loss;
850 char st0_tag = st0_ptr->tag;
851
852 if ( st0_tag == TW_Empty )
853 {
854
855 EXCEPTION(EX_StackUnder);
856 goto invalid_operand;
857 }
858 else if ( (st0_tag == TW_Infinity) ||
859 (st0_tag == TW_NaN) )
860 {
861 EXCEPTION(EX_Invalid);
862 goto invalid_operand;
863 }
864
865 reg_move(st0_ptr, &t);
866 precision_loss = round_to_int(&t);
867 ((long *)&tll)[0] = t.sigl;
868 ((long *)&tll)[1] = t.sigh;
869 if ( (precision_loss == 1) ||
870 ((t.sigh & 0x80000000) &&
871 !((t.sigh == 0x80000000) && (t.sigl == 0) &&
872 (t.sign == SIGN_NEG))) )
873 {
874 EXCEPTION(EX_Invalid);
875
876 invalid_operand:
877 if ( control_word & EX_Invalid )
878 {
879
880 tll = 0x8000000000000000LL;
881 }
882 else
883 return 0;
884 }
885 else
886 {
887 if ( precision_loss )
888 set_precision_flag(precision_loss);
889 if ( t.sign )
890 tll = - tll;
891 }
892
893 RE_ENTRANT_CHECK_OFF;
894 FPU_verify_area(VERIFY_WRITE,(void *)d,8);
895 put_fs_long(((long *)&tll)[0],(unsigned long *) d);
896 put_fs_long(((long *)&tll)[1],1 + (unsigned long *) d);
897 RE_ENTRANT_CHECK_ON;
898
899 return 1;
900 }
901
902
903
904 int reg_store_int32(long *d, FPU_REG *st0_ptr)
905 {
906 FPU_REG t;
907 int precision_loss;
908 char st0_tag = st0_ptr->tag;
909
910 if ( st0_tag == TW_Empty )
911 {
912
913 EXCEPTION(EX_StackUnder);
914 goto invalid_operand;
915 }
916 else if ( (st0_tag == TW_Infinity) ||
917 (st0_tag == TW_NaN) )
918 {
919 EXCEPTION(EX_Invalid);
920 goto invalid_operand;
921 }
922
923 reg_move(st0_ptr, &t);
924 precision_loss = round_to_int(&t);
925 if (t.sigh ||
926 ((t.sigl & 0x80000000) &&
927 !((t.sigl == 0x80000000) && (t.sign == SIGN_NEG))) )
928 {
929 EXCEPTION(EX_Invalid);
930
931 invalid_operand:
932 if ( control_word & EX_Invalid )
933 {
934
935 t.sigl = 0x80000000;
936 }
937 else
938 return 0;
939 }
940 else
941 {
942 if ( precision_loss )
943 set_precision_flag(precision_loss);
944 if ( t.sign )
945 t.sigl = -(long)t.sigl;
946 }
947
948 RE_ENTRANT_CHECK_OFF;
949 FPU_verify_area(VERIFY_WRITE,d,4);
950 put_fs_long(t.sigl, (unsigned long *) d);
951 RE_ENTRANT_CHECK_ON;
952
953 return 1;
954 }
955
956
957
958 int reg_store_int16(short *d, FPU_REG *st0_ptr)
959 {
960 FPU_REG t;
961 int precision_loss;
962 char st0_tag = st0_ptr->tag;
963
964 if ( st0_tag == TW_Empty )
965 {
966
967 EXCEPTION(EX_StackUnder);
968 goto invalid_operand;
969 }
970 else if ( (st0_tag == TW_Infinity) ||
971 (st0_tag == TW_NaN) )
972 {
973 EXCEPTION(EX_Invalid);
974 goto invalid_operand;
975 }
976
977 reg_move(st0_ptr, &t);
978 precision_loss = round_to_int(&t);
979 if (t.sigh ||
980 ((t.sigl & 0xffff8000) &&
981 !((t.sigl == 0x8000) && (t.sign == SIGN_NEG))) )
982 {
983 EXCEPTION(EX_Invalid);
984
985 invalid_operand:
986 if ( control_word & EX_Invalid )
987 {
988
989 t.sigl = 0x8000;
990 }
991 else
992 return 0;
993 }
994 else
995 {
996 if ( precision_loss )
997 set_precision_flag(precision_loss);
998 if ( t.sign )
999 t.sigl = -t.sigl;
1000 }
1001
1002 RE_ENTRANT_CHECK_OFF;
1003 FPU_verify_area(VERIFY_WRITE,d,2);
1004 put_fs_word((short)t.sigl,(short *) d);
1005 RE_ENTRANT_CHECK_ON;
1006
1007 return 1;
1008 }
1009
1010
1011
1012 int reg_store_bcd(char *d, FPU_REG *st0_ptr)
1013 {
1014 FPU_REG t;
1015 unsigned long long ll;
1016 unsigned char b;
1017 int i, precision_loss;
1018 unsigned char sign = (st0_ptr->sign == SIGN_NEG) ? 0x80 : 0;
1019 char st0_tag = st0_ptr->tag;
1020
1021 if ( st0_tag == TW_Empty )
1022 {
1023
1024 EXCEPTION(EX_StackUnder);
1025 goto invalid_operand;
1026 }
1027
1028 reg_move(st0_ptr, &t);
1029 precision_loss = round_to_int(&t);
1030 ll = significand(&t);
1031
1032
1033 if ( (t.sigh > 0x0de0b6b3) ||
1034 ((t.sigh == 0x0de0b6b3) && (t.sigl > 0xa763ffff)) )
1035 {
1036 EXCEPTION(EX_Invalid);
1037
1038 invalid_operand:
1039 if ( control_word & CW_Invalid )
1040 {
1041
1042 RE_ENTRANT_CHECK_OFF;
1043 FPU_verify_area(VERIFY_WRITE,d,10);
1044 for ( i = 0; i < 7; i++)
1045 put_fs_byte(0, (unsigned char *) d+i);
1046 put_fs_byte(0xc0, (unsigned char *) d+7);
1047 put_fs_byte(0xff, (unsigned char *) d+8);
1048 put_fs_byte(0xff, (unsigned char *) d+9);
1049 RE_ENTRANT_CHECK_ON;
1050 return 1;
1051 }
1052 else
1053 return 0;
1054 }
1055 else if ( precision_loss )
1056 {
1057
1058 set_precision_flag(precision_loss);
1059 }
1060
1061 RE_ENTRANT_CHECK_OFF;
1062 FPU_verify_area(VERIFY_WRITE,d,10);
1063 RE_ENTRANT_CHECK_ON;
1064 for ( i = 0; i < 9; i++)
1065 {
1066 b = div_small(&ll, 10);
1067 b |= (div_small(&ll, 10)) << 4;
1068 RE_ENTRANT_CHECK_OFF;
1069 put_fs_byte(b,(unsigned char *) d+i);
1070 RE_ENTRANT_CHECK_ON;
1071 }
1072 RE_ENTRANT_CHECK_OFF;
1073 put_fs_byte(sign,(unsigned char *) d+9);
1074 RE_ENTRANT_CHECK_ON;
1075
1076 return 1;
1077 }
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089 int round_to_int(FPU_REG *r)
1090 {
1091 char very_big;
1092 unsigned eax;
1093
1094 if (r->tag == TW_Zero)
1095 {
1096
1097 significand(r) = 0;
1098 return 0;
1099 }
1100
1101 if (r->exp > EXP_BIAS + 63)
1102 {
1103 r->sigl = r->sigh = ~0;
1104 return 1;
1105 }
1106
1107 eax = shrxs(&r->sigl, EXP_BIAS + 63 - r->exp);
1108 very_big = !(~(r->sigh) | ~(r->sigl));
1109 #define half_or_more (eax & 0x80000000)
1110 #define frac_part (eax)
1111 #define more_than_half ((eax & 0x80000001) == 0x80000001)
1112 switch (control_word & CW_RC)
1113 {
1114 case RC_RND:
1115 if ( more_than_half
1116 || (half_or_more && (r->sigl & 1)) )
1117 {
1118 if ( very_big ) return 1;
1119 significand(r) ++;
1120 return PRECISION_LOST_UP;
1121 }
1122 break;
1123 case RC_DOWN:
1124 if (frac_part && r->sign)
1125 {
1126 if ( very_big ) return 1;
1127 significand(r) ++;
1128 return PRECISION_LOST_UP;
1129 }
1130 break;
1131 case RC_UP:
1132 if (frac_part && !r->sign)
1133 {
1134 if ( very_big ) return 1;
1135 significand(r) ++;
1136 return PRECISION_LOST_UP;
1137 }
1138 break;
1139 case RC_CHOP:
1140 break;
1141 }
1142
1143 return eax ? PRECISION_LOST_DOWN : 0;
1144
1145 }
1146
1147
1148
1149 char *fldenv(fpu_addr_modes addr_modes, char *s)
1150 {
1151 unsigned short tag_word = 0;
1152 unsigned char tag;
1153 int i;
1154
1155 if ( (addr_modes.default_mode == VM86) ||
1156 ((addr_modes.default_mode == PM16)
1157 ^ (addr_modes.override.operand_size == OP_SIZE_PREFIX)) )
1158 {
1159 RE_ENTRANT_CHECK_OFF;
1160 FPU_verify_area(VERIFY_READ, s, 0x0e);
1161 control_word = get_fs_word((unsigned short *) s);
1162 partial_status = get_fs_word((unsigned short *) (s+2));
1163 tag_word = get_fs_word((unsigned short *) (s+4));
1164 instruction_address.offset = get_fs_word((unsigned short *) (s+6));
1165 instruction_address.selector = get_fs_word((unsigned short *) (s+8));
1166 operand_address.offset = get_fs_word((unsigned short *) (s+0x0a));
1167 operand_address.selector = get_fs_word((unsigned short *) (s+0x0c));
1168 RE_ENTRANT_CHECK_ON;
1169 s += 0x0e;
1170 if ( addr_modes.default_mode == VM86 )
1171 {
1172 instruction_address.offset
1173 += (instruction_address.selector & 0xf000) << 4;
1174 operand_address.offset += (operand_address.selector & 0xf000) << 4;
1175 }
1176 }
1177 else
1178 {
1179 RE_ENTRANT_CHECK_OFF;
1180 FPU_verify_area(VERIFY_READ, s, 0x1c);
1181 control_word = get_fs_word((unsigned short *) s);
1182 partial_status = get_fs_word((unsigned short *) (s+4));
1183 tag_word = get_fs_word((unsigned short *) (s+8));
1184 instruction_address.offset = get_fs_long((unsigned long *) (s+0x0c));
1185 instruction_address.selector = get_fs_word((unsigned short *) (s+0x10));
1186 instruction_address.opcode = get_fs_word((unsigned short *) (s+0x12));
1187 operand_address.offset = get_fs_long((unsigned long *) (s+0x14));
1188 operand_address.selector = get_fs_long((unsigned long *) (s+0x18));
1189 RE_ENTRANT_CHECK_ON;
1190 s += 0x1c;
1191 }
1192
1193 #ifdef PECULIAR_486
1194 control_word &= ~0xe080;
1195 #endif PECULIAR_486
1196
1197 top = (partial_status >> SW_Top_Shift) & 7;
1198
1199 if ( partial_status & ~control_word & CW_Exceptions )
1200 partial_status |= (SW_Summary | SW_Backward);
1201 else
1202 partial_status &= ~(SW_Summary | SW_Backward);
1203
1204 for ( i = 0; i < 8; i++ )
1205 {
1206 tag = tag_word & 3;
1207 tag_word >>= 2;
1208
1209 if ( tag == 3 )
1210
1211 regs[i].tag = TW_Empty;
1212 else if ( regs[i].tag == TW_Empty )
1213 {
1214
1215
1216 if ( regs[i].exp == EXP_BIAS - EXTENDED_Ebias )
1217 {
1218 if ( !(regs[i].sigl | regs[i].sigh) )
1219 regs[i].tag = TW_Zero;
1220 else
1221 regs[i].tag = TW_Valid;
1222 }
1223 else if ( regs[i].exp == 0x7fff + EXP_BIAS - EXTENDED_Ebias )
1224 {
1225 if ( !((regs[i].sigh & ~0x80000000) | regs[i].sigl) )
1226 regs[i].tag = TW_Infinity;
1227 else
1228 regs[i].tag = TW_NaN;
1229 }
1230 else
1231 regs[i].tag = TW_Valid;
1232 }
1233
1234
1235 }
1236
1237 return s;
1238 }
1239
1240
1241 void frstor(fpu_addr_modes addr_modes, char *data_address)
1242 {
1243 int i, stnr;
1244 unsigned char tag;
1245 char *s = fldenv(addr_modes, data_address);
1246
1247 for ( i = 0; i < 8; i++ )
1248 {
1249
1250 stnr = (i+top) & 7;
1251 tag = regs[stnr].tag;
1252 reg_load_extended((long double *)(s+i*10), ®s[stnr]);
1253 if ( tag == TW_Empty )
1254 regs[stnr].tag = tag;
1255 }
1256
1257 }
1258
1259
1260 unsigned short tag_word(void)
1261 {
1262 unsigned short word = 0;
1263 unsigned char tag;
1264 int i;
1265
1266 for ( i = 7; i >= 0; i-- )
1267 {
1268 switch ( tag = regs[i].tag )
1269 {
1270 case TW_Valid:
1271 if ( regs[i].exp <= (EXP_BIAS - EXTENDED_Ebias) )
1272 tag = 2;
1273 break;
1274 case TW_Infinity:
1275 case TW_NaN:
1276 tag = 2;
1277 break;
1278 case TW_Empty:
1279 tag = 3;
1280 break;
1281
1282 }
1283 word <<= 2;
1284 word |= tag;
1285 }
1286 return word;
1287 }
1288
1289
1290 char *fstenv(fpu_addr_modes addr_modes, char *d)
1291 {
1292 if ( (addr_modes.default_mode == VM86) ||
1293 ((addr_modes.default_mode == PM16)
1294 ^ (addr_modes.override.operand_size == OP_SIZE_PREFIX)) )
1295 {
1296 RE_ENTRANT_CHECK_OFF;
1297 FPU_verify_area(VERIFY_WRITE,d,14);
1298 #ifdef PECULIAR_486
1299 put_fs_long(control_word & ~0xe080, (unsigned short *) d);
1300 #else
1301 put_fs_word(control_word, (unsigned short *) d);
1302 #endif PECULIAR_486
1303 put_fs_word(status_word(), (unsigned short *) (d+2));
1304 put_fs_word(tag_word(), (unsigned short *) (d+4));
1305 put_fs_word(instruction_address.offset, (unsigned short *) (d+6));
1306 put_fs_word(operand_address.offset, (unsigned short *) (d+0x0a));
1307 if ( addr_modes.default_mode == VM86 )
1308 {
1309 put_fs_word((instruction_address.offset & 0xf0000) >> 4,
1310 (unsigned short *) (d+8));
1311 put_fs_word((operand_address.offset & 0xf0000) >> 4,
1312 (unsigned short *) (d+0x0c));
1313 }
1314 else
1315 {
1316 put_fs_word(instruction_address.selector, (unsigned short *) (d+8));
1317 put_fs_word(operand_address.selector, (unsigned short *) (d+0x0c));
1318 }
1319 RE_ENTRANT_CHECK_ON;
1320 d += 0x0e;
1321 }
1322 else
1323 {
1324 RE_ENTRANT_CHECK_OFF;
1325 FPU_verify_area(VERIFY_WRITE,d,28);
1326 #ifdef PECULIAR_486
1327
1328 put_fs_long(0xffff0040 | (control_word & ~0xe080), (unsigned long *) d);
1329 put_fs_long(0xffff0000 | status_word(), (unsigned long *) (d+4));
1330 put_fs_long(0xffff0000 | tag_word(), (unsigned long *) (d+8));
1331 #else
1332 put_fs_word(control_word, (unsigned short *) d);
1333 put_fs_word(status_word(), (unsigned short *) (d+4));
1334 put_fs_word(tag_word(), (unsigned short *) (d+8));
1335 #endif PECULIAR_486
1336 put_fs_long(instruction_address.offset, (unsigned long *) (d+0x0c));
1337 put_fs_word(instruction_address.selector, (unsigned short *) (d+0x10));
1338 put_fs_word(instruction_address.opcode, (unsigned short *) (d+0x12));
1339 put_fs_long(operand_address.offset, (unsigned long *) (d+0x14));
1340 #ifdef PECULIAR_486
1341
1342 put_fs_word(operand_address.selector, (unsigned short *) (d+0x18));
1343 put_fs_word(0xffff, (unsigned short *) (d+0x1a));
1344 #else
1345 put_fs_long(operand_address.selector, (unsigned long *) (d+0x18));
1346 #endif PECULIAR_486
1347 RE_ENTRANT_CHECK_ON;
1348 d += 0x1c;
1349 }
1350
1351 control_word |= CW_Exceptions;
1352 partial_status &= ~(SW_Summary | SW_Backward);
1353
1354 return d;
1355 }
1356
1357
1358 void fsave(fpu_addr_modes addr_modes, char *data_address)
1359 {
1360 char *d;
1361 int i;
1362
1363 d = fstenv(addr_modes, data_address);
1364 RE_ENTRANT_CHECK_OFF;
1365 FPU_verify_area(VERIFY_WRITE,d,80);
1366 RE_ENTRANT_CHECK_ON;
1367 for ( i = 0; i < 8; i++ )
1368 write_to_extended(®s[(top + i) & 7], d + 10 * i);
1369
1370 finit();
1371
1372 }
1373
1374
1375
1376
1377
1378
1379
1380 static void write_to_extended(FPU_REG *rp, char *d)
1381 {
1382 long e;
1383 FPU_REG tmp;
1384
1385 e = rp->exp - EXP_BIAS + EXTENDED_Ebias;
1386
1387 #ifdef PARANOID
1388 switch ( rp->tag )
1389 {
1390 case TW_Zero:
1391 if ( rp->sigh | rp->sigl | e )
1392 EXCEPTION(EX_INTERNAL | 0x160);
1393 break;
1394 case TW_Infinity:
1395 case TW_NaN:
1396 if ( (e ^ 0x7fff) | !(rp->sigh & 0x80000000) )
1397 EXCEPTION(EX_INTERNAL | 0x161);
1398 break;
1399 default:
1400 if (e > 0x7fff || e < -63)
1401 EXCEPTION(EX_INTERNAL | 0x162);
1402 }
1403 #endif PARANOID
1404
1405
1406
1407
1408
1409
1410 if ( e > 0 )
1411 {
1412
1413 RE_ENTRANT_CHECK_OFF;
1414 put_fs_long(rp->sigl, (unsigned long *) d);
1415 put_fs_long(rp->sigh, (unsigned long *) (d + 4));
1416 RE_ENTRANT_CHECK_ON;
1417 }
1418 else
1419 {
1420
1421
1422
1423
1424
1425 reg_move(rp, &tmp);
1426 tmp.exp += -EXTENDED_Emin + 63;
1427 round_to_int(&tmp);
1428 e = 0;
1429 RE_ENTRANT_CHECK_OFF;
1430 put_fs_long(tmp.sigl, (unsigned long *) d);
1431 put_fs_long(tmp.sigh, (unsigned long *) (d + 4));
1432 RE_ENTRANT_CHECK_ON;
1433 }
1434 e |= rp->sign == SIGN_POS ? 0 : 0x8000;
1435 RE_ENTRANT_CHECK_OFF;
1436 put_fs_word(e, (unsigned short *) (d + 8));
1437 RE_ENTRANT_CHECK_ON;
1438 }