OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [uclinux/] [uClinux-2.0.x/] [arch/] [alpha/] [math-emu/] [ieee-math.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 199 simons
/*
2
 * ieee-math.c - IEEE floating point emulation code
3
 * Copyright (C) 1989,1990,1991,1995 by
4
 * Digital Equipment Corporation, Maynard, Massachusetts.
5
 *
6
 * Heavily modified for Linux/Alpha.  Changes are Copyright (c) 1995
7
 * by David Mosberger (davidm@azstarnet.com).
8
 *
9
 * This file may be redistributed according to the terms of the
10
 * GNU General Public License.
11
 */
12
/*
13
 * The original code did not have any comments. I have created many
14
 * comments as I fix the bugs in the code.  My comments are based on
15
 * my observation and interpretation of the code.  If the original
16
 * author would have spend a few minutes to comment the code, we would
17
 * never had a problem of misinterpretation.  -HA
18
 *
19
 * This code could probably be a lot more optimized (especially the
20
 * division routine).  However, my foremost concern was to get the
21
 * IEEE behavior right.  Performance is less critical as these
22
 * functions are used on exceptional numbers only (well, assuming you
23
 * don't turn on the "trap on inexact"...).
24
 */
25
#include "ieee-math.h"
26
 
27
#define STICKY_S        0x20000000      /* both in longword 0 of fraction */
28
#define STICKY_T        1
29
 
30
/*
31
 * Careful: order matters here!
32
 */
33
enum {
34
        NaN, QNaN, INFTY, ZERO, DENORM, NORMAL
35
};
36
 
37
enum {
38
        SINGLE, DOUBLE
39
};
40
 
41
typedef unsigned long fpclass_t;
42
 
43
#define IEEE_TMAX       0x7fefffffffffffff
44
#define IEEE_SMAX       0x47efffffe0000000
45
#define IEEE_SNaN       0xfff00000000f0000
46
#define IEEE_QNaN       0xfff8000000000000
47
#define IEEE_PINF       0x7ff0000000000000
48
#define IEEE_NINF       0xfff0000000000000
49
 
50
 
51
/*
52
 * The memory format of S floating point numbers differs from the
53
 * register format.  In the following, the bitnumbers above the
54
 * diagram below give the memory format while the numbers below give
55
 * the register format.
56
 *
57
 *        31 30      23 22                              0
58
 *      +-----------------------------------------------+
59
 * S    | s |   exp    |       fraction                 |
60
 *      +-----------------------------------------------+
61
 *        63 62      52 51                            29
62
 *
63
 * For T floating point numbers, the register and memory formats
64
 * match:
65
 *
66
 *      +-------------------------------------------------------------------+
67
 * T    | s |        exp        |           frac | tion                     |
68
 *      +-------------------------------------------------------------------+
69
 *        63 62               52 51            32 31                       0
70
 */
71
typedef struct {
72
        unsigned long   f[2];   /* bit 55 in f[0] is the factor of 2^0*/
73
        int             s;      /* 1 bit sign (0 for +, 1 for -) */
74
        int             e;      /* 16 bit signed exponent */
75
} EXTENDED;
76
 
77
 
78
/*
79
 * Return the sign of a Q integer, S or T fp number in the register
80
 * format.
81
 */
82
static inline int
83
sign (unsigned long a)
84
{
85
        if ((long) a < 0)
86
                return -1;
87
        else
88
                return 1;
89
}
90
 
91
 
92
static inline long
93
cmp128 (const long a[2], const long b[2])
94
{
95
        if (a[1] < b[1]) return -1;
96
        if (a[1] > b[1]) return  1;
97
        return a[0] - b[0];
98
}
99
 
100
 
101
static inline void
102
sll128 (unsigned long a[2])
103
{
104
        a[1] = (a[1] << 1) | (a[0] >> 63);
105
        a[0] <<= 1;
106
}
107
 
108
 
109
static inline void
110
srl128 (unsigned long a[2])
111
{
112
        a[0] = (a[0] >> 1) | (a[1] << 63);
113
        a[1] >>= 1;
114
}
115
 
116
 
117
static inline void
118
add128 (const unsigned long a[2], const unsigned long b[2], unsigned long c[2])
119
{
120
        unsigned long carry = a[0] > (0xffffffffffffffff - b[0]);
121
 
122
        c[0] = a[0] + b[0];
123
        c[1] = a[1] + b[1] + carry;
124
}
125
 
126
 
127
static inline void
128
sub128 (const unsigned long a[2], const unsigned long b[2], unsigned long c[2])
129
{
130
        unsigned long borrow = a[0] < b[0];
131
 
132
        c[0] = a[0] - b[0];
133
        c[1] = a[1] - b[1] - borrow;
134
}
135
 
136
 
137
static inline void
138
mul64 (const unsigned long a, const unsigned long b, unsigned long c[2])
139
{
140
        c[0] = a * b;
141
        asm ("umulh %1,%2,%0" : "=r"(c[1]) : "r"(a), "r"(b));
142
}
143
 
144
 
145
static void
146
div128 (unsigned long a[2], unsigned long b[2], unsigned long c[2])
147
{
148
        unsigned long mask[2] = {1, 0};
149
 
150
        /*
151
         * Shift b until either the sign bit is set or until it is at
152
         * least as big as the dividend:
153
         */
154
        while (cmp128(b, a) < 0 && sign(b[1]) >= 0) {
155
                sll128(b);
156
                sll128(mask);
157
        }
158
        c[0] = c[1] = 0;
159
        do {
160
                if (cmp128(a, b) >= 0) {
161
                        sub128(a, b, a);
162
                        add128(mask, c, c);
163
                }
164
                srl128(mask);
165
                srl128(b);
166
        } while (mask[0] || mask[1]);
167
}
168
 
169
 
170
static void
171
normalize (EXTENDED *a)
172
{
173
        if (!a->f[0] && !a->f[1])
174
                return;         /* zero fraction, unnormalizable... */
175
        /*
176
         * In "extended" format, the "1" in "1.f" is explicit; it is
177
         * in bit 55 of f[0], and the decimal point is understood to
178
         * be between bit 55 and bit 54.  To normalize, shift the
179
         * fraction until we have a "1" in bit 55.
180
         */
181
        if ((a->f[0] & 0xff00000000000000) != 0 || a->f[1] != 0) {
182
                /*
183
                 * Mantissa is greater than 1.0:
184
                 */
185
                while ((a->f[0] & 0xff80000000000000) != 0x0080000000000000 ||
186
                       a->f[1] != 0)
187
                {
188
                        unsigned long sticky;
189
 
190
                        ++a->e;
191
                        sticky = a->f[0] & 1;
192
                        srl128(a->f);
193
                        a->f[0] |= sticky;
194
                }
195
                return;
196
        }
197
 
198
        if (!(a->f[0] & 0x0080000000000000)) {
199
                /*
200
                 * Mantissa is less than 1.0:
201
                 */
202
                while (!(a->f[0] & 0x0080000000000000)) {
203
                        --a->e;
204
                        a->f[0] <<= 1;
205
                }
206
                return;
207
        }
208
}
209
 
210
 
211
static inline fpclass_t
212
ieee_fpclass (unsigned long a)
213
{
214
        unsigned long exp, fract;
215
 
216
        exp   = (a >> 52) & 0x7ff;      /* 11 bits of exponent */
217
        fract = a & 0x000fffffffffffff; /* 52 bits of fraction */
218
        if (exp == 0) {
219
                if (fract == 0)
220
                        return ZERO;
221
                return DENORM;
222
        }
223
        if (exp == 0x7ff) {
224
                if (fract == 0)
225
                        return INFTY;
226
                if (((fract >> 51) & 1) != 0)
227
                        return QNaN;
228
                return NaN;
229
        }
230
        return NORMAL;
231
}
232
 
233
 
234
/*
235
 * Translate S/T fp number in register format into extended format.
236
 */
237
static fpclass_t
238
extend_ieee (unsigned long a, EXTENDED *b, int prec)
239
{
240
        fpclass_t result_kind;
241
 
242
        b->s = a >> 63;
243
        b->e = ((a >> 52) & 0x7ff) - 0x3ff;     /* remove bias */
244
        b->f[1] = 0;
245
        /*
246
         * We shift f[1] left three bits so that the higher order bits
247
         * of the fraction will reside in bits 55 through 0 of f[0].
248
         */
249
        b->f[0] = (a & 0x000fffffffffffff) << 3;
250
        result_kind = ieee_fpclass(a);
251
        if (result_kind == NORMAL) {
252
                /* set implied 1. bit: */
253
                b->f[0] |= 1UL << 55;
254
        } else if (result_kind == DENORM) {
255
                if (prec == SINGLE)
256
                        b->e = -126;
257
                else
258
                        b->e = -1022;
259
        }
260
        return result_kind;
261
}
262
 
263
 
264
/*
265
 * INPUT PARAMETERS:
266
 *       a           a number in EXTENDED format to be converted to
267
 *                   s-floating format.
268
 *       f           rounding mode and exception enable bits.
269
 * OUTPUT PARAMETERS:
270
 *       b          will contain the s-floating number that "a" was
271
 *                  converted to (in register format).
272
 */
273
static unsigned long
274
make_s_ieee (long f, EXTENDED *a, unsigned long *b)
275
{
276
        unsigned long res, sticky;
277
 
278
        if (!a->e && !a->f[0] && !a->f[1]) {
279
                *b = (unsigned long) a->s << 63;        /* return +/-0 */
280
                return 0;
281
        }
282
 
283
        normalize(a);
284
        res = 0;
285
 
286
        if (a->e < -0x7e) {
287
                res = FPCR_INE;
288
                if (f & IEEE_TRAP_ENABLE_UNF) {
289
                        res |= FPCR_UNF;
290
                        a->e += 0xc0;   /* scale up result by 2^alpha */
291
                } else {
292
                        /* try making denormalized number: */
293
                        while (a->e < -0x7e) {
294
                                ++a->e;
295
                                sticky = a->f[0] & 1;
296
                                srl128(a->f);
297
                                if (!a->f[0] && !a->f[0]) {
298
                                        /* underflow: replace with exact 0 */
299
                                        res |= FPCR_UNF;
300
                                        break;
301
                                }
302
                                a->f[0] |= sticky;
303
                        }
304
                        a->e = -0x3ff;
305
                }
306
        }
307
        if (a->e >= 0x80) {
308
                res = FPCR_OVF | FPCR_INE;
309
                if (f & IEEE_TRAP_ENABLE_OVF) {
310
                        a->e -= 0xc0;   /* scale down result by 2^alpha */
311
                } else {
312
                        /*
313
                         * Overflow without trap enabled, substitute
314
                         * result according to rounding mode:
315
                         */
316
                        switch (RM(f)) {
317
                              case ROUND_NEAR:
318
                                *b = IEEE_PINF;
319
                                break;
320
 
321
                              case ROUND_CHOP:
322
                                *b = IEEE_SMAX;
323
                                break;
324
 
325
                              case ROUND_NINF:
326
                                if (a->s) {
327
                                        *b = IEEE_PINF;
328
                                } else {
329
                                        *b = IEEE_SMAX;
330
                                }
331
                                break;
332
 
333
                              case ROUND_PINF:
334
                                if (a->s) {
335
                                        *b = IEEE_SMAX;
336
                                } else {
337
                                        *b = IEEE_PINF;
338
                                }
339
                                break;
340
                        }
341
                        *b |= ((unsigned long) a->s << 63);
342
                        return res;
343
                }
344
        }
345
 
346
        *b = (((unsigned long) a->s << 63) |
347
              (((unsigned long) a->e + 0x3ff) << 52) |
348
              ((a->f[0] >> 3) & 0x000fffffe0000000));
349
        return res;
350
}
351
 
352
 
353
static unsigned long
354
make_t_ieee (long f, EXTENDED *a, unsigned long *b)
355
{
356
        unsigned long res, sticky;
357
 
358
        if (!a->e && !a->f[0] && !a->f[1]) {
359
                *b = (unsigned long) a->s << 63;        /* return +/-0 */
360
                return 0;
361
        }
362
 
363
        normalize(a);
364
        res = 0;
365
        if (a->e < -0x3fe) {
366
                res = FPCR_INE;
367
                if (f & IEEE_TRAP_ENABLE_UNF) {
368
                        res |= FPCR_UNF;
369
                        a->e += 0x600;
370
                } else {
371
                        /* try making denormalized number: */
372
                        while (a->e < -0x3fe) {
373
                                ++a->e;
374
                                sticky = a->f[0] & 1;
375
                                srl128(a->f);
376
                                if (!a->f[0] && !a->f[0]) {
377
                                        /* underflow: replace with exact 0 */
378
                                        res |= FPCR_UNF;
379
                                        break;
380
                                }
381
                                a->f[0] |= sticky;
382
                        }
383
                        a->e = -0x3ff;
384
                }
385
        }
386
        if (a->e >= 0x3ff) {
387
                res = FPCR_OVF | FPCR_INE;
388
                if (f & IEEE_TRAP_ENABLE_OVF) {
389
                        a->e -= 0x600;  /* scale down result by 2^alpha */
390
                } else {
391
                        /*
392
                         * Overflow without trap enabled, substitute
393
                         * result according to rounding mode:
394
                         */
395
                        switch (RM(f)) {
396
                              case ROUND_NEAR:
397
                                *b = IEEE_PINF;
398
                                break;
399
 
400
                              case ROUND_CHOP:
401
                                *b = IEEE_TMAX;
402
                                break;
403
 
404
                              case ROUND_NINF:
405
                                if (a->s) {
406
                                        *b = IEEE_PINF;
407
                                } else {
408
                                        *b = IEEE_TMAX;
409
                                }
410
                                break;
411
 
412
                              case ROUND_PINF:
413
                                if (a->s) {
414
                                        *b = IEEE_TMAX;
415
                                } else {
416
                                        *b = IEEE_PINF;
417
                                }
418
                                break;
419
                        }
420
                        *b |= ((unsigned long) a->s << 63);
421
                        return res;
422
                }
423
        }
424
        *b = (((unsigned long) a->s << 63) |
425
              (((unsigned long) a->e + 0x3ff) << 52) |
426
              ((a->f[0] >> 3) & 0x000fffffffffffff));
427
        return res;
428
}
429
 
430
 
431
/*
432
 * INPUT PARAMETERS:
433
 *       a          EXTENDED format number to be rounded.
434
 *       rm         integer with value ROUND_NEAR, ROUND_CHOP, etc.
435
 *                  indicates how "a" should be rounded to produce "b".
436
 * OUTPUT PARAMETERS:
437
 *       b          s-floating number produced by rounding "a".
438
 * RETURN VALUE:
439
 *       if no errors occurred, will be zero.  Else will contain flags
440
 *       like FPCR_INE_OP, etc.
441
 */
442
static unsigned long
443
round_s_ieee (int f, EXTENDED *a, unsigned long *b)
444
{
445
        unsigned long diff1, diff2, res = 0;
446
        EXTENDED z1, z2;
447
 
448
        if (!(a->f[0] & 0xffffffff)) {
449
                return make_s_ieee(f, a, b);    /* no rounding error */
450
        }
451
 
452
        /*
453
         * z1 and z2 are the S-floating numbers with the next smaller/greater
454
         * magnitude than a, respectively.
455
         */
456
        z1.s = z2.s = a->s;
457
        z1.e = z2.e = a->e;
458
        z1.f[0] = z2.f[0] = a->f[0] & 0xffffffff00000000;
459
        z1.f[1] = z2.f[1] = 0;
460
        z2.f[0] += 0x100000000;  /* next bigger S float number */
461
 
462
        switch (RM(f)) {
463
              case ROUND_NEAR:
464
                diff1 = a->f[0] - z1.f[0];
465
                diff2 = z2.f[0] - a->f[0];
466
                if (diff1 > diff2)
467
                        res = make_s_ieee(f, &z2, b);
468
                else if (diff2 > diff1)
469
                        res = make_s_ieee(f, &z1, b);
470
                else
471
                        /* equal distance: round towards even */
472
                        if (z1.f[0] & 0x100000000)
473
                                res = make_s_ieee(f, &z2, b);
474
                        else
475
                                res = make_s_ieee(f, &z1, b);
476
                break;
477
 
478
              case ROUND_CHOP:
479
                res = make_s_ieee(f, &z1, b);
480
                break;
481
 
482
              case ROUND_PINF:
483
                if (a->s) {
484
                        res = make_s_ieee(f, &z1, b);
485
                } else {
486
                        res = make_s_ieee(f, &z2, b);
487
                }
488
                break;
489
 
490
              case ROUND_NINF:
491
                if (a->s) {
492
                        res = make_s_ieee(f, &z2, b);
493
                } else {
494
                        res = make_s_ieee(f, &z1, b);
495
                }
496
                break;
497
        }
498
        return FPCR_INE | res;
499
}
500
 
501
 
502
static unsigned long
503
round_t_ieee (int f, EXTENDED *a, unsigned long *b)
504
{
505
        unsigned long diff1, diff2, res;
506
        EXTENDED z1, z2;
507
 
508
        if (!(a->f[0] & 0x7)) {
509
                /* no rounding error */
510
                return make_t_ieee(f, a, b);
511
        }
512
 
513
        z1.s = z2.s = a->s;
514
        z1.e = z2.e = a->e;
515
        z1.f[0] = z2.f[0] = a->f[0] & ~0x7;
516
        z1.f[1] = z2.f[1] = 0;
517
        z2.f[0] += (1 << 3);
518
 
519
        res = 0;
520
        switch (RM(f)) {
521
              case ROUND_NEAR:
522
                diff1 = a->f[0] - z1.f[0];
523
                diff2 = z2.f[0] - a->f[0];
524
                if (diff1 > diff2)
525
                        res = make_t_ieee(f, &z2, b);
526
                else if (diff2 > diff1)
527
                        res = make_t_ieee(f, &z1, b);
528
                else
529
                        /* equal distance: round towards even */
530
                        if (z1.f[0] & (1 << 3))
531
                                res = make_t_ieee(f, &z2, b);
532
                        else
533
                                res = make_t_ieee(f, &z1, b);
534
                break;
535
 
536
              case ROUND_CHOP:
537
                res = make_t_ieee(f, &z1, b);
538
                break;
539
 
540
              case ROUND_PINF:
541
                if (a->s) {
542
                        res = make_t_ieee(f, &z1, b);
543
                } else {
544
                        res = make_t_ieee(f, &z2, b);
545
                }
546
                break;
547
 
548
              case ROUND_NINF:
549
                if (a->s) {
550
                        res = make_t_ieee(f, &z2, b);
551
                } else {
552
                        res = make_t_ieee(f, &z1, b);
553
                }
554
                break;
555
        }
556
        return FPCR_INE | res;
557
}
558
 
559
 
560
static fpclass_t
561
add_kernel_ieee (EXTENDED *op_a, EXTENDED *op_b, EXTENDED *op_c)
562
{
563
        unsigned long mask, fa, fb, fc;
564
        int diff;
565
 
566
        diff = op_a->e - op_b->e;
567
        fa = op_a->f[0];
568
        fb = op_b->f[0];
569
        if (diff < 0) {
570
                diff = -diff;
571
                op_c->e = op_b->e;
572
                mask = (1UL << diff) - 1;
573
                fa >>= diff;
574
                if (op_a->f[0] & mask) {
575
                        fa |= 1;                /* set sticky bit */
576
                }
577
        } else {
578
                op_c->e = op_a->e;
579
                mask = (1UL << diff) - 1;
580
                fb >>= diff;
581
                if (op_b->f[0] & mask) {
582
                        fb |= 1;                /* set sticky bit */
583
                }
584
        }
585
        if (op_a->s)
586
                fa = -fa;
587
        if (op_b->s)
588
                fb = -fb;
589
        fc = fa + fb;
590
        op_c->f[1] = 0;
591
        op_c->s = fc >> 63;
592
        if (op_c->s) {
593
                fc = -fc;
594
        }
595
        op_c->f[0] = fc;
596
        normalize(op_c);
597
        return 0;
598
}
599
 
600
 
601
/*
602
 * converts s-floating "a" to t-floating "b".
603
 *
604
 * INPUT PARAMETERS:
605
 *       a           a s-floating number to be converted
606
 *       f           the rounding mode (ROUND_NEAR, etc. )
607
 * OUTPUT PARAMETERS:
608
 *       b           the t-floating number that "a" is converted to.
609
 * RETURN VALUE:
610
 *       error flags - i.e., zero if no errors occurred,
611
 *       FPCR_INV if invalid operation occurred, etc.
612
 */
613
unsigned long
614
ieee_CVTST (int f, unsigned long a, unsigned long *b)
615
{
616
        EXTENDED temp;
617
        fpclass_t a_type;
618
 
619
        a_type = extend_ieee(a, &temp, SINGLE);
620
        if (a_type >= NaN && a_type <= INFTY) {
621
                *b = a;
622
                if (a_type == NaN) {
623
                        *b |= (1UL << 51);      /* turn SNaN into QNaN */
624
                        return FPCR_INV;
625
                }
626
                return 0;
627
        }
628
        return round_t_ieee(f, &temp, b);
629
}
630
 
631
 
632
/*
633
 * converts t-floating "a" to s-floating "b".
634
 *
635
 * INPUT PARAMETERS:
636
 *       a           a t-floating number to be converted
637
 *       f           the rounding mode (ROUND_NEAR, etc. )
638
 * OUTPUT PARAMETERS:
639
 *       b           the s-floating number that "a" is converted to.
640
 * RETURN VALUE:
641
 *       error flags - i.e., zero if no errors occurred,
642
 *       FPCR_INV if invalid operation occurred, etc.
643
 */
644
unsigned long
645
ieee_CVTTS (int f, unsigned long a, unsigned long *b)
646
{
647
        EXTENDED temp;
648
        fpclass_t a_type;
649
 
650
        a_type = extend_ieee(a, &temp, DOUBLE);
651
        if (a_type >= NaN && a_type <= INFTY) {
652
                *b = a;
653
                if (a_type == NaN) {
654
                        *b |= (1UL << 51);      /* turn SNaN into QNaN */
655
                        return FPCR_INV;
656
                }
657
                return 0;
658
        }
659
        return round_s_ieee(f, &temp, b);
660
}
661
 
662
 
663
/*
664
 * converts q-format (64-bit integer) "a" to s-floating "b".
665
 *
666
 * INPUT PARAMETERS:
667
 *       a           an 64-bit integer to be converted.
668
 *       f           the rounding mode (ROUND_NEAR, etc. )
669
 * OUTPUT PARAMETERS:
670
 *       b           the s-floating number "a" is converted to.
671
 * RETURN VALUE:
672
 *       error flags - i.e., zero if no errors occurred,
673
 *       FPCR_INV if invalid operation occurred, etc.
674
 */
675
unsigned long
676
ieee_CVTQS (int f, unsigned long a, unsigned long *b)
677
{
678
        EXTENDED op_b;
679
 
680
        op_b.s    = 0;
681
        op_b.f[0] = a;
682
        op_b.f[1] = 0;
683
        if (sign(a) < 0) {
684
                op_b.s = 1;
685
                op_b.f[0] = -a;
686
        }
687
        op_b.e = 55;
688
        normalize(&op_b);
689
        return round_s_ieee(f, &op_b, b);
690
}
691
 
692
 
693
/*
694
 * converts 64-bit integer "a" to t-floating "b".
695
 *
696
 * INPUT PARAMETERS:
697
 *       a           a 64-bit integer to be converted.
698
 *       f           the rounding mode (ROUND_NEAR, etc.)
699
 * OUTPUT PARAMETERS:
700
 *       b           the t-floating number "a" is converted to.
701
 * RETURN VALUE:
702
 *       error flags - i.e., zero if no errors occurred,
703
 *       FPCR_INV if invalid operation occurred, etc.
704
 */
705
unsigned long
706
ieee_CVTQT (int f, unsigned long a, unsigned long *b)
707
{
708
        EXTENDED op_b;
709
 
710
        op_b.s    = 0;
711
        op_b.f[0] = a;
712
        op_b.f[1] = 0;
713
        if (sign(a) < 0) {
714
                op_b.s = 1;
715
                op_b.f[0] = -a;
716
        }
717
        op_b.e = 55;
718
        normalize(&op_b);
719
        return round_t_ieee(f, &op_b, b);
720
}
721
 
722
 
723
/*
724
 * converts t-floating "a" to 64-bit integer (q-format) "b".
725
 *
726
 * INPUT PARAMETERS:
727
 *       a           a t-floating number to be converted.
728
 *       f           the rounding mode (ROUND_NEAR, etc. )
729
 * OUTPUT PARAMETERS:
730
 *       b           the 64-bit integer "a" is converted to.
731
 * RETURN VALUE:
732
 *       error flags - i.e., zero if no errors occurred,
733
 *       FPCR_INV if invalid operation occurred, etc.
734
 */
735
unsigned long
736
ieee_CVTTQ (int f, unsigned long a, unsigned long *pb)
737
{
738
        unsigned int midway;
739
        unsigned long ov, uv, res, b;
740
        fpclass_t a_type;
741
        EXTENDED temp;
742
 
743
        a_type = extend_ieee(a, &temp, DOUBLE);
744
 
745
        b = 0x7fffffffffffffff;
746
        res = FPCR_INV;
747
        if (a_type == NaN || a_type == INFTY)
748
                goto out;
749
 
750
        res = 0;
751
        if (a_type == QNaN)
752
                goto out;
753
 
754
        if (temp.e > 0) {
755
                ov = 0;
756
                while (temp.e > 0) {
757
                        --temp.e;
758
                        ov |= temp.f[1] >> 63;
759
                        sll128(temp.f);
760
                }
761
                if (ov || (temp.f[1] & 0xffc0000000000000))
762
                        res |= FPCR_IOV | FPCR_INE;
763
        }
764
        else if (temp.e < 0) {
765
                while (temp.e < 0) {
766
                        ++temp.e;
767
                        uv = temp.f[0] & 1;              /* save sticky bit */
768
                        srl128(temp.f);
769
                        temp.f[0] |= uv;
770
                }
771
        }
772
        b = (temp.f[1] << 9) | (temp.f[0] >> 55);
773
 
774
        /*
775
         * Notice: the fraction is only 52 bits long.  Thus, rounding
776
         * cannot possibly result in an integer overflow.
777
         */
778
        switch (RM(f)) {
779
              case ROUND_NEAR:
780
                if (temp.f[0] & 0x0040000000000000) {
781
                        midway = (temp.f[0] & 0x003fffffffffffff) == 0;
782
                        if ((midway && (temp.f[0] & 0x0080000000000000)) ||
783
                            !midway)
784
                                ++b;
785
                }
786
                break;
787
 
788
              case ROUND_PINF:
789
                if ((temp.f[0] & 0x007fffffffffffff) != 0)
790
                        ++b;
791
                break;
792
 
793
              case ROUND_NINF:
794
                if ((temp.f[0] & 0x007fffffffffffff) != 0)
795
                        --b;
796
                break;
797
 
798
              case ROUND_CHOP:
799
                /* no action needed */
800
                break;
801
        }
802
        if ((temp.f[0] & 0x007fffffffffffff) != 0)
803
                res |= FPCR_INE;
804
 
805
        if (temp.s) {
806
                b = -b;
807
        }
808
 
809
out:
810
        *pb = b;
811
        return res;
812
}
813
 
814
 
815
unsigned long
816
ieee_CMPTEQ (unsigned long a, unsigned long b, unsigned long *c)
817
{
818
        EXTENDED op_a, op_b;
819
        fpclass_t a_type, b_type;
820
 
821
        *c = 0;
822
        a_type = extend_ieee(a, &op_a, DOUBLE);
823
        b_type = extend_ieee(b, &op_b, DOUBLE);
824
        if (a_type == NaN || b_type == NaN)
825
                return FPCR_INV;
826
        if (a_type == QNaN || b_type == QNaN)
827
                return 0;
828
 
829
        if ((op_a.e == op_b.e && op_a.s == op_b.s &&
830
             op_a.f[0] == op_b.f[0] && op_a.f[1] == op_b.f[1]) ||
831
            (a_type == ZERO && b_type == ZERO))
832
                *c = 0x4000000000000000;
833
        return 0;
834
}
835
 
836
 
837
unsigned long
838
ieee_CMPTLT (unsigned long a, unsigned long b, unsigned long *c)
839
{
840
        fpclass_t a_type, b_type;
841
        EXTENDED op_a, op_b;
842
 
843
        *c = 0;
844
        a_type = extend_ieee(a, &op_a, DOUBLE);
845
        b_type = extend_ieee(b, &op_b, DOUBLE);
846
        if (a_type == NaN || b_type == NaN)
847
                return FPCR_INV;
848
        if (a_type == QNaN || b_type == QNaN)
849
                return 0;
850
 
851
        if ((op_a.s == 1 && op_b.s == 0 &&
852
             (a_type != ZERO || b_type != ZERO)) ||
853
            (op_a.s == 1 && op_b.s == 1 &&
854
             (op_a.e > op_b.e || (op_a.e == op_b.e &&
855
                                  cmp128(op_a.f, op_b.f) > 0))) ||
856
            (op_a.s == 0 && op_b.s == 0 &&
857
             (op_a.e < op_b.e || (op_a.e == op_b.e &&
858
                                  cmp128(op_a.f,op_b.f) < 0))))
859
                *c = 0x4000000000000000;
860
        return 0;
861
}
862
 
863
 
864
unsigned long
865
ieee_CMPTLE (unsigned long a, unsigned long b, unsigned long *c)
866
{
867
        fpclass_t a_type, b_type;
868
        EXTENDED op_a, op_b;
869
 
870
        *c = 0;
871
        a_type = extend_ieee(a, &op_a, DOUBLE);
872
        b_type = extend_ieee(b, &op_b, DOUBLE);
873
        if (a_type == NaN || b_type == NaN)
874
                return FPCR_INV;
875
        if (a_type == QNaN || b_type == QNaN)
876
                return 0;
877
 
878
        if ((a_type == ZERO && b_type == ZERO) ||
879
            (op_a.s == 1 && op_b.s == 0) ||
880
            (op_a.s == 1 && op_b.s == 1 &&
881
             (op_a.e > op_b.e || (op_a.e == op_b.e &&
882
                                  cmp128(op_a.f,op_b.f) >= 0))) ||
883
            (op_a.s == 0 && op_b.s == 0 &&
884
             (op_a.e < op_b.e || (op_a.e == op_b.e &&
885
                                  cmp128(op_a.f,op_b.f) <= 0))))
886
                *c = 0x4000000000000000;
887
        return 0;
888
}
889
 
890
 
891
unsigned long
892
ieee_CMPTUN (unsigned long a, unsigned long b, unsigned long *c)
893
{
894
        fpclass_t a_type, b_type;
895
        EXTENDED op_a, op_b;
896
 
897
        *c = 0x4000000000000000;
898
        a_type = extend_ieee(a, &op_a, DOUBLE);
899
        b_type = extend_ieee(b, &op_b, DOUBLE);
900
        if (a_type == NaN || b_type == NaN)
901
                return FPCR_INV;
902
        if (a_type == QNaN || b_type == QNaN)
903
                return 0;
904
        *c = 0;
905
        return 0;
906
}
907
 
908
 
909
/*
910
 * Add a + b = c, where a, b, and c are ieee s-floating numbers.  "f"
911
 * contains the rounding mode etc.
912
 */
913
unsigned long
914
ieee_ADDS (int f, unsigned long a, unsigned long b, unsigned long *c)
915
{
916
        fpclass_t a_type, b_type;
917
        EXTENDED op_a, op_b, op_c;
918
 
919
        a_type = extend_ieee(a, &op_a, SINGLE);
920
        b_type = extend_ieee(b, &op_b, SINGLE);
921
        if ((a_type >= NaN && a_type <= INFTY) ||
922
            (b_type >= NaN && b_type <= INFTY))
923
        {
924
                /* propagate NaNs according to arch. ref. handbook: */
925
                if (b_type == QNaN)
926
                        *c = b;
927
                else if (b_type == NaN)
928
                        *c = b | (1UL << 51);
929
                else if (a_type == QNaN)
930
                        *c = a;
931
                else if (a_type == NaN)
932
                        *c = a | (1UL << 51);
933
 
934
                if (a_type == NaN || b_type == NaN)
935
                        return FPCR_INV;
936
                if (a_type == QNaN || b_type == QNaN)
937
                        return 0;
938
 
939
                if (a_type == INFTY && b_type == INFTY && sign(a) != sign(b)) {
940
                        *c = IEEE_QNaN;
941
                        return FPCR_INV;
942
                }
943
                if (a_type == INFTY)
944
                        *c = a;
945
                else
946
                        *c = b;
947
                return 0;
948
        }
949
 
950
        add_kernel_ieee(&op_a, &op_b, &op_c);
951
        /* special case for -0 + -0 ==> -0 */
952
        if (a_type == ZERO && b_type == ZERO)
953
                op_c.s = op_a.s && op_b.s;
954
        return round_s_ieee(f, &op_c, c);
955
}
956
 
957
 
958
/*
959
 * Add a + b = c, where a, b, and c are ieee t-floating numbers.  "f"
960
 * contains the rounding mode etc.
961
 */
962
unsigned long
963
ieee_ADDT (int f, unsigned long a, unsigned long b, unsigned long *c)
964
{
965
        fpclass_t a_type, b_type;
966
        EXTENDED op_a, op_b, op_c;
967
 
968
        a_type = extend_ieee(a, &op_a, DOUBLE);
969
        b_type = extend_ieee(b, &op_b, DOUBLE);
970
        if ((a_type >= NaN && a_type <= INFTY) ||
971
            (b_type >= NaN && b_type <= INFTY))
972
        {
973
                /* propagate NaNs according to arch. ref. handbook: */
974
                if (b_type == QNaN)
975
                        *c = b;
976
                else if (b_type == NaN)
977
                        *c = b | (1UL << 51);
978
                else if (a_type == QNaN)
979
                        *c = a;
980
                else if (a_type == NaN)
981
                        *c = a | (1UL << 51);
982
 
983
                if (a_type == NaN || b_type == NaN)
984
                        return FPCR_INV;
985
                if (a_type == QNaN || b_type == QNaN)
986
                        return 0;
987
 
988
                if (a_type == INFTY && b_type == INFTY && sign(a) != sign(b)) {
989
                        *c = IEEE_QNaN;
990
                        return FPCR_INV;
991
                }
992
                if (a_type == INFTY)
993
                        *c = a;
994
                else
995
                        *c = b;
996
                return 0;
997
        }
998
        add_kernel_ieee(&op_a, &op_b, &op_c);
999
        /* special case for -0 + -0 ==> -0 */
1000
        if (a_type == ZERO && b_type == ZERO)
1001
                op_c.s = op_a.s && op_b.s;
1002
 
1003
        return round_t_ieee(f, &op_c, c);
1004
}
1005
 
1006
 
1007
/*
1008
 * Subtract a - b = c, where a, b, and c are ieee s-floating numbers.
1009
 * "f" contains the rounding mode etc.
1010
 */
1011
unsigned long
1012
ieee_SUBS (int f, unsigned long a, unsigned long b, unsigned long *c)
1013
{
1014
        fpclass_t a_type, b_type;
1015
        EXTENDED op_a, op_b, op_c;
1016
 
1017
        a_type = extend_ieee(a, &op_a, SINGLE);
1018
        b_type = extend_ieee(b, &op_b, SINGLE);
1019
        if ((a_type >= NaN && a_type <= INFTY) ||
1020
            (b_type >= NaN && b_type <= INFTY))
1021
        {
1022
                /* propagate NaNs according to arch. ref. handbook: */
1023
                if (b_type == QNaN)
1024
                        *c = b;
1025
                else if (b_type == NaN)
1026
                        *c = b | (1UL << 51);
1027
                else if (a_type == QNaN)
1028
                        *c = a;
1029
                else if (a_type == NaN)
1030
                        *c = a | (1UL << 51);
1031
 
1032
                if (a_type == NaN || b_type == NaN)
1033
                        return FPCR_INV;
1034
                if (a_type == QNaN || b_type == QNaN)
1035
                        return 0;
1036
 
1037
                if (a_type == INFTY && b_type == INFTY && sign(a) == sign(b)) {
1038
                        *c = IEEE_QNaN;
1039
                        return FPCR_INV;
1040
                }
1041
                if (a_type == INFTY)
1042
                        *c = a;
1043
                else
1044
                        *c = b ^ (1UL << 63);
1045
                return 0;
1046
        }
1047
        op_b.s = !op_b.s;
1048
        add_kernel_ieee(&op_a, &op_b, &op_c);
1049
        /* special case for -0 - +0 ==> -0 */
1050
        if (a_type == ZERO && b_type == ZERO)
1051
                op_c.s = op_a.s && op_b.s;
1052
 
1053
        return round_s_ieee(f, &op_c, c);
1054
}
1055
 
1056
 
1057
/*
1058
 * Subtract a - b = c, where a, b, and c are ieee t-floating numbers.
1059
 * "f" contains the rounding mode etc.
1060
 */
1061
unsigned long
1062
ieee_SUBT (int f, unsigned long a, unsigned long b, unsigned long *c)
1063
{
1064
        fpclass_t a_type, b_type;
1065
        EXTENDED op_a, op_b, op_c;
1066
 
1067
        a_type = extend_ieee(a, &op_a, DOUBLE);
1068
        b_type = extend_ieee(b, &op_b, DOUBLE);
1069
        if ((a_type >= NaN && a_type <= INFTY) ||
1070
            (b_type >= NaN && b_type <= INFTY))
1071
        {
1072
                /* propagate NaNs according to arch. ref. handbook: */
1073
                if (b_type == QNaN)
1074
                        *c = b;
1075
                else if (b_type == NaN)
1076
                        *c = b | (1UL << 51);
1077
                else if (a_type == QNaN)
1078
                        *c = a;
1079
                else if (a_type == NaN)
1080
                        *c = a | (1UL << 51);
1081
 
1082
                if (a_type == NaN || b_type == NaN)
1083
                        return FPCR_INV;
1084
                if (a_type == QNaN || b_type == QNaN)
1085
                        return 0;
1086
 
1087
                if (a_type == INFTY && b_type == INFTY && sign(a) == sign(b)) {
1088
                        *c = IEEE_QNaN;
1089
                        return FPCR_INV;
1090
                }
1091
                if (a_type == INFTY)
1092
                        *c = a;
1093
                else
1094
                        *c = b ^ (1UL << 63);
1095
                return 0;
1096
        }
1097
        op_b.s = !op_b.s;
1098
        add_kernel_ieee(&op_a, &op_b, &op_c);
1099
        /* special case for -0 - +0 ==> -0 */
1100
        if (a_type == ZERO && b_type == ZERO)
1101
                op_c.s = op_a.s && op_b.s;
1102
 
1103
        return round_t_ieee(f, &op_c, c);
1104
}
1105
 
1106
 
1107
/*
1108
 * Multiply a x b = c, where a, b, and c are ieee s-floating numbers.
1109
 * "f" contains the rounding mode.
1110
 */
1111
unsigned long
1112
ieee_MULS (int f, unsigned long a, unsigned long b, unsigned long *c)
1113
{
1114
        fpclass_t a_type, b_type;
1115
        EXTENDED op_a, op_b, op_c;
1116
 
1117
        a_type = extend_ieee(a, &op_a, SINGLE);
1118
        b_type = extend_ieee(b, &op_b, SINGLE);
1119
        if ((a_type >= NaN && a_type <= INFTY) ||
1120
            (b_type >= NaN && b_type <= INFTY))
1121
        {
1122
                /* propagate NaNs according to arch. ref. handbook: */
1123
                if (b_type == QNaN)
1124
                        *c = b;
1125
                else if (b_type == NaN)
1126
                        *c = b | (1UL << 51);
1127
                else if (a_type == QNaN)
1128
                        *c = a;
1129
                else if (a_type == NaN)
1130
                        *c = a | (1UL << 51);
1131
 
1132
                if (a_type == NaN || b_type == NaN)
1133
                        return FPCR_INV;
1134
                if (a_type == QNaN || b_type == QNaN)
1135
                        return 0;
1136
 
1137
                if ((a_type == INFTY && b_type == ZERO) ||
1138
                    (b_type == INFTY && a_type == ZERO))
1139
                {
1140
                        *c = IEEE_QNaN;         /* return canonical QNaN */
1141
                        return FPCR_INV;
1142
                }
1143
                if (a_type == INFTY)
1144
                        *c = a ^ ((b >> 63) << 63);
1145
                else if (b_type == INFTY)
1146
                        *c = b ^ ((a >> 63) << 63);
1147
                else
1148
                        /* either of a and b are +/-0 */
1149
                        *c = ((unsigned long) op_a.s ^ op_b.s) << 63;
1150
                return 0;
1151
        }
1152
        op_c.s = op_a.s ^ op_b.s;
1153
        op_c.e = op_a.e + op_b.e - 55;
1154
        mul64(op_a.f[0], op_b.f[0], op_c.f);
1155
 
1156
        return round_s_ieee(f, &op_c, c);
1157
}
1158
 
1159
 
1160
/*
1161
 * Multiply a x b = c, where a, b, and c are ieee t-floating numbers.
1162
 * "f" contains the rounding mode.
1163
 */
1164
unsigned long
1165
ieee_MULT (int f, unsigned long a, unsigned long b, unsigned long *c)
1166
{
1167
        fpclass_t a_type, b_type;
1168
        EXTENDED op_a, op_b, op_c;
1169
 
1170
        *c = IEEE_QNaN;
1171
        a_type = extend_ieee(a, &op_a, DOUBLE);
1172
        b_type = extend_ieee(b, &op_b, DOUBLE);
1173
        if ((a_type >= NaN && a_type <= ZERO) ||
1174
            (b_type >= NaN && b_type <= ZERO))
1175
        {
1176
                /* propagate NaNs according to arch. ref. handbook: */
1177
                if (b_type == QNaN)
1178
                        *c = b;
1179
                else if (b_type == NaN)
1180
                        *c = b | (1UL << 51);
1181
                else if (a_type == QNaN)
1182
                        *c = a;
1183
                else if (a_type == NaN)
1184
                        *c = a | (1UL << 51);
1185
 
1186
                if (a_type == NaN || b_type == NaN)
1187
                        return FPCR_INV;
1188
                if (a_type == QNaN || b_type == QNaN)
1189
                        return 0;
1190
 
1191
                if ((a_type == INFTY && b_type == ZERO) ||
1192
                    (b_type == INFTY && a_type == ZERO))
1193
                {
1194
                        *c = IEEE_QNaN;         /* return canonical QNaN */
1195
                        return FPCR_INV;
1196
                }
1197
                if (a_type == INFTY)
1198
                        *c = a ^ ((b >> 63) << 63);
1199
                else if (b_type == INFTY)
1200
                        *c = b ^ ((a >> 63) << 63);
1201
                else
1202
                        /* either of a and b are +/-0 */
1203
                        *c = ((unsigned long) op_a.s ^ op_b.s) << 63;
1204
                return 0;
1205
        }
1206
        op_c.s = op_a.s ^ op_b.s;
1207
        op_c.e = op_a.e + op_b.e - 55;
1208
        mul64(op_a.f[0], op_b.f[0], op_c.f);
1209
 
1210
        return round_t_ieee(f, &op_c, c);
1211
}
1212
 
1213
 
1214
/*
1215
 * Divide a / b = c, where a, b, and c are ieee s-floating numbers.
1216
 * "f" contains the rounding mode etc.
1217
 */
1218
unsigned long
1219
ieee_DIVS (int f, unsigned long a, unsigned long b, unsigned long *c)
1220
{
1221
        fpclass_t a_type, b_type;
1222
        EXTENDED op_a, op_b, op_c;
1223
 
1224
        a_type = extend_ieee(a, &op_a, SINGLE);
1225
        b_type = extend_ieee(b, &op_b, SINGLE);
1226
        if ((a_type >= NaN && a_type <= ZERO) ||
1227
            (b_type >= NaN && b_type <= ZERO))
1228
        {
1229
                unsigned long res;
1230
 
1231
                /* propagate NaNs according to arch. ref. handbook: */
1232
                if (b_type == QNaN)
1233
                        *c = b;
1234
                else if (b_type == NaN)
1235
                        *c = b | (1UL << 51);
1236
                else if (a_type == QNaN)
1237
                        *c = a;
1238
                else if (a_type == NaN)
1239
                        *c = a | (1UL << 51);
1240
 
1241
                if (a_type == NaN || b_type == NaN)
1242
                        return FPCR_INV;
1243
                if (a_type == QNaN || b_type == QNaN)
1244
                        return 0;
1245
 
1246
                res = 0;
1247
                *c = IEEE_PINF;
1248
                if (a_type == INFTY) {
1249
                        if (b_type == INFTY) {
1250
                                *c = IEEE_QNaN;
1251
                                return FPCR_INV;
1252
                        }
1253
                } else if (b_type == ZERO) {
1254
                        if (a_type == ZERO) {
1255
                                *c = IEEE_QNaN;
1256
                                return FPCR_INV;
1257
                        }
1258
                        res = FPCR_DZE;
1259
                } else
1260
                        /* a_type == ZERO || b_type == INFTY */
1261
                        *c = 0;
1262
                *c |= (unsigned long) (op_a.s ^ op_b.s) << 63;
1263
                return res;
1264
        }
1265
        op_c.s = op_a.s ^ op_b.s;
1266
        op_c.e = op_a.e - op_b.e;
1267
 
1268
        op_a.f[1] = op_a.f[0];
1269
        op_a.f[0] = 0;
1270
        div128(op_a.f, op_b.f, op_c.f);
1271
        if (a_type != ZERO)
1272
                /* force a sticky bit because DIVs never hit exact .5: */
1273
                op_c.f[0] |= STICKY_S;
1274
        normalize(&op_c);
1275
        op_c.e -= 9;            /* remove excess exp from original shift */
1276
        return round_s_ieee(f, &op_c, c);
1277
}
1278
 
1279
 
1280
/*
1281
 * Divide a/b = c, where a, b, and c are ieee t-floating numbers.  "f"
1282
 * contains the rounding mode etc.
1283
 */
1284
unsigned long
1285
ieee_DIVT (int f, unsigned long a, unsigned long b, unsigned long *c)
1286
{
1287
        fpclass_t a_type, b_type;
1288
        EXTENDED op_a, op_b, op_c;
1289
 
1290
        *c = IEEE_QNaN;
1291
        a_type = extend_ieee(a, &op_a, DOUBLE);
1292
        b_type = extend_ieee(b, &op_b, DOUBLE);
1293
        if ((a_type >= NaN && a_type <= ZERO) ||
1294
            (b_type >= NaN && b_type <= ZERO))
1295
        {
1296
                unsigned long res;
1297
 
1298
                /* propagate NaNs according to arch. ref. handbook: */
1299
                if (b_type == QNaN)
1300
                        *c = b;
1301
                else if (b_type == NaN)
1302
                        *c = b | (1UL << 51);
1303
                else if (a_type == QNaN)
1304
                        *c = a;
1305
                else if (a_type == NaN)
1306
                        *c = a | (1UL << 51);
1307
 
1308
                if (a_type == NaN || b_type == NaN)
1309
                        return FPCR_INV;
1310
                if (a_type == QNaN || b_type == QNaN)
1311
                        return 0;
1312
 
1313
                res = 0;
1314
                *c = IEEE_PINF;
1315
                if (a_type == INFTY) {
1316
                        if (b_type == INFTY) {
1317
                                *c = IEEE_QNaN;
1318
                                return FPCR_INV;
1319
                        }
1320
                } else if (b_type == ZERO) {
1321
                        if (a_type == ZERO) {
1322
                                *c = IEEE_QNaN;
1323
                                return FPCR_INV;
1324
                        }
1325
                        res = FPCR_DZE;
1326
                } else
1327
                        /* a_type == ZERO || b_type == INFTY */
1328
                        *c = 0;
1329
                *c |= (unsigned long) (op_a.s ^ op_b.s) << 63;
1330
                return res;
1331
        }
1332
        op_c.s = op_a.s ^ op_b.s;
1333
        op_c.e = op_a.e - op_b.e;
1334
 
1335
        op_a.f[1] = op_a.f[0];
1336
        op_a.f[0] = 0;
1337
        div128(op_a.f, op_b.f, op_c.f);
1338
        if (a_type != ZERO)
1339
                /* force a sticky bit because DIVs never hit exact .5 */
1340
                op_c.f[0] |= STICKY_T;
1341
        normalize(&op_c);
1342
        op_c.e -= 9;            /* remove excess exp from original shift */
1343
        return round_t_ieee(f, &op_c, c);
1344
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.