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