Linux kernel & device driver programming

Cross-Referenced Linux and Device Driver Code

[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]
Version: [ 2.6.11.8 ] [ 2.6.25 ] [ 2.6.25.8 ] [ 2.6.31.13 ] Architecture: [ i386 ]
  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 
  This page was automatically generated by the LXR engine.