This source file includes following definitions.
- trig_arg
- convert_l2reg
- single_arg_error
- single_arg_2_error
- f2xm1
- fptan
- fxtract
- fdecstp
- fincstp
- fsqrt_
- frndint_
- fsin
- f_cos
- fcos
- fsincos
- rem_kernel
- do_fprem
- fyl2x
- fpatan
- fprem
- fprem1
- fyl2xp1
- fscale
- FPU_triga
- FPU_trigb
1
2
3
4
5
6
7
8
9
10
11
12
13
14 #include "fpu_system.h"
15 #include "exception.h"
16 #include "fpu_emu.h"
17 #include "status_w.h"
18 #include "control_w.h"
19 #include "reg_constant.h"
20
21 static void rem_kernel(unsigned long long st0, unsigned long long *y,
22 unsigned long long st1, unsigned long long q, int n);
23
24 #define BETTER_THAN_486
25
26 #define FCOS 4
27
28
29
30
31
32
33
34 static int trig_arg(FPU_REG *st0_ptr, int even)
35 {
36 FPU_REG tmp;
37 u_char tmptag;
38 unsigned long long q;
39 int old_cw = control_word, saved_status = partial_status;
40 int tag, st0_tag = TAG_Valid;
41
42 if (exponent(st0_ptr) >= 63) {
43 partial_status |= SW_C2;
44 return -1;
45 }
46
47 control_word &= ~CW_RC;
48 control_word |= RC_CHOP;
49
50 setpositive(st0_ptr);
51 tag = FPU_u_div(st0_ptr, &CONST_PI2, &tmp, PR_64_BITS | RC_CHOP | 0x3f,
52 SIGN_POS);
53
54 FPU_round_to_int(&tmp, tag);
55
56 q = significand(&tmp);
57 if (q) {
58 rem_kernel(significand(st0_ptr),
59 &significand(&tmp),
60 significand(&CONST_PI2),
61 q, exponent(st0_ptr) - exponent(&CONST_PI2));
62 setexponent16(&tmp, exponent(&CONST_PI2));
63 st0_tag = FPU_normalize(&tmp);
64 FPU_copy_to_reg0(&tmp, st0_tag);
65 }
66
67 if ((even && !(q & 1)) || (!even && (q & 1))) {
68 st0_tag =
69 FPU_sub(REV | LOADED | TAG_Valid, (int)&CONST_PI2,
70 FULL_PRECISION);
71
72 #ifdef BETTER_THAN_486
73
74
75
76
77 if ((exponent(st0_ptr) <= exponent(&CONST_PI2extra) + 64)
78 || (q > 1)) {
79
80
81
82 significand(&tmp) = q + 1;
83 setexponent16(&tmp, 63);
84 FPU_normalize(&tmp);
85 tmptag =
86 FPU_u_mul(&CONST_PI2extra, &tmp, &tmp,
87 FULL_PRECISION, SIGN_POS,
88 exponent(&CONST_PI2extra) +
89 exponent(&tmp));
90 setsign(&tmp, getsign(&CONST_PI2extra));
91 st0_tag = FPU_add(&tmp, tmptag, 0, FULL_PRECISION);
92 if (signnegative(st0_ptr)) {
93
94
95
96
97 setpositive(st0_ptr);
98 q++;
99 }
100 }
101 #endif
102 }
103 #ifdef BETTER_THAN_486
104 else {
105
106
107
108
109 if (((q > 0)
110 && (exponent(st0_ptr) <= exponent(&CONST_PI2extra) + 64))
111 || (q > 1)) {
112
113
114
115 significand(&tmp) = q;
116 setexponent16(&tmp, 63);
117 FPU_normalize(&tmp);
118 tmptag =
119 FPU_u_mul(&CONST_PI2extra, &tmp, &tmp,
120 FULL_PRECISION, SIGN_POS,
121 exponent(&CONST_PI2extra) +
122 exponent(&tmp));
123 setsign(&tmp, getsign(&CONST_PI2extra));
124 st0_tag = FPU_sub(LOADED | (tmptag & 0x0f), (int)&tmp,
125 FULL_PRECISION);
126 if ((exponent(st0_ptr) == exponent(&CONST_PI2)) &&
127 ((st0_ptr->sigh > CONST_PI2.sigh)
128 || ((st0_ptr->sigh == CONST_PI2.sigh)
129 && (st0_ptr->sigl > CONST_PI2.sigl)))) {
130
131
132
133
134
135 st0_tag =
136 FPU_sub(REV | LOADED | TAG_Valid,
137 (int)&CONST_PI2, FULL_PRECISION);
138 q++;
139 }
140 }
141 }
142 #endif
143
144 FPU_settag0(st0_tag);
145 control_word = old_cw;
146 partial_status = saved_status & ~SW_C2;
147
148 return (q & 3) | even;
149 }
150
151
152 static void convert_l2reg(long const *arg, int deststnr)
153 {
154 int tag;
155 long num = *arg;
156 u_char sign;
157 FPU_REG *dest = &st(deststnr);
158
159 if (num == 0) {
160 FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr);
161 return;
162 }
163
164 if (num > 0) {
165 sign = SIGN_POS;
166 } else {
167 num = -num;
168 sign = SIGN_NEG;
169 }
170
171 dest->sigh = num;
172 dest->sigl = 0;
173 setexponent16(dest, 31);
174 tag = FPU_normalize(dest);
175 FPU_settagi(deststnr, tag);
176 setsign(dest, sign);
177 return;
178 }
179
180 static void single_arg_error(FPU_REG *st0_ptr, u_char st0_tag)
181 {
182 if (st0_tag == TAG_Empty)
183 FPU_stack_underflow();
184 else if (st0_tag == TW_NaN)
185 real_1op_NaN(st0_ptr);
186 #ifdef PARANOID
187 else
188 EXCEPTION(EX_INTERNAL | 0x0112);
189 #endif
190 }
191
192 static void single_arg_2_error(FPU_REG *st0_ptr, u_char st0_tag)
193 {
194 int isNaN;
195
196 switch (st0_tag) {
197 case TW_NaN:
198 isNaN = (exponent(st0_ptr) == EXP_OVER)
199 && (st0_ptr->sigh & 0x80000000);
200 if (isNaN && !(st0_ptr->sigh & 0x40000000)) {
201 EXCEPTION(EX_Invalid);
202 if (control_word & CW_Invalid) {
203
204
205 st0_ptr->sigh |= 0x40000000;
206 push();
207 FPU_copy_to_reg0(st0_ptr, TAG_Special);
208 }
209 } else if (isNaN) {
210
211 push();
212 FPU_copy_to_reg0(st0_ptr, TAG_Special);
213 } else {
214
215 EXCEPTION(EX_Invalid);
216 if (control_word & CW_Invalid) {
217
218 FPU_copy_to_reg0(&CONST_QNaN, TAG_Special);
219 push();
220 FPU_copy_to_reg0(&CONST_QNaN, TAG_Special);
221 }
222 }
223 break;
224 #ifdef PARANOID
225 default:
226 EXCEPTION(EX_INTERNAL | 0x0112);
227 #endif
228 }
229 }
230
231
232
233 static void f2xm1(FPU_REG *st0_ptr, u_char tag)
234 {
235 FPU_REG a;
236
237 clear_C1();
238
239 if (tag == TAG_Valid) {
240
241 if (exponent(st0_ptr) < 0) {
242 denormal_arg:
243
244 FPU_to_exp16(st0_ptr, &a);
245
246
247 poly_2xm1(getsign(st0_ptr), &a, st0_ptr);
248 }
249 set_precision_flag_up();
250 return;
251 }
252
253 if (tag == TAG_Zero)
254 return;
255
256 if (tag == TAG_Special)
257 tag = FPU_Special(st0_ptr);
258
259 switch (tag) {
260 case TW_Denormal:
261 if (denormal_operand() < 0)
262 return;
263 goto denormal_arg;
264 case TW_Infinity:
265 if (signnegative(st0_ptr)) {
266
267 FPU_copy_to_reg0(&CONST_1, TAG_Valid);
268 setnegative(st0_ptr);
269 }
270 return;
271 default:
272 single_arg_error(st0_ptr, tag);
273 }
274 }
275
276 static void fptan(FPU_REG *st0_ptr, u_char st0_tag)
277 {
278 FPU_REG *st_new_ptr;
279 int q;
280 u_char arg_sign = getsign(st0_ptr);
281
282
283 if (st0_tag == TAG_Empty) {
284 FPU_stack_underflow();
285 if (control_word & CW_Invalid) {
286 st_new_ptr = &st(-1);
287 push();
288 FPU_stack_underflow();
289 }
290 return;
291 }
292
293 if (STACK_OVERFLOW) {
294 FPU_stack_overflow();
295 return;
296 }
297
298 if (st0_tag == TAG_Valid) {
299 if (exponent(st0_ptr) > -40) {
300 if ((q = trig_arg(st0_ptr, 0)) == -1) {
301
302 return;
303 }
304
305 poly_tan(st0_ptr);
306 setsign(st0_ptr, (q & 1) ^ (arg_sign != 0));
307 set_precision_flag_up();
308 } else {
309
310
311
312 denormal_arg:
313
314 FPU_to_exp16(st0_ptr, st0_ptr);
315
316 st0_tag =
317 FPU_round(st0_ptr, 1, 0, FULL_PRECISION, arg_sign);
318 FPU_settag0(st0_tag);
319 }
320 push();
321 FPU_copy_to_reg0(&CONST_1, TAG_Valid);
322 return;
323 }
324
325 if (st0_tag == TAG_Zero) {
326 push();
327 FPU_copy_to_reg0(&CONST_1, TAG_Valid);
328 setcc(0);
329 return;
330 }
331
332 if (st0_tag == TAG_Special)
333 st0_tag = FPU_Special(st0_ptr);
334
335 if (st0_tag == TW_Denormal) {
336 if (denormal_operand() < 0)
337 return;
338
339 goto denormal_arg;
340 }
341
342 if (st0_tag == TW_Infinity) {
343
344 if (arith_invalid(0) >= 0) {
345 st_new_ptr = &st(-1);
346 push();
347 arith_invalid(0);
348 }
349 return;
350 }
351
352 single_arg_2_error(st0_ptr, st0_tag);
353 }
354
355 static void fxtract(FPU_REG *st0_ptr, u_char st0_tag)
356 {
357 FPU_REG *st_new_ptr;
358 u_char sign;
359 register FPU_REG *st1_ptr = st0_ptr;
360
361 if (STACK_OVERFLOW) {
362 FPU_stack_overflow();
363 return;
364 }
365
366 clear_C1();
367
368 if (st0_tag == TAG_Valid) {
369 long e;
370
371 push();
372 sign = getsign(st1_ptr);
373 reg_copy(st1_ptr, st_new_ptr);
374 setexponent16(st_new_ptr, exponent(st_new_ptr));
375
376 denormal_arg:
377
378 e = exponent16(st_new_ptr);
379 convert_l2reg(&e, 1);
380 setexponentpos(st_new_ptr, 0);
381 setsign(st_new_ptr, sign);
382 FPU_settag0(TAG_Valid);
383 return;
384 } else if (st0_tag == TAG_Zero) {
385 sign = getsign(st0_ptr);
386
387 if (FPU_divide_by_zero(0, SIGN_NEG) < 0)
388 return;
389
390 push();
391 FPU_copy_to_reg0(&CONST_Z, TAG_Zero);
392 setsign(st_new_ptr, sign);
393 return;
394 }
395
396 if (st0_tag == TAG_Special)
397 st0_tag = FPU_Special(st0_ptr);
398
399 if (st0_tag == TW_Denormal) {
400 if (denormal_operand() < 0)
401 return;
402
403 push();
404 sign = getsign(st1_ptr);
405 FPU_to_exp16(st1_ptr, st_new_ptr);
406 goto denormal_arg;
407 } else if (st0_tag == TW_Infinity) {
408 sign = getsign(st0_ptr);
409 setpositive(st0_ptr);
410 push();
411 FPU_copy_to_reg0(&CONST_INF, TAG_Special);
412 setsign(st_new_ptr, sign);
413 return;
414 } else if (st0_tag == TW_NaN) {
415 if (real_1op_NaN(st0_ptr) < 0)
416 return;
417
418 push();
419 FPU_copy_to_reg0(st0_ptr, TAG_Special);
420 return;
421 } else if (st0_tag == TAG_Empty) {
422
423 if (control_word & EX_Invalid) {
424 FPU_stack_underflow();
425 push();
426 FPU_stack_underflow();
427 } else
428 EXCEPTION(EX_StackUnder);
429 }
430 #ifdef PARANOID
431 else
432 EXCEPTION(EX_INTERNAL | 0x119);
433 #endif
434 }
435
436 static void fdecstp(void)
437 {
438 clear_C1();
439 top--;
440 }
441
442 static void fincstp(void)
443 {
444 clear_C1();
445 top++;
446 }
447
448 static void fsqrt_(FPU_REG *st0_ptr, u_char st0_tag)
449 {
450 int expon;
451
452 clear_C1();
453
454 if (st0_tag == TAG_Valid) {
455 u_char tag;
456
457 if (signnegative(st0_ptr)) {
458 arith_invalid(0);
459 return;
460 }
461
462
463 expon = exponent(st0_ptr);
464
465 denormal_arg:
466
467 setexponent16(st0_ptr, (expon & 1));
468
469
470 tag = wm_sqrt(st0_ptr, 0, 0, control_word, SIGN_POS);
471 addexponent(st0_ptr, expon >> 1);
472 FPU_settag0(tag);
473 return;
474 }
475
476 if (st0_tag == TAG_Zero)
477 return;
478
479 if (st0_tag == TAG_Special)
480 st0_tag = FPU_Special(st0_ptr);
481
482 if (st0_tag == TW_Infinity) {
483 if (signnegative(st0_ptr))
484 arith_invalid(0);
485 return;
486 } else if (st0_tag == TW_Denormal) {
487 if (signnegative(st0_ptr)) {
488 arith_invalid(0);
489 return;
490 }
491
492 if (denormal_operand() < 0)
493 return;
494
495 FPU_to_exp16(st0_ptr, st0_ptr);
496
497 expon = exponent16(st0_ptr);
498
499 goto denormal_arg;
500 }
501
502 single_arg_error(st0_ptr, st0_tag);
503
504 }
505
506 static void frndint_(FPU_REG *st0_ptr, u_char st0_tag)
507 {
508 int flags, tag;
509
510 if (st0_tag == TAG_Valid) {
511 u_char sign;
512
513 denormal_arg:
514
515 sign = getsign(st0_ptr);
516
517 if (exponent(st0_ptr) > 63)
518 return;
519
520 if (st0_tag == TW_Denormal) {
521 if (denormal_operand() < 0)
522 return;
523 }
524
525
526 if ((flags = FPU_round_to_int(st0_ptr, st0_tag)))
527 set_precision_flag(flags);
528
529 setexponent16(st0_ptr, 63);
530 tag = FPU_normalize(st0_ptr);
531 setsign(st0_ptr, sign);
532 FPU_settag0(tag);
533 return;
534 }
535
536 if (st0_tag == TAG_Zero)
537 return;
538
539 if (st0_tag == TAG_Special)
540 st0_tag = FPU_Special(st0_ptr);
541
542 if (st0_tag == TW_Denormal)
543 goto denormal_arg;
544 else if (st0_tag == TW_Infinity)
545 return;
546 else
547 single_arg_error(st0_ptr, st0_tag);
548 }
549
550 static int fsin(FPU_REG *st0_ptr, u_char tag)
551 {
552 u_char arg_sign = getsign(st0_ptr);
553
554 if (tag == TAG_Valid) {
555 int q;
556
557 if (exponent(st0_ptr) > -40) {
558 if ((q = trig_arg(st0_ptr, 0)) == -1) {
559
560 return 1;
561 }
562
563 poly_sine(st0_ptr);
564
565 if (q & 2)
566 changesign(st0_ptr);
567
568 setsign(st0_ptr, getsign(st0_ptr) ^ arg_sign);
569
570
571 set_precision_flag_up();
572 return 0;
573 } else {
574
575 set_precision_flag_up();
576 return 0;
577 }
578 }
579
580 if (tag == TAG_Zero) {
581 setcc(0);
582 return 0;
583 }
584
585 if (tag == TAG_Special)
586 tag = FPU_Special(st0_ptr);
587
588 if (tag == TW_Denormal) {
589 if (denormal_operand() < 0)
590 return 1;
591
592
593
594 FPU_to_exp16(st0_ptr, st0_ptr);
595
596 tag = FPU_round(st0_ptr, 1, 0, FULL_PRECISION, arg_sign);
597
598 FPU_settag0(tag);
599
600 return 0;
601 } else if (tag == TW_Infinity) {
602
603 arith_invalid(0);
604 return 1;
605 } else {
606 single_arg_error(st0_ptr, tag);
607 return 1;
608 }
609 }
610
611 static int f_cos(FPU_REG *st0_ptr, u_char tag)
612 {
613 u_char st0_sign;
614
615 st0_sign = getsign(st0_ptr);
616
617 if (tag == TAG_Valid) {
618 int q;
619
620 if (exponent(st0_ptr) > -40) {
621 if ((exponent(st0_ptr) < 0)
622 || ((exponent(st0_ptr) == 0)
623 && (significand(st0_ptr) <=
624 0xc90fdaa22168c234LL))) {
625 poly_cos(st0_ptr);
626
627
628 set_precision_flag_down();
629
630 return 0;
631 } else if ((q = trig_arg(st0_ptr, FCOS)) != -1) {
632 poly_sine(st0_ptr);
633
634 if ((q + 1) & 2)
635 changesign(st0_ptr);
636
637
638 set_precision_flag_down();
639
640 return 0;
641 } else {
642
643 return 1;
644 }
645 } else {
646 denormal_arg:
647
648 setcc(0);
649 FPU_copy_to_reg0(&CONST_1, TAG_Valid);
650 #ifdef PECULIAR_486
651 set_precision_flag_down();
652 #else
653 set_precision_flag_up();
654 #endif
655 return 0;
656 }
657 } else if (tag == TAG_Zero) {
658 FPU_copy_to_reg0(&CONST_1, TAG_Valid);
659 setcc(0);
660 return 0;
661 }
662
663 if (tag == TAG_Special)
664 tag = FPU_Special(st0_ptr);
665
666 if (tag == TW_Denormal) {
667 if (denormal_operand() < 0)
668 return 1;
669
670 goto denormal_arg;
671 } else if (tag == TW_Infinity) {
672
673 arith_invalid(0);
674 return 1;
675 } else {
676 single_arg_error(st0_ptr, tag);
677 return 1;
678 }
679 }
680
681 static void fcos(FPU_REG *st0_ptr, u_char st0_tag)
682 {
683 f_cos(st0_ptr, st0_tag);
684 }
685
686 static void fsincos(FPU_REG *st0_ptr, u_char st0_tag)
687 {
688 FPU_REG *st_new_ptr;
689 FPU_REG arg;
690 u_char tag;
691
692
693 if (st0_tag == TAG_Empty) {
694 FPU_stack_underflow();
695 if (control_word & CW_Invalid) {
696 st_new_ptr = &st(-1);
697 push();
698 FPU_stack_underflow();
699 }
700 return;
701 }
702
703 if (STACK_OVERFLOW) {
704 FPU_stack_overflow();
705 return;
706 }
707
708 if (st0_tag == TAG_Special)
709 tag = FPU_Special(st0_ptr);
710 else
711 tag = st0_tag;
712
713 if (tag == TW_NaN) {
714 single_arg_2_error(st0_ptr, TW_NaN);
715 return;
716 } else if (tag == TW_Infinity) {
717
718 if (arith_invalid(0) >= 0) {
719
720 push();
721 arith_invalid(0);
722 }
723 return;
724 }
725
726 reg_copy(st0_ptr, &arg);
727 if (!fsin(st0_ptr, st0_tag)) {
728 push();
729 FPU_copy_to_reg0(&arg, st0_tag);
730 f_cos(&st(0), st0_tag);
731 } else {
732
733 FPU_copy_to_reg0(&arg, st0_tag);
734 }
735 }
736
737
738
739
740
741
742
743
744
745
746 static void rem_kernel(unsigned long long st0, unsigned long long *y,
747 unsigned long long st1, unsigned long long q, int n)
748 {
749 int dummy;
750 unsigned long long x;
751
752 x = st0 << n;
753
754
755
756
757 asm volatile ("mull %4; subl %%eax,%0; sbbl %%edx,%1":"=m"
758 (((unsigned *)&x)[0]), "=m"(((unsigned *)&x)[1]),
759 "=a"(dummy)
760 :"2"(((unsigned *)&st1)[0]), "m"(((unsigned *)&q)[0])
761 :"%dx");
762
763 asm volatile ("mull %3; subl %%eax,%0":"=m" (((unsigned *)&x)[1]),
764 "=a"(dummy)
765 :"1"(((unsigned *)&st1)[1]), "m"(((unsigned *)&q)[0])
766 :"%dx");
767
768 asm volatile ("mull %3; subl %%eax,%0":"=m" (((unsigned *)&x)[1]),
769 "=a"(dummy)
770 :"1"(((unsigned *)&st1)[0]), "m"(((unsigned *)&q)[1])
771 :"%dx");
772
773 *y = x;
774 }
775
776
777
778
779 static void do_fprem(FPU_REG *st0_ptr, u_char st0_tag, int round)
780 {
781 FPU_REG *st1_ptr = &st(1);
782 u_char st1_tag = FPU_gettagi(1);
783
784 if (!((st0_tag ^ TAG_Valid) | (st1_tag ^ TAG_Valid))) {
785 FPU_REG tmp, st0, st1;
786 u_char st0_sign, st1_sign;
787 u_char tmptag;
788 int tag;
789 int old_cw;
790 int expdif;
791 long long q;
792 unsigned short saved_status;
793 int cc;
794
795 fprem_valid:
796
797 st0_sign = FPU_to_exp16(st0_ptr, &st0);
798 st1_sign = FPU_to_exp16(st1_ptr, &st1);
799 expdif = exponent16(&st0) - exponent16(&st1);
800
801 old_cw = control_word;
802 cc = 0;
803
804
805
806 saved_status = partial_status;
807 control_word &= ~CW_RC;
808 control_word |= RC_CHOP;
809
810 if (expdif < 64) {
811
812
813 if (expdif > -2) {
814 u_char sign = st0_sign ^ st1_sign;
815 tag = FPU_u_div(&st0, &st1, &tmp,
816 PR_64_BITS | RC_CHOP | 0x3f,
817 sign);
818 setsign(&tmp, sign);
819
820 if (exponent(&tmp) >= 0) {
821 FPU_round_to_int(&tmp, tag);
822
823 q = significand(&tmp);
824
825 rem_kernel(significand(&st0),
826 &significand(&tmp),
827 significand(&st1),
828 q, expdif);
829
830 setexponent16(&tmp, exponent16(&st1));
831 } else {
832 reg_copy(&st0, &tmp);
833 q = 0;
834 }
835
836 if ((round == RC_RND)
837 && (tmp.sigh & 0xc0000000)) {
838
839
840 unsigned long long x;
841 expdif =
842 exponent16(&st1) - exponent16(&tmp);
843 if (expdif <= 1) {
844 if (expdif == 0)
845 x = significand(&st1) -
846 significand(&tmp);
847 else
848 x = (significand(&st1)
849 << 1) -
850 significand(&tmp);
851 if ((x < significand(&tmp)) ||
852
853 ((x == significand(&tmp))
854 && (q & 1))) {
855 st0_sign = !st0_sign;
856 significand(&tmp) = x;
857 q++;
858 }
859 }
860 }
861
862 if (q & 4)
863 cc |= SW_C0;
864 if (q & 2)
865 cc |= SW_C3;
866 if (q & 1)
867 cc |= SW_C1;
868 } else {
869 control_word = old_cw;
870 setcc(0);
871 return;
872 }
873 } else {
874
875
876
877 int exp_1, N;
878 u_char sign;
879
880
881
882 reg_copy(&st0, &tmp);
883 tmptag = st0_tag;
884 N = (expdif & 0x0000001f) + 32;
885
886 setexponent16(&tmp, N);
887 exp_1 = exponent16(&st1);
888 setexponent16(&st1, 0);
889 expdif -= N;
890
891 sign = getsign(&tmp) ^ st1_sign;
892 tag =
893 FPU_u_div(&tmp, &st1, &tmp,
894 PR_64_BITS | RC_CHOP | 0x3f, sign);
895 setsign(&tmp, sign);
896
897 FPU_round_to_int(&tmp, tag);
898
899
900 rem_kernel(significand(&st0),
901 &significand(&tmp),
902 significand(&st1),
903 significand(&tmp), exponent(&tmp)
904 );
905 setexponent16(&tmp, exp_1 + expdif);
906
907
908
909
910
911
912 if (!(tmp.sigh | tmp.sigl)) {
913
914 control_word = old_cw;
915 partial_status = saved_status;
916 FPU_copy_to_reg0(&CONST_Z, TAG_Zero);
917 setsign(&st0, st0_sign);
918 #ifdef PECULIAR_486
919 setcc(SW_C2);
920 #else
921 setcc(0);
922 #endif
923 return;
924 }
925 cc = SW_C2;
926 }
927
928 control_word = old_cw;
929 partial_status = saved_status;
930 tag = FPU_normalize_nuo(&tmp);
931 reg_copy(&tmp, st0_ptr);
932
933
934
935 if ((exponent16(&tmp) <= EXP_UNDER) && (tag != TAG_Zero)
936 && !(control_word & CW_Underflow)) {
937 setcc(cc);
938 tag = arith_underflow(st0_ptr);
939 setsign(st0_ptr, st0_sign);
940 FPU_settag0(tag);
941 return;
942 } else if ((exponent16(&tmp) > EXP_UNDER) || (tag == TAG_Zero)) {
943 stdexp(st0_ptr);
944 setsign(st0_ptr, st0_sign);
945 } else {
946 tag =
947 FPU_round(st0_ptr, 0, 0, FULL_PRECISION, st0_sign);
948 }
949 FPU_settag0(tag);
950 setcc(cc);
951
952 return;
953 }
954
955 if (st0_tag == TAG_Special)
956 st0_tag = FPU_Special(st0_ptr);
957 if (st1_tag == TAG_Special)
958 st1_tag = FPU_Special(st1_ptr);
959
960 if (((st0_tag == TAG_Valid) && (st1_tag == TW_Denormal))
961 || ((st0_tag == TW_Denormal) && (st1_tag == TAG_Valid))
962 || ((st0_tag == TW_Denormal) && (st1_tag == TW_Denormal))) {
963 if (denormal_operand() < 0)
964 return;
965 goto fprem_valid;
966 } else if ((st0_tag == TAG_Empty) || (st1_tag == TAG_Empty)) {
967 FPU_stack_underflow();
968 return;
969 } else if (st0_tag == TAG_Zero) {
970 if (st1_tag == TAG_Valid) {
971 setcc(0);
972 return;
973 } else if (st1_tag == TW_Denormal) {
974 if (denormal_operand() < 0)
975 return;
976 setcc(0);
977 return;
978 } else if (st1_tag == TAG_Zero) {
979 arith_invalid(0);
980 return;
981 }
982 else if (st1_tag == TW_Infinity) {
983 setcc(0);
984 return;
985 }
986 } else if ((st0_tag == TAG_Valid) || (st0_tag == TW_Denormal)) {
987 if (st1_tag == TAG_Zero) {
988 arith_invalid(0);
989 return;
990 } else if (st1_tag != TW_NaN) {
991 if (((st0_tag == TW_Denormal)
992 || (st1_tag == TW_Denormal))
993 && (denormal_operand() < 0))
994 return;
995
996 if (st1_tag == TW_Infinity) {
997
998 setcc(0);
999 return;
1000 }
1001 }
1002 } else if (st0_tag == TW_Infinity) {
1003 if (st1_tag != TW_NaN) {
1004 arith_invalid(0);
1005 return;
1006 }
1007 }
1008
1009
1010
1011 #ifdef PARANOID
1012 if ((st0_tag != TW_NaN) && (st1_tag != TW_NaN))
1013 EXCEPTION(EX_INTERNAL | 0x118);
1014 #endif
1015
1016 real_2op_NaN(st1_ptr, st1_tag, 0, st1_ptr);
1017
1018 }
1019
1020
1021 static void fyl2x(FPU_REG *st0_ptr, u_char st0_tag)
1022 {
1023 FPU_REG *st1_ptr = &st(1), exponent;
1024 u_char st1_tag = FPU_gettagi(1);
1025 u_char sign;
1026 int e, tag;
1027
1028 clear_C1();
1029
1030 if ((st0_tag == TAG_Valid) && (st1_tag == TAG_Valid)) {
1031 both_valid:
1032
1033 if (signpositive(st0_ptr)) {
1034 if (st0_tag == TW_Denormal)
1035 FPU_to_exp16(st0_ptr, st0_ptr);
1036 else
1037
1038 setexponent16(st0_ptr, exponent(st0_ptr));
1039
1040 if ((st0_ptr->sigh == 0x80000000)
1041 && (st0_ptr->sigl == 0)) {
1042
1043 u_char esign;
1044 e = exponent16(st0_ptr);
1045 if (e >= 0) {
1046 exponent.sigh = e;
1047 esign = SIGN_POS;
1048 } else {
1049 exponent.sigh = -e;
1050 esign = SIGN_NEG;
1051 }
1052 exponent.sigl = 0;
1053 setexponent16(&exponent, 31);
1054 tag = FPU_normalize_nuo(&exponent);
1055 stdexp(&exponent);
1056 setsign(&exponent, esign);
1057 tag =
1058 FPU_mul(&exponent, tag, 1, FULL_PRECISION);
1059 if (tag >= 0)
1060 FPU_settagi(1, tag);
1061 } else {
1062
1063 sign = getsign(st1_ptr);
1064 if (st1_tag == TW_Denormal)
1065 FPU_to_exp16(st1_ptr, st1_ptr);
1066 else
1067
1068 setexponent16(st1_ptr,
1069 exponent(st1_ptr));
1070 poly_l2(st0_ptr, st1_ptr, sign);
1071 }
1072 } else {
1073
1074 if (arith_invalid(1) < 0)
1075 return;
1076 }
1077
1078 FPU_pop();
1079
1080 return;
1081 }
1082
1083 if (st0_tag == TAG_Special)
1084 st0_tag = FPU_Special(st0_ptr);
1085 if (st1_tag == TAG_Special)
1086 st1_tag = FPU_Special(st1_ptr);
1087
1088 if ((st0_tag == TAG_Empty) || (st1_tag == TAG_Empty)) {
1089 FPU_stack_underflow_pop(1);
1090 return;
1091 } else if ((st0_tag <= TW_Denormal) && (st1_tag <= TW_Denormal)) {
1092 if (st0_tag == TAG_Zero) {
1093 if (st1_tag == TAG_Zero) {
1094
1095 if (arith_invalid(1) < 0)
1096 return;
1097 } else {
1098 u_char sign;
1099 sign = getsign(st1_ptr) ^ SIGN_NEG;
1100 if (FPU_divide_by_zero(1, sign) < 0)
1101 return;
1102
1103 setsign(st1_ptr, sign);
1104 }
1105 } else if (st1_tag == TAG_Zero) {
1106
1107
1108 sign = getsign(st1_ptr);
1109
1110 if (signnegative(st0_ptr)) {
1111
1112 if (arith_invalid(1) < 0)
1113 return;
1114 } else if ((st0_tag == TW_Denormal)
1115 && (denormal_operand() < 0))
1116 return;
1117 else {
1118 if (exponent(st0_ptr) < 0)
1119 sign ^= SIGN_NEG;
1120
1121 FPU_copy_to_reg1(&CONST_Z, TAG_Zero);
1122 setsign(st1_ptr, sign);
1123 }
1124 } else {
1125
1126 if (denormal_operand() < 0)
1127 return;
1128 goto both_valid;
1129 }
1130 } else if ((st0_tag == TW_NaN) || (st1_tag == TW_NaN)) {
1131 if (real_2op_NaN(st0_ptr, st0_tag, 1, st0_ptr) < 0)
1132 return;
1133 }
1134
1135 else if (st0_tag == TW_Infinity) {
1136 if ((signnegative(st0_ptr)) || (st1_tag == TAG_Zero)) {
1137
1138 if (arith_invalid(1) < 0)
1139 return;
1140 } else {
1141 u_char sign = getsign(st1_ptr);
1142
1143 if ((st1_tag == TW_Denormal)
1144 && (denormal_operand() < 0))
1145 return;
1146
1147 FPU_copy_to_reg1(&CONST_INF, TAG_Special);
1148 setsign(st1_ptr, sign);
1149 }
1150 }
1151
1152 else if (((st0_tag == TAG_Valid) || (st0_tag == TW_Denormal))
1153 && (signpositive(st0_ptr))) {
1154 if (exponent(st0_ptr) >= 0) {
1155 if ((exponent(st0_ptr) == 0) &&
1156 (st0_ptr->sigh == 0x80000000) &&
1157 (st0_ptr->sigl == 0)) {
1158
1159
1160 if (arith_invalid(1) < 0)
1161 return;
1162 }
1163
1164 } else {
1165
1166
1167 if ((st0_tag == TW_Denormal)
1168 && (denormal_operand() < 0))
1169 return;
1170
1171 changesign(st1_ptr);
1172 }
1173 } else {
1174
1175 if (st0_tag == TAG_Zero) {
1176
1177
1178 #ifndef PECULIAR_486
1179 sign = getsign(st1_ptr);
1180 if (FPU_divide_by_zero(1, sign) < 0)
1181 return;
1182 #endif
1183
1184 changesign(st1_ptr);
1185 } else if (arith_invalid(1) < 0)
1186 return;
1187 }
1188
1189 FPU_pop();
1190 }
1191
1192 static void fpatan(FPU_REG *st0_ptr, u_char st0_tag)
1193 {
1194 FPU_REG *st1_ptr = &st(1);
1195 u_char st1_tag = FPU_gettagi(1);
1196 int tag;
1197
1198 clear_C1();
1199 if (!((st0_tag ^ TAG_Valid) | (st1_tag ^ TAG_Valid))) {
1200 valid_atan:
1201
1202 poly_atan(st0_ptr, st0_tag, st1_ptr, st1_tag);
1203
1204 FPU_pop();
1205
1206 return;
1207 }
1208
1209 if (st0_tag == TAG_Special)
1210 st0_tag = FPU_Special(st0_ptr);
1211 if (st1_tag == TAG_Special)
1212 st1_tag = FPU_Special(st1_ptr);
1213
1214 if (((st0_tag == TAG_Valid) && (st1_tag == TW_Denormal))
1215 || ((st0_tag == TW_Denormal) && (st1_tag == TAG_Valid))
1216 || ((st0_tag == TW_Denormal) && (st1_tag == TW_Denormal))) {
1217 if (denormal_operand() < 0)
1218 return;
1219
1220 goto valid_atan;
1221 } else if ((st0_tag == TAG_Empty) || (st1_tag == TAG_Empty)) {
1222 FPU_stack_underflow_pop(1);
1223 return;
1224 } else if ((st0_tag == TW_NaN) || (st1_tag == TW_NaN)) {
1225 if (real_2op_NaN(st0_ptr, st0_tag, 1, st0_ptr) >= 0)
1226 FPU_pop();
1227 return;
1228 } else if ((st0_tag == TW_Infinity) || (st1_tag == TW_Infinity)) {
1229 u_char sign = getsign(st1_ptr);
1230 if (st0_tag == TW_Infinity) {
1231 if (st1_tag == TW_Infinity) {
1232 if (signpositive(st0_ptr)) {
1233 FPU_copy_to_reg1(&CONST_PI4, TAG_Valid);
1234 } else {
1235 setpositive(st1_ptr);
1236 tag =
1237 FPU_u_add(&CONST_PI4, &CONST_PI2,
1238 st1_ptr, FULL_PRECISION,
1239 SIGN_POS,
1240 exponent(&CONST_PI4),
1241 exponent(&CONST_PI2));
1242 if (tag >= 0)
1243 FPU_settagi(1, tag);
1244 }
1245 } else {
1246 if ((st1_tag == TW_Denormal)
1247 && (denormal_operand() < 0))
1248 return;
1249
1250 if (signpositive(st0_ptr)) {
1251 FPU_copy_to_reg1(&CONST_Z, TAG_Zero);
1252 setsign(st1_ptr, sign);
1253 FPU_pop();
1254 return;
1255 } else {
1256 FPU_copy_to_reg1(&CONST_PI, TAG_Valid);
1257 }
1258 }
1259 } else {
1260
1261 if ((st0_tag == TW_Denormal)
1262 && (denormal_operand() < 0))
1263 return;
1264
1265 FPU_copy_to_reg1(&CONST_PI2, TAG_Valid);
1266 }
1267 setsign(st1_ptr, sign);
1268 } else if (st1_tag == TAG_Zero) {
1269
1270 u_char sign = getsign(st1_ptr);
1271
1272 if ((st0_tag == TW_Denormal) && (denormal_operand() < 0))
1273 return;
1274
1275 if (signpositive(st0_ptr)) {
1276
1277 FPU_pop();
1278 return;
1279 }
1280
1281 FPU_copy_to_reg1(&CONST_PI, TAG_Valid);
1282 setsign(st1_ptr, sign);
1283 } else if (st0_tag == TAG_Zero) {
1284
1285 u_char sign = getsign(st1_ptr);
1286
1287 if ((st1_tag == TW_Denormal) && (denormal_operand() < 0))
1288 return;
1289
1290 FPU_copy_to_reg1(&CONST_PI2, TAG_Valid);
1291 setsign(st1_ptr, sign);
1292 }
1293 #ifdef PARANOID
1294 else
1295 EXCEPTION(EX_INTERNAL | 0x125);
1296 #endif
1297
1298 FPU_pop();
1299 set_precision_flag_up();
1300 }
1301
1302 static void fprem(FPU_REG *st0_ptr, u_char st0_tag)
1303 {
1304 do_fprem(st0_ptr, st0_tag, RC_CHOP);
1305 }
1306
1307 static void fprem1(FPU_REG *st0_ptr, u_char st0_tag)
1308 {
1309 do_fprem(st0_ptr, st0_tag, RC_RND);
1310 }
1311
1312 static void fyl2xp1(FPU_REG *st0_ptr, u_char st0_tag)
1313 {
1314 u_char sign, sign1;
1315 FPU_REG *st1_ptr = &st(1), a, b;
1316 u_char st1_tag = FPU_gettagi(1);
1317
1318 clear_C1();
1319 if (!((st0_tag ^ TAG_Valid) | (st1_tag ^ TAG_Valid))) {
1320 valid_yl2xp1:
1321
1322 sign = getsign(st0_ptr);
1323 sign1 = getsign(st1_ptr);
1324
1325 FPU_to_exp16(st0_ptr, &a);
1326 FPU_to_exp16(st1_ptr, &b);
1327
1328 if (poly_l2p1(sign, sign1, &a, &b, st1_ptr))
1329 return;
1330
1331 FPU_pop();
1332 return;
1333 }
1334
1335 if (st0_tag == TAG_Special)
1336 st0_tag = FPU_Special(st0_ptr);
1337 if (st1_tag == TAG_Special)
1338 st1_tag = FPU_Special(st1_ptr);
1339
1340 if (((st0_tag == TAG_Valid) && (st1_tag == TW_Denormal))
1341 || ((st0_tag == TW_Denormal) && (st1_tag == TAG_Valid))
1342 || ((st0_tag == TW_Denormal) && (st1_tag == TW_Denormal))) {
1343 if (denormal_operand() < 0)
1344 return;
1345
1346 goto valid_yl2xp1;
1347 } else if ((st0_tag == TAG_Empty) | (st1_tag == TAG_Empty)) {
1348 FPU_stack_underflow_pop(1);
1349 return;
1350 } else if (st0_tag == TAG_Zero) {
1351 switch (st1_tag) {
1352 case TW_Denormal:
1353 if (denormal_operand() < 0)
1354 return;
1355
1356 case TAG_Zero:
1357 case TAG_Valid:
1358 setsign(st0_ptr, getsign(st0_ptr) ^ getsign(st1_ptr));
1359 FPU_copy_to_reg1(st0_ptr, st0_tag);
1360 break;
1361
1362 case TW_Infinity:
1363
1364 if (arith_invalid(1) < 0)
1365 return;
1366 break;
1367
1368 case TW_NaN:
1369 if (real_2op_NaN(st0_ptr, st0_tag, 1, st0_ptr) < 0)
1370 return;
1371 break;
1372
1373 default:
1374 #ifdef PARANOID
1375 EXCEPTION(EX_INTERNAL | 0x116);
1376 return;
1377 #endif
1378 break;
1379 }
1380 } else if ((st0_tag == TAG_Valid) || (st0_tag == TW_Denormal)) {
1381 switch (st1_tag) {
1382 case TAG_Zero:
1383 if (signnegative(st0_ptr)) {
1384 if (exponent(st0_ptr) >= 0) {
1385
1386 #ifdef PECULIAR_486
1387 changesign(st1_ptr);
1388 #else
1389 if (arith_invalid(1) < 0)
1390 return;
1391 #endif
1392 } else if ((st0_tag == TW_Denormal)
1393 && (denormal_operand() < 0))
1394 return;
1395 else
1396 changesign(st1_ptr);
1397 } else if ((st0_tag == TW_Denormal)
1398 && (denormal_operand() < 0))
1399 return;
1400 break;
1401
1402 case TW_Infinity:
1403 if (signnegative(st0_ptr)) {
1404 if ((exponent(st0_ptr) >= 0) &&
1405 !((st0_ptr->sigh == 0x80000000) &&
1406 (st0_ptr->sigl == 0))) {
1407
1408 #ifdef PECULIAR_486
1409 changesign(st1_ptr);
1410 #else
1411 if (arith_invalid(1) < 0)
1412 return;
1413 #endif
1414 } else if ((st0_tag == TW_Denormal)
1415 && (denormal_operand() < 0))
1416 return;
1417 else
1418 changesign(st1_ptr);
1419 } else if ((st0_tag == TW_Denormal)
1420 && (denormal_operand() < 0))
1421 return;
1422 break;
1423
1424 case TW_NaN:
1425 if (real_2op_NaN(st0_ptr, st0_tag, 1, st0_ptr) < 0)
1426 return;
1427 }
1428
1429 } else if (st0_tag == TW_NaN) {
1430 if (real_2op_NaN(st0_ptr, st0_tag, 1, st0_ptr) < 0)
1431 return;
1432 } else if (st0_tag == TW_Infinity) {
1433 if (st1_tag == TW_NaN) {
1434 if (real_2op_NaN(st0_ptr, st0_tag, 1, st0_ptr) < 0)
1435 return;
1436 } else if (signnegative(st0_ptr)) {
1437 #ifndef PECULIAR_486
1438
1439 if (arith_invalid(1) < 0)
1440 return;
1441 #endif
1442 if ((st1_tag == TW_Denormal)
1443 && (denormal_operand() < 0))
1444 return;
1445 #ifdef PECULIAR_486
1446
1447 if (arith_invalid(1) < 0)
1448 return;
1449 #endif
1450 } else if (st1_tag == TAG_Zero) {
1451
1452 if (arith_invalid(1) < 0)
1453 return;
1454 }
1455
1456
1457
1458 else if ((st1_tag == TW_Denormal) && (denormal_operand() < 0))
1459 return;
1460
1461
1462
1463 else {
1464 u_char sign = getsign(st1_ptr);
1465 FPU_copy_to_reg1(&CONST_INF, TAG_Special);
1466 setsign(st1_ptr, sign);
1467 }
1468 }
1469 #ifdef PARANOID
1470 else {
1471 EXCEPTION(EX_INTERNAL | 0x117);
1472 return;
1473 }
1474 #endif
1475
1476 FPU_pop();
1477 return;
1478
1479 }
1480
1481 static void fscale(FPU_REG *st0_ptr, u_char st0_tag)
1482 {
1483 FPU_REG *st1_ptr = &st(1);
1484 u_char st1_tag = FPU_gettagi(1);
1485 int old_cw = control_word;
1486 u_char sign = getsign(st0_ptr);
1487
1488 clear_C1();
1489 if (!((st0_tag ^ TAG_Valid) | (st1_tag ^ TAG_Valid))) {
1490 long scale;
1491 FPU_REG tmp;
1492
1493
1494 setexponent16(st0_ptr, exponent(st0_ptr));
1495
1496 valid_scale:
1497
1498 if (exponent(st1_ptr) > 30) {
1499
1500
1501 if (signpositive(st1_ptr)) {
1502 EXCEPTION(EX_Overflow);
1503 FPU_copy_to_reg0(&CONST_INF, TAG_Special);
1504 } else {
1505 EXCEPTION(EX_Underflow);
1506 FPU_copy_to_reg0(&CONST_Z, TAG_Zero);
1507 }
1508 setsign(st0_ptr, sign);
1509 return;
1510 }
1511
1512 control_word &= ~CW_RC;
1513 control_word |= RC_CHOP;
1514 reg_copy(st1_ptr, &tmp);
1515 FPU_round_to_int(&tmp, st1_tag);
1516 control_word = old_cw;
1517 scale = signnegative(st1_ptr) ? -tmp.sigl : tmp.sigl;
1518 scale += exponent16(st0_ptr);
1519
1520 setexponent16(st0_ptr, scale);
1521
1522
1523 FPU_round(st0_ptr, 0, 0, control_word, sign);
1524
1525 return;
1526 }
1527
1528 if (st0_tag == TAG_Special)
1529 st0_tag = FPU_Special(st0_ptr);
1530 if (st1_tag == TAG_Special)
1531 st1_tag = FPU_Special(st1_ptr);
1532
1533 if ((st0_tag == TAG_Valid) || (st0_tag == TW_Denormal)) {
1534 switch (st1_tag) {
1535 case TAG_Valid:
1536
1537 if ((st0_tag == TW_Denormal)
1538 && (denormal_operand() < 0))
1539 return;
1540
1541 FPU_to_exp16(st0_ptr, st0_ptr);
1542 goto valid_scale;
1543
1544 case TAG_Zero:
1545 if (st0_tag == TW_Denormal)
1546 denormal_operand();
1547 return;
1548
1549 case TW_Denormal:
1550 denormal_operand();
1551 return;
1552
1553 case TW_Infinity:
1554 if ((st0_tag == TW_Denormal)
1555 && (denormal_operand() < 0))
1556 return;
1557
1558 if (signpositive(st1_ptr))
1559 FPU_copy_to_reg0(&CONST_INF, TAG_Special);
1560 else
1561 FPU_copy_to_reg0(&CONST_Z, TAG_Zero);
1562 setsign(st0_ptr, sign);
1563 return;
1564
1565 case TW_NaN:
1566 real_2op_NaN(st1_ptr, st1_tag, 0, st0_ptr);
1567 return;
1568 }
1569 } else if (st0_tag == TAG_Zero) {
1570 switch (st1_tag) {
1571 case TAG_Valid:
1572 case TAG_Zero:
1573 return;
1574
1575 case TW_Denormal:
1576 denormal_operand();
1577 return;
1578
1579 case TW_Infinity:
1580 if (signpositive(st1_ptr))
1581 arith_invalid(0);
1582 return;
1583
1584 case TW_NaN:
1585 real_2op_NaN(st1_ptr, st1_tag, 0, st0_ptr);
1586 return;
1587 }
1588 } else if (st0_tag == TW_Infinity) {
1589 switch (st1_tag) {
1590 case TAG_Valid:
1591 case TAG_Zero:
1592 return;
1593
1594 case TW_Denormal:
1595 denormal_operand();
1596 return;
1597
1598 case TW_Infinity:
1599 if (signnegative(st1_ptr))
1600 arith_invalid(0);
1601 return;
1602
1603 case TW_NaN:
1604 real_2op_NaN(st1_ptr, st1_tag, 0, st0_ptr);
1605 return;
1606 }
1607 } else if (st0_tag == TW_NaN) {
1608 if (st1_tag != TAG_Empty) {
1609 real_2op_NaN(st1_ptr, st1_tag, 0, st0_ptr);
1610 return;
1611 }
1612 }
1613 #ifdef PARANOID
1614 if (!((st0_tag == TAG_Empty) || (st1_tag == TAG_Empty))) {
1615 EXCEPTION(EX_INTERNAL | 0x115);
1616 return;
1617 }
1618 #endif
1619
1620
1621 FPU_stack_underflow();
1622
1623 }
1624
1625
1626
1627 static FUNC_ST0 const trig_table_a[] = {
1628 f2xm1, fyl2x, fptan, fpatan,
1629 fxtract, fprem1, (FUNC_ST0) fdecstp, (FUNC_ST0) fincstp
1630 };
1631
1632 void FPU_triga(void)
1633 {
1634 (trig_table_a[FPU_rm]) (&st(0), FPU_gettag0());
1635 }
1636
1637 static FUNC_ST0 const trig_table_b[] = {
1638 fprem, fyl2xp1, fsqrt_, fsincos, frndint_, fscale, (FUNC_ST0) fsin, fcos
1639 };
1640
1641 void FPU_trigb(void)
1642 {
1643 (trig_table_b[FPU_rm]) (&st(0), FPU_gettag0());
1644 }