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