This source file includes following definitions.
- trig_arg
- convert_l2reg
- single_arg_error
- f2xm1
- fptan
- fxtract
- fdecstp
- fincstp
- fsqrt_
- frndint_
- fsin
- f_cos
- fcos
- fsincos
- fprem_kernel
- fyl2x
- fpatan
- fprem
- fprem1
- fyl2xp1
- fscale
- trig_a
- trig_b
1
2
3
4
5
6
7
8
9
10
11
12 #include "fpu_system.h"
13 #include "exception.h"
14 #include "fpu_emu.h"
15 #include "status_w.h"
16 #include "control_w.h"
17 #include "reg_constant.h"
18
19
20
21 static int trig_arg(FPU_REG *X)
22 {
23 FPU_REG tmp, quot;
24 int rv;
25 long long q;
26 int old_cw = control_word;
27
28 control_word &= ~CW_RC;
29 control_word |= RC_CHOP;
30
31 reg_move(X, ");
32 reg_div(", &CONST_PI2, ");
33
34 reg_move(", &tmp);
35 round_to_int(&tmp);
36 if ( tmp.sigh & 0x80000000 )
37 return -1;
38 tmp.exp = EXP_BIAS + 63;
39 q = *(long long *)&(tmp.sigl);
40 normalize(&tmp);
41
42 reg_sub(", &tmp, X);
43 rv = q & 7;
44
45 control_word = old_cw;
46 return rv;;
47 }
48
49
50
51 void convert_l2reg(long *arg, FPU_REG *dest)
52 {
53 long num = *arg;
54
55 if (num == 0)
56 { reg_move(&CONST_Z, dest); return; }
57
58 if (num > 0)
59 dest->sign = SIGN_POS;
60 else
61 { num = -num; dest->sign = SIGN_NEG; }
62
63 dest->sigh = num;
64 dest->sigl = 0;
65 dest->exp = EXP_BIAS + 31;
66 dest->tag = TW_Valid;
67 normalize(dest);
68 }
69
70
71 static void single_arg_error(void)
72 {
73 switch ( FPU_st0_tag )
74 {
75 case TW_NaN:
76 if ( !(FPU_st0_ptr->sigh & 0x40000000) )
77 {
78 EXCEPTION(EX_Invalid);
79
80 FPU_st0_ptr->sigh |= 0x40000000;
81 }
82 case TW_Empty:
83 stack_underflow();
84 #ifdef PARANOID
85 default:
86 EXCEPTION(EX_INTERNAL|0x0112);
87 #endif PARANOID
88 }
89 }
90
91
92
93
94 static void f2xm1()
95 {
96 switch ( FPU_st0_tag )
97 {
98 case TW_Valid:
99 {
100 FPU_REG rv, tmp;
101
102 if ( FPU_st0_ptr->sign == SIGN_POS )
103 {
104
105 if ( poly_2xm1(FPU_st0_ptr, &rv) )
106 return;
107 reg_mul(&rv, FPU_st0_ptr, FPU_st0_ptr);
108 return;
109 }
110 else
111 {
112
113
114
115 reg_add(FPU_st0_ptr, &CONST_1, &tmp);
116 poly_2xm1(&tmp, &rv);
117 reg_mul(&rv, &tmp, &tmp);
118 reg_sub(&tmp, &CONST_1, FPU_st0_ptr);
119 FPU_st0_ptr->exp--;
120 }
121 if ( FPU_st0_ptr->exp <= EXP_UNDER )
122 arith_underflow(FPU_st0_ptr);
123 return;
124 }
125 case TW_Zero:
126 return;
127 case TW_Infinity:
128 if ( FPU_st0_ptr->sign == SIGN_NEG )
129 {
130
131 reg_move(&CONST_1, FPU_st0_ptr);
132 FPU_st0_ptr->sign = SIGN_NEG;
133 }
134 return;
135 default:
136 single_arg_error();
137 }
138 }
139
140 static void fptan()
141 {
142 FPU_REG *st_new_ptr;
143 int q;
144 char arg_sign = FPU_st0_ptr->sign;
145
146 if ( STACK_OVERFLOW )
147 { stack_overflow(); return; }
148
149 switch ( FPU_st0_tag )
150 {
151 case TW_Valid:
152 FPU_st0_ptr->sign = SIGN_POS;
153 if ( (q = trig_arg(FPU_st0_ptr)) != -1 )
154 {
155 if (q & 1)
156 reg_sub(&CONST_1, FPU_st0_ptr, FPU_st0_ptr);
157
158 poly_tan(FPU_st0_ptr, FPU_st0_ptr);
159
160 FPU_st0_ptr->sign = (q & 1) ^ arg_sign;
161
162 if ( FPU_st0_ptr->exp <= EXP_UNDER )
163 arith_underflow(FPU_st0_ptr);
164
165 push();
166 reg_move(&CONST_1, FPU_st0_ptr);
167 setcc(0);
168 }
169 else
170 {
171
172 setcc(SW_C2);
173 FPU_st0_ptr->sign = arg_sign;
174 return;
175 }
176 break;
177 case TW_Infinity:
178 arith_invalid(FPU_st0_ptr);
179 setcc(0);
180 return;
181 case TW_Zero:
182 push();
183 reg_move(&CONST_1, FPU_st0_ptr);
184 setcc(0);
185 break;
186 default:
187 single_arg_error();
188 break;
189 }
190 }
191
192
193 static void fxtract()
194 {
195 FPU_REG *st_new_ptr;
196 register FPU_REG *st1_ptr = FPU_st0_ptr;
197
198 if ( STACK_OVERFLOW )
199 { stack_overflow(); return; }
200
201 if ( !(FPU_st0_tag ^ TW_Valid) )
202 {
203 long e;
204
205 push();
206 reg_move(st1_ptr, FPU_st0_ptr);
207 FPU_st0_ptr->exp = EXP_BIAS;
208 e = st1_ptr->exp - EXP_BIAS;
209 convert_l2reg(&e, st1_ptr);
210 return;
211 }
212 else if ( FPU_st0_tag == TW_Zero )
213 {
214 char sign = FPU_st0_ptr->sign;
215 divide_by_zero(SIGN_NEG, FPU_st0_ptr);
216 push();
217 reg_move(&CONST_Z, FPU_st0_ptr);
218 FPU_st0_ptr->sign = sign;
219 return;
220 }
221 else if ( FPU_st0_tag == TW_Infinity )
222 {
223 char sign = FPU_st0_ptr->sign;
224 FPU_st0_ptr->sign = SIGN_POS;
225 push();
226 reg_move(&CONST_INF, FPU_st0_ptr);
227 FPU_st0_ptr->sign = sign;
228 return;
229 }
230 else if ( FPU_st0_tag == TW_NaN )
231 {
232 if ( !(FPU_st0_ptr->sigh & 0x40000000) )
233 {
234 EXCEPTION(EX_Invalid);
235
236 FPU_st0_ptr->sigh |= 0x40000000;
237 }
238 push();
239 reg_move(st1_ptr, FPU_st0_ptr);
240 return;
241 }
242 else if ( FPU_st0_tag == TW_Empty )
243 {
244
245 if ( control_word & EX_Invalid )
246 {
247 stack_underflow();
248 push();
249 stack_underflow();
250 }
251 else
252 EXCEPTION(EX_StackUnder);
253 }
254 #ifdef PARANOID
255 else
256 EXCEPTION(EX_INTERNAL | 0x119);
257 #endif PARANOID
258 }
259
260
261 static void fdecstp()
262 {
263 top--;
264 }
265
266 static void fincstp()
267 {
268 top++;
269 }
270
271
272 static void fsqrt_()
273 {
274 if ( !(FPU_st0_tag ^ TW_Valid) )
275 {
276 int expon;
277
278 if (FPU_st0_ptr->sign == SIGN_NEG)
279 {
280 arith_invalid(FPU_st0_ptr);
281 return;
282 }
283
284 expon = FPU_st0_ptr->exp - EXP_BIAS;
285 FPU_st0_ptr->exp = EXP_BIAS + (expon & 1);
286
287 wm_sqrt(FPU_st0_ptr);
288
289 FPU_st0_ptr->exp += expon >> 1;
290 FPU_st0_ptr->tag = TW_Valid;
291 FPU_st0_ptr->sign = SIGN_POS;
292 }
293 else if ( FPU_st0_tag == TW_Zero )
294 return;
295 else if ( FPU_st0_tag == TW_Infinity )
296 {
297 if ( FPU_st0_ptr->sign == SIGN_NEG )
298 arith_invalid(FPU_st0_ptr);
299 return;
300 }
301 else
302 single_arg_error();
303 }
304
305
306 static void frndint_()
307 {
308 if ( !(FPU_st0_tag ^ TW_Valid) )
309 {
310 if (FPU_st0_ptr->exp > EXP_BIAS+63)
311 return;
312
313 round_to_int(FPU_st0_ptr);
314 FPU_st0_ptr->exp = EXP_BIAS + 63;
315 normalize(FPU_st0_ptr);
316 return;
317 }
318 else if ( (FPU_st0_tag == TW_Zero) || (FPU_st0_tag == TW_Infinity) )
319 return;
320 else
321 single_arg_error();
322 }
323
324
325 static void fsin()
326 {
327 if ( FPU_st0_tag == TW_Valid )
328 {
329 int q;
330 char arg_sign = FPU_st0_ptr->sign;
331 FPU_st0_ptr->sign = SIGN_POS;
332 if ( (q = trig_arg(FPU_st0_ptr)) != -1 )
333 {
334 FPU_REG rv;
335
336 if (q & 1)
337 reg_sub(&CONST_1, FPU_st0_ptr, FPU_st0_ptr);
338
339 poly_sine(FPU_st0_ptr, &rv);
340
341 setcc(0);
342 if (q & 2)
343 rv.sign ^= SIGN_POS ^ SIGN_NEG;
344 rv.sign ^= arg_sign;
345 reg_move(&rv, FPU_st0_ptr);
346
347 if ( FPU_st0_ptr->exp <= EXP_UNDER )
348 arith_underflow(FPU_st0_ptr);
349
350 return;
351 }
352 else
353 {
354
355 setcc(SW_C2);
356 FPU_st0_ptr->sign = arg_sign;
357 EXCEPTION(EX_Invalid);
358 return;
359 }
360 }
361 else if ( FPU_st0_tag == TW_Zero )
362 {
363 setcc(0);
364 return;
365 }
366 else if ( FPU_st0_tag == TW_Infinity )
367 {
368 arith_invalid(FPU_st0_ptr);
369 setcc(0);
370 return;
371 }
372 else
373 single_arg_error();
374 }
375
376
377 static int f_cos(FPU_REG *arg)
378 {
379 if ( arg->tag == TW_Valid )
380 {
381 int q;
382 char arg_sign = arg->sign;
383 arg->sign = SIGN_POS;
384 if ( (q = trig_arg(arg)) != -1 )
385 {
386 FPU_REG rv;
387
388 if ( !(q & 1) )
389 reg_sub(&CONST_1, arg, arg);
390
391 poly_sine(arg, &rv);
392
393 setcc(0);
394 if ((q+1) & 2)
395 rv.sign ^= SIGN_POS ^ SIGN_NEG;
396 reg_move(&rv, arg);
397
398 return 0;
399 }
400 else
401 {
402
403 setcc(SW_C2);
404 arg->sign = arg_sign;
405 EXCEPTION(EX_Invalid);
406 return 1;
407 }
408 }
409 else if ( arg->tag == TW_Zero )
410 {
411 reg_move(&CONST_1, arg);
412 setcc(0);
413 return 0;
414 }
415 else if ( FPU_st0_tag == TW_Infinity )
416 {
417 arith_invalid(FPU_st0_ptr);
418 setcc(0);
419 return 1;
420 }
421 else
422 {
423 single_arg_error();
424 return 1;
425 }
426 }
427
428
429 static void fcos()
430 {
431 f_cos(FPU_st0_ptr);
432 }
433
434
435 static void fsincos()
436 {
437 FPU_REG *st_new_ptr;
438 FPU_REG arg;
439
440 if ( STACK_OVERFLOW )
441 { stack_overflow(); return; }
442
443 reg_move(FPU_st0_ptr,&arg);
444 if ( !f_cos(&arg) )
445 {
446 fsin();
447 push();
448 reg_move(&arg,FPU_st0_ptr);
449 }
450
451 }
452
453
454
455
456
457
458
459 static void fprem_kernel(int round)
460 {
461 FPU_REG *st1_ptr = &st(1);
462 char st1_tag = st1_ptr->tag;
463
464 if ( !((FPU_st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid)) )
465 {
466 FPU_REG tmp;
467 int old_cw = control_word;
468 int expdif = FPU_st0_ptr->exp - (st1_ptr)->exp;
469
470 control_word &= ~CW_RC;
471 control_word |= round;
472
473 if (expdif < 64)
474 {
475
476 long long q;
477 int c = 0;
478 reg_div(FPU_st0_ptr, st1_ptr, &tmp);
479
480 round_to_int(&tmp);
481 tmp.exp = EXP_BIAS + 63;
482 q = *(long long *)&(tmp.sigl);
483 normalize(&tmp);
484
485 reg_mul(st1_ptr, &tmp, &tmp);
486 reg_sub(FPU_st0_ptr, &tmp, FPU_st0_ptr);
487
488 if (q&4) c |= SW_C3;
489 if (q&2) c |= SW_C1;
490 if (q&1) c |= SW_C0;
491
492 setcc(c);
493 }
494 else
495 {
496
497 int N_exp;
498
499 reg_div(FPU_st0_ptr, st1_ptr, &tmp);
500
501 N_exp = (tmp.exp & 31) + 32;
502 tmp.exp = EXP_BIAS + N_exp;
503
504 round_to_int(&tmp);
505 tmp.exp = EXP_BIAS + 63;
506 normalize(&tmp);
507
508 tmp.exp = EXP_BIAS + expdif - N_exp;
509
510 reg_mul(st1_ptr, &tmp, &tmp);
511 reg_sub(FPU_st0_ptr, &tmp, FPU_st0_ptr);
512
513 setcc(SW_C2);
514 }
515 control_word = old_cw;
516
517 if ( FPU_st0_ptr->exp <= EXP_UNDER )
518 arith_underflow(FPU_st0_ptr);
519 return;
520 }
521 else if ( (FPU_st0_tag == TW_Empty) | (st1_tag == TW_Empty) )
522 { stack_underflow(); return; }
523 else if ( FPU_st0_tag == TW_Zero )
524 {
525 if ( (st1_tag == TW_Valid) || (st1_tag == TW_Infinity) )
526 { setcc(0); return; }
527 if ( st1_tag == TW_Zero )
528 { arith_invalid(FPU_st0_ptr); return; }
529 }
530
531 if ( (FPU_st0_tag == TW_NaN) | (st1_tag == TW_NaN) )
532 { real_2op_NaN(FPU_st0_ptr, st1_ptr, FPU_st0_ptr); return; }
533 else if ( FPU_st0_tag == TW_Infinity )
534 { arith_invalid(FPU_st0_ptr); return; }
535 #ifdef PARANOID
536 else
537 EXCEPTION(EX_INTERNAL | 0x118);
538 #endif PARANOID
539
540 }
541
542
543
544 static void fyl2x()
545 {
546 FPU_REG *st1_ptr = &st(1);
547 char st1_tag = st1_ptr->tag;
548
549 if ( !((FPU_st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid)) )
550 {
551 if ( FPU_st0_ptr->sign == SIGN_POS )
552 {
553 poly_l2(FPU_st0_ptr, FPU_st0_ptr);
554
555 reg_mul(FPU_st0_ptr, st1_ptr, st1_ptr);
556 pop(); FPU_st0_ptr = &st(0);
557 if ( FPU_st0_ptr->exp <= EXP_UNDER )
558 arith_underflow(FPU_st0_ptr);
559 else if ( FPU_st0_ptr->exp >= EXP_OVER )
560 arith_overflow(FPU_st0_ptr);
561 }
562 else
563 {
564
565 pop(); FPU_st0_ptr = &st(0);
566 arith_invalid(FPU_st0_ptr);
567 }
568 return;
569 }
570
571 if ( (FPU_st0_tag == TW_Empty) || (st1_tag == TW_Empty) )
572 { stack_underflow(); return; }
573
574 if ( (FPU_st0_tag == TW_NaN) || (st1_tag == TW_NaN) )
575 {
576 real_2op_NaN(FPU_st0_ptr, st1_ptr, st1_ptr);
577 pop();
578 return;
579 }
580
581 if ( (FPU_st0_tag <= TW_Zero) && (st1_tag <= TW_Zero) )
582 {
583
584 if ( FPU_st0_tag == TW_Zero )
585 {
586 pop(); FPU_st0_ptr = &st(0);
587 if ( FPU_st0_ptr->tag == TW_Zero )
588 arith_invalid(FPU_st0_ptr);
589 else
590 divide_by_zero(st1_ptr->sign ^ SIGN_NEG, FPU_st0_ptr);
591 return;
592 }
593 if ( st1_ptr->sign == SIGN_POS )
594 {
595
596 char sign = FPU_st0_ptr->sign;
597 if ( FPU_st0_ptr->exp < EXP_BIAS ) sign ^= SIGN_NEG;
598 pop(); FPU_st0_ptr = &st(0);
599 reg_move(&CONST_Z, FPU_st0_ptr);
600 FPU_st0_ptr->sign = sign;
601 return;
602 }
603 pop(); FPU_st0_ptr = &st(0);
604 arith_invalid(FPU_st0_ptr);
605 return;
606 }
607
608
609 if ( FPU_st0_tag == TW_Infinity )
610 {
611 if ( (FPU_st0_ptr->sign == SIGN_NEG) || (st1_tag == TW_Zero) )
612 { pop(); FPU_st0_ptr = &st(0); arith_invalid(FPU_st0_ptr); return; }
613 else
614 {
615 char sign = st1_ptr->sign;
616 pop(); FPU_st0_ptr = &st(0);
617 reg_move(&CONST_INF, FPU_st0_ptr);
618 FPU_st0_ptr->sign = sign;
619 return;
620 }
621 }
622
623
624 if ( (FPU_st0_tag == TW_Valid) && (FPU_st0_ptr->sign == SIGN_POS) )
625 {
626 if ( FPU_st0_ptr->exp >= EXP_BIAS )
627 {
628 if ( (FPU_st0_ptr->exp == EXP_BIAS) &&
629 (FPU_st0_ptr->sigh == 0x80000000) &&
630 (FPU_st0_ptr->sigl == 0) )
631 {
632 pop(); FPU_st0_ptr = &st(0);
633 arith_invalid(FPU_st0_ptr);
634 return;
635 }
636 pop();
637 return;
638 }
639 else
640 {
641 pop(); FPU_st0_ptr = &st(0);
642 FPU_st0_ptr->sign ^= SIGN_NEG;
643 return;
644 }
645 }
646
647 pop(); FPU_st0_ptr = &st(0);
648 arith_invalid(FPU_st0_ptr);
649 return;
650 }
651
652
653 static void fpatan()
654 {
655 FPU_REG *st1_ptr = &st(1);
656 char st1_tag = st1_ptr->tag;
657
658 if ( !((FPU_st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid)) )
659 {
660 FPU_REG sum;
661 int quadrant = st1_ptr->sign | ((FPU_st0_ptr->sign)<<1);
662 st1_ptr->sign = FPU_st0_ptr->sign = SIGN_POS;
663 if (compare(st1_ptr) == COMP_A_LT_B)
664 {
665 quadrant |= 4;
666 reg_div(FPU_st0_ptr, st1_ptr, &sum);
667 }
668 else
669 reg_div(st1_ptr, FPU_st0_ptr, &sum);
670
671 poly_atan(&sum);
672
673 if (quadrant & 4)
674 {
675 reg_sub(&CONST_PI2, &sum, &sum);
676 }
677 if (quadrant & 2)
678 {
679 reg_sub(&CONST_PI, &sum, &sum);
680 }
681 if (quadrant & 1)
682 sum.sign ^= SIGN_POS^SIGN_NEG;
683
684 reg_move(&sum, st1_ptr);
685 pop(); FPU_st0_ptr = &st(0);
686 if ( FPU_st0_ptr->exp <= EXP_UNDER )
687 arith_underflow(FPU_st0_ptr);
688 return;
689 }
690
691 if ( (FPU_st0_tag == TW_Empty) || (st1_tag == TW_Empty) )
692 { stack_underflow(); return; }
693
694 if ( (FPU_st0_tag == TW_NaN) || (st1_tag == TW_NaN) )
695 {
696 real_2op_NaN(FPU_st0_ptr, st1_ptr, st1_ptr);
697 pop();
698 return;
699 }
700
701 if ( (FPU_st0_tag == TW_Infinity) || (st1_tag == TW_Infinity) )
702 {
703 char sign = st1_ptr->sign;
704 if ( FPU_st0_tag == TW_Infinity )
705 {
706 if ( st1_tag == TW_Infinity )
707 {
708 if ( FPU_st0_ptr->sign == SIGN_POS )
709 { reg_move(&CONST_PI4, st1_ptr); }
710 else
711 reg_add(&CONST_PI4, &CONST_PI2, st1_ptr);
712 }
713 else
714 {
715 if ( FPU_st0_ptr->sign == SIGN_POS )
716 { reg_move(&CONST_Z, st1_ptr); }
717 else
718 reg_move(&CONST_PI, st1_ptr);
719 }
720 }
721 else
722 {
723 reg_move(&CONST_PI2, st1_ptr);
724 }
725 st1_ptr->sign = sign;
726 pop();
727 return;
728 }
729
730 if ( st1_tag == TW_Zero )
731 {
732 char sign = st1_ptr->sign;
733
734 if ( FPU_st0_ptr->sign == SIGN_POS )
735 { reg_move(&CONST_Z, st1_ptr); }
736 else
737 reg_move(&CONST_PI, st1_ptr);
738 st1_tag = sign;
739 pop();
740 return;
741 }
742 else if ( FPU_st0_tag == TW_Zero )
743 {
744 char sign = st1_ptr->sign;
745
746 reg_move(&CONST_PI2, st1_ptr);
747 st1_tag = sign;
748 pop();
749 return;
750 }
751 #ifdef PARANOID
752 EXCEPTION(EX_INTERNAL | 0x220);
753 #endif PARANOID
754 }
755
756
757 static void fprem()
758 {
759 fprem_kernel(RC_CHOP);
760 }
761
762
763 static void fprem1()
764 {
765 fprem_kernel(RC_RND);
766 }
767
768
769 static void fyl2xp1()
770 {
771 FPU_REG *st1_ptr = &st(1);
772 char st1_tag = st1_ptr->tag;
773
774 if ( !((FPU_st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid)) )
775 {
776 if ( poly_l2p1(FPU_st0_ptr, FPU_st0_ptr) )
777 {
778 arith_invalid(st1_ptr); pop(); return;
779 }
780
781 reg_mul(FPU_st0_ptr, st1_ptr, st1_ptr);
782 pop();
783 return;
784 }
785 else if ( (FPU_st0_tag == TW_Empty) | (st1_tag == TW_Empty) )
786 stack_underflow();
787 else if ( FPU_st0_tag == TW_Zero )
788 {
789 if ( st1_tag <= TW_Zero )
790 {
791 st1_ptr->sign ^= FPU_st0_ptr->sign;
792 reg_move(FPU_st0_ptr, st1_ptr);
793 }
794 else if ( st1_tag == TW_Infinity )
795 {
796 arith_invalid(st1_ptr);
797 }
798 else if ( st1_tag == TW_NaN )
799 {
800 if ( !(st1_ptr->sigh & 0x40000000) )
801 EXCEPTION(EX_Invalid);
802 st1_ptr->sigh |= 0x40000000;
803 }
804 #ifdef PARANOID
805 else
806 {
807 EXCEPTION(EX_INTERNAL | 0x116);
808 }
809 #endif PARANOID
810 pop();
811 return;
812 }
813 else if ( FPU_st0_tag == TW_NaN )
814 {
815 real_2op_NaN(FPU_st0_ptr, st1_ptr, st1_ptr);
816 pop();
817 return;
818 }
819 else if ( FPU_st0_tag == TW_Infinity )
820 {
821 if ( st1_tag == TW_NaN )
822 real_2op_NaN(FPU_st0_ptr, st1_ptr, st1_ptr);
823 else
824 arith_invalid(st1_ptr);
825 pop();
826 return;
827 }
828 #ifdef PARANOID
829 else
830 EXCEPTION(EX_INTERNAL | 0x117);
831 #endif PARANOID
832 }
833
834
835 static void fscale()
836 {
837 FPU_REG *st1_ptr = &st(1);
838 char st1_tag = st1_ptr->tag;
839
840 if ( !((FPU_st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid)) )
841 {
842 long scale;
843 FPU_REG tmp;
844
845
846 if ( st1_ptr->exp > EXP_BIAS + 30 )
847 {
848 char sign;
849 EXCEPTION(EX_Overflow);
850 sign = FPU_st0_ptr->sign;
851 reg_move(&CONST_INF, FPU_st0_ptr);
852 FPU_st0_ptr->sign = sign;
853 return;
854 }
855 else if ( st1_ptr->exp < EXP_BIAS - 30 )
856 {
857 EXCEPTION(EX_Underflow);
858 reg_move(&CONST_Z, FPU_st0_ptr);
859 return;
860 }
861
862 reg_move(st1_ptr, &tmp);
863 round_to_int(&tmp);
864 scale = st1_ptr->sign ? -tmp.sigl : tmp.sigl;
865 scale += FPU_st0_ptr->exp;
866 FPU_st0_ptr->exp = scale;
867
868 if ( scale <= EXP_UNDER )
869 arith_underflow(FPU_st0_ptr);
870 else if ( scale >= EXP_OVER )
871 arith_overflow(FPU_st0_ptr);
872
873 return;
874 }
875 else if ( FPU_st0_tag == TW_Valid )
876 {
877 if ( st1_tag == TW_Zero )
878 { return; }
879 if ( st1_tag == TW_Infinity )
880 {
881 char sign = st1_ptr->sign;
882 if ( sign == SIGN_POS )
883 { reg_move(&CONST_INF, FPU_st0_ptr); }
884 else
885 reg_move(&CONST_Z, FPU_st0_ptr);
886 FPU_st0_ptr->sign = sign;
887 return;
888 }
889 if ( st1_tag == TW_NaN )
890 { real_2op_NaN(FPU_st0_ptr, st1_ptr, FPU_st0_ptr); return; }
891 }
892 else if ( FPU_st0_tag == TW_Zero )
893 {
894 if ( st1_tag <= TW_Zero ) { return; }
895 else if ( st1_tag == TW_Infinity )
896 {
897 if ( st1_ptr->sign == SIGN_NEG )
898 return;
899 else
900 { arith_invalid(FPU_st0_ptr); return; }
901 }
902 else if ( st1_tag == TW_NaN )
903 { real_2op_NaN(FPU_st0_ptr, st1_ptr, FPU_st0_ptr); return; }
904 }
905 else if ( FPU_st0_tag == TW_Infinity )
906 {
907 if ( ((st1_tag == TW_Infinity) && (st1_ptr->sign == SIGN_POS))
908 || (st1_tag <= TW_Zero) )
909 return;
910 else if ( st1_tag == TW_Infinity )
911 { arith_invalid(FPU_st0_ptr); return; }
912 else if ( st1_tag == TW_NaN )
913 { real_2op_NaN(FPU_st0_ptr, st1_ptr, FPU_st0_ptr); return; }
914 }
915 else if ( FPU_st0_tag == TW_NaN )
916 {
917 if ( st1_tag != TW_Empty )
918 { real_2op_NaN(FPU_st0_ptr, st1_ptr, FPU_st0_ptr); return; }
919 }
920
921 #ifdef PARANOID
922 if ( !((FPU_st0_tag == TW_Empty) || (st1_tag == TW_Empty)) )
923 {
924 EXCEPTION(EX_INTERNAL | 0x115);
925 return;
926 }
927 #endif
928
929
930 stack_underflow();
931
932 }
933
934
935
936
937 static FUNC trig_table_a[] = {
938 f2xm1, fyl2x, fptan, fpatan, fxtract, fprem1, fdecstp, fincstp
939 };
940
941 void trig_a()
942 {
943 (trig_table_a[FPU_rm])();
944 }
945
946
947 static FUNC trig_table_b[] =
948 {
949 fprem, fyl2xp1, fsqrt_, fsincos, frndint_, fscale, fsin, fcos
950 };
951
952 void trig_b()
953 {
954 (trig_table_b[FPU_rm])();
955 }