4 * Implementation of the FPU "transcendental" functions.
7 * Copyright (C) 1992,1993,1994
8 * W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
9 * Australia. E-mail billm@vaxc.cc.monash.edu.au
10 * All rights reserved.
12 * This copyright notice covers the redistribution and use of the
13 * FPU emulator developed by W. Metzenthen. It covers only its use
14 * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
15 * use is not permitted under this copyright.
17 * Redistribution and use in source and binary forms, with or without
18 * modification, are permitted provided that the following conditions
20 * 1. Redistributions of source code must retain the above copyright
21 * notice, this list of conditions and the following disclaimer.
22 * 2. Redistributions in binary form must include information specifying
23 * that source code for the emulator is freely available and include
25 * a) an offer to provide the source code for a nominal distribution
27 * b) list at least two alternative methods whereby the source
28 * can be obtained, e.g. a publically accessible bulletin board
29 * and an anonymous ftp site from which the software can be
31 * 3. All advertising materials specifically mentioning features or use of
32 * this emulator must acknowledge that it was developed by W. Metzenthen.
33 * 4. The name of W. Metzenthen may not be used to endorse or promote
34 * products derived from this software without specific prior written
37 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
38 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
39 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
40 * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
41 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
42 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
43 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
44 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
45 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
46 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
49 * The purpose of this copyright, based upon the Berkeley copyright, is to
50 * ensure that the covered software remains freely available to everyone.
52 * The software (with necessary differences) is also available, but under
53 * the terms of the GNU copyleft, for the Linux operating system and for
54 * the djgpp ms-dos extender.
56 * W. Metzenthen June 1994.
59 * $FreeBSD: src/sys/gnu/i386/fpemul/fpu_trig.c,v 1.10 1999/08/28 00:42:52 peter Exp $
64 #include <sys/param.h>
66 #include <sys/systm.h> /* for printf() in EXCEPTION() */
69 #include <machine/pcb.h>
71 #include <gnu/i386/fpemul/fpu_emu.h>
72 #include <gnu/i386/fpemul/fpu_system.h>
73 #include <gnu/i386/fpemul/exception.h>
74 #include <gnu/i386/fpemul/status_w.h>
75 #include <gnu/i386/fpemul/reg_constant.h>
76 #include <gnu/i386/fpemul/control_w.h>
78 static void convert_l2reg(long *arg, FPU_REG * dest);
86 int old_cw = control_word;
88 control_word &= ~CW_RC;
89 control_word |= RC_CHOP;
92 reg_div(", &CONST_PI2, ", FULL_PRECISION);
94 reg_move(", &tmp);
96 if (tmp.sigh & 0x80000000)
97 return -1; /* |Arg| is >= 2^63 */
98 tmp.exp = EXP_BIAS + 63;
99 q = *(long long *) &(tmp.sigl);
102 reg_sub(", &tmp, X, FULL_PRECISION);
105 control_word = old_cw;
110 /* Convert a long to register */
112 convert_l2reg(long *arg, FPU_REG * dest)
117 reg_move(&CONST_Z, dest);
121 dest->sign = SIGN_POS;
124 dest->sign = SIGN_NEG;
129 dest->exp = EXP_BIAS + 31;
130 dest->tag = TW_Valid;
136 single_arg_error(void)
138 switch (FPU_st0_tag) {
140 if (!(FPU_st0_ptr->sigh & 0x40000000)) { /* Signaling ? */
141 EXCEPTION(EX_Invalid);
142 /* Convert to a QNaN */
143 FPU_st0_ptr->sigh |= 0x40000000;
145 break; /* return with a NaN in st(0) */
147 stack_underflow(); /* Puts a QNaN in st(0) */
151 EXCEPTION(EX_INTERNAL | 0x0112);
152 #endif /* PARANOID */
157 /*---------------------------------------------------------------------------*/
162 switch (FPU_st0_tag) {
167 #ifdef DENORM_OPERAND
168 if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
170 #endif /* DENORM_OPERAND */
172 if (FPU_st0_ptr->sign == SIGN_POS) {
173 /* poly_2xm1(x) requires 0 < x < 1. */
174 if (poly_2xm1(FPU_st0_ptr, &rv))
176 reg_mul(&rv, FPU_st0_ptr, FPU_st0_ptr, FULL_PRECISION);
178 /* **** Should change poly_2xm1() to at least handle numbers near 0 */
179 /* poly_2xm1(x) doesn't handle negative
181 /* So we compute (poly_2xm1(x+1)-1)/2, for -1
183 reg_add(FPU_st0_ptr, &CONST_1, &tmp, FULL_PRECISION);
184 poly_2xm1(&tmp, &rv);
185 reg_mul(&rv, &tmp, &tmp, FULL_PRECISION);
186 reg_sub(&tmp, &CONST_1, FPU_st0_ptr, FULL_PRECISION);
188 if (FPU_st0_ptr->exp <= EXP_UNDER)
189 arith_underflow(FPU_st0_ptr);
196 if (FPU_st0_ptr->sign == SIGN_NEG) {
197 /* -infinity gives -1 (p16-10) */
198 reg_move(&CONST_1, FPU_st0_ptr);
199 FPU_st0_ptr->sign = SIGN_NEG;
212 char arg_sign = FPU_st0_ptr->sign;
214 if (STACK_OVERFLOW) {
218 switch (FPU_st0_tag) {
221 #ifdef DENORM_OPERAND
222 if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
224 #endif /* DENORM_OPERAND */
226 FPU_st0_ptr->sign = SIGN_POS;
227 if ((q = trig_arg(FPU_st0_ptr)) != -1) {
229 reg_sub(&CONST_1, FPU_st0_ptr, FPU_st0_ptr, FULL_PRECISION);
231 poly_tan(FPU_st0_ptr, FPU_st0_ptr);
233 FPU_st0_ptr->sign = (q & 1) ^ arg_sign;
235 if (FPU_st0_ptr->exp <= EXP_UNDER)
236 arith_underflow(FPU_st0_ptr);
239 reg_move(&CONST_1, FPU_st0_ptr);
242 /* Operand is out of range */
244 FPU_st0_ptr->sign = arg_sign; /* restore st(0) */
249 /* Operand is out of range */
251 FPU_st0_ptr->sign = arg_sign; /* restore st(0) */
255 reg_move(&CONST_1, FPU_st0_ptr);
269 register FPU_REG *st1_ptr = FPU_st0_ptr; /* anticipate */
271 if (STACK_OVERFLOW) {
275 if (!(FPU_st0_tag ^ TW_Valid)) {
278 #ifdef DENORM_OPERAND
279 if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
281 #endif /* DENORM_OPERAND */
284 reg_move(st1_ptr, FPU_st0_ptr);
285 FPU_st0_ptr->exp = EXP_BIAS;
286 e = st1_ptr->exp - EXP_BIAS;
287 convert_l2reg(&e, st1_ptr);
290 if (FPU_st0_tag == TW_Zero) {
291 char sign = FPU_st0_ptr->sign;
292 divide_by_zero(SIGN_NEG, FPU_st0_ptr);
294 reg_move(&CONST_Z, FPU_st0_ptr);
295 FPU_st0_ptr->sign = sign;
298 if (FPU_st0_tag == TW_Infinity) {
299 char sign = FPU_st0_ptr->sign;
300 FPU_st0_ptr->sign = SIGN_POS;
302 reg_move(&CONST_INF, FPU_st0_ptr);
303 FPU_st0_ptr->sign = sign;
306 if (FPU_st0_tag == TW_NaN) {
307 if (!(FPU_st0_ptr->sigh & 0x40000000)) { /* Signaling ? */
308 EXCEPTION(EX_Invalid);
309 /* Convert to a QNaN */
310 FPU_st0_ptr->sigh |= 0x40000000;
313 reg_move(st1_ptr, FPU_st0_ptr);
316 if (FPU_st0_tag == TW_Empty) {
317 /* Is this the correct
319 if (control_word & EX_Invalid) {
324 EXCEPTION(EX_StackUnder);
328 EXCEPTION(EX_INTERNAL | 0x119);
329 #endif /* PARANOID */
336 top--; /* FPU_st0_ptr will be fixed in math_emulate()
337 * before the next instr */
343 top++; /* FPU_st0_ptr will be fixed in math_emulate()
344 * before the next instr */
351 if (!(FPU_st0_tag ^ TW_Valid)) {
354 if (FPU_st0_ptr->sign == SIGN_NEG) {
355 arith_invalid(FPU_st0_ptr); /* sqrt(negative) is
359 #ifdef DENORM_OPERAND
360 if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
362 #endif /* DENORM_OPERAND */
364 expon = FPU_st0_ptr->exp - EXP_BIAS;
365 FPU_st0_ptr->exp = EXP_BIAS + (expon & 1); /* make st(0) in [1.0
368 wm_sqrt(FPU_st0_ptr, control_word); /* Do the computation */
370 FPU_st0_ptr->exp += expon >> 1;
371 FPU_st0_ptr->sign = SIGN_POS;
373 if (FPU_st0_tag == TW_Zero)
376 if (FPU_st0_tag == TW_Infinity) {
377 if (FPU_st0_ptr->sign == SIGN_NEG)
378 arith_invalid(FPU_st0_ptr); /* sqrt(-Infinity) is
392 if (!(FPU_st0_tag ^ TW_Valid)) {
393 if (FPU_st0_ptr->exp > EXP_BIAS + 63)
396 #ifdef DENORM_OPERAND
397 if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
399 #endif /* DENORM_OPERAND */
401 round_to_int(FPU_st0_ptr); /* Fortunately, this can't
402 * overflow to 2^64 */
403 FPU_st0_ptr->exp = EXP_BIAS + 63;
404 normalize(FPU_st0_ptr);
407 if ((FPU_st0_tag == TW_Zero) || (FPU_st0_tag == TW_Infinity))
417 char arg_sign = FPU_st0_ptr->sign;
419 if (FPU_st0_tag == TW_Valid) {
421 FPU_st0_ptr->sign = SIGN_POS;
423 #ifdef DENORM_OPERAND
424 if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
426 #endif /* DENORM_OPERAND */
428 if ((q = trig_arg(FPU_st0_ptr)) != -1) {
432 reg_sub(&CONST_1, FPU_st0_ptr, FPU_st0_ptr, FULL_PRECISION);
434 poly_sine(FPU_st0_ptr, &rv);
438 rv.sign ^= SIGN_POS ^ SIGN_NEG;
440 reg_move(&rv, FPU_st0_ptr);
442 if (FPU_st0_ptr->exp <= EXP_UNDER)
443 arith_underflow(FPU_st0_ptr);
445 set_precision_flag_up(); /* We do not really know
450 /* Operand is out of range */
452 FPU_st0_ptr->sign = arg_sign; /* restore st(0) */
456 if (FPU_st0_tag == TW_Zero) {
460 if (FPU_st0_tag == TW_Infinity) {
461 /* Operand is out of range */
463 FPU_st0_ptr->sign = arg_sign; /* restore st(0) */
473 char arg_sign = arg->sign;
475 if (arg->tag == TW_Valid) {
478 #ifdef DENORM_OPERAND
479 if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
481 #endif /* DENORM_OPERAND */
483 arg->sign = SIGN_POS;
484 if ((q = trig_arg(arg)) != -1) {
488 reg_sub(&CONST_1, arg, arg, FULL_PRECISION);
494 rv.sign ^= SIGN_POS ^ SIGN_NEG;
497 set_precision_flag_up(); /* We do not really know
502 /* Operand is out of range */
504 arg->sign = arg_sign; /* restore st(0) */
508 if (arg->tag == TW_Zero) {
509 reg_move(&CONST_1, arg);
513 if (FPU_st0_tag == TW_Infinity) {
514 /* Operand is out of range */
516 arg->sign = arg_sign; /* restore st(0) */
519 single_arg_error(); /* requires arg ==
539 if (STACK_OVERFLOW) {
543 reg_move(FPU_st0_ptr, &arg);
547 reg_move(&arg, FPU_st0_ptr);
552 /*---------------------------------------------------------------------------*/
553 /* The following all require two arguments: st(0) and st(1) */
555 /* remainder of st(0) / st(1) */
556 /* Assumes that st(0) and st(1) are both TW_Valid */
558 fprem_kernel(int round)
560 FPU_REG *st1_ptr = &st(1);
561 char st1_tag = st1_ptr->tag;
563 if (!((FPU_st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid))) {
565 int old_cw = control_word;
566 int expdif = FPU_st0_ptr->exp - (st1_ptr)->exp;
568 #ifdef DENORM_OPERAND
569 if (((FPU_st0_ptr->exp <= EXP_UNDER) ||
570 (st1_ptr->exp <= EXP_UNDER)) && (denormal_operand()))
572 #endif /* DENORM_OPERAND */
574 control_word &= ~CW_RC;
575 control_word |= round;
578 /* This should be the most common case */
582 reg_div(FPU_st0_ptr, st1_ptr, &tmp, FULL_PRECISION);
584 round_to_int(&tmp); /* Fortunately, this can't
585 * overflow to 2^64 */
586 tmp.exp = EXP_BIAS + 63;
587 q = *(long long *) &(tmp.sigl);
590 reg_mul(st1_ptr, &tmp, &tmp, FULL_PRECISION);
591 reg_sub(FPU_st0_ptr, &tmp, FPU_st0_ptr, FULL_PRECISION);
602 /* There is a large exponent difference ( >= 64 ) */
605 reg_div(FPU_st0_ptr, st1_ptr, &tmp, FULL_PRECISION);
606 /* N is 'a number between 32 and 63' (p26-113) */
607 N_exp = (tmp.exp & 31) + 32;
608 tmp.exp = EXP_BIAS + N_exp;
610 round_to_int(&tmp); /* Fortunately, this can't
611 * overflow to 2^64 */
612 tmp.exp = EXP_BIAS + 63;
615 tmp.exp = EXP_BIAS + expdif - N_exp;
617 reg_mul(st1_ptr, &tmp, &tmp, FULL_PRECISION);
618 reg_sub(FPU_st0_ptr, &tmp, FPU_st0_ptr, FULL_PRECISION);
622 control_word = old_cw;
624 if (FPU_st0_ptr->exp <= EXP_UNDER)
625 arith_underflow(FPU_st0_ptr);
628 if ((FPU_st0_tag == TW_Empty) | (st1_tag == TW_Empty)) {
632 if (FPU_st0_tag == TW_Zero) {
633 if (st1_tag == TW_Valid) {
635 #ifdef DENORM_OPERAND
636 if ((st1_ptr->exp <= EXP_UNDER) && (denormal_operand()))
638 #endif /* DENORM_OPERAND */
643 if (st1_tag == TW_Zero) {
644 arith_invalid(FPU_st0_ptr);
647 /* fprem(?,0) always invalid */
649 if (st1_tag == TW_Infinity) {
654 if (FPU_st0_tag == TW_Valid) {
655 if (st1_tag == TW_Zero) {
656 arith_invalid(FPU_st0_ptr); /* fprem(Valid,Zero) is
660 if (st1_tag != TW_NaN) {
661 #ifdef DENORM_OPERAND
662 if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
664 #endif /* DENORM_OPERAND */
666 if (st1_tag == TW_Infinity) {
675 if (FPU_st0_tag == TW_Infinity) {
676 if (st1_tag != TW_NaN) {
677 arith_invalid(FPU_st0_ptr); /* fprem(Infinity,?) is
682 /* One of the registers must contain a NaN is we got here. */
685 if ((FPU_st0_tag != TW_NaN) && (st1_tag != TW_NaN))
686 EXCEPTION(EX_INTERNAL | 0x118);
687 #endif /* PARANOID */
689 real_2op_NaN(FPU_st0_ptr, st1_ptr, FPU_st0_ptr);
694 /* ST(1) <- ST(1) * log ST; pop ST */
698 FPU_REG *st1_ptr = &st(1);
699 char st1_tag = st1_ptr->tag;
701 if (!((FPU_st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid))) {
702 if (FPU_st0_ptr->sign == SIGN_POS) {
703 int saved_control, saved_status;
705 #ifdef DENORM_OPERAND
706 if (((FPU_st0_ptr->exp <= EXP_UNDER) ||
707 (st1_ptr->exp <= EXP_UNDER)) && (denormal_operand()))
709 #endif /* DENORM_OPERAND */
711 /* We use the general purpose arithmetic, so we need
713 saved_status = status_word;
714 saved_control = control_word;
715 control_word = FULL_PRECISION;
717 poly_l2(FPU_st0_ptr, FPU_st0_ptr);
719 /* Enough of the basic arithmetic is done now */
720 control_word = saved_control;
721 status_word = saved_status;
723 /* Let the multiply set the flags */
724 reg_mul(FPU_st0_ptr, st1_ptr, st1_ptr, FULL_PRECISION);
727 FPU_st0_ptr = &st(0);
731 FPU_st0_ptr = &st(0);
732 arith_invalid(FPU_st0_ptr); /* st(0) cannot be
737 if ((FPU_st0_tag == TW_Empty) || (st1_tag == TW_Empty)) {
738 stack_underflow_pop(1);
741 if ((FPU_st0_tag == TW_NaN) || (st1_tag == TW_NaN)) {
742 real_2op_NaN(FPU_st0_ptr, st1_ptr, st1_ptr);
746 if ((FPU_st0_tag <= TW_Zero) && (st1_tag <= TW_Zero)) {
747 /* one of the args is zero, the other
748 * valid, or both zero */
749 if (FPU_st0_tag == TW_Zero) {
751 FPU_st0_ptr = &st(0);
752 if (FPU_st0_ptr->tag == TW_Zero)
753 arith_invalid(FPU_st0_ptr); /* Both args zero is
757 * specifically covered in the
758 * manual, but divide-by-zero
759 * would seem to be the best
760 * response. However, a real
761 * 80486 does it this way... */
763 if (FPU_st0_ptr->tag == TW_Infinity) {
764 reg_move(&CONST_INF, FPU_st0_ptr);
767 #endif /* PECULIAR_486 */
769 divide_by_zero(st1_ptr->sign ^ SIGN_NEG ^ SIGN_POS, FPU_st0_ptr);
772 /* st(1) contains zero, st(0)
774 /* Zero is the valid answer */
775 char sign = st1_ptr->sign;
777 #ifdef DENORM_OPERAND
778 if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
780 #endif /* DENORM_OPERAND */
781 if (FPU_st0_ptr->sign == SIGN_NEG) {
783 FPU_st0_ptr = &st(0);
784 arith_invalid(FPU_st0_ptr); /* log(negative) */
787 if (FPU_st0_ptr->exp < EXP_BIAS)
788 sign ^= SIGN_NEG ^ SIGN_POS;
790 FPU_st0_ptr = &st(0);
791 reg_move(&CONST_Z, FPU_st0_ptr);
792 FPU_st0_ptr->sign = sign;
796 /* One or both arg must be an infinity */
798 if (FPU_st0_tag == TW_Infinity) {
799 if ((FPU_st0_ptr->sign == SIGN_NEG) || (st1_tag == TW_Zero)) {
801 FPU_st0_ptr = &st(0);
802 arith_invalid(FPU_st0_ptr); /* log(-infinity) or
806 char sign = st1_ptr->sign;
808 #ifdef DENORM_OPERAND
809 if ((st1_ptr->exp <= EXP_UNDER) && (denormal_operand()))
811 #endif /* DENORM_OPERAND */
814 FPU_st0_ptr = &st(0);
815 reg_move(&CONST_INF, FPU_st0_ptr);
816 FPU_st0_ptr->sign = sign;
820 /* st(1) must be infinity here */
822 if ((FPU_st0_tag == TW_Valid) && (FPU_st0_ptr->sign == SIGN_POS)) {
823 if (FPU_st0_ptr->exp >= EXP_BIAS) {
824 if ((FPU_st0_ptr->exp == EXP_BIAS) &&
825 (FPU_st0_ptr->sigh == 0x80000000) &&
826 (FPU_st0_ptr->sigl == 0)) {
833 FPU_st0_ptr = &st(0);
834 arith_invalid(FPU_st0_ptr); /* infinity*log(1) */
846 #ifdef DENORM_OPERAND
847 if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
849 #endif /* DENORM_OPERAND */
851 st1_ptr->sign ^= SIGN_NEG;
856 /* st(0) must be zero
858 if (FPU_st0_ptr->tag == TW_Zero) {
860 FPU_st0_ptr = st1_ptr;
861 st1_ptr->sign ^= SIGN_NEG ^ SIGN_POS;
869 divide_by_zero(st1_ptr->sign, FPU_st0_ptr);
870 #endif /* PECULIAR_486 */
873 FPU_st0_ptr = st1_ptr;
874 arith_invalid(FPU_st0_ptr); /* log(negative) */
884 FPU_REG *st1_ptr = &st(1);
885 char st1_tag = st1_ptr->tag;
887 if (!((FPU_st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid))) {
888 int saved_control, saved_status;
890 int quadrant = st1_ptr->sign | ((FPU_st0_ptr->sign) << 1);
892 #ifdef DENORM_OPERAND
893 if (((FPU_st0_ptr->exp <= EXP_UNDER) ||
894 (st1_ptr->exp <= EXP_UNDER)) && (denormal_operand()))
896 #endif /* DENORM_OPERAND */
898 /* We use the general purpose arithmetic so we need to save
900 saved_status = status_word;
901 saved_control = control_word;
902 control_word = FULL_PRECISION;
904 st1_ptr->sign = FPU_st0_ptr->sign = SIGN_POS;
905 if (compare(st1_ptr) == COMP_A_lt_B) {
907 reg_div(FPU_st0_ptr, st1_ptr, &sum, FULL_PRECISION);
909 reg_div(st1_ptr, FPU_st0_ptr, &sum, FULL_PRECISION);
914 reg_sub(&CONST_PI2, &sum, &sum, FULL_PRECISION);
917 reg_sub(&CONST_PI, &sum, &sum, FULL_PRECISION);
920 sum.sign ^= SIGN_POS ^ SIGN_NEG;
922 /* All of the basic arithmetic is done now */
923 control_word = saved_control;
924 status_word = saved_status;
926 reg_move(&sum, st1_ptr);
928 if ((FPU_st0_tag == TW_Empty) || (st1_tag == TW_Empty)) {
929 stack_underflow_pop(1);
932 if ((FPU_st0_tag == TW_NaN) || (st1_tag == TW_NaN)) {
933 real_2op_NaN(FPU_st0_ptr, st1_ptr, st1_ptr);
937 if ((FPU_st0_tag == TW_Infinity) || (st1_tag == TW_Infinity)) {
938 char sign = st1_ptr->sign;
939 if (FPU_st0_tag == TW_Infinity) {
940 if (st1_tag == TW_Infinity) {
941 if (FPU_st0_ptr->sign == SIGN_POS) {
942 reg_move(&CONST_PI4, st1_ptr);
944 reg_add(&CONST_PI4, &CONST_PI2, st1_ptr, FULL_PRECISION);
947 #ifdef DENORM_OPERAND
948 if ((st1_ptr->exp <= EXP_UNDER) && (denormal_operand()))
950 #endif /* DENORM_OPERAND */
952 if (FPU_st0_ptr->sign == SIGN_POS) {
953 reg_move(&CONST_Z, st1_ptr);
957 reg_move(&CONST_PI, st1_ptr);
960 /* st(1) is infinity, st(0)
962 #ifdef DENORM_OPERAND
963 if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
965 #endif /* DENORM_OPERAND */
967 reg_move(&CONST_PI2, st1_ptr);
969 st1_ptr->sign = sign;
971 if (st1_tag == TW_Zero) {
972 /* st(0) must be valid or zero */
973 char sign = st1_ptr->sign;
975 #ifdef DENORM_OPERAND
976 if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
978 #endif /* DENORM_OPERAND */
980 if (FPU_st0_ptr->sign == SIGN_POS) {
981 reg_move(&CONST_Z, st1_ptr);
985 reg_move(&CONST_PI, st1_ptr);
986 st1_ptr->sign = sign;
988 if (FPU_st0_tag == TW_Zero) {
991 char sign = st1_ptr->sign;
993 #ifdef DENORM_OPERAND
994 if ((st1_ptr->exp <= EXP_UNDER) && (denormal_operand()))
996 #endif /* DENORM_OPERAND */
998 reg_move(&CONST_PI2, st1_ptr);
999 st1_ptr->sign = sign;
1003 EXCEPTION(EX_INTERNAL | 0x220);
1004 #endif /* PARANOID */
1007 set_precision_flag_up();/* We do not really know if up or down */
1014 fprem_kernel(RC_CHOP);
1021 fprem_kernel(RC_RND);
1028 FPU_REG *st1_ptr = &st(1);
1029 char st1_tag = st1_ptr->tag;
1031 if (!((FPU_st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid))) {
1032 int saved_control, saved_status;
1034 #ifdef DENORM_OPERAND
1035 if (((FPU_st0_ptr->exp <= EXP_UNDER) ||
1036 (st1_ptr->exp <= EXP_UNDER)) && (denormal_operand()))
1038 #endif /* DENORM_OPERAND */
1040 /* We use the general purpose arithmetic so we need to save
1042 saved_status = status_word;
1043 saved_control = control_word;
1044 control_word = FULL_PRECISION;
1046 if (poly_l2p1(FPU_st0_ptr, FPU_st0_ptr)) {
1047 arith_invalid(st1_ptr); /* poly_l2p1() returned
1052 /* Enough of the basic arithmetic is done now */
1053 control_word = saved_control;
1054 status_word = saved_status;
1056 /* Let the multiply set the flags */
1057 reg_mul(FPU_st0_ptr, st1_ptr, st1_ptr, FULL_PRECISION);
1061 if ((FPU_st0_tag == TW_Empty) | (st1_tag == TW_Empty)) {
1062 stack_underflow_pop(1);
1065 if (FPU_st0_tag == TW_Zero) {
1066 if (st1_tag <= TW_Zero) {
1068 #ifdef DENORM_OPERAND
1069 if ((st1_tag == TW_Valid) && (st1_ptr->exp <= EXP_UNDER) &&
1070 (denormal_operand()))
1072 #endif /* DENORM_OPERAND */
1074 st1_ptr->sign ^= FPU_st0_ptr->sign;
1075 reg_move(FPU_st0_ptr, st1_ptr);
1077 if (st1_tag == TW_Infinity) {
1078 arith_invalid(st1_ptr); /* Infinity*log(1) */
1082 if (st1_tag == TW_NaN) {
1083 real_2op_NaN(FPU_st0_ptr, st1_ptr, st1_ptr);
1089 EXCEPTION(EX_INTERNAL | 0x116);
1092 #endif /* PARANOID */
1096 if (FPU_st0_tag == TW_Valid) {
1097 if (st1_tag == TW_Zero) {
1098 if (FPU_st0_ptr->sign == SIGN_NEG) {
1099 if (FPU_st0_ptr->exp >= EXP_BIAS) {
1102 arith_invalid(st1_ptr); /* infinity*log(1) */
1106 #ifdef DENORM_OPERAND
1107 if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
1109 #endif /* DENORM_OPERAND */
1110 st1_ptr->sign ^= SIGN_POS ^ SIGN_NEG;
1114 #ifdef DENORM_OPERAND
1115 if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
1117 #endif /* DENORM_OPERAND */
1121 if (st1_tag == TW_Infinity) {
1122 if (FPU_st0_ptr->sign == SIGN_NEG) {
1123 if ((FPU_st0_ptr->exp >= EXP_BIAS) &&
1124 !((FPU_st0_ptr->sigh == 0x80000000) &&
1125 (FPU_st0_ptr->sigl == 0))) {
1128 arith_invalid(st1_ptr);
1132 #ifdef DENORM_OPERAND
1133 if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
1135 #endif /* DENORM_OPERAND */
1136 st1_ptr->sign ^= SIGN_POS ^ SIGN_NEG;
1140 #ifdef DENORM_OPERAND
1141 if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
1143 #endif /* DENORM_OPERAND */
1147 if (st1_tag == TW_NaN) {
1148 real_2op_NaN(FPU_st0_ptr, st1_ptr, st1_ptr);
1153 if (FPU_st0_tag == TW_NaN) {
1154 real_2op_NaN(FPU_st0_ptr, st1_ptr, st1_ptr);
1158 if (FPU_st0_tag == TW_Infinity) {
1159 if (st1_tag == TW_NaN) {
1160 real_2op_NaN(FPU_st0_ptr, st1_ptr, st1_ptr);
1164 if ((FPU_st0_ptr->sign == SIGN_NEG) ||
1165 (st1_tag == TW_Zero)) {
1166 arith_invalid(st1_ptr); /* log(infinity) */
1170 /* st(1) must be valid
1173 #ifdef DENORM_OPERAND
1174 if ((st1_ptr->exp <= EXP_UNDER) && (denormal_operand()))
1176 #endif /* DENORM_OPERAND */
1179 * that log(Infinity)
1181 * real 80486 sensibly
1185 char sign = st1_ptr->sign;
1186 reg_move(&CONST_INF, st1_ptr);
1187 st1_ptr->sign = sign;
1194 EXCEPTION(EX_INTERNAL | 0x117);
1196 #endif /* PARANOID */
1203 FPU_REG *st1_ptr = &st(1);
1204 char st1_tag = st1_ptr->tag;
1205 int old_cw = control_word;
1207 if (!((FPU_st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid))) {
1211 #ifdef DENORM_OPERAND
1212 if (((FPU_st0_ptr->exp <= EXP_UNDER) ||
1213 (st1_ptr->exp <= EXP_UNDER)) && (denormal_operand()))
1215 #endif /* DENORM_OPERAND */
1217 if (st1_ptr->exp > EXP_BIAS + 30) {
1218 /* 2^31 is far too large, would require 2^(2^30) or
1222 if (st1_ptr->sign == SIGN_POS) {
1223 EXCEPTION(EX_Overflow);
1224 sign = FPU_st0_ptr->sign;
1225 reg_move(&CONST_INF, FPU_st0_ptr);
1226 FPU_st0_ptr->sign = sign;
1228 EXCEPTION(EX_Underflow);
1229 sign = FPU_st0_ptr->sign;
1230 reg_move(&CONST_Z, FPU_st0_ptr);
1231 FPU_st0_ptr->sign = sign;
1235 control_word &= ~CW_RC;
1236 control_word |= RC_CHOP;
1237 reg_move(st1_ptr, &tmp);
1238 round_to_int(&tmp); /* This can never overflow here */
1239 control_word = old_cw;
1240 scale = st1_ptr->sign ? -tmp.sigl : tmp.sigl;
1241 scale += FPU_st0_ptr->exp;
1242 FPU_st0_ptr->exp = scale;
1244 /* Use round_reg() to properly detect under/overflow etc */
1245 round_reg(FPU_st0_ptr, 0, control_word);
1249 if (FPU_st0_tag == TW_Valid) {
1250 if (st1_tag == TW_Zero) {
1252 #ifdef DENORM_OPERAND
1253 if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
1255 #endif /* DENORM_OPERAND */
1259 if (st1_tag == TW_Infinity) {
1260 char sign = st1_ptr->sign;
1262 #ifdef DENORM_OPERAND
1263 if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
1265 #endif /* DENORM_OPERAND */
1267 if (sign == SIGN_POS) {
1268 reg_move(&CONST_INF, FPU_st0_ptr);
1270 reg_move(&CONST_Z, FPU_st0_ptr);
1271 FPU_st0_ptr->sign = sign;
1274 if (st1_tag == TW_NaN) {
1275 real_2op_NaN(FPU_st0_ptr, st1_ptr, FPU_st0_ptr);
1279 if (FPU_st0_tag == TW_Zero) {
1280 if (st1_tag == TW_Valid) {
1282 #ifdef DENORM_OPERAND
1283 if ((st1_ptr->exp <= EXP_UNDER) && (denormal_operand()))
1285 #endif /* DENORM_OPERAND */
1289 if (st1_tag == TW_Zero) {
1292 if (st1_tag == TW_Infinity) {
1293 if (st1_ptr->sign == SIGN_NEG)
1296 arith_invalid(FPU_st0_ptr); /* Zero scaled by
1301 if (st1_tag == TW_NaN) {
1302 real_2op_NaN(FPU_st0_ptr, st1_ptr, FPU_st0_ptr);
1306 if (FPU_st0_tag == TW_Infinity) {
1307 if (st1_tag == TW_Valid) {
1309 #ifdef DENORM_OPERAND
1310 if ((st1_ptr->exp <= EXP_UNDER) && (denormal_operand()))
1312 #endif /* DENORM_OPERAND */
1316 if (((st1_tag == TW_Infinity) && (st1_ptr->sign == SIGN_POS))
1317 || (st1_tag == TW_Zero))
1320 if (st1_tag == TW_Infinity) {
1321 arith_invalid(FPU_st0_ptr); /* Infinity scaled by
1325 if (st1_tag == TW_NaN) {
1326 real_2op_NaN(FPU_st0_ptr, st1_ptr, FPU_st0_ptr);
1330 if (FPU_st0_tag == TW_NaN) {
1331 if (st1_tag != TW_Empty) {
1332 real_2op_NaN(FPU_st0_ptr, st1_ptr, FPU_st0_ptr);
1337 if (!((FPU_st0_tag == TW_Empty) || (st1_tag == TW_Empty))) {
1338 EXCEPTION(EX_INTERNAL | 0x115);
1343 /* At least one of st(0), st(1) must be empty */
1349 /*---------------------------------------------------------------------------*/
1351 static FUNC trig_table_a[] = {
1352 f2xm1, fyl2x, fptan, fpatan, fxtract, fprem1, fdecstp, fincstp
1358 (trig_table_a[FPU_rm]) ();
1362 static FUNC trig_table_b[] =
1364 fprem, fyl2xp1, fsqrt_, fsincos, frndint_, emu_fscale, fsin, fcos
1370 (trig_table_b[FPU_rm]) ();