1 /*---------------------------------------------------------------------------+
4 | Implementation of the FPU "transcendental" functions. |
6 | Copyright (C) 1992,1993,1994,1997,1999 |
7 | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
8 | Australia. E-mail billm@melbpc.org.au |
11 +---------------------------------------------------------------------------*/
13 #include "fpu_system.h"
14 #include "exception.h"
17 #include "control_w.h"
18 #include "reg_constant.h"
20 static void rem_kernel(unsigned long long st0
, unsigned long long *y
,
21 unsigned long long st1
,
22 unsigned long long q
, int n
);
24 #define BETTER_THAN_486
28 /* Used only by fptan, fsin, fcos, and fsincos. */
29 /* This routine produces very accurate results, similar to
30 using a value of pi with more than 128 bits precision. */
31 /* Limited measurements show no results worse than 64 bit precision
32 except for the results for arguments close to 2^63, where the
33 precision of the result sometimes degrades to about 63.9 bits */
34 static int trig_arg(FPU_REG
*st0_ptr
, int even
)
39 int old_cw
= control_word
, saved_status
= partial_status
;
40 int tag
, st0_tag
= TAG_Valid
;
42 if ( exponent(st0_ptr
) >= 63 )
44 partial_status
|= SW_C2
; /* Reduction incomplete. */
48 control_word
&= ~CW_RC
;
49 control_word
|= RC_CHOP
;
52 tag
= FPU_u_div(st0_ptr
, &CONST_PI2
, &tmp
, PR_64_BITS
| RC_CHOP
| 0x3f,
55 FPU_round_to_int(&tmp
, tag
); /* Fortunately, this can't overflow
57 q
= significand(&tmp
);
60 rem_kernel(significand(st0_ptr
),
62 significand(&CONST_PI2
),
63 q
, exponent(st0_ptr
) - exponent(&CONST_PI2
));
64 setexponent16(&tmp
, exponent(&CONST_PI2
));
65 st0_tag
= FPU_normalize(&tmp
);
66 FPU_copy_to_reg0(&tmp
, st0_tag
);
69 if ( (even
&& !(q
& 1)) || (!even
&& (q
& 1)) )
71 st0_tag
= FPU_sub(REV
|LOADED
|TAG_Valid
, (int)&CONST_PI2
, FULL_PRECISION
);
73 #ifdef BETTER_THAN_486
74 /* So far, the results are exact but based upon a 64 bit
75 precision approximation to pi/2. The technique used
76 now is equivalent to using an approximation to pi/2 which
77 is accurate to about 128 bits. */
78 if ( (exponent(st0_ptr
) <= exponent(&CONST_PI2extra
) + 64) || (q
> 1) )
80 /* This code gives the effect of having pi/2 to better than
81 128 bits precision. */
83 significand(&tmp
) = q
+ 1;
84 setexponent16(&tmp
, 63);
87 FPU_u_mul(&CONST_PI2extra
, &tmp
, &tmp
, FULL_PRECISION
, SIGN_POS
,
88 exponent(&CONST_PI2extra
) + exponent(&tmp
));
89 setsign(&tmp
, getsign(&CONST_PI2extra
));
90 st0_tag
= FPU_add(&tmp
, tmptag
, 0, FULL_PRECISION
);
91 if ( signnegative(st0_ptr
) )
93 /* CONST_PI2extra is negative, so the result of the addition
94 can be negative. This means that the argument is actually
95 in a different quadrant. The correction is always < pi/2,
96 so it can't overflow into yet another quadrant. */
101 #endif /* BETTER_THAN_486 */
103 #ifdef BETTER_THAN_486
106 /* So far, the results are exact but based upon a 64 bit
107 precision approximation to pi/2. The technique used
108 now is equivalent to using an approximation to pi/2 which
109 is accurate to about 128 bits. */
110 if ( ((q
> 0) && (exponent(st0_ptr
) <= exponent(&CONST_PI2extra
) + 64))
113 /* This code gives the effect of having p/2 to better than
114 128 bits precision. */
116 significand(&tmp
) = q
;
117 setexponent16(&tmp
, 63);
118 FPU_normalize(&tmp
); /* This must return TAG_Valid */
119 tmptag
= FPU_u_mul(&CONST_PI2extra
, &tmp
, &tmp
, FULL_PRECISION
,
121 exponent(&CONST_PI2extra
) + exponent(&tmp
));
122 setsign(&tmp
, getsign(&CONST_PI2extra
));
123 st0_tag
= FPU_sub(LOADED
|(tmptag
& 0x0f), (int)&tmp
,
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
))) )
130 /* CONST_PI2extra is negative, so the result of the
131 subtraction can be larger than pi/2. This means
132 that the argument is actually in a different quadrant.
133 The correction is always < pi/2, so it can't overflow
134 into yet another quadrant. */
135 st0_tag
= FPU_sub(REV
|LOADED
|TAG_Valid
, (int)&CONST_PI2
,
141 #endif /* BETTER_THAN_486 */
143 FPU_settag0(st0_tag
);
144 control_word
= old_cw
;
145 partial_status
= saved_status
& ~SW_C2
; /* Reduction complete. */
147 return (q
& 3) | even
;
151 /* Convert a long to register */
152 static void convert_l2reg(long const *arg
, int deststnr
)
157 FPU_REG
*dest
= &st(deststnr
);
161 FPU_copy_to_regi(&CONST_Z
, TAG_Zero
, deststnr
);
168 { num
= -num
; sign
= SIGN_NEG
; }
172 setexponent16(dest
, 31);
173 tag
= FPU_normalize(dest
);
174 FPU_settagi(deststnr
, tag
);
180 static void single_arg_error(FPU_REG
*st0_ptr
, u_char st0_tag
)
182 if ( st0_tag
== TAG_Empty
)
183 FPU_stack_underflow(); /* Puts a QNaN in st(0) */
184 else if ( st0_tag
== TW_NaN
)
185 real_1op_NaN(st0_ptr
); /* return with a NaN in st(0) */
188 EXCEPTION(EX_INTERNAL
|0x0112);
189 #endif /* PARANOID */
193 static void single_arg_2_error(FPU_REG
*st0_ptr
, u_char st0_tag
)
200 isNaN
= (exponent(st0_ptr
) == EXP_OVER
) && (st0_ptr
->sigh
& 0x80000000);
201 if ( isNaN
&& !(st0_ptr
->sigh
& 0x40000000) ) /* Signaling ? */
203 EXCEPTION(EX_Invalid
);
204 if ( control_word
& CW_Invalid
)
206 /* The masked response */
207 /* Convert to a QNaN */
208 st0_ptr
->sigh
|= 0x40000000;
210 FPU_copy_to_reg0(st0_ptr
, TAG_Special
);
217 FPU_copy_to_reg0(st0_ptr
, TAG_Special
);
221 /* pseudoNaN or other unsupported */
222 EXCEPTION(EX_Invalid
);
223 if ( control_word
& CW_Invalid
)
225 /* The masked response */
226 FPU_copy_to_reg0(&CONST_QNaN
, TAG_Special
);
228 FPU_copy_to_reg0(&CONST_QNaN
, TAG_Special
);
231 break; /* return with a NaN in st(0) */
234 EXCEPTION(EX_INTERNAL
|0x0112);
235 #endif /* PARANOID */
240 /*---------------------------------------------------------------------------*/
242 static void f2xm1(FPU_REG
*st0_ptr
, u_char tag
)
248 if ( tag
== TAG_Valid
)
250 /* For an 80486 FPU, the result is undefined if the arg is >= 1.0 */
251 if ( exponent(st0_ptr
) < 0 )
255 FPU_to_exp16(st0_ptr
, &a
);
257 /* poly_2xm1(x) requires 0 < st(0) < 1. */
258 poly_2xm1(getsign(st0_ptr
), &a
, st0_ptr
);
260 set_precision_flag_up(); /* 80486 appears to always do this */
264 if ( tag
== TAG_Zero
)
267 if ( tag
== TAG_Special
)
268 tag
= FPU_Special(st0_ptr
);
273 if ( denormal_operand() < 0 )
277 if ( signnegative(st0_ptr
) )
279 /* -infinity gives -1 (p16-10) */
280 FPU_copy_to_reg0(&CONST_1
, TAG_Valid
);
281 setnegative(st0_ptr
);
285 single_arg_error(st0_ptr
, tag
);
290 static void fptan(FPU_REG
*st0_ptr
, u_char st0_tag
)
294 u_char arg_sign
= getsign(st0_ptr
);
296 /* Stack underflow has higher priority */
297 if ( st0_tag
== TAG_Empty
)
299 FPU_stack_underflow(); /* Puts a QNaN in st(0) */
300 if ( control_word
& CW_Invalid
)
302 st_new_ptr
= &st(-1);
304 FPU_stack_underflow(); /* Puts a QNaN in the new st(0) */
309 if ( STACK_OVERFLOW
)
310 { FPU_stack_overflow(); return; }
312 if ( st0_tag
== TAG_Valid
)
314 if ( exponent(st0_ptr
) > -40 )
316 if ( (q
= trig_arg(st0_ptr
, 0)) == -1 )
318 /* Operand is out of range */
323 setsign(st0_ptr
, (q
& 1) ^ (arg_sign
!= 0));
324 set_precision_flag_up(); /* We do not really know if up or down */
328 /* For a small arg, the result == the argument */
329 /* Underflow may happen */
333 FPU_to_exp16(st0_ptr
, st0_ptr
);
335 st0_tag
= FPU_round(st0_ptr
, 1, 0, FULL_PRECISION
, arg_sign
);
336 FPU_settag0(st0_tag
);
339 FPU_copy_to_reg0(&CONST_1
, TAG_Valid
);
343 if ( st0_tag
== TAG_Zero
)
346 FPU_copy_to_reg0(&CONST_1
, TAG_Valid
);
351 if ( st0_tag
== TAG_Special
)
352 st0_tag
= FPU_Special(st0_ptr
);
354 if ( st0_tag
== TW_Denormal
)
356 if ( denormal_operand() < 0 )
362 if ( st0_tag
== TW_Infinity
)
364 /* The 80486 treats infinity as an invalid operand */
365 if ( arith_invalid(0) >= 0 )
367 st_new_ptr
= &st(-1);
374 single_arg_2_error(st0_ptr
, st0_tag
);
378 static void fxtract(FPU_REG
*st0_ptr
, u_char st0_tag
)
382 register FPU_REG
*st1_ptr
= st0_ptr
; /* anticipate */
384 if ( STACK_OVERFLOW
)
385 { FPU_stack_overflow(); return; }
389 if ( st0_tag
== TAG_Valid
)
394 sign
= getsign(st1_ptr
);
395 reg_copy(st1_ptr
, st_new_ptr
);
396 setexponent16(st_new_ptr
, exponent(st_new_ptr
));
400 e
= exponent16(st_new_ptr
);
401 convert_l2reg(&e
, 1);
402 setexponentpos(st_new_ptr
, 0);
403 setsign(st_new_ptr
, sign
);
404 FPU_settag0(TAG_Valid
); /* Needed if arg was a denormal */
407 else if ( st0_tag
== TAG_Zero
)
409 sign
= getsign(st0_ptr
);
411 if ( FPU_divide_by_zero(0, SIGN_NEG
) < 0 )
415 FPU_copy_to_reg0(&CONST_Z
, TAG_Zero
);
416 setsign(st_new_ptr
, sign
);
420 if ( st0_tag
== TAG_Special
)
421 st0_tag
= FPU_Special(st0_ptr
);
423 if ( st0_tag
== TW_Denormal
)
425 if (denormal_operand() < 0 )
429 sign
= getsign(st1_ptr
);
430 FPU_to_exp16(st1_ptr
, st_new_ptr
);
433 else if ( st0_tag
== TW_Infinity
)
435 sign
= getsign(st0_ptr
);
436 setpositive(st0_ptr
);
438 FPU_copy_to_reg0(&CONST_INF
, TAG_Special
);
439 setsign(st_new_ptr
, sign
);
442 else if ( st0_tag
== TW_NaN
)
444 if ( real_1op_NaN(st0_ptr
) < 0 )
448 FPU_copy_to_reg0(st0_ptr
, TAG_Special
);
451 else if ( st0_tag
== TAG_Empty
)
453 /* Is this the correct behaviour? */
454 if ( control_word
& EX_Invalid
)
456 FPU_stack_underflow();
458 FPU_stack_underflow();
461 EXCEPTION(EX_StackUnder
);
465 EXCEPTION(EX_INTERNAL
| 0x119);
466 #endif /* PARANOID */
470 static void fdecstp(void)
476 static void fincstp(void)
483 static void fsqrt_(FPU_REG
*st0_ptr
, u_char st0_tag
)
489 if ( st0_tag
== TAG_Valid
)
493 if (signnegative(st0_ptr
))
495 arith_invalid(0); /* sqrt(negative) is invalid */
499 /* make st(0) in [1.0 .. 4.0) */
500 expon
= exponent(st0_ptr
);
504 setexponent16(st0_ptr
, (expon
& 1));
506 /* Do the computation, the sign of the result will be positive. */
507 tag
= wm_sqrt(st0_ptr
, 0, 0, control_word
, SIGN_POS
);
508 addexponent(st0_ptr
, expon
>> 1);
513 if ( st0_tag
== TAG_Zero
)
516 if ( st0_tag
== TAG_Special
)
517 st0_tag
= FPU_Special(st0_ptr
);
519 if ( st0_tag
== TW_Infinity
)
521 if ( signnegative(st0_ptr
) )
522 arith_invalid(0); /* sqrt(-Infinity) is invalid */
525 else if ( st0_tag
== TW_Denormal
)
527 if (signnegative(st0_ptr
))
529 arith_invalid(0); /* sqrt(negative) is invalid */
533 if ( denormal_operand() < 0 )
536 FPU_to_exp16(st0_ptr
, st0_ptr
);
538 expon
= exponent16(st0_ptr
);
543 single_arg_error(st0_ptr
, st0_tag
);
548 static void frndint_(FPU_REG
*st0_ptr
, u_char st0_tag
)
552 if ( st0_tag
== TAG_Valid
)
558 sign
= getsign(st0_ptr
);
560 if (exponent(st0_ptr
) > 63)
563 if ( st0_tag
== TW_Denormal
)
565 if (denormal_operand() < 0 )
569 /* Fortunately, this can't overflow to 2^64 */
570 if ( (flags
= FPU_round_to_int(st0_ptr
, st0_tag
)) )
571 set_precision_flag(flags
);
573 setexponent16(st0_ptr
, 63);
574 tag
= FPU_normalize(st0_ptr
);
575 setsign(st0_ptr
, sign
);
580 if ( st0_tag
== TAG_Zero
)
583 if ( st0_tag
== TAG_Special
)
584 st0_tag
= FPU_Special(st0_ptr
);
586 if ( st0_tag
== TW_Denormal
)
588 else if ( st0_tag
== TW_Infinity
)
591 single_arg_error(st0_ptr
, st0_tag
);
595 static int fsin(FPU_REG
*st0_ptr
, u_char tag
)
597 u_char arg_sign
= getsign(st0_ptr
);
599 if ( tag
== TAG_Valid
)
603 if ( exponent(st0_ptr
) > -40 )
605 if ( (q
= trig_arg(st0_ptr
, 0)) == -1 )
607 /* Operand is out of range */
616 setsign(st0_ptr
, getsign(st0_ptr
) ^ arg_sign
);
618 /* We do not really know if up or down */
619 set_precision_flag_up();
624 /* For a small arg, the result == the argument */
625 set_precision_flag_up(); /* Must be up. */
630 if ( tag
== TAG_Zero
)
636 if ( tag
== TAG_Special
)
637 tag
= FPU_Special(st0_ptr
);
639 if ( tag
== TW_Denormal
)
641 if ( denormal_operand() < 0 )
644 /* For a small arg, the result == the argument */
645 /* Underflow may happen */
646 FPU_to_exp16(st0_ptr
, st0_ptr
);
648 tag
= FPU_round(st0_ptr
, 1, 0, FULL_PRECISION
, arg_sign
);
654 else if ( tag
== TW_Infinity
)
656 /* The 80486 treats infinity as an invalid operand */
662 single_arg_error(st0_ptr
, tag
);
668 static int f_cos(FPU_REG
*st0_ptr
, u_char tag
)
672 st0_sign
= getsign(st0_ptr
);
674 if ( tag
== TAG_Valid
)
678 if ( exponent(st0_ptr
) > -40 )
680 if ( (exponent(st0_ptr
) < 0)
681 || ((exponent(st0_ptr
) == 0)
682 && (significand(st0_ptr
) <= 0xc90fdaa22168c234LL
)) )
686 /* We do not really know if up or down */
687 set_precision_flag_down();
691 else if ( (q
= trig_arg(st0_ptr
, FCOS
)) != -1 )
698 /* We do not really know if up or down */
699 set_precision_flag_down();
705 /* Operand is out of range */
714 FPU_copy_to_reg0(&CONST_1
, TAG_Valid
);
716 set_precision_flag_down(); /* 80486 appears to do this. */
718 set_precision_flag_up(); /* Must be up. */
719 #endif /* PECULIAR_486 */
723 else if ( tag
== TAG_Zero
)
725 FPU_copy_to_reg0(&CONST_1
, TAG_Valid
);
730 if ( tag
== TAG_Special
)
731 tag
= FPU_Special(st0_ptr
);
733 if ( tag
== TW_Denormal
)
735 if ( denormal_operand() < 0 )
740 else if ( tag
== TW_Infinity
)
742 /* The 80486 treats infinity as an invalid operand */
748 single_arg_error(st0_ptr
, tag
); /* requires st0_ptr == &st(0) */
754 static void fcos(FPU_REG
*st0_ptr
, u_char st0_tag
)
756 f_cos(st0_ptr
, st0_tag
);
760 static void fsincos(FPU_REG
*st0_ptr
, u_char st0_tag
)
766 /* Stack underflow has higher priority */
767 if ( st0_tag
== TAG_Empty
)
769 FPU_stack_underflow(); /* Puts a QNaN in st(0) */
770 if ( control_word
& CW_Invalid
)
772 st_new_ptr
= &st(-1);
774 FPU_stack_underflow(); /* Puts a QNaN in the new st(0) */
779 if ( STACK_OVERFLOW
)
780 { FPU_stack_overflow(); return; }
782 if ( st0_tag
== TAG_Special
)
783 tag
= FPU_Special(st0_ptr
);
789 single_arg_2_error(st0_ptr
, TW_NaN
);
792 else if ( tag
== TW_Infinity
)
794 /* The 80486 treats infinity as an invalid operand */
795 if ( arith_invalid(0) >= 0 )
797 /* Masked response */
804 reg_copy(st0_ptr
, &arg
);
805 if ( !fsin(st0_ptr
, st0_tag
) )
808 FPU_copy_to_reg0(&arg
, st0_tag
);
809 f_cos(&st(0), st0_tag
);
813 /* An error, so restore st(0) */
814 FPU_copy_to_reg0(&arg
, st0_tag
);
819 /*---------------------------------------------------------------------------*/
820 /* The following all require two arguments: st(0) and st(1) */
822 /* A lean, mean kernel for the fprem instructions. This relies upon
823 the division and rounding to an integer in do_fprem giving an
824 exact result. Because of this, rem_kernel() needs to deal only with
825 the least significant 64 bits, the more significant bits of the
828 static void rem_kernel(unsigned long long st0
, unsigned long long *y
,
829 unsigned long long st1
,
830 unsigned long long q
, int n
)
833 unsigned long long x
;
837 /* Do the required multiplication and subtraction in the one operation */
839 /* lsw x -= lsw st1 * lsw q */
840 asm volatile ("mull %4; subl %%eax,%0; sbbl %%edx,%1"
841 :"=m" (((unsigned *)&x
)[0]), "=m" (((unsigned *)&x
)[1]),
843 :"2" (((unsigned *)&st1
)[0]), "m" (((unsigned *)&q
)[0])
845 /* msw x -= msw st1 * lsw q */
846 asm volatile ("mull %3; subl %%eax,%0"
847 :"=m" (((unsigned *)&x
)[1]), "=a" (dummy
)
848 :"1" (((unsigned *)&st1
)[1]), "m" (((unsigned *)&q
)[0])
850 /* msw x -= lsw st1 * msw q */
851 asm volatile ("mull %3; subl %%eax,%0"
852 :"=m" (((unsigned *)&x
)[1]), "=a" (dummy
)
853 :"1" (((unsigned *)&st1
)[0]), "m" (((unsigned *)&q
)[1])
860 /* Remainder of st(0) / st(1) */
861 /* This routine produces exact results, i.e. there is never any
862 rounding or truncation, etc of the result. */
863 static void do_fprem(FPU_REG
*st0_ptr
, u_char st0_tag
, int round
)
865 FPU_REG
*st1_ptr
= &st(1);
866 u_char st1_tag
= FPU_gettagi(1);
868 if ( !((st0_tag
^ TAG_Valid
) | (st1_tag
^ TAG_Valid
)) )
870 FPU_REG tmp
, st0
, st1
;
871 u_char st0_sign
, st1_sign
;
877 unsigned short saved_status
;
881 /* Convert registers for internal use. */
882 st0_sign
= FPU_to_exp16(st0_ptr
, &st0
);
883 st1_sign
= FPU_to_exp16(st1_ptr
, &st1
);
884 expdif
= exponent16(&st0
) - exponent16(&st1
);
886 old_cw
= control_word
;
889 /* We want the status following the denorm tests, but don't want
890 the status changed by the arithmetic operations. */
891 saved_status
= partial_status
;
892 control_word
&= ~CW_RC
;
893 control_word
|= RC_CHOP
;
897 /* This should be the most common case */
901 u_char sign
= st0_sign
^ st1_sign
;
902 tag
= FPU_u_div(&st0
, &st1
, &tmp
,
903 PR_64_BITS
| RC_CHOP
| 0x3f,
907 if ( exponent(&tmp
) >= 0 )
909 FPU_round_to_int(&tmp
, tag
); /* Fortunately, this can't
911 q
= significand(&tmp
);
913 rem_kernel(significand(&st0
),
918 setexponent16(&tmp
, exponent16(&st1
));
922 reg_copy(&st0
, &tmp
);
926 if ( (round
== RC_RND
) && (tmp
.sigh
& 0xc0000000) )
928 /* We may need to subtract st(1) once more,
929 to get a result <= 1/2 of st(1). */
930 unsigned long long x
;
931 expdif
= exponent16(&st1
) - exponent16(&tmp
);
935 x
= significand(&st1
) - significand(&tmp
);
936 else /* expdif is 1 */
937 x
= (significand(&st1
) << 1) - significand(&tmp
);
938 if ( (x
< significand(&tmp
)) ||
939 /* or equi-distant (from 0 & st(1)) and q is odd */
940 ((x
== significand(&tmp
)) && (q
& 1) ) )
942 st0_sign
= ! st0_sign
;
943 significand(&tmp
) = x
;
949 if (q
& 4) cc
|= SW_C0
;
950 if (q
& 2) cc
|= SW_C3
;
951 if (q
& 1) cc
|= SW_C1
;
955 control_word
= old_cw
;
962 /* There is a large exponent difference ( >= 64 ) */
963 /* To make much sense, the code in this section should
964 be done at high precision. */
968 /* prevent overflow here */
969 /* N is 'a number between 32 and 63' (p26-113) */
970 reg_copy(&st0
, &tmp
);
972 N
= (expdif
& 0x0000001f) + 32; /* This choice gives results
973 identical to an AMD 486 */
974 setexponent16(&tmp
, N
);
975 exp_1
= exponent16(&st1
);
976 setexponent16(&st1
, 0);
979 sign
= getsign(&tmp
) ^ st1_sign
;
980 tag
= FPU_u_div(&tmp
, &st1
, &tmp
, PR_64_BITS
| RC_CHOP
| 0x3f,
984 FPU_round_to_int(&tmp
, tag
); /* Fortunately, this can't
987 rem_kernel(significand(&st0
),
993 setexponent16(&tmp
, exp_1
+ expdif
);
995 /* It is possible for the operation to be complete here.
996 What does the IEEE standard say? The Intel 80486 manual
997 implies that the operation will never be completed at this
998 point, and the behaviour of a real 80486 confirms this.
1000 if ( !(tmp
.sigh
| tmp
.sigl
) )
1002 /* The result is zero */
1003 control_word
= old_cw
;
1004 partial_status
= saved_status
;
1005 FPU_copy_to_reg0(&CONST_Z
, TAG_Zero
);
1006 setsign(&st0
, st0_sign
);
1011 #endif /* PECULIAR_486 */
1017 control_word
= old_cw
;
1018 partial_status
= saved_status
;
1019 tag
= FPU_normalize_nuo(&tmp
);
1020 reg_copy(&tmp
, st0_ptr
);
1022 /* The only condition to be looked for is underflow,
1023 and it can occur here only if underflow is unmasked. */
1024 if ( (exponent16(&tmp
) <= EXP_UNDER
) && (tag
!= TAG_Zero
)
1025 && !(control_word
& CW_Underflow
) )
1028 tag
= arith_underflow(st0_ptr
);
1029 setsign(st0_ptr
, st0_sign
);
1033 else if ( (exponent16(&tmp
) > EXP_UNDER
) || (tag
== TAG_Zero
) )
1036 setsign(st0_ptr
, st0_sign
);
1040 tag
= FPU_round(st0_ptr
, 0, 0, FULL_PRECISION
, st0_sign
);
1048 if ( st0_tag
== TAG_Special
)
1049 st0_tag
= FPU_Special(st0_ptr
);
1050 if ( st1_tag
== TAG_Special
)
1051 st1_tag
= FPU_Special(st1_ptr
);
1053 if ( ((st0_tag
== TAG_Valid
) && (st1_tag
== TW_Denormal
))
1054 || ((st0_tag
== TW_Denormal
) && (st1_tag
== TAG_Valid
))
1055 || ((st0_tag
== TW_Denormal
) && (st1_tag
== TW_Denormal
)) )
1057 if ( denormal_operand() < 0 )
1061 else if ( (st0_tag
== TAG_Empty
) || (st1_tag
== TAG_Empty
) )
1063 FPU_stack_underflow();
1066 else if ( st0_tag
== TAG_Zero
)
1068 if ( st1_tag
== TAG_Valid
)
1072 else if ( st1_tag
== TW_Denormal
)
1074 if ( denormal_operand() < 0 )
1078 else if ( st1_tag
== TAG_Zero
)
1079 { arith_invalid(0); return; } /* fprem(?,0) always invalid */
1080 else if ( st1_tag
== TW_Infinity
)
1081 { setcc(0); return; }
1083 else if ( (st0_tag
== TAG_Valid
) || (st0_tag
== TW_Denormal
) )
1085 if ( st1_tag
== TAG_Zero
)
1087 arith_invalid(0); /* fprem(Valid,Zero) is invalid */
1090 else if ( st1_tag
!= TW_NaN
)
1092 if ( ((st0_tag
== TW_Denormal
) || (st1_tag
== TW_Denormal
))
1093 && (denormal_operand() < 0) )
1096 if ( st1_tag
== TW_Infinity
)
1098 /* fprem(Valid,Infinity) is o.k. */
1103 else if ( st0_tag
== TW_Infinity
)
1105 if ( st1_tag
!= TW_NaN
)
1107 arith_invalid(0); /* fprem(Infinity,?) is invalid */
1112 /* One of the registers must contain a NaN if we got here. */
1115 if ( (st0_tag
!= TW_NaN
) && (st1_tag
!= TW_NaN
) )
1116 EXCEPTION(EX_INTERNAL
| 0x118);
1117 #endif /* PARANOID */
1119 real_2op_NaN(st1_ptr
, st1_tag
, 0, st1_ptr
);
1124 /* ST(1) <- ST(1) * log ST; pop ST */
1125 static void fyl2x(FPU_REG
*st0_ptr
, u_char st0_tag
)
1127 FPU_REG
*st1_ptr
= &st(1), exponent
;
1128 u_char st1_tag
= FPU_gettagi(1);
1134 if ( (st0_tag
== TAG_Valid
) && (st1_tag
== TAG_Valid
) )
1137 /* Both regs are Valid or Denormal */
1138 if ( signpositive(st0_ptr
) )
1140 if ( st0_tag
== TW_Denormal
)
1141 FPU_to_exp16(st0_ptr
, st0_ptr
);
1143 /* Convert st(0) for internal use. */
1144 setexponent16(st0_ptr
, exponent(st0_ptr
));
1146 if ( (st0_ptr
->sigh
== 0x80000000) && (st0_ptr
->sigl
== 0) )
1148 /* Special case. The result can be precise. */
1150 e
= exponent16(st0_ptr
);
1162 setexponent16(&exponent
, 31);
1163 tag
= FPU_normalize_nuo(&exponent
);
1165 setsign(&exponent
, esign
);
1166 tag
= FPU_mul(&exponent
, tag
, 1, FULL_PRECISION
);
1168 FPU_settagi(1, tag
);
1172 /* The usual case */
1173 sign
= getsign(st1_ptr
);
1174 if ( st1_tag
== TW_Denormal
)
1175 FPU_to_exp16(st1_ptr
, st1_ptr
);
1177 /* Convert st(1) for internal use. */
1178 setexponent16(st1_ptr
, exponent(st1_ptr
));
1179 poly_l2(st0_ptr
, st1_ptr
, sign
);
1185 if ( arith_invalid(1) < 0 )
1194 if ( st0_tag
== TAG_Special
)
1195 st0_tag
= FPU_Special(st0_ptr
);
1196 if ( st1_tag
== TAG_Special
)
1197 st1_tag
= FPU_Special(st1_ptr
);
1199 if ( (st0_tag
== TAG_Empty
) || (st1_tag
== TAG_Empty
) )
1201 FPU_stack_underflow_pop(1);
1204 else if ( (st0_tag
<= TW_Denormal
) && (st1_tag
<= TW_Denormal
) )
1206 if ( st0_tag
== TAG_Zero
)
1208 if ( st1_tag
== TAG_Zero
)
1210 /* Both args zero is invalid */
1211 if ( arith_invalid(1) < 0 )
1217 sign
= getsign(st1_ptr
)^SIGN_NEG
;
1218 if ( FPU_divide_by_zero(1, sign
) < 0 )
1221 setsign(st1_ptr
, sign
);
1224 else if ( st1_tag
== TAG_Zero
)
1226 /* st(1) contains zero, st(0) valid <> 0 */
1227 /* Zero is the valid answer */
1228 sign
= getsign(st1_ptr
);
1230 if ( signnegative(st0_ptr
) )
1233 if ( arith_invalid(1) < 0 )
1236 else if ( (st0_tag
== TW_Denormal
) && (denormal_operand() < 0) )
1240 if ( exponent(st0_ptr
) < 0 )
1243 FPU_copy_to_reg1(&CONST_Z
, TAG_Zero
);
1244 setsign(st1_ptr
, sign
);
1249 /* One or both operands are denormals. */
1250 if ( denormal_operand() < 0 )
1255 else if ( (st0_tag
== TW_NaN
) || (st1_tag
== TW_NaN
) )
1257 if ( real_2op_NaN(st0_ptr
, st0_tag
, 1, st0_ptr
) < 0 )
1260 /* One or both arg must be an infinity */
1261 else if ( st0_tag
== TW_Infinity
)
1263 if ( (signnegative(st0_ptr
)) || (st1_tag
== TAG_Zero
) )
1265 /* log(-infinity) or 0*log(infinity) */
1266 if ( arith_invalid(1) < 0 )
1271 u_char sign
= getsign(st1_ptr
);
1273 if ( (st1_tag
== TW_Denormal
) && (denormal_operand() < 0) )
1276 FPU_copy_to_reg1(&CONST_INF
, TAG_Special
);
1277 setsign(st1_ptr
, sign
);
1280 /* st(1) must be infinity here */
1281 else if ( ((st0_tag
== TAG_Valid
) || (st0_tag
== TW_Denormal
))
1282 && ( signpositive(st0_ptr
) ) )
1284 if ( exponent(st0_ptr
) >= 0 )
1286 if ( (exponent(st0_ptr
) == 0) &&
1287 (st0_ptr
->sigh
== 0x80000000) &&
1288 (st0_ptr
->sigl
== 0) )
1290 /* st(0) holds 1.0 */
1291 /* infinity*log(1) */
1292 if ( arith_invalid(1) < 0 )
1295 /* else st(0) is positive and > 1.0 */
1299 /* st(0) is positive and < 1.0 */
1301 if ( (st0_tag
== TW_Denormal
) && (denormal_operand() < 0) )
1304 changesign(st1_ptr
);
1309 /* st(0) must be zero or negative */
1310 if ( st0_tag
== TAG_Zero
)
1312 /* This should be invalid, but a real 80486 is happy with it. */
1314 #ifndef PECULIAR_486
1315 sign
= getsign(st1_ptr
);
1316 if ( FPU_divide_by_zero(1, sign
) < 0 )
1318 #endif /* PECULIAR_486 */
1320 changesign(st1_ptr
);
1322 else if ( arith_invalid(1) < 0 ) /* log(negative) */
1330 static void fpatan(FPU_REG
*st0_ptr
, u_char st0_tag
)
1332 FPU_REG
*st1_ptr
= &st(1);
1333 u_char st1_tag
= FPU_gettagi(1);
1337 if ( !((st0_tag
^ TAG_Valid
) | (st1_tag
^ TAG_Valid
)) )
1341 poly_atan(st0_ptr
, st0_tag
, st1_ptr
, st1_tag
);
1348 if ( st0_tag
== TAG_Special
)
1349 st0_tag
= FPU_Special(st0_ptr
);
1350 if ( st1_tag
== TAG_Special
)
1351 st1_tag
= FPU_Special(st1_ptr
);
1353 if ( ((st0_tag
== TAG_Valid
) && (st1_tag
== TW_Denormal
))
1354 || ((st0_tag
== TW_Denormal
) && (st1_tag
== TAG_Valid
))
1355 || ((st0_tag
== TW_Denormal
) && (st1_tag
== TW_Denormal
)) )
1357 if ( denormal_operand() < 0 )
1362 else if ( (st0_tag
== TAG_Empty
) || (st1_tag
== TAG_Empty
) )
1364 FPU_stack_underflow_pop(1);
1367 else if ( (st0_tag
== TW_NaN
) || (st1_tag
== TW_NaN
) )
1369 if ( real_2op_NaN(st0_ptr
, st0_tag
, 1, st0_ptr
) >= 0 )
1373 else if ( (st0_tag
== TW_Infinity
) || (st1_tag
== TW_Infinity
) )
1375 u_char sign
= getsign(st1_ptr
);
1376 if ( st0_tag
== TW_Infinity
)
1378 if ( st1_tag
== TW_Infinity
)
1380 if ( signpositive(st0_ptr
) )
1382 FPU_copy_to_reg1(&CONST_PI4
, TAG_Valid
);
1386 setpositive(st1_ptr
);
1387 tag
= FPU_u_add(&CONST_PI4
, &CONST_PI2
, st1_ptr
,
1388 FULL_PRECISION
, SIGN_POS
,
1389 exponent(&CONST_PI4
), exponent(&CONST_PI2
));
1391 FPU_settagi(1, tag
);
1396 if ( (st1_tag
== TW_Denormal
) && (denormal_operand() < 0) )
1399 if ( signpositive(st0_ptr
) )
1401 FPU_copy_to_reg1(&CONST_Z
, TAG_Zero
);
1402 setsign(st1_ptr
, sign
); /* An 80486 preserves the sign */
1408 FPU_copy_to_reg1(&CONST_PI
, TAG_Valid
);
1414 /* st(1) is infinity, st(0) not infinity */
1415 if ( (st0_tag
== TW_Denormal
) && (denormal_operand() < 0) )
1418 FPU_copy_to_reg1(&CONST_PI2
, TAG_Valid
);
1420 setsign(st1_ptr
, sign
);
1422 else if ( st1_tag
== TAG_Zero
)
1424 /* st(0) must be valid or zero */
1425 u_char sign
= getsign(st1_ptr
);
1427 if ( (st0_tag
== TW_Denormal
) && (denormal_operand() < 0) )
1430 if ( signpositive(st0_ptr
) )
1432 /* An 80486 preserves the sign */
1437 FPU_copy_to_reg1(&CONST_PI
, TAG_Valid
);
1438 setsign(st1_ptr
, sign
);
1440 else if ( st0_tag
== TAG_Zero
)
1442 /* st(1) must be TAG_Valid here */
1443 u_char sign
= getsign(st1_ptr
);
1445 if ( (st1_tag
== TW_Denormal
) && (denormal_operand() < 0) )
1448 FPU_copy_to_reg1(&CONST_PI2
, TAG_Valid
);
1449 setsign(st1_ptr
, sign
);
1453 EXCEPTION(EX_INTERNAL
| 0x125);
1454 #endif /* PARANOID */
1457 set_precision_flag_up(); /* We do not really know if up or down */
1461 static void fprem(FPU_REG
*st0_ptr
, u_char st0_tag
)
1463 do_fprem(st0_ptr
, st0_tag
, RC_CHOP
);
1467 static void fprem1(FPU_REG
*st0_ptr
, u_char st0_tag
)
1469 do_fprem(st0_ptr
, st0_tag
, RC_RND
);
1473 static void fyl2xp1(FPU_REG
*st0_ptr
, u_char st0_tag
)
1476 FPU_REG
*st1_ptr
= &st(1), a
, b
;
1477 u_char st1_tag
= FPU_gettagi(1);
1480 if ( !((st0_tag
^ TAG_Valid
) | (st1_tag
^ TAG_Valid
)) )
1484 sign
= getsign(st0_ptr
);
1485 sign1
= getsign(st1_ptr
);
1487 FPU_to_exp16(st0_ptr
, &a
);
1488 FPU_to_exp16(st1_ptr
, &b
);
1490 if ( poly_l2p1(sign
, sign1
, &a
, &b
, st1_ptr
) )
1497 if ( st0_tag
== TAG_Special
)
1498 st0_tag
= FPU_Special(st0_ptr
);
1499 if ( st1_tag
== TAG_Special
)
1500 st1_tag
= FPU_Special(st1_ptr
);
1502 if ( ((st0_tag
== TAG_Valid
) && (st1_tag
== TW_Denormal
))
1503 || ((st0_tag
== TW_Denormal
) && (st1_tag
== TAG_Valid
))
1504 || ((st0_tag
== TW_Denormal
) && (st1_tag
== TW_Denormal
)) )
1506 if ( denormal_operand() < 0 )
1511 else if ( (st0_tag
== TAG_Empty
) | (st1_tag
== TAG_Empty
) )
1513 FPU_stack_underflow_pop(1);
1516 else if ( st0_tag
== TAG_Zero
)
1521 if ( denormal_operand() < 0 )
1526 setsign(st0_ptr
, getsign(st0_ptr
) ^ getsign(st1_ptr
));
1527 FPU_copy_to_reg1(st0_ptr
, st0_tag
);
1531 /* Infinity*log(1) */
1532 if ( arith_invalid(1) < 0 )
1537 if ( real_2op_NaN(st0_ptr
, st0_tag
, 1, st0_ptr
) < 0 )
1543 EXCEPTION(EX_INTERNAL
| 0x116);
1545 #endif /* PARANOID */
1549 else if ( (st0_tag
== TAG_Valid
) || (st0_tag
== TW_Denormal
) )
1554 if ( signnegative(st0_ptr
) )
1556 if ( exponent(st0_ptr
) >= 0 )
1558 /* st(0) holds <= -1.0 */
1559 #ifdef PECULIAR_486 /* Stupid 80486 doesn't worry about log(negative). */
1560 changesign(st1_ptr
);
1562 if ( arith_invalid(1) < 0 )
1564 #endif /* PECULIAR_486 */
1566 else if ( (st0_tag
== TW_Denormal
) && (denormal_operand() < 0) )
1569 changesign(st1_ptr
);
1571 else if ( (st0_tag
== TW_Denormal
) && (denormal_operand() < 0) )
1576 if ( signnegative(st0_ptr
) )
1578 if ( (exponent(st0_ptr
) >= 0) &&
1579 !((st0_ptr
->sigh
== 0x80000000) &&
1580 (st0_ptr
->sigl
== 0)) )
1582 /* st(0) holds < -1.0 */
1583 #ifdef PECULIAR_486 /* Stupid 80486 doesn't worry about log(negative). */
1584 changesign(st1_ptr
);
1586 if ( arith_invalid(1) < 0 ) return;
1587 #endif /* PECULIAR_486 */
1589 else if ( (st0_tag
== TW_Denormal
) && (denormal_operand() < 0) )
1592 changesign(st1_ptr
);
1594 else if ( (st0_tag
== TW_Denormal
) && (denormal_operand() < 0) )
1599 if ( real_2op_NaN(st0_ptr
, st0_tag
, 1, st0_ptr
) < 0 )
1604 else if ( st0_tag
== TW_NaN
)
1606 if ( real_2op_NaN(st0_ptr
, st0_tag
, 1, st0_ptr
) < 0 )
1609 else if ( st0_tag
== TW_Infinity
)
1611 if ( st1_tag
== TW_NaN
)
1613 if ( real_2op_NaN(st0_ptr
, st0_tag
, 1, st0_ptr
) < 0 )
1616 else if ( signnegative(st0_ptr
) )
1618 #ifndef PECULIAR_486
1619 /* This should have higher priority than denormals, but... */
1620 if ( arith_invalid(1) < 0 ) /* log(-infinity) */
1622 #endif /* PECULIAR_486 */
1623 if ( (st1_tag
== TW_Denormal
) && (denormal_operand() < 0) )
1626 /* Denormal operands actually get higher priority */
1627 if ( arith_invalid(1) < 0 ) /* log(-infinity) */
1629 #endif /* PECULIAR_486 */
1631 else if ( st1_tag
== TAG_Zero
)
1634 if ( arith_invalid(1) < 0 )
1638 /* st(1) must be valid here. */
1640 else if ( (st1_tag
== TW_Denormal
) && (denormal_operand() < 0) )
1643 /* The Manual says that log(Infinity) is invalid, but a real
1644 80486 sensibly says that it is o.k. */
1647 u_char sign
= getsign(st1_ptr
);
1648 FPU_copy_to_reg1(&CONST_INF
, TAG_Special
);
1649 setsign(st1_ptr
, sign
);
1655 EXCEPTION(EX_INTERNAL
| 0x117);
1658 #endif /* PARANOID */
1666 static void fscale(FPU_REG
*st0_ptr
, u_char st0_tag
)
1668 FPU_REG
*st1_ptr
= &st(1);
1669 u_char st1_tag
= FPU_gettagi(1);
1670 int old_cw
= control_word
;
1671 u_char sign
= getsign(st0_ptr
);
1674 if ( !((st0_tag
^ TAG_Valid
) | (st1_tag
^ TAG_Valid
)) )
1679 /* Convert register for internal use. */
1680 setexponent16(st0_ptr
, exponent(st0_ptr
));
1684 if ( exponent(st1_ptr
) > 30 )
1686 /* 2^31 is far too large, would require 2^(2^30) or 2^(-2^30) */
1688 if ( signpositive(st1_ptr
) )
1690 EXCEPTION(EX_Overflow
);
1691 FPU_copy_to_reg0(&CONST_INF
, TAG_Special
);
1695 EXCEPTION(EX_Underflow
);
1696 FPU_copy_to_reg0(&CONST_Z
, TAG_Zero
);
1698 setsign(st0_ptr
, sign
);
1702 control_word
&= ~CW_RC
;
1703 control_word
|= RC_CHOP
;
1704 reg_copy(st1_ptr
, &tmp
);
1705 FPU_round_to_int(&tmp
, st1_tag
); /* This can never overflow here */
1706 control_word
= old_cw
;
1707 scale
= signnegative(st1_ptr
) ? -tmp
.sigl
: tmp
.sigl
;
1708 scale
+= exponent16(st0_ptr
);
1710 setexponent16(st0_ptr
, scale
);
1712 /* Use FPU_round() to properly detect under/overflow etc */
1713 FPU_round(st0_ptr
, 0, 0, control_word
, sign
);
1718 if ( st0_tag
== TAG_Special
)
1719 st0_tag
= FPU_Special(st0_ptr
);
1720 if ( st1_tag
== TAG_Special
)
1721 st1_tag
= FPU_Special(st1_ptr
);
1723 if ( (st0_tag
== TAG_Valid
) || (st0_tag
== TW_Denormal
) )
1728 /* st(0) must be a denormal */
1729 if ( (st0_tag
== TW_Denormal
) && (denormal_operand() < 0) )
1732 FPU_to_exp16(st0_ptr
, st0_ptr
); /* Will not be left on stack */
1736 if ( st0_tag
== TW_Denormal
)
1745 if ( (st0_tag
== TW_Denormal
) && (denormal_operand() < 0) )
1748 if ( signpositive(st1_ptr
) )
1749 FPU_copy_to_reg0(&CONST_INF
, TAG_Special
);
1751 FPU_copy_to_reg0(&CONST_Z
, TAG_Zero
);
1752 setsign(st0_ptr
, sign
);
1756 real_2op_NaN(st1_ptr
, st1_tag
, 0, st0_ptr
);
1760 else if ( st0_tag
== TAG_Zero
)
1773 if ( signpositive(st1_ptr
) )
1774 arith_invalid(0); /* Zero scaled by +Infinity */
1778 real_2op_NaN(st1_ptr
, st1_tag
, 0, st0_ptr
);
1782 else if ( st0_tag
== TW_Infinity
)
1795 if ( signnegative(st1_ptr
) )
1796 arith_invalid(0); /* Infinity scaled by -Infinity */
1800 real_2op_NaN(st1_ptr
, st1_tag
, 0, st0_ptr
);
1804 else if ( st0_tag
== TW_NaN
)
1806 if ( st1_tag
!= TAG_Empty
)
1807 { real_2op_NaN(st1_ptr
, st1_tag
, 0, st0_ptr
); return; }
1811 if ( !((st0_tag
== TAG_Empty
) || (st1_tag
== TAG_Empty
)) )
1813 EXCEPTION(EX_INTERNAL
| 0x115);
1818 /* At least one of st(0), st(1) must be empty */
1819 FPU_stack_underflow();
1824 /*---------------------------------------------------------------------------*/
1826 static FUNC_ST0
const trig_table_a
[] = {
1827 f2xm1
, fyl2x
, fptan
, fpatan
,
1828 fxtract
, fprem1
, (FUNC_ST0
)fdecstp
, (FUNC_ST0
)fincstp
1831 void FPU_triga(void)
1833 (trig_table_a
[FPU_rm
])(&st(0), FPU_gettag0());
1837 static FUNC_ST0
const trig_table_b
[] =
1839 fprem
, fyl2xp1
, fsqrt_
, fsincos
, frndint_
, fscale
, (FUNC_ST0
)fsin
, fcos
1842 void FPU_trigb(void)
1844 (trig_table_b
[FPU_rm
])(&st(0), FPU_gettag0());