Merge from vendor branch LESS:
[dragonfly.git] / sys / i386 / gnu / fpemul / fpu_trig.c
1 /*
2  *  fpu_trig.c
3  *
4  * Implementation of the FPU "transcendental" functions.
5  *
6  *
7  * Copyright (C) 1992,1993,1994
8  *                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
9  *                       Australia.  E-mail   billm@vaxc.cc.monash.edu.au
10  * All rights reserved.
11  *
12  * This copyright notice covers the redistribution and use of the
13  * FPU emulator developed by W. Metzenthen. It covers only its use
14  * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
15  * use is not permitted under this copyright.
16  *
17  * Redistribution and use in source and binary forms, with or without
18  * modification, are permitted provided that the following conditions
19  * are met:
20  * 1. Redistributions of source code must retain the above copyright
21  *    notice, this list of conditions and the following disclaimer.
22  * 2. Redistributions in binary form must include information specifying
23  *    that source code for the emulator is freely available and include
24  *    either:
25  *      a) an offer to provide the source code for a nominal distribution
26  *         fee, or
27  *      b) list at least two alternative methods whereby the source
28  *         can be obtained, e.g. a publically accessible bulletin board
29  *         and an anonymous ftp site from which the software can be
30  *         downloaded.
31  * 3. All advertising materials specifically mentioning features or use of
32  *    this emulator must acknowledge that it was developed by W. Metzenthen.
33  * 4. The name of W. Metzenthen may not be used to endorse or promote
34  *    products derived from this software without specific prior written
35  *    permission.
36  *
37  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
38  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
39  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
40  * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
41  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
42  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
43  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
44  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
45  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
46  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
47  *
48  *
49  * The purpose of this copyright, based upon the Berkeley copyright, is to
50  * ensure that the covered software remains freely available to everyone.
51  *
52  * The software (with necessary differences) is also available, but under
53  * the terms of the GNU copyleft, for the Linux operating system and for
54  * the djgpp ms-dos extender.
55  *
56  * W. Metzenthen   June 1994.
57  *
58  *
59  * $FreeBSD: src/sys/gnu/i386/fpemul/fpu_trig.c,v 1.10 1999/08/28 00:42:52 peter Exp $
60  * $DragonFly: src/sys/i386/gnu/fpemul/Attic/fpu_trig.c,v 1.3 2003/08/07 21:17:20 dillon Exp $
61  *
62  */
63
64
65 #include <sys/param.h>
66 #ifdef DEBUG
67 #include <sys/systm.h>          /* for printf() in EXCEPTION() */
68 #endif
69 #include <sys/proc.h>
70 #include <machine/pcb.h>
71
72 #include "fpu_emu.h"
73 #include "fpu_system.h"
74 #include "exception.h"
75 #include "status_w.h"
76 #include "reg_constant.h"
77 #include "control_w.h"
78
79 static void convert_l2reg(long *arg, FPU_REG * dest);
80
81 static int
82 trig_arg(FPU_REG * X)
83 {
84         FPU_REG tmp, quot;
85         int     rv;
86         long long q;
87         int     old_cw = control_word;
88
89         control_word &= ~CW_RC;
90         control_word |= RC_CHOP;
91
92         reg_move(X, &quot);
93         reg_div(&quot, &CONST_PI2, &quot, FULL_PRECISION);
94
95         reg_move(&quot, &tmp);
96         round_to_int(&tmp);
97         if (tmp.sigh & 0x80000000)
98                 return -1;      /* |Arg| is >= 2^63 */
99         tmp.exp = EXP_BIAS + 63;
100         q = *(long long *) &(tmp.sigl);
101         normalize(&tmp);
102
103         reg_sub(&quot, &tmp, X, FULL_PRECISION);
104         rv = q & 7;
105
106         control_word = old_cw;
107         return rv;;
108 }
109
110
111 /* Convert a long to register */
112 static void
113 convert_l2reg(long *arg, FPU_REG * dest)
114 {
115         long    num = *arg;
116
117         if (num == 0) {
118                 reg_move(&CONST_Z, dest);
119                 return;
120         }
121         if (num > 0)
122                 dest->sign = SIGN_POS;
123         else {
124                 num = -num;
125                 dest->sign = SIGN_NEG;
126         }
127
128         dest->sigh = num;
129         dest->sigl = 0;
130         dest->exp = EXP_BIAS + 31;
131         dest->tag = TW_Valid;
132         normalize(dest);
133 }
134
135
136 static void
137 single_arg_error(void)
138 {
139         switch (FPU_st0_tag) {
140                 case TW_NaN:
141                 if (!(FPU_st0_ptr->sigh & 0x40000000)) {        /* Signaling ? */
142                         EXCEPTION(EX_Invalid);
143                         /* Convert to a QNaN */
144                         FPU_st0_ptr->sigh |= 0x40000000;
145                 }
146                 break;          /* return with a NaN in st(0) */
147         case TW_Empty:
148                 stack_underflow();      /* Puts a QNaN in st(0) */
149                 break;
150 #ifdef PARANOID
151         default:
152                 EXCEPTION(EX_INTERNAL | 0x0112);
153 #endif                          /* PARANOID */
154         }
155 }
156
157
158 /*---------------------------------------------------------------------------*/
159
160 static void
161 f2xm1(void)
162 {
163         switch (FPU_st0_tag) {
164                 case TW_Valid:
165                 {
166                         FPU_REG rv, tmp;
167
168 #ifdef DENORM_OPERAND
169                         if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
170                                 return;
171 #endif                          /* DENORM_OPERAND */
172
173                         if (FPU_st0_ptr->sign == SIGN_POS) {
174                                 /* poly_2xm1(x) requires 0 < x < 1. */
175                                 if (poly_2xm1(FPU_st0_ptr, &rv))
176                                         return; /* error */
177                                 reg_mul(&rv, FPU_st0_ptr, FPU_st0_ptr, FULL_PRECISION);
178                         } else {
179 /* **** Should change poly_2xm1() to at least handle numbers near 0 */
180                                 /* poly_2xm1(x) doesn't handle negative
181                                  * numbers. */
182                                 /* So we compute (poly_2xm1(x+1)-1)/2, for -1
183                                  * < x < 0 */
184                                 reg_add(FPU_st0_ptr, &CONST_1, &tmp, FULL_PRECISION);
185                                 poly_2xm1(&tmp, &rv);
186                                 reg_mul(&rv, &tmp, &tmp, FULL_PRECISION);
187                                 reg_sub(&tmp, &CONST_1, FPU_st0_ptr, FULL_PRECISION);
188                                 FPU_st0_ptr->exp--;
189                                 if (FPU_st0_ptr->exp <= EXP_UNDER)
190                                         arith_underflow(FPU_st0_ptr);
191                         }
192                         return;
193                 }
194         case TW_Zero:
195                 return;
196         case TW_Infinity:
197                 if (FPU_st0_ptr->sign == SIGN_NEG) {
198                         /* -infinity gives -1 (p16-10) */
199                         reg_move(&CONST_1, FPU_st0_ptr);
200                         FPU_st0_ptr->sign = SIGN_NEG;
201                 }
202                 return;
203         default:
204                 single_arg_error();
205         }
206 }
207
208 static void
209 fptan(void)
210 {
211         FPU_REG *st_new_ptr;
212         int     q;
213         char    arg_sign = FPU_st0_ptr->sign;
214
215         if (STACK_OVERFLOW) {
216                 stack_overflow();
217                 return;
218         }
219         switch (FPU_st0_tag) {
220         case TW_Valid:
221
222 #ifdef DENORM_OPERAND
223                 if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
224                         return;
225 #endif                          /* DENORM_OPERAND */
226
227                 FPU_st0_ptr->sign = SIGN_POS;
228                 if ((q = trig_arg(FPU_st0_ptr)) != -1) {
229                         if (q & 1)
230                                 reg_sub(&CONST_1, FPU_st0_ptr, FPU_st0_ptr, FULL_PRECISION);
231
232                         poly_tan(FPU_st0_ptr, FPU_st0_ptr);
233
234                         FPU_st0_ptr->sign = (q & 1) ^ arg_sign;
235
236                         if (FPU_st0_ptr->exp <= EXP_UNDER)
237                                 arith_underflow(FPU_st0_ptr);
238
239                         push();
240                         reg_move(&CONST_1, FPU_st0_ptr);
241                         setcc(0);
242                 } else {
243                         /* Operand is out of range */
244                         setcc(SW_C2);
245                         FPU_st0_ptr->sign = arg_sign;   /* restore st(0) */
246                         return;
247                 }
248                 break;
249         case TW_Infinity:
250                 /* Operand is out of range */
251                 setcc(SW_C2);
252                 FPU_st0_ptr->sign = arg_sign;   /* restore st(0) */
253                 return;
254         case TW_Zero:
255                 push();
256                 reg_move(&CONST_1, FPU_st0_ptr);
257                 setcc(0);
258                 break;
259         default:
260                 single_arg_error();
261                 break;
262         }
263 }
264
265
266 static void
267 fxtract(void)
268 {
269         FPU_REG *st_new_ptr;
270         register FPU_REG *st1_ptr = FPU_st0_ptr;        /* anticipate */
271
272         if (STACK_OVERFLOW) {
273                 stack_overflow();
274                 return;
275         }
276         if (!(FPU_st0_tag ^ TW_Valid)) {
277                 long    e;
278
279 #ifdef DENORM_OPERAND
280                 if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
281                         return;
282 #endif                          /* DENORM_OPERAND */
283
284                 push();
285                 reg_move(st1_ptr, FPU_st0_ptr);
286                 FPU_st0_ptr->exp = EXP_BIAS;
287                 e = st1_ptr->exp - EXP_BIAS;
288                 convert_l2reg(&e, st1_ptr);
289                 return;
290         } else
291                 if (FPU_st0_tag == TW_Zero) {
292                         char    sign = FPU_st0_ptr->sign;
293                         divide_by_zero(SIGN_NEG, FPU_st0_ptr);
294                         push();
295                         reg_move(&CONST_Z, FPU_st0_ptr);
296                         FPU_st0_ptr->sign = sign;
297                         return;
298                 } else
299                         if (FPU_st0_tag == TW_Infinity) {
300                                 char    sign = FPU_st0_ptr->sign;
301                                 FPU_st0_ptr->sign = SIGN_POS;
302                                 push();
303                                 reg_move(&CONST_INF, FPU_st0_ptr);
304                                 FPU_st0_ptr->sign = sign;
305                                 return;
306                         } else
307                                 if (FPU_st0_tag == TW_NaN) {
308                                         if (!(FPU_st0_ptr->sigh & 0x40000000)) {        /* Signaling ? */
309                                                 EXCEPTION(EX_Invalid);
310                                                 /* Convert to a QNaN */
311                                                 FPU_st0_ptr->sigh |= 0x40000000;
312                                         }
313                                         push();
314                                         reg_move(st1_ptr, FPU_st0_ptr);
315                                         return;
316                                 } else
317                                         if (FPU_st0_tag == TW_Empty) {
318                                                 /* Is this the correct
319                                                  * behaviour? */
320                                                 if (control_word & EX_Invalid) {
321                                                         stack_underflow();
322                                                         push();
323                                                         stack_underflow();
324                                                 } else
325                                                         EXCEPTION(EX_StackUnder);
326                                         }
327 #ifdef PARANOID
328                                         else
329                                                 EXCEPTION(EX_INTERNAL | 0x119);
330 #endif                          /* PARANOID */
331 }
332
333
334 static void
335 fdecstp(void)
336 {
337         top--;                  /* FPU_st0_ptr will be fixed in math_emulate()
338                                  * before the next instr */
339 }
340
341 static void
342 fincstp(void)
343 {
344         top++;                  /* FPU_st0_ptr will be fixed in math_emulate()
345                                  * before the next instr */
346 }
347
348
349 static void
350 fsqrt_(void)
351 {
352         if (!(FPU_st0_tag ^ TW_Valid)) {
353                 int     expon;
354
355                 if (FPU_st0_ptr->sign == SIGN_NEG) {
356                         arith_invalid(FPU_st0_ptr);     /* sqrt(negative) is
357                                                          * invalid */
358                         return;
359                 }
360 #ifdef DENORM_OPERAND
361                 if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
362                         return;
363 #endif                          /* DENORM_OPERAND */
364
365                 expon = FPU_st0_ptr->exp - EXP_BIAS;
366                 FPU_st0_ptr->exp = EXP_BIAS + (expon & 1);      /* make st(0) in  [1.0
367                                                                  * .. 4.0) */
368
369                 wm_sqrt(FPU_st0_ptr, control_word);     /* Do the computation */
370
371                 FPU_st0_ptr->exp += expon >> 1;
372                 FPU_st0_ptr->sign = SIGN_POS;
373         } else
374                 if (FPU_st0_tag == TW_Zero)
375                         return;
376                 else
377                         if (FPU_st0_tag == TW_Infinity) {
378                                 if (FPU_st0_ptr->sign == SIGN_NEG)
379                                         arith_invalid(FPU_st0_ptr);     /* sqrt(-Infinity) is
380                                                                          * invalid */
381                                 return;
382                         } else {
383                                 single_arg_error();
384                                 return;
385                         }
386
387 }
388
389
390 static void
391 frndint_(void)
392 {
393         if (!(FPU_st0_tag ^ TW_Valid)) {
394                 if (FPU_st0_ptr->exp > EXP_BIAS + 63)
395                         return;
396
397 #ifdef DENORM_OPERAND
398                 if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
399                         return;
400 #endif                          /* DENORM_OPERAND */
401
402                 round_to_int(FPU_st0_ptr);      /* Fortunately, this can't
403                                                  * overflow to 2^64 */
404                 FPU_st0_ptr->exp = EXP_BIAS + 63;
405                 normalize(FPU_st0_ptr);
406                 return;
407         } else
408                 if ((FPU_st0_tag == TW_Zero) || (FPU_st0_tag == TW_Infinity))
409                         return;
410                 else
411                         single_arg_error();
412 }
413
414
415 static void
416 fsin(void)
417 {
418         char    arg_sign = FPU_st0_ptr->sign;
419
420         if (FPU_st0_tag == TW_Valid) {
421                 int     q;
422                 FPU_st0_ptr->sign = SIGN_POS;
423
424 #ifdef DENORM_OPERAND
425                 if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
426                         return;
427 #endif                          /* DENORM_OPERAND */
428
429                 if ((q = trig_arg(FPU_st0_ptr)) != -1) {
430                         FPU_REG rv;
431
432                         if (q & 1)
433                                 reg_sub(&CONST_1, FPU_st0_ptr, FPU_st0_ptr, FULL_PRECISION);
434
435                         poly_sine(FPU_st0_ptr, &rv);
436
437                         setcc(0);
438                         if (q & 2)
439                                 rv.sign ^= SIGN_POS ^ SIGN_NEG;
440                         rv.sign ^= arg_sign;
441                         reg_move(&rv, FPU_st0_ptr);
442
443                         if (FPU_st0_ptr->exp <= EXP_UNDER)
444                                 arith_underflow(FPU_st0_ptr);
445
446                         set_precision_flag_up();        /* We do not really know
447                                                          * if up or down */
448
449                         return;
450                 } else {
451                         /* Operand is out of range */
452                         setcc(SW_C2);
453                         FPU_st0_ptr->sign = arg_sign;   /* restore st(0) */
454                         return;
455                 }
456         } else
457                 if (FPU_st0_tag == TW_Zero) {
458                         setcc(0);
459                         return;
460                 } else
461                         if (FPU_st0_tag == TW_Infinity) {
462                                 /* Operand is out of range */
463                                 setcc(SW_C2);
464                                 FPU_st0_ptr->sign = arg_sign;   /* restore st(0) */
465                                 return;
466                         } else
467                                 single_arg_error();
468 }
469
470
471 static int
472 f_cos(FPU_REG * arg)
473 {
474         char    arg_sign = arg->sign;
475
476         if (arg->tag == TW_Valid) {
477                 int     q;
478
479 #ifdef DENORM_OPERAND
480                 if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
481                         return 1;
482 #endif                          /* DENORM_OPERAND */
483
484                 arg->sign = SIGN_POS;
485                 if ((q = trig_arg(arg)) != -1) {
486                         FPU_REG rv;
487
488                         if (!(q & 1))
489                                 reg_sub(&CONST_1, arg, arg, FULL_PRECISION);
490
491                         poly_sine(arg, &rv);
492
493                         setcc(0);
494                         if ((q + 1) & 2)
495                                 rv.sign ^= SIGN_POS ^ SIGN_NEG;
496                         reg_move(&rv, arg);
497
498                         set_precision_flag_up();        /* We do not really know
499                                                          * if up or down */
500
501                         return 0;
502                 } else {
503                         /* Operand is out of range */
504                         setcc(SW_C2);
505                         arg->sign = arg_sign;   /* restore st(0) */
506                         return 1;
507                 }
508         } else
509                 if (arg->tag == TW_Zero) {
510                         reg_move(&CONST_1, arg);
511                         setcc(0);
512                         return 0;
513                 } else
514                         if (FPU_st0_tag == TW_Infinity) {
515                                 /* Operand is out of range */
516                                 setcc(SW_C2);
517                                 arg->sign = arg_sign;   /* restore st(0) */
518                                 return 1;
519                         } else {
520                                 single_arg_error();     /* requires arg ==
521                                                          * &st(0) */
522                                 return 1;
523                         }
524 }
525
526
527 static void
528 fcos(void)
529 {
530         f_cos(FPU_st0_ptr);
531 }
532
533
534 static void
535 fsincos(void)
536 {
537         FPU_REG *st_new_ptr;
538         FPU_REG arg;
539
540         if (STACK_OVERFLOW) {
541                 stack_overflow();
542                 return;
543         }
544         reg_move(FPU_st0_ptr, &arg);
545         if (!f_cos(&arg)) {
546                 fsin();
547                 push();
548                 reg_move(&arg, FPU_st0_ptr);
549         }
550 }
551
552
553 /*---------------------------------------------------------------------------*/
554 /* The following all require two arguments: st(0) and st(1) */
555
556 /* remainder of st(0) / st(1) */
557 /* Assumes that st(0) and st(1) are both TW_Valid */
558 static void
559 fprem_kernel(int round)
560 {
561         FPU_REG *st1_ptr = &st(1);
562         char    st1_tag = st1_ptr->tag;
563
564         if (!((FPU_st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid))) {
565                 FPU_REG tmp;
566                 int     old_cw = control_word;
567                 int     expdif = FPU_st0_ptr->exp - (st1_ptr)->exp;
568
569 #ifdef DENORM_OPERAND
570                 if (((FPU_st0_ptr->exp <= EXP_UNDER) ||
571                         (st1_ptr->exp <= EXP_UNDER)) && (denormal_operand()))
572                         return;
573 #endif                          /* DENORM_OPERAND */
574
575                 control_word &= ~CW_RC;
576                 control_word |= round;
577
578                 if (expdif < 64) {
579                         /* This should be the most common case */
580                         long long q;
581                         int     c = 0;
582
583                         reg_div(FPU_st0_ptr, st1_ptr, &tmp, FULL_PRECISION);
584
585                         round_to_int(&tmp);     /* Fortunately, this can't
586                                                  * overflow to 2^64 */
587                         tmp.exp = EXP_BIAS + 63;
588                         q = *(long long *) &(tmp.sigl);
589                         normalize(&tmp);
590
591                         reg_mul(st1_ptr, &tmp, &tmp, FULL_PRECISION);
592                         reg_sub(FPU_st0_ptr, &tmp, FPU_st0_ptr, FULL_PRECISION);
593
594                         if (q & 4)
595                                 c |= SW_C3;
596                         if (q & 2)
597                                 c |= SW_C1;
598                         if (q & 1)
599                                 c |= SW_C0;
600
601                         setcc(c);
602                 } else {
603                         /* There is a large exponent difference ( >= 64 ) */
604                         int     N_exp;
605
606                         reg_div(FPU_st0_ptr, st1_ptr, &tmp, FULL_PRECISION);
607                         /* N is 'a number between 32 and 63' (p26-113) */
608                         N_exp = (tmp.exp & 31) + 32;
609                         tmp.exp = EXP_BIAS + N_exp;
610
611                         round_to_int(&tmp);     /* Fortunately, this can't
612                                                  * overflow to 2^64 */
613                         tmp.exp = EXP_BIAS + 63;
614                         normalize(&tmp);
615
616                         tmp.exp = EXP_BIAS + expdif - N_exp;
617
618                         reg_mul(st1_ptr, &tmp, &tmp, FULL_PRECISION);
619                         reg_sub(FPU_st0_ptr, &tmp, FPU_st0_ptr, FULL_PRECISION);
620
621                         setcc(SW_C2);
622                 }
623                 control_word = old_cw;
624
625                 if (FPU_st0_ptr->exp <= EXP_UNDER)
626                         arith_underflow(FPU_st0_ptr);
627                 return;
628         } else
629                 if ((FPU_st0_tag == TW_Empty) | (st1_tag == TW_Empty)) {
630                         stack_underflow();
631                         return;
632                 } else
633                         if (FPU_st0_tag == TW_Zero) {
634                                 if (st1_tag == TW_Valid) {
635
636 #ifdef DENORM_OPERAND
637                                         if ((st1_ptr->exp <= EXP_UNDER) && (denormal_operand()))
638                                                 return;
639 #endif                          /* DENORM_OPERAND */
640
641                                         setcc(0);
642                                         return;
643                                 } else
644                                         if (st1_tag == TW_Zero) {
645                                                 arith_invalid(FPU_st0_ptr);
646                                                 return;
647                                         }
648                                 /* fprem(?,0) always invalid */
649                                         else
650                                                 if (st1_tag == TW_Infinity) {
651                                                         setcc(0);
652                                                         return;
653                                                 }
654                         } else
655                                 if (FPU_st0_tag == TW_Valid) {
656                                         if (st1_tag == TW_Zero) {
657                                                 arith_invalid(FPU_st0_ptr);     /* fprem(Valid,Zero) is
658                                                                                  * invalid */
659                                                 return;
660                                         } else
661                                                 if (st1_tag != TW_NaN) {
662 #ifdef DENORM_OPERAND
663                                                         if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
664                                                                 return;
665 #endif                          /* DENORM_OPERAND */
666
667                                                         if (st1_tag == TW_Infinity) {
668                                                                 /* fprem(Valid,
669                                                                  * Infinity)
670                                                                  * is o.k. */
671                                                                 setcc(0);
672                                                                 return;
673                                                         }
674                                                 }
675                                 } else
676                                         if (FPU_st0_tag == TW_Infinity) {
677                                                 if (st1_tag != TW_NaN) {
678                                                         arith_invalid(FPU_st0_ptr);     /* fprem(Infinity,?) is
679                                                                                          * invalid */
680                                                         return;
681                                                 }
682                                         }
683         /* One of the registers must contain a NaN is we got here. */
684
685 #ifdef PARANOID
686         if ((FPU_st0_tag != TW_NaN) && (st1_tag != TW_NaN))
687                 EXCEPTION(EX_INTERNAL | 0x118);
688 #endif                          /* PARANOID */
689
690         real_2op_NaN(FPU_st0_ptr, st1_ptr, FPU_st0_ptr);
691
692 }
693
694
695 /* ST(1) <- ST(1) * log ST;  pop ST */
696 static void
697 fyl2x(void)
698 {
699         FPU_REG *st1_ptr = &st(1);
700         char    st1_tag = st1_ptr->tag;
701
702         if (!((FPU_st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid))) {
703                 if (FPU_st0_ptr->sign == SIGN_POS) {
704                         int     saved_control, saved_status;
705
706 #ifdef DENORM_OPERAND
707                         if (((FPU_st0_ptr->exp <= EXP_UNDER) ||
708                                 (st1_ptr->exp <= EXP_UNDER)) && (denormal_operand()))
709                                 return;
710 #endif                          /* DENORM_OPERAND */
711
712                         /* We use the general purpose arithmetic, so we need
713                          * to save these. */
714                         saved_status = status_word;
715                         saved_control = control_word;
716                         control_word = FULL_PRECISION;
717
718                         poly_l2(FPU_st0_ptr, FPU_st0_ptr);
719
720                         /* Enough of the basic arithmetic is done now */
721                         control_word = saved_control;
722                         status_word = saved_status;
723
724                         /* Let the multiply set the flags */
725                         reg_mul(FPU_st0_ptr, st1_ptr, st1_ptr, FULL_PRECISION);
726
727                         pop();
728                         FPU_st0_ptr = &st(0);
729                 } else {
730                         /* negative      */
731                         pop();
732                         FPU_st0_ptr = &st(0);
733                         arith_invalid(FPU_st0_ptr);     /* st(0) cannot be
734                                                          * negative */
735                         return;
736                 }
737         } else
738                 if ((FPU_st0_tag == TW_Empty) || (st1_tag == TW_Empty)) {
739                         stack_underflow_pop(1);
740                         return;
741                 } else
742                         if ((FPU_st0_tag == TW_NaN) || (st1_tag == TW_NaN)) {
743                                 real_2op_NaN(FPU_st0_ptr, st1_ptr, st1_ptr);
744                                 pop();
745                                 return;
746                         } else
747                                 if ((FPU_st0_tag <= TW_Zero) && (st1_tag <= TW_Zero)) {
748                                         /* one of the args is zero, the other
749                                          * valid, or both zero */
750                                         if (FPU_st0_tag == TW_Zero) {
751                                                 pop();
752                                                 FPU_st0_ptr = &st(0);
753                                                 if (FPU_st0_ptr->tag == TW_Zero)
754                                                         arith_invalid(FPU_st0_ptr);     /* Both args zero is
755                                                                                          * invalid */
756 #ifdef PECULIAR_486
757                                                 /* This case is not
758                                                  * specifically covered in the
759                                                  * manual, but divide-by-zero
760                                                  * would seem to be the best
761                                                  * response. However, a real
762                                                  * 80486 does it this way... */
763                                                 else
764                                                         if (FPU_st0_ptr->tag == TW_Infinity) {
765                                                                 reg_move(&CONST_INF, FPU_st0_ptr);
766                                                                 return;
767                                                         }
768 #endif                          /* PECULIAR_486 */
769                                                         else
770                                                                 divide_by_zero(st1_ptr->sign ^ SIGN_NEG ^ SIGN_POS, FPU_st0_ptr);
771                                                 return;
772                                         } else {
773                                                 /* st(1) contains zero, st(0)
774                                                  * valid <> 0 */
775                                                 /* Zero is the valid answer */
776                                                 char    sign = st1_ptr->sign;
777
778 #ifdef DENORM_OPERAND
779                                                 if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
780                                                         return;
781 #endif                          /* DENORM_OPERAND */
782                                                 if (FPU_st0_ptr->sign == SIGN_NEG) {
783                                                         pop();
784                                                         FPU_st0_ptr = &st(0);
785                                                         arith_invalid(FPU_st0_ptr);     /* log(negative) */
786                                                         return;
787                                                 }
788                                                 if (FPU_st0_ptr->exp < EXP_BIAS)
789                                                         sign ^= SIGN_NEG ^ SIGN_POS;
790                                                 pop();
791                                                 FPU_st0_ptr = &st(0);
792                                                 reg_move(&CONST_Z, FPU_st0_ptr);
793                                                 FPU_st0_ptr->sign = sign;
794                                                 return;
795                                         }
796                                 }
797         /* One or both arg must be an infinity */
798                                 else
799                                         if (FPU_st0_tag == TW_Infinity) {
800                                                 if ((FPU_st0_ptr->sign == SIGN_NEG) || (st1_tag == TW_Zero)) {
801                                                         pop();
802                                                         FPU_st0_ptr = &st(0);
803                                                         arith_invalid(FPU_st0_ptr);     /* log(-infinity) or
804                                                                                          * 0*log(infinity) */
805                                                         return;
806                                                 } else {
807                                                         char    sign = st1_ptr->sign;
808
809 #ifdef DENORM_OPERAND
810                                                         if ((st1_ptr->exp <= EXP_UNDER) && (denormal_operand()))
811                                                                 return;
812 #endif                          /* DENORM_OPERAND */
813
814                                                         pop();
815                                                         FPU_st0_ptr = &st(0);
816                                                         reg_move(&CONST_INF, FPU_st0_ptr);
817                                                         FPU_st0_ptr->sign = sign;
818                                                         return;
819                                                 }
820                                         }
821         /* st(1) must be infinity here */
822                                         else
823                                                 if ((FPU_st0_tag == TW_Valid) && (FPU_st0_ptr->sign == SIGN_POS)) {
824                                                         if (FPU_st0_ptr->exp >= EXP_BIAS) {
825                                                                 if ((FPU_st0_ptr->exp == EXP_BIAS) &&
826                                                                     (FPU_st0_ptr->sigh == 0x80000000) &&
827                                                                     (FPU_st0_ptr->sigl == 0)) {
828                                                                         /* st(0
829                                                                          * )
830                                                                          * hold
831                                                                          * s
832                                                                          * 1.0 */
833                                                                         pop();
834                                                                         FPU_st0_ptr = &st(0);
835                                                                         arith_invalid(FPU_st0_ptr);     /* infinity*log(1) */
836                                                                         return;
837                                                                 }
838                                                                 /* st(0) is
839                                                                  * positive
840                                                                  * and > 1.0 */
841                                                                 pop();
842                                                         } else {
843                                                                 /* st(0) is
844                                                                  * positive
845                                                                  * and < 1.0 */
846
847 #ifdef DENORM_OPERAND
848                                                                 if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
849                                                                         return;
850 #endif                          /* DENORM_OPERAND */
851
852                                                                 st1_ptr->sign ^= SIGN_NEG;
853                                                                 pop();
854                                                         }
855                                                         return;
856                                                 } else {
857                                                         /* st(0) must be zero
858                                                          * or negative */
859                                                         if (FPU_st0_ptr->tag == TW_Zero) {
860                                                                 pop();
861                                                                 FPU_st0_ptr = st1_ptr;
862                                                                 st1_ptr->sign ^= SIGN_NEG ^ SIGN_POS;
863                                                                 /* This should
864                                                                  * be invalid,
865                                                                  * but a real
866                                                                  * 80486 is
867                                                                  * happy with
868                                                                  * it. */
869 #ifndef PECULIAR_486
870                                                                 divide_by_zero(st1_ptr->sign, FPU_st0_ptr);
871 #endif                          /* PECULIAR_486 */
872                                                         } else {
873                                                                 pop();
874                                                                 FPU_st0_ptr = st1_ptr;
875                                                                 arith_invalid(FPU_st0_ptr);     /* log(negative) */
876                                                         }
877                                                         return;
878                                                 }
879 }
880
881
882 static void
883 fpatan(void)
884 {
885         FPU_REG *st1_ptr = &st(1);
886         char    st1_tag = st1_ptr->tag;
887
888         if (!((FPU_st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid))) {
889                 int     saved_control, saved_status;
890                 FPU_REG sum;
891                 int     quadrant = st1_ptr->sign | ((FPU_st0_ptr->sign) << 1);
892
893 #ifdef DENORM_OPERAND
894                 if (((FPU_st0_ptr->exp <= EXP_UNDER) ||
895                         (st1_ptr->exp <= EXP_UNDER)) && (denormal_operand()))
896                         return;
897 #endif                          /* DENORM_OPERAND */
898
899                 /* We use the general purpose arithmetic so we need to save
900                  * these. */
901                 saved_status = status_word;
902                 saved_control = control_word;
903                 control_word = FULL_PRECISION;
904
905                 st1_ptr->sign = FPU_st0_ptr->sign = SIGN_POS;
906                 if (compare(st1_ptr) == COMP_A_lt_B) {
907                         quadrant |= 4;
908                         reg_div(FPU_st0_ptr, st1_ptr, &sum, FULL_PRECISION);
909                 } else
910                         reg_div(st1_ptr, FPU_st0_ptr, &sum, FULL_PRECISION);
911
912                 poly_atan(&sum);
913
914                 if (quadrant & 4) {
915                         reg_sub(&CONST_PI2, &sum, &sum, FULL_PRECISION);
916                 }
917                 if (quadrant & 2) {
918                         reg_sub(&CONST_PI, &sum, &sum, FULL_PRECISION);
919                 }
920                 if (quadrant & 1)
921                         sum.sign ^= SIGN_POS ^ SIGN_NEG;
922
923                 /* All of the basic arithmetic is done now */
924                 control_word = saved_control;
925                 status_word = saved_status;
926
927                 reg_move(&sum, st1_ptr);
928         } else
929                 if ((FPU_st0_tag == TW_Empty) || (st1_tag == TW_Empty)) {
930                         stack_underflow_pop(1);
931                         return;
932                 } else
933                         if ((FPU_st0_tag == TW_NaN) || (st1_tag == TW_NaN)) {
934                                 real_2op_NaN(FPU_st0_ptr, st1_ptr, st1_ptr);
935                                 pop();
936                                 return;
937                         } else
938                                 if ((FPU_st0_tag == TW_Infinity) || (st1_tag == TW_Infinity)) {
939                                         char    sign = st1_ptr->sign;
940                                         if (FPU_st0_tag == TW_Infinity) {
941                                                 if (st1_tag == TW_Infinity) {
942                                                         if (FPU_st0_ptr->sign == SIGN_POS) {
943                                                                 reg_move(&CONST_PI4, st1_ptr);
944                                                         } else
945                                                                 reg_add(&CONST_PI4, &CONST_PI2, st1_ptr, FULL_PRECISION);
946                                                 } else {
947
948 #ifdef DENORM_OPERAND
949                                                         if ((st1_ptr->exp <= EXP_UNDER) && (denormal_operand()))
950                                                                 return;
951 #endif                          /* DENORM_OPERAND */
952
953                                                         if (FPU_st0_ptr->sign == SIGN_POS) {
954                                                                 reg_move(&CONST_Z, st1_ptr);
955                                                                 pop();
956                                                                 return;
957                                                         } else
958                                                                 reg_move(&CONST_PI, st1_ptr);
959                                                 }
960                                         } else {
961                                                 /* st(1) is infinity, st(0)
962                                                  * not infinity */
963 #ifdef DENORM_OPERAND
964                                                 if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
965                                                         return;
966 #endif                          /* DENORM_OPERAND */
967
968                                                 reg_move(&CONST_PI2, st1_ptr);
969                                         }
970                                         st1_ptr->sign = sign;
971                                 } else
972                                         if (st1_tag == TW_Zero) {
973                                                 /* st(0) must be valid or zero */
974                                                 char    sign = st1_ptr->sign;
975
976 #ifdef DENORM_OPERAND
977                                                 if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
978                                                         return;
979 #endif                          /* DENORM_OPERAND */
980
981                                                 if (FPU_st0_ptr->sign == SIGN_POS) {
982                                                         reg_move(&CONST_Z, st1_ptr);
983                                                         pop();
984                                                         return;
985                                                 } else
986                                                         reg_move(&CONST_PI, st1_ptr);
987                                                 st1_ptr->sign = sign;
988                                         } else
989                                                 if (FPU_st0_tag == TW_Zero) {
990                                                         /* st(1) must be
991                                                          * TW_Valid here */
992                                                         char    sign = st1_ptr->sign;
993
994 #ifdef DENORM_OPERAND
995                                                         if ((st1_ptr->exp <= EXP_UNDER) && (denormal_operand()))
996                                                                 return;
997 #endif                          /* DENORM_OPERAND */
998
999                                                         reg_move(&CONST_PI2, st1_ptr);
1000                                                         st1_ptr->sign = sign;
1001                                                 }
1002 #ifdef PARANOID
1003                                                 else
1004                                                         EXCEPTION(EX_INTERNAL | 0x220);
1005 #endif                          /* PARANOID */
1006
1007         pop();
1008         set_precision_flag_up();/* We do not really know if up or down */
1009 }
1010
1011
1012 static void
1013 fprem(void)
1014 {
1015         fprem_kernel(RC_CHOP);
1016 }
1017
1018
1019 static void
1020 fprem1(void)
1021 {
1022         fprem_kernel(RC_RND);
1023 }
1024
1025
1026 static void
1027 fyl2xp1(void)
1028 {
1029         FPU_REG *st1_ptr = &st(1);
1030         char    st1_tag = st1_ptr->tag;
1031
1032         if (!((FPU_st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid))) {
1033                 int     saved_control, saved_status;
1034
1035 #ifdef DENORM_OPERAND
1036                 if (((FPU_st0_ptr->exp <= EXP_UNDER) ||
1037                         (st1_ptr->exp <= EXP_UNDER)) && (denormal_operand()))
1038                         return;
1039 #endif                          /* DENORM_OPERAND */
1040
1041                 /* We use the general purpose arithmetic so we need to save
1042                  * these. */
1043                 saved_status = status_word;
1044                 saved_control = control_word;
1045                 control_word = FULL_PRECISION;
1046
1047                 if (poly_l2p1(FPU_st0_ptr, FPU_st0_ptr)) {
1048                         arith_invalid(st1_ptr); /* poly_l2p1() returned
1049                                                  * invalid */
1050                         pop();
1051                         return;
1052                 }
1053                 /* Enough of the basic arithmetic is done now */
1054                 control_word = saved_control;
1055                 status_word = saved_status;
1056
1057                 /* Let the multiply set the flags */
1058                 reg_mul(FPU_st0_ptr, st1_ptr, st1_ptr, FULL_PRECISION);
1059
1060                 pop();
1061         } else
1062                 if ((FPU_st0_tag == TW_Empty) | (st1_tag == TW_Empty)) {
1063                         stack_underflow_pop(1);
1064                         return;
1065                 } else
1066                         if (FPU_st0_tag == TW_Zero) {
1067                                 if (st1_tag <= TW_Zero) {
1068
1069 #ifdef DENORM_OPERAND
1070                                         if ((st1_tag == TW_Valid) && (st1_ptr->exp <= EXP_UNDER) &&
1071                                             (denormal_operand()))
1072                                                 return;
1073 #endif                          /* DENORM_OPERAND */
1074
1075                                         st1_ptr->sign ^= FPU_st0_ptr->sign;
1076                                         reg_move(FPU_st0_ptr, st1_ptr);
1077                                 } else
1078                                         if (st1_tag == TW_Infinity) {
1079                                                 arith_invalid(st1_ptr); /* Infinity*log(1) */
1080                                                 pop();
1081                                                 return;
1082                                         } else
1083                                                 if (st1_tag == TW_NaN) {
1084                                                         real_2op_NaN(FPU_st0_ptr, st1_ptr, st1_ptr);
1085                                                         pop();
1086                                                         return;
1087                                                 }
1088 #ifdef PARANOID
1089                                                 else {
1090                                                         EXCEPTION(EX_INTERNAL | 0x116);
1091                                                         return;
1092                                                 }
1093 #endif                          /* PARANOID */
1094                                 pop();
1095                                 return;
1096                         } else
1097                                 if (FPU_st0_tag == TW_Valid) {
1098                                         if (st1_tag == TW_Zero) {
1099                                                 if (FPU_st0_ptr->sign == SIGN_NEG) {
1100                                                         if (FPU_st0_ptr->exp >= EXP_BIAS) {
1101                                                                 /* st(0) holds
1102                                                                  * <= -1.0 */
1103                                                                 arith_invalid(st1_ptr); /* infinity*log(1) */
1104                                                                 pop();
1105                                                                 return;
1106                                                         }
1107 #ifdef DENORM_OPERAND
1108                                                         if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
1109                                                                 return;
1110 #endif                          /* DENORM_OPERAND */
1111                                                         st1_ptr->sign ^= SIGN_POS ^ SIGN_NEG;
1112                                                         pop();
1113                                                         return;
1114                                                 }
1115 #ifdef DENORM_OPERAND
1116                                                 if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
1117                                                         return;
1118 #endif                          /* DENORM_OPERAND */
1119                                                 pop();
1120                                                 return;
1121                                         }
1122                                         if (st1_tag == TW_Infinity) {
1123                                                 if (FPU_st0_ptr->sign == SIGN_NEG) {
1124                                                         if ((FPU_st0_ptr->exp >= EXP_BIAS) &&
1125                                                             !((FPU_st0_ptr->sigh == 0x80000000) &&
1126                                                                 (FPU_st0_ptr->sigl == 0))) {
1127                                                                 /* st(0) holds
1128                                                                  * < -1.0 */
1129                                                                 arith_invalid(st1_ptr);
1130                                                                 pop();
1131                                                                 return;
1132                                                         }
1133 #ifdef DENORM_OPERAND
1134                                                         if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
1135                                                                 return;
1136 #endif                          /* DENORM_OPERAND */
1137                                                         st1_ptr->sign ^= SIGN_POS ^ SIGN_NEG;
1138                                                         pop();
1139                                                         return;
1140                                                 }
1141 #ifdef DENORM_OPERAND
1142                                                 if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
1143                                                         return;
1144 #endif                          /* DENORM_OPERAND */
1145                                                 pop();
1146                                                 return;
1147                                         }
1148                                         if (st1_tag == TW_NaN) {
1149                                                 real_2op_NaN(FPU_st0_ptr, st1_ptr, st1_ptr);
1150                                                 pop();
1151                                                 return;
1152                                         }
1153                                 } else
1154                                         if (FPU_st0_tag == TW_NaN) {
1155                                                 real_2op_NaN(FPU_st0_ptr, st1_ptr, st1_ptr);
1156                                                 pop();
1157                                                 return;
1158                                         } else
1159                                                 if (FPU_st0_tag == TW_Infinity) {
1160                                                         if (st1_tag == TW_NaN) {
1161                                                                 real_2op_NaN(FPU_st0_ptr, st1_ptr, st1_ptr);
1162                                                                 pop();
1163                                                                 return;
1164                                                         } else
1165                                                                 if ((FPU_st0_ptr->sign == SIGN_NEG) ||
1166                                                                     (st1_tag == TW_Zero)) {
1167                                                                         arith_invalid(st1_ptr); /* log(infinity) */
1168                                                                         pop();
1169                                                                         return;
1170                                                                 }
1171                                                         /* st(1) must be valid
1172                                                          * here. */
1173
1174 #ifdef DENORM_OPERAND
1175                                                         if ((st1_ptr->exp <= EXP_UNDER) && (denormal_operand()))
1176                                                                 return;
1177 #endif                          /* DENORM_OPERAND */
1178
1179                                                         /* The Manual says
1180                                                          * that log(Infinity)
1181                                                          * is invalid, but a
1182                                                          * real 80486 sensibly
1183                                                          * says that it is
1184                                                          * o.k. */
1185                                                         {
1186                                                                 char    sign = st1_ptr->sign;
1187                                                                 reg_move(&CONST_INF, st1_ptr);
1188                                                                 st1_ptr->sign = sign;
1189                                                         }
1190                                                         pop();
1191                                                         return;
1192                                                 }
1193 #ifdef PARANOID
1194                                                 else {
1195                                                         EXCEPTION(EX_INTERNAL | 0x117);
1196                                                 }
1197 #endif                          /* PARANOID */
1198 }
1199
1200
1201 static void
1202 emu_fscale(void)
1203 {
1204         FPU_REG *st1_ptr = &st(1);
1205         char    st1_tag = st1_ptr->tag;
1206         int     old_cw = control_word;
1207
1208         if (!((FPU_st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid))) {
1209                 long    scale;
1210                 FPU_REG tmp;
1211
1212 #ifdef DENORM_OPERAND
1213                 if (((FPU_st0_ptr->exp <= EXP_UNDER) ||
1214                         (st1_ptr->exp <= EXP_UNDER)) && (denormal_operand()))
1215                         return;
1216 #endif                          /* DENORM_OPERAND */
1217
1218                 if (st1_ptr->exp > EXP_BIAS + 30) {
1219                         /* 2^31 is far too large, would require 2^(2^30) or
1220                          * 2^(-2^30) */
1221                         char    sign;
1222
1223                         if (st1_ptr->sign == SIGN_POS) {
1224                                 EXCEPTION(EX_Overflow);
1225                                 sign = FPU_st0_ptr->sign;
1226                                 reg_move(&CONST_INF, FPU_st0_ptr);
1227                                 FPU_st0_ptr->sign = sign;
1228                         } else {
1229                                 EXCEPTION(EX_Underflow);
1230                                 sign = FPU_st0_ptr->sign;
1231                                 reg_move(&CONST_Z, FPU_st0_ptr);
1232                                 FPU_st0_ptr->sign = sign;
1233                         }
1234                         return;
1235                 }
1236                 control_word &= ~CW_RC;
1237                 control_word |= RC_CHOP;
1238                 reg_move(st1_ptr, &tmp);
1239                 round_to_int(&tmp);     /* This can never overflow here */
1240                 control_word = old_cw;
1241                 scale = st1_ptr->sign ? -tmp.sigl : tmp.sigl;
1242                 scale += FPU_st0_ptr->exp;
1243                 FPU_st0_ptr->exp = scale;
1244
1245                 /* Use round_reg() to properly detect under/overflow etc */
1246                 round_reg(FPU_st0_ptr, 0, control_word);
1247
1248                 return;
1249         } else
1250                 if (FPU_st0_tag == TW_Valid) {
1251                         if (st1_tag == TW_Zero) {
1252
1253 #ifdef DENORM_OPERAND
1254                                 if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
1255                                         return;
1256 #endif                          /* DENORM_OPERAND */
1257
1258                                 return;
1259                         }
1260                         if (st1_tag == TW_Infinity) {
1261                                 char    sign = st1_ptr->sign;
1262
1263 #ifdef DENORM_OPERAND
1264                                 if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
1265                                         return;
1266 #endif                          /* DENORM_OPERAND */
1267
1268                                 if (sign == SIGN_POS) {
1269                                         reg_move(&CONST_INF, FPU_st0_ptr);
1270                                 } else
1271                                         reg_move(&CONST_Z, FPU_st0_ptr);
1272                                 FPU_st0_ptr->sign = sign;
1273                                 return;
1274                         }
1275                         if (st1_tag == TW_NaN) {
1276                                 real_2op_NaN(FPU_st0_ptr, st1_ptr, FPU_st0_ptr);
1277                                 return;
1278                         }
1279                 } else
1280                         if (FPU_st0_tag == TW_Zero) {
1281                                 if (st1_tag == TW_Valid) {
1282
1283 #ifdef DENORM_OPERAND
1284                                         if ((st1_ptr->exp <= EXP_UNDER) && (denormal_operand()))
1285                                                 return;
1286 #endif                          /* DENORM_OPERAND */
1287
1288                                         return;
1289                                 } else
1290                                         if (st1_tag == TW_Zero) {
1291                                                 return;
1292                                         } else
1293                                                 if (st1_tag == TW_Infinity) {
1294                                                         if (st1_ptr->sign == SIGN_NEG)
1295                                                                 return;
1296                                                         else {
1297                                                                 arith_invalid(FPU_st0_ptr);     /* Zero scaled by
1298                                                                                                  * +Infinity */
1299                                                                 return;
1300                                                         }
1301                                                 } else
1302                                                         if (st1_tag == TW_NaN) {
1303                                                                 real_2op_NaN(FPU_st0_ptr, st1_ptr, FPU_st0_ptr);
1304                                                                 return;
1305                                                         }
1306                         } else
1307                                 if (FPU_st0_tag == TW_Infinity) {
1308                                         if (st1_tag == TW_Valid) {
1309
1310 #ifdef DENORM_OPERAND
1311                                                 if ((st1_ptr->exp <= EXP_UNDER) && (denormal_operand()))
1312                                                         return;
1313 #endif                          /* DENORM_OPERAND */
1314
1315                                                 return;
1316                                         }
1317                                         if (((st1_tag == TW_Infinity) && (st1_ptr->sign == SIGN_POS))
1318                                             || (st1_tag == TW_Zero))
1319                                                 return;
1320                                         else
1321                                                 if (st1_tag == TW_Infinity) {
1322                                                         arith_invalid(FPU_st0_ptr);     /* Infinity scaled by
1323                                                                                          * -Infinity */
1324                                                         return;
1325                                                 } else
1326                                                         if (st1_tag == TW_NaN) {
1327                                                                 real_2op_NaN(FPU_st0_ptr, st1_ptr, FPU_st0_ptr);
1328                                                                 return;
1329                                                         }
1330                                 } else
1331                                         if (FPU_st0_tag == TW_NaN) {
1332                                                 if (st1_tag != TW_Empty) {
1333                                                         real_2op_NaN(FPU_st0_ptr, st1_ptr, FPU_st0_ptr);
1334                                                         return;
1335                                                 }
1336                                         }
1337 #ifdef PARANOID
1338         if (!((FPU_st0_tag == TW_Empty) || (st1_tag == TW_Empty))) {
1339                 EXCEPTION(EX_INTERNAL | 0x115);
1340                 return;
1341         }
1342 #endif
1343
1344         /* At least one of st(0), st(1) must be empty */
1345         stack_underflow();
1346
1347 }
1348
1349
1350 /*---------------------------------------------------------------------------*/
1351
1352 static FUNC trig_table_a[] = {
1353         f2xm1, fyl2x, fptan, fpatan, fxtract, fprem1, fdecstp, fincstp
1354 };
1355
1356 void
1357 trig_a(void)
1358 {
1359         (trig_table_a[FPU_rm]) ();
1360 }
1361
1362
1363 static FUNC trig_table_b[] =
1364 {
1365         fprem, fyl2xp1, fsqrt_, fsincos, frndint_, emu_fscale, fsin, fcos
1366 };
1367
1368 void
1369 trig_b(void)
1370 {
1371         (trig_table_b[FPU_rm]) ();
1372 }