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