Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/x86/math-emu/fpu_trig.c
10820 views
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;
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 */
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 ? */
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
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
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
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
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 */
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
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
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) {
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
*/
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;
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 */
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
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
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)) {
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
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
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
}
1644
1645