|
|
1.1 root 1: /*---------------------------------------------------------------------------+
2: | fpu_trig.c |
3: | |
4: | Implementation of the FPU "transcendental" functions. |
5: | |
6: | Copyright (C) 1992 W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
7: | Australia. E-mail [email protected] |
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; /* |Arg| is >= 2^63 */
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: /* Convert a long to register */
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) ) /* Signaling ? */
77: {
78: EXCEPTION(EX_Invalid);
79: /* Convert to a QNaN */
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: /* poly_2xm1(x) requires 0 < x < 1. */
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: /* **** Should change poly_2xm1() to at least handle numbers near 0 */
113: /* poly_2xm1(x) doesn't handle negative numbers. */
114: /* So we compute (poly_2xm1(x+1)-1)/2, for -1 < x < 0 */
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: /* -infinity gives -1 (p16-10) */
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: /* Operand is out of range */
172: setcc(SW_C2);
173: FPU_st0_ptr->sign = arg_sign; /* restore st(0) */
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; /* anticipate */
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) ) /* Signaling ? */
233: {
234: EXCEPTION(EX_Invalid);
235: /* Convert to a QNaN */
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: /* Is this the correct behaviour? */
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--; /* FPU_st0_ptr will be fixed in math_emulate() before the next instr */
264: }
265:
266: static void fincstp()
267: {
268: top++; /* FPU_st0_ptr will be fixed in math_emulate() before the next instr */
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); /* make st(0) in [1.0 .. 4.0) */
286:
287: wm_sqrt(FPU_st0_ptr); /* Do the computation */
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); /* Fortunately, this can't overflow to 2^64 */
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: /* Operand is out of range */
355: setcc(SW_C2);
356: FPU_st0_ptr->sign = arg_sign; /* restore st(0) */
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: /* Operand is out of range */
403: setcc(SW_C2);
404: arg->sign = arg_sign; /* restore st(0) */
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(); /* requires arg == &st(0) */
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: /* The following all require two arguments: st(0) and st(1) */
456:
457: /* remainder of st(0) / st(1) */
458: /* Assumes that st(0) and st(1) are both TW_Valid */
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: /* This should be the most common case */
476: long long q;
477: int c = 0;
478: reg_div(FPU_st0_ptr, st1_ptr, &tmp);
479:
480: round_to_int(&tmp); /* Fortunately, this can't overflow to 2^64 */
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: /* There is a large exponent difference ( >= 64 ) */
497: int N_exp;
498:
499: reg_div(FPU_st0_ptr, st1_ptr, &tmp);
500: /* N is 'a number between 32 and 63' (p26-113) */
501: N_exp = (tmp.exp & 31) + 32;
502: tmp.exp = EXP_BIAS + N_exp;
503:
504: round_to_int(&tmp); /* Fortunately, this can't overflow to 2^64 */
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: /* ST(1) <- ST(1) * log ST; pop ST */
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: /* negative */
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: /* one of the args is zero, the other valid, or both zero */
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: /* Zero is the valid answer */
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: /* One or both arg must be an infinity */
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: /* st(1) must be infinity here */
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: /* st(0) must be zero or negative */
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 (emCompare(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: /* st(0) must be valid or zero */
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: /* st(1) must be TW_Valid here */
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); /* signaling NaN */
802: st1_ptr->sigh |= 0x40000000; /* QNaN */
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: /* 2^31 is far too large, 2^-31 is far too small */
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); /* This can never overflow here */
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: /* At least one of st(0), st(1) must be empty */
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.