File: /usr/src/linux/arch/i386/math-emu/fpu_trig.c

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