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