• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, 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 */
trig_arg(FPU_REG * st0_ptr,int even)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;
47 	control_word |= RC_CHOP;
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),
59 			   significand(&CONST_PI2),
60 			   q, exponent(st0_ptr) - exponent(&CONST_PI2));
61 		setexponent16(&tmp, 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 =
68 		    FPU_sub(REV | LOADED | TAG_Valid, (int)&CONST_PI2,
69 			    FULL_PRECISION);
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,
86 				      FULL_PRECISION, SIGN_POS,
87 				      exponent(&CONST_PI2extra) +
88 				      exponent(&tmp));
89 			setsign(&tmp, getsign(&CONST_PI2extra));
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,
119 				      FULL_PRECISION, SIGN_POS,
120 				      exponent(&CONST_PI2extra) +
121 				      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 				/* 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 =
135 				    FPU_sub(REV | LOADED | TAG_Valid,
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 */
convert_l2reg(long const * arg,int deststnr)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 
single_arg_error(FPU_REG * st0_ptr,u_char st0_tag)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 
single_arg_2_error(FPU_REG * st0_ptr,u_char st0_tag)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 ? */
200 			EXCEPTION(EX_Invalid);
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 */
214 			EXCEPTION(EX_Invalid);
215 			if (control_word & CW_Invalid) {
216 				/* The masked response */
217 				FPU_copy_to_reg0(&CONST_QNaN, TAG_Special);
218 				push();
219 				FPU_copy_to_reg0(&CONST_QNaN, TAG_Special);
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 
f2xm1(FPU_REG * st0_ptr,u_char tag)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) */
266 			FPU_copy_to_reg0(&CONST_1, TAG_Valid);
267 			setnegative(st0_ptr);
268 		}
269 		return;
270 	default:
271 		single_arg_error(st0_ptr, tag);
272 	}
273 }
274 
fptan(FPU_REG * st0_ptr,u_char st0_tag)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) {
293 		FPU_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();
320 		FPU_copy_to_reg0(&CONST_1, TAG_Valid);
321 		return;
322 	}
323 
324 	if (st0_tag == TAG_Zero) {
325 		push();
326 		FPU_copy_to_reg0(&CONST_1, TAG_Valid);
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 
fxtract(FPU_REG * st0_ptr,u_char st0_tag)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) {
361 		FPU_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();
390 		FPU_copy_to_reg0(&CONST_Z, TAG_Zero);
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();
410 		FPU_copy_to_reg0(&CONST_INF, TAG_Special);
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) {
423 			FPU_stack_underflow();
424 			push();
425 			FPU_stack_underflow();
426 		} else
427 			EXCEPTION(EX_StackUnder);
428 	}
429 #ifdef PARANOID
430 	else
431 		EXCEPTION(EX_INTERNAL | 0x119);
432 #endif /* PARANOID */
433 }
434 
fdecstp(void)435 static void fdecstp(void)
436 {
437 	clear_C1();
438 	top--;
439 }
440 
fincstp(void)441 static void fincstp(void)
442 {
443 	clear_C1();
444 	top++;
445 }
446 
fsqrt_(FPU_REG * st0_ptr,u_char st0_tag)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 
frndint_(FPU_REG * st0_ptr,u_char st0_tag)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 
fsin(FPU_REG * st0_ptr,u_char tag)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 */
570 			set_precision_flag_up();
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 
f_cos(FPU_REG * st0_ptr,u_char tag)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 */
627 				set_precision_flag_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 */
637 				set_precision_flag_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);
648 			FPU_copy_to_reg0(&CONST_1, TAG_Valid);
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) {
657 		FPU_copy_to_reg0(&CONST_1, TAG_Valid);
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 
fcos(FPU_REG * st0_ptr,u_char st0_tag)680 static void fcos(FPU_REG *st0_ptr, u_char st0_tag)
681 {
682 	f_cos(st0_ptr, st0_tag);
683 }
684 
fsincos(FPU_REG * st0_ptr,u_char st0_tag)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) {
703 		FPU_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  */
rem_kernel(unsigned long long st0,unsigned long long * y,unsigned long long st1,unsigned long long q,int n)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. */
do_fprem(FPU_REG * st0_ptr,u_char st0_tag,int round)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;
807 		control_word |= RC_CHOP;
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;
915 				FPU_copy_to_reg0(&CONST_Z, TAG_Zero);
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)) {
966 		FPU_stack_underflow();
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 */
fyl2x(FPU_REG * st0_ptr,u_char st0_tag)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)) {
1088 		FPU_stack_underflow_pop(1);
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 
1120 				FPU_copy_to_reg1(&CONST_Z, TAG_Zero);
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 
1146 			FPU_copy_to_reg1(&CONST_INF, TAG_Special);
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 
fpatan(FPU_REG * st0_ptr,u_char st0_tag)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)) {
1221 		FPU_stack_underflow_pop(1);
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 =
1236 					    FPU_u_add(&CONST_PI4, &CONST_PI2,
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)) {
1250 					FPU_copy_to_reg1(&CONST_Z, TAG_Zero);
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 
fprem(FPU_REG * st0_ptr,u_char st0_tag)1301 static void fprem(FPU_REG *st0_ptr, u_char st0_tag)
1302 {
1303 	do_fprem(st0_ptr, st0_tag, RC_CHOP);
1304 }
1305 
fprem1(FPU_REG * st0_ptr,u_char st0_tag)1306 static void fprem1(FPU_REG *st0_ptr, u_char st0_tag)
1307 {
1308 	do_fprem(st0_ptr, st0_tag, RC_RND);
1309 }
1310 
fyl2xp1(FPU_REG * st0_ptr,u_char st0_tag)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)) {
1347 		FPU_stack_underflow_pop(1);
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);
1464 			FPU_copy_to_reg1(&CONST_INF, TAG_Special);
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 
fscale(FPU_REG * st0_ptr,u_char st0_tag)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)) {
1501 				EXCEPTION(EX_Overflow);
1502 				FPU_copy_to_reg0(&CONST_INF, TAG_Special);
1503 			} else {
1504 				EXCEPTION(EX_Underflow);
1505 				FPU_copy_to_reg0(&CONST_Z, TAG_Zero);
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))
1558 				FPU_copy_to_reg0(&CONST_INF, TAG_Special);
1559 			else
1560 				FPU_copy_to_reg0(&CONST_Z, TAG_Zero);
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 */
1620 	FPU_stack_underflow();
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 
FPU_triga(void)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 
FPU_trigb(void)1640 void FPU_trigb(void)
1641 {
1642 	(trig_table_b[FPU_rm]) (&st(0), FPU_gettag0());
1643 }
1644