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