diff options
author | Linus Torvalds <torvalds@g5.osdl.org> | 2006-03-29 14:28:30 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-03-29 14:28:30 -0500 |
commit | 76babde121d2ffef04ca692ce64ef9f8a9866086 (patch) | |
tree | 294923bbb4974258d86d223e35eee691abacdfb1 /arch/powerpc/math-emu | |
parent | e71ac6032edf77a1e4a81f3e3b260807e94b37a5 (diff) | |
parent | 15e812ad849e142e3dfc984d33c4d8042389f148 (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc
* git://git.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc: (67 commits)
[PATCH] powerpc: Remove oprofile spinlock backtrace code
[PATCH] powerpc: Add oprofile calltrace support to all powerpc cpus
[PATCH] powerpc: Add oprofile calltrace support
[PATCH] for_each_possible_cpu: ppc
[PATCH] for_each_possible_cpu: powerpc
[PATCH] lock PTE before updating it in 440/BookE page fault handler
[PATCH] powerpc: Kill _machine and hard-coded platform numbers
ppc: Fix compile error in arch/ppc/lib/strcase.c
[PATCH] git-powerpc: WARN was a dumb idea
[PATCH] powerpc: a couple of trivial compile warning fixes
powerpc: remove OCP references
powerpc: Make uImage default build output for MPC8540 ADS
powerpc: move math-emu over to arch/powerpc
powerpc: use memparse() for mem= command line parsing
ppc: fix strncasecmp prototype
[PATCH] powerpc: make ISA floppies work again
[PATCH] powerpc: Fix some initcall return values
[PATCH] powerpc: Workaround for pSeries RTAS bug
[PATCH] spufs: fix __init/__exit annotations
[PATCH] powerpc: add hvc backend for rtas
...
Diffstat (limited to 'arch/powerpc/math-emu')
53 files changed, 4506 insertions, 0 deletions
diff --git a/arch/powerpc/math-emu/Makefile b/arch/powerpc/math-emu/Makefile new file mode 100644 index 000000000000..754143e8936b --- /dev/null +++ b/arch/powerpc/math-emu/Makefile | |||
@@ -0,0 +1,13 @@ | |||
1 | |||
2 | obj-y := math.o fmr.o lfd.o stfd.o | ||
3 | |||
4 | obj-$(CONFIG_MATH_EMULATION) += fabs.o fadd.o fadds.o fcmpo.o fcmpu.o \ | ||
5 | fctiw.o fctiwz.o fdiv.o fdivs.o \ | ||
6 | fmadd.o fmadds.o fmsub.o fmsubs.o \ | ||
7 | fmul.o fmuls.o fnabs.o fneg.o types.o \ | ||
8 | fnmadd.o fnmadds.o fnmsub.o fnmsubs.o \ | ||
9 | fres.o frsp.o frsqrte.o fsel.o lfs.o \ | ||
10 | fsqrt.o fsqrts.o fsub.o fsubs.o \ | ||
11 | mcrfs.o mffs.o mtfsb0.o mtfsb1.o \ | ||
12 | mtfsf.o mtfsfi.o stfiwx.o stfs.o \ | ||
13 | udivmodti4.o | ||
diff --git a/arch/powerpc/math-emu/double.h b/arch/powerpc/math-emu/double.h new file mode 100644 index 000000000000..ffba8b67f059 --- /dev/null +++ b/arch/powerpc/math-emu/double.h | |||
@@ -0,0 +1,129 @@ | |||
1 | /* | ||
2 | * Definitions for IEEE Double Precision | ||
3 | */ | ||
4 | |||
5 | #if _FP_W_TYPE_SIZE < 32 | ||
6 | #error "Here's a nickel kid. Go buy yourself a real computer." | ||
7 | #endif | ||
8 | |||
9 | #if _FP_W_TYPE_SIZE < 64 | ||
10 | #define _FP_FRACTBITS_D (2 * _FP_W_TYPE_SIZE) | ||
11 | #else | ||
12 | #define _FP_FRACTBITS_D _FP_W_TYPE_SIZE | ||
13 | #endif | ||
14 | |||
15 | #define _FP_FRACBITS_D 53 | ||
16 | #define _FP_FRACXBITS_D (_FP_FRACTBITS_D - _FP_FRACBITS_D) | ||
17 | #define _FP_WFRACBITS_D (_FP_WORKBITS + _FP_FRACBITS_D) | ||
18 | #define _FP_WFRACXBITS_D (_FP_FRACTBITS_D - _FP_WFRACBITS_D) | ||
19 | #define _FP_EXPBITS_D 11 | ||
20 | #define _FP_EXPBIAS_D 1023 | ||
21 | #define _FP_EXPMAX_D 2047 | ||
22 | |||
23 | #define _FP_QNANBIT_D \ | ||
24 | ((_FP_W_TYPE)1 << ((_FP_FRACBITS_D-2) % _FP_W_TYPE_SIZE)) | ||
25 | #define _FP_IMPLBIT_D \ | ||
26 | ((_FP_W_TYPE)1 << ((_FP_FRACBITS_D-1) % _FP_W_TYPE_SIZE)) | ||
27 | #define _FP_OVERFLOW_D \ | ||
28 | ((_FP_W_TYPE)1 << (_FP_WFRACBITS_D % _FP_W_TYPE_SIZE)) | ||
29 | |||
30 | #if _FP_W_TYPE_SIZE < 64 | ||
31 | |||
32 | union _FP_UNION_D | ||
33 | { | ||
34 | double flt; | ||
35 | struct { | ||
36 | #if __BYTE_ORDER == __BIG_ENDIAN | ||
37 | unsigned sign : 1; | ||
38 | unsigned exp : _FP_EXPBITS_D; | ||
39 | unsigned frac1 : _FP_FRACBITS_D - (_FP_IMPLBIT_D != 0) - _FP_W_TYPE_SIZE; | ||
40 | unsigned frac0 : _FP_W_TYPE_SIZE; | ||
41 | #else | ||
42 | unsigned frac0 : _FP_W_TYPE_SIZE; | ||
43 | unsigned frac1 : _FP_FRACBITS_D - (_FP_IMPLBIT_D != 0) - _FP_W_TYPE_SIZE; | ||
44 | unsigned exp : _FP_EXPBITS_D; | ||
45 | unsigned sign : 1; | ||
46 | #endif | ||
47 | } bits __attribute__((packed)); | ||
48 | }; | ||
49 | |||
50 | #define FP_DECL_D(X) _FP_DECL(2,X) | ||
51 | #define FP_UNPACK_RAW_D(X,val) _FP_UNPACK_RAW_2(D,X,val) | ||
52 | #define FP_PACK_RAW_D(val,X) _FP_PACK_RAW_2(D,val,X) | ||
53 | |||
54 | #define FP_UNPACK_D(X,val) \ | ||
55 | do { \ | ||
56 | _FP_UNPACK_RAW_2(D,X,val); \ | ||
57 | _FP_UNPACK_CANONICAL(D,2,X); \ | ||
58 | } while (0) | ||
59 | |||
60 | #define FP_PACK_D(val,X) \ | ||
61 | do { \ | ||
62 | _FP_PACK_CANONICAL(D,2,X); \ | ||
63 | _FP_PACK_RAW_2(D,val,X); \ | ||
64 | } while (0) | ||
65 | |||
66 | #define FP_NEG_D(R,X) _FP_NEG(D,2,R,X) | ||
67 | #define FP_ADD_D(R,X,Y) _FP_ADD(D,2,R,X,Y) | ||
68 | #define FP_SUB_D(R,X,Y) _FP_SUB(D,2,R,X,Y) | ||
69 | #define FP_MUL_D(R,X,Y) _FP_MUL(D,2,R,X,Y) | ||
70 | #define FP_DIV_D(R,X,Y) _FP_DIV(D,2,R,X,Y) | ||
71 | #define FP_SQRT_D(R,X) _FP_SQRT(D,2,R,X) | ||
72 | |||
73 | #define FP_CMP_D(r,X,Y,un) _FP_CMP(D,2,r,X,Y,un) | ||
74 | #define FP_CMP_EQ_D(r,X,Y) _FP_CMP_EQ(D,2,r,X,Y) | ||
75 | |||
76 | #define FP_TO_INT_D(r,X,rsz,rsg) _FP_TO_INT(D,2,r,X,rsz,rsg) | ||
77 | #define FP_FROM_INT_D(X,r,rs,rt) _FP_FROM_INT(D,2,X,r,rs,rt) | ||
78 | |||
79 | #else | ||
80 | |||
81 | union _FP_UNION_D | ||
82 | { | ||
83 | double flt; | ||
84 | struct { | ||
85 | #if __BYTE_ORDER == __BIG_ENDIAN | ||
86 | unsigned sign : 1; | ||
87 | unsigned exp : _FP_EXPBITS_D; | ||
88 | unsigned long frac : _FP_FRACBITS_D - (_FP_IMPLBIT_D != 0); | ||
89 | #else | ||
90 | unsigned long frac : _FP_FRACBITS_D - (_FP_IMPLBIT_D != 0); | ||
91 | unsigned exp : _FP_EXPBITS_D; | ||
92 | unsigned sign : 1; | ||
93 | #endif | ||
94 | } bits __attribute__((packed)); | ||
95 | }; | ||
96 | |||
97 | #define FP_DECL_D(X) _FP_DECL(1,X) | ||
98 | #define FP_UNPACK_RAW_D(X,val) _FP_UNPACK_RAW_1(D,X,val) | ||
99 | #define FP_PACK_RAW_D(val,X) _FP_PACK_RAW_1(D,val,X) | ||
100 | |||
101 | #define FP_UNPACK_D(X,val) \ | ||
102 | do { \ | ||
103 | _FP_UNPACK_RAW_1(D,X,val); \ | ||
104 | _FP_UNPACK_CANONICAL(D,1,X); \ | ||
105 | } while (0) | ||
106 | |||
107 | #define FP_PACK_D(val,X) \ | ||
108 | do { \ | ||
109 | _FP_PACK_CANONICAL(D,1,X); \ | ||
110 | _FP_PACK_RAW_1(D,val,X); \ | ||
111 | } while (0) | ||
112 | |||
113 | #define FP_NEG_D(R,X) _FP_NEG(D,1,R,X) | ||
114 | #define FP_ADD_D(R,X,Y) _FP_ADD(D,1,R,X,Y) | ||
115 | #define FP_SUB_D(R,X,Y) _FP_SUB(D,1,R,X,Y) | ||
116 | #define FP_MUL_D(R,X,Y) _FP_MUL(D,1,R,X,Y) | ||
117 | #define FP_DIV_D(R,X,Y) _FP_DIV(D,1,R,X,Y) | ||
118 | #define FP_SQRT_D(R,X) _FP_SQRT(D,1,R,X) | ||
119 | |||
120 | /* The implementation of _FP_MUL_D and _FP_DIV_D should be chosen by | ||
121 | the target machine. */ | ||
122 | |||
123 | #define FP_CMP_D(r,X,Y,un) _FP_CMP(D,1,r,X,Y,un) | ||
124 | #define FP_CMP_EQ_D(r,X,Y) _FP_CMP_EQ(D,1,r,X,Y) | ||
125 | |||
126 | #define FP_TO_INT_D(r,X,rsz,rsg) _FP_TO_INT(D,1,r,X,rsz,rsg) | ||
127 | #define FP_FROM_INT_D(X,r,rs,rt) _FP_FROM_INT(D,1,X,r,rs,rt) | ||
128 | |||
129 | #endif /* W_TYPE_SIZE < 64 */ | ||
diff --git a/arch/powerpc/math-emu/fabs.c b/arch/powerpc/math-emu/fabs.c new file mode 100644 index 000000000000..41f0617f3d3a --- /dev/null +++ b/arch/powerpc/math-emu/fabs.c | |||
@@ -0,0 +1,18 @@ | |||
1 | #include <linux/types.h> | ||
2 | #include <linux/errno.h> | ||
3 | #include <asm/uaccess.h> | ||
4 | |||
5 | int | ||
6 | fabs(u32 *frD, u32 *frB) | ||
7 | { | ||
8 | frD[0] = frB[0] & 0x7fffffff; | ||
9 | frD[1] = frB[1]; | ||
10 | |||
11 | #ifdef DEBUG | ||
12 | printk("%s: D %p, B %p: ", __FUNCTION__, frD, frB); | ||
13 | dump_double(frD); | ||
14 | printk("\n"); | ||
15 | #endif | ||
16 | |||
17 | return 0; | ||
18 | } | ||
diff --git a/arch/powerpc/math-emu/fadd.c b/arch/powerpc/math-emu/fadd.c new file mode 100644 index 000000000000..fc8836488b64 --- /dev/null +++ b/arch/powerpc/math-emu/fadd.c | |||
@@ -0,0 +1,38 @@ | |||
1 | #include <linux/types.h> | ||
2 | #include <linux/errno.h> | ||
3 | #include <asm/uaccess.h> | ||
4 | |||
5 | #include "soft-fp.h" | ||
6 | #include "double.h" | ||
7 | |||
8 | int | ||
9 | fadd(void *frD, void *frA, void *frB) | ||
10 | { | ||
11 | FP_DECL_D(A); | ||
12 | FP_DECL_D(B); | ||
13 | FP_DECL_D(R); | ||
14 | int ret = 0; | ||
15 | |||
16 | #ifdef DEBUG | ||
17 | printk("%s: %p %p %p\n", __FUNCTION__, frD, frA, frB); | ||
18 | #endif | ||
19 | |||
20 | __FP_UNPACK_D(A, frA); | ||
21 | __FP_UNPACK_D(B, frB); | ||
22 | |||
23 | #ifdef DEBUG | ||
24 | printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c); | ||
25 | printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c); | ||
26 | #endif | ||
27 | |||
28 | if (A_s != B_s && A_c == FP_CLS_INF && B_c == FP_CLS_INF) | ||
29 | ret |= EFLAG_VXISI; | ||
30 | |||
31 | FP_ADD_D(R, A, B); | ||
32 | |||
33 | #ifdef DEBUG | ||
34 | printk("D: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c); | ||
35 | #endif | ||
36 | |||
37 | return (ret | __FP_PACK_D(frD, R)); | ||
38 | } | ||
diff --git a/arch/powerpc/math-emu/fadds.c b/arch/powerpc/math-emu/fadds.c new file mode 100644 index 000000000000..93025b6c8f3c --- /dev/null +++ b/arch/powerpc/math-emu/fadds.c | |||
@@ -0,0 +1,39 @@ | |||
1 | #include <linux/types.h> | ||
2 | #include <linux/errno.h> | ||
3 | #include <asm/uaccess.h> | ||
4 | |||
5 | #include "soft-fp.h" | ||
6 | #include "double.h" | ||
7 | #include "single.h" | ||
8 | |||
9 | int | ||
10 | fadds(void *frD, void *frA, void *frB) | ||
11 | { | ||
12 | FP_DECL_D(A); | ||
13 | FP_DECL_D(B); | ||
14 | FP_DECL_D(R); | ||
15 | int ret = 0; | ||
16 | |||
17 | #ifdef DEBUG | ||
18 | printk("%s: %p %p %p\n", __FUNCTION__, frD, frA, frB); | ||
19 | #endif | ||
20 | |||
21 | __FP_UNPACK_D(A, frA); | ||
22 | __FP_UNPACK_D(B, frB); | ||
23 | |||
24 | #ifdef DEBUG | ||
25 | printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c); | ||
26 | printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c); | ||
27 | #endif | ||
28 | |||
29 | if (A_s != B_s && A_c == FP_CLS_INF && B_c == FP_CLS_INF) | ||
30 | ret |= EFLAG_VXISI; | ||
31 | |||
32 | FP_ADD_D(R, A, B); | ||
33 | |||
34 | #ifdef DEBUG | ||
35 | printk("D: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c); | ||
36 | #endif | ||
37 | |||
38 | return (ret | __FP_PACK_DS(frD, R)); | ||
39 | } | ||
diff --git a/arch/powerpc/math-emu/fcmpo.c b/arch/powerpc/math-emu/fcmpo.c new file mode 100644 index 000000000000..4efac394b4cb --- /dev/null +++ b/arch/powerpc/math-emu/fcmpo.c | |||
@@ -0,0 +1,46 @@ | |||
1 | #include <linux/types.h> | ||
2 | #include <linux/errno.h> | ||
3 | #include <asm/uaccess.h> | ||
4 | |||
5 | #include "soft-fp.h" | ||
6 | #include "double.h" | ||
7 | |||
8 | int | ||
9 | fcmpo(u32 *ccr, int crfD, void *frA, void *frB) | ||
10 | { | ||
11 | FP_DECL_D(A); | ||
12 | FP_DECL_D(B); | ||
13 | int code[4] = { (1 << 3), (1 << 1), (1 << 2), (1 << 0) }; | ||
14 | long cmp; | ||
15 | int ret = 0; | ||
16 | |||
17 | #ifdef DEBUG | ||
18 | printk("%s: %p (%08x) %d %p %p\n", __FUNCTION__, ccr, *ccr, crfD, frA, frB); | ||
19 | #endif | ||
20 | |||
21 | __FP_UNPACK_D(A, frA); | ||
22 | __FP_UNPACK_D(B, frB); | ||
23 | |||
24 | #ifdef DEBUG | ||
25 | printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c); | ||
26 | printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c); | ||
27 | #endif | ||
28 | |||
29 | if (A_c == FP_CLS_NAN || B_c == FP_CLS_NAN) | ||
30 | ret |= EFLAG_VXVC; | ||
31 | |||
32 | FP_CMP_D(cmp, A, B, 2); | ||
33 | cmp = code[(cmp + 1) & 3]; | ||
34 | |||
35 | __FPU_FPSCR &= ~(0x1f000); | ||
36 | __FPU_FPSCR |= (cmp << 12); | ||
37 | |||
38 | *ccr &= ~(15 << ((7 - crfD) << 2)); | ||
39 | *ccr |= (cmp << ((7 - crfD) << 2)); | ||
40 | |||
41 | #ifdef DEBUG | ||
42 | printk("CR: %08x\n", *ccr); | ||
43 | #endif | ||
44 | |||
45 | return ret; | ||
46 | } | ||
diff --git a/arch/powerpc/math-emu/fcmpu.c b/arch/powerpc/math-emu/fcmpu.c new file mode 100644 index 000000000000..b7e33176e618 --- /dev/null +++ b/arch/powerpc/math-emu/fcmpu.c | |||
@@ -0,0 +1,42 @@ | |||
1 | #include <linux/types.h> | ||
2 | #include <linux/errno.h> | ||
3 | #include <asm/uaccess.h> | ||
4 | |||
5 | #include "soft-fp.h" | ||
6 | #include "double.h" | ||
7 | |||
8 | int | ||
9 | fcmpu(u32 *ccr, int crfD, void *frA, void *frB) | ||
10 | { | ||
11 | FP_DECL_D(A); | ||
12 | FP_DECL_D(B); | ||
13 | int code[4] = { (1 << 3), (1 << 1), (1 << 2), (1 << 0) }; | ||
14 | long cmp; | ||
15 | |||
16 | #ifdef DEBUG | ||
17 | printk("%s: %p (%08x) %d %p %p\n", __FUNCTION__, ccr, *ccr, crfD, frA, frB); | ||
18 | #endif | ||
19 | |||
20 | __FP_UNPACK_D(A, frA); | ||
21 | __FP_UNPACK_D(B, frB); | ||
22 | |||
23 | #ifdef DEBUG | ||
24 | printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c); | ||
25 | printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c); | ||
26 | #endif | ||
27 | |||
28 | FP_CMP_D(cmp, A, B, 2); | ||
29 | cmp = code[(cmp + 1) & 3]; | ||
30 | |||
31 | __FPU_FPSCR &= ~(0x1f000); | ||
32 | __FPU_FPSCR |= (cmp << 12); | ||
33 | |||
34 | *ccr &= ~(15 << ((7 - crfD) << 2)); | ||
35 | *ccr |= (cmp << ((7 - crfD) << 2)); | ||
36 | |||
37 | #ifdef DEBUG | ||
38 | printk("CR: %08x\n", *ccr); | ||
39 | #endif | ||
40 | |||
41 | return 0; | ||
42 | } | ||
diff --git a/arch/powerpc/math-emu/fctiw.c b/arch/powerpc/math-emu/fctiw.c new file mode 100644 index 000000000000..3b3c98b840cf --- /dev/null +++ b/arch/powerpc/math-emu/fctiw.c | |||
@@ -0,0 +1,25 @@ | |||
1 | #include <linux/types.h> | ||
2 | #include <linux/errno.h> | ||
3 | #include <asm/uaccess.h> | ||
4 | |||
5 | #include "soft-fp.h" | ||
6 | #include "double.h" | ||
7 | |||
8 | int | ||
9 | fctiw(u32 *frD, void *frB) | ||
10 | { | ||
11 | FP_DECL_D(B); | ||
12 | unsigned int r; | ||
13 | |||
14 | __FP_UNPACK_D(B, frB); | ||
15 | FP_TO_INT_D(r, B, 32, 1); | ||
16 | frD[1] = r; | ||
17 | |||
18 | #ifdef DEBUG | ||
19 | printk("%s: D %p, B %p: ", __FUNCTION__, frD, frB); | ||
20 | dump_double(frD); | ||
21 | printk("\n"); | ||
22 | #endif | ||
23 | |||
24 | return 0; | ||
25 | } | ||
diff --git a/arch/powerpc/math-emu/fctiwz.c b/arch/powerpc/math-emu/fctiwz.c new file mode 100644 index 000000000000..7717eb6fcfb6 --- /dev/null +++ b/arch/powerpc/math-emu/fctiwz.c | |||
@@ -0,0 +1,32 @@ | |||
1 | #include <linux/types.h> | ||
2 | #include <linux/errno.h> | ||
3 | #include <asm/uaccess.h> | ||
4 | |||
5 | #include "soft-fp.h" | ||
6 | #include "double.h" | ||
7 | |||
8 | int | ||
9 | fctiwz(u32 *frD, void *frB) | ||
10 | { | ||
11 | FP_DECL_D(B); | ||
12 | u32 fpscr; | ||
13 | unsigned int r; | ||
14 | |||
15 | fpscr = __FPU_FPSCR; | ||
16 | __FPU_FPSCR &= ~(3); | ||
17 | __FPU_FPSCR |= FP_RND_ZERO; | ||
18 | |||
19 | __FP_UNPACK_D(B, frB); | ||
20 | FP_TO_INT_D(r, B, 32, 1); | ||
21 | frD[1] = r; | ||
22 | |||
23 | __FPU_FPSCR = fpscr; | ||
24 | |||
25 | #ifdef DEBUG | ||
26 | printk("%s: D %p, B %p: ", __FUNCTION__, frD, frB); | ||
27 | dump_double(frD); | ||
28 | printk("\n"); | ||
29 | #endif | ||
30 | |||
31 | return 0; | ||
32 | } | ||
diff --git a/arch/powerpc/math-emu/fdiv.c b/arch/powerpc/math-emu/fdiv.c new file mode 100644 index 000000000000..f2fba825b2d0 --- /dev/null +++ b/arch/powerpc/math-emu/fdiv.c | |||
@@ -0,0 +1,53 @@ | |||
1 | #include <linux/types.h> | ||
2 | #include <linux/errno.h> | ||
3 | #include <asm/uaccess.h> | ||
4 | |||
5 | #include "soft-fp.h" | ||
6 | #include "double.h" | ||
7 | |||
8 | int | ||
9 | fdiv(void *frD, void *frA, void *frB) | ||
10 | { | ||
11 | FP_DECL_D(A); | ||
12 | FP_DECL_D(B); | ||
13 | FP_DECL_D(R); | ||
14 | int ret = 0; | ||
15 | |||
16 | #ifdef DEBUG | ||
17 | printk("%s: %p %p %p\n", __FUNCTION__, frD, frA, frB); | ||
18 | #endif | ||
19 | |||
20 | __FP_UNPACK_D(A, frA); | ||
21 | __FP_UNPACK_D(B, frB); | ||
22 | |||
23 | #ifdef DEBUG | ||
24 | printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c); | ||
25 | printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c); | ||
26 | #endif | ||
27 | |||
28 | if (A_c == FP_CLS_ZERO && B_c == FP_CLS_ZERO) { | ||
29 | ret |= EFLAG_VXZDZ; | ||
30 | #ifdef DEBUG | ||
31 | printk("%s: FPSCR_VXZDZ raised\n", __FUNCTION__); | ||
32 | #endif | ||
33 | } | ||
34 | if (A_c == FP_CLS_INF && B_c == FP_CLS_INF) { | ||
35 | ret |= EFLAG_VXIDI; | ||
36 | #ifdef DEBUG | ||
37 | printk("%s: FPSCR_VXIDI raised\n", __FUNCTION__); | ||
38 | #endif | ||
39 | } | ||
40 | |||
41 | if (B_c == FP_CLS_ZERO && A_c != FP_CLS_ZERO) { | ||
42 | ret |= EFLAG_DIVZERO; | ||
43 | if (__FPU_TRAP_P(EFLAG_DIVZERO)) | ||
44 | return ret; | ||
45 | } | ||
46 | FP_DIV_D(R, A, B); | ||
47 | |||
48 | #ifdef DEBUG | ||
49 | printk("D: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c); | ||
50 | #endif | ||
51 | |||
52 | return (ret | __FP_PACK_D(frD, R)); | ||
53 | } | ||
diff --git a/arch/powerpc/math-emu/fdivs.c b/arch/powerpc/math-emu/fdivs.c new file mode 100644 index 000000000000..b971196e3175 --- /dev/null +++ b/arch/powerpc/math-emu/fdivs.c | |||
@@ -0,0 +1,55 @@ | |||
1 | #include <linux/types.h> | ||
2 | #include <linux/errno.h> | ||
3 | #include <asm/uaccess.h> | ||
4 | |||
5 | #include "soft-fp.h" | ||
6 | #include "double.h" | ||
7 | #include "single.h" | ||
8 | |||
9 | int | ||
10 | fdivs(void *frD, void *frA, void *frB) | ||
11 | { | ||
12 | FP_DECL_D(A); | ||
13 | FP_DECL_D(B); | ||
14 | FP_DECL_D(R); | ||
15 | int ret = 0; | ||
16 | |||
17 | #ifdef DEBUG | ||
18 | printk("%s: %p %p %p\n", __FUNCTION__, frD, frA, frB); | ||
19 | #endif | ||
20 | |||
21 | __FP_UNPACK_D(A, frA); | ||
22 | __FP_UNPACK_D(B, frB); | ||
23 | |||
24 | #ifdef DEBUG | ||
25 | printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c); | ||
26 | printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c); | ||
27 | #endif | ||
28 | |||
29 | if (A_c == FP_CLS_ZERO && B_c == FP_CLS_ZERO) { | ||
30 | ret |= EFLAG_VXZDZ; | ||
31 | #ifdef DEBUG | ||
32 | printk("%s: FPSCR_VXZDZ raised\n", __FUNCTION__); | ||
33 | #endif | ||
34 | } | ||
35 | if (A_c == FP_CLS_INF && B_c == FP_CLS_INF) { | ||
36 | ret |= EFLAG_VXIDI; | ||
37 | #ifdef DEBUG | ||
38 | printk("%s: FPSCR_VXIDI raised\n", __FUNCTION__); | ||
39 | #endif | ||
40 | } | ||
41 | |||
42 | if (B_c == FP_CLS_ZERO && A_c != FP_CLS_ZERO) { | ||
43 | ret |= EFLAG_DIVZERO; | ||
44 | if (__FPU_TRAP_P(EFLAG_DIVZERO)) | ||
45 | return ret; | ||
46 | } | ||
47 | |||
48 | FP_DIV_D(R, A, B); | ||
49 | |||
50 | #ifdef DEBUG | ||
51 | printk("D: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c); | ||
52 | #endif | ||
53 | |||
54 | return (ret | __FP_PACK_DS(frD, R)); | ||
55 | } | ||
diff --git a/arch/powerpc/math-emu/fmadd.c b/arch/powerpc/math-emu/fmadd.c new file mode 100644 index 000000000000..0a1dbce793e9 --- /dev/null +++ b/arch/powerpc/math-emu/fmadd.c | |||
@@ -0,0 +1,48 @@ | |||
1 | #include <linux/types.h> | ||
2 | #include <linux/errno.h> | ||
3 | #include <asm/uaccess.h> | ||
4 | |||
5 | #include "soft-fp.h" | ||
6 | #include "double.h" | ||
7 | |||
8 | int | ||
9 | fmadd(void *frD, void *frA, void *frB, void *frC) | ||
10 | { | ||
11 | FP_DECL_D(R); | ||
12 | FP_DECL_D(A); | ||
13 | FP_DECL_D(B); | ||
14 | FP_DECL_D(C); | ||
15 | FP_DECL_D(T); | ||
16 | int ret = 0; | ||
17 | |||
18 | #ifdef DEBUG | ||
19 | printk("%s: %p %p %p %p\n", __FUNCTION__, frD, frA, frB, frC); | ||
20 | #endif | ||
21 | |||
22 | __FP_UNPACK_D(A, frA); | ||
23 | __FP_UNPACK_D(B, frB); | ||
24 | __FP_UNPACK_D(C, frC); | ||
25 | |||
26 | #ifdef DEBUG | ||
27 | printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c); | ||
28 | printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c); | ||
29 | printk("C: %ld %lu %lu %ld (%ld)\n", C_s, C_f1, C_f0, C_e, C_c); | ||
30 | #endif | ||
31 | |||
32 | if ((A_c == FP_CLS_INF && C_c == FP_CLS_ZERO) || | ||
33 | (A_c == FP_CLS_ZERO && C_c == FP_CLS_INF)) | ||
34 | ret |= EFLAG_VXIMZ; | ||
35 | |||
36 | FP_MUL_D(T, A, C); | ||
37 | |||
38 | if (T_s != B_s && T_c == FP_CLS_INF && B_c == FP_CLS_INF) | ||
39 | ret |= EFLAG_VXISI; | ||
40 | |||
41 | FP_ADD_D(R, T, B); | ||
42 | |||
43 | #ifdef DEBUG | ||
44 | printk("D: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c); | ||
45 | #endif | ||
46 | |||
47 | return (ret | __FP_PACK_D(frD, R)); | ||
48 | } | ||
diff --git a/arch/powerpc/math-emu/fmadds.c b/arch/powerpc/math-emu/fmadds.c new file mode 100644 index 000000000000..0f70bba9445e --- /dev/null +++ b/arch/powerpc/math-emu/fmadds.c | |||
@@ -0,0 +1,49 @@ | |||
1 | #include <linux/types.h> | ||
2 | #include <linux/errno.h> | ||
3 | #include <asm/uaccess.h> | ||
4 | |||
5 | #include "soft-fp.h" | ||
6 | #include "double.h" | ||
7 | #include "single.h" | ||
8 | |||
9 | int | ||
10 | fmadds(void *frD, void *frA, void *frB, void *frC) | ||
11 | { | ||
12 | FP_DECL_D(R); | ||
13 | FP_DECL_D(A); | ||
14 | FP_DECL_D(B); | ||
15 | FP_DECL_D(C); | ||
16 | FP_DECL_D(T); | ||
17 | int ret = 0; | ||
18 | |||
19 | #ifdef DEBUG | ||
20 | printk("%s: %p %p %p %p\n", __FUNCTION__, frD, frA, frB, frC); | ||
21 | #endif | ||
22 | |||
23 | __FP_UNPACK_D(A, frA); | ||
24 | __FP_UNPACK_D(B, frB); | ||
25 | __FP_UNPACK_D(C, frC); | ||
26 | |||
27 | #ifdef DEBUG | ||
28 | printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c); | ||
29 | printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c); | ||
30 | printk("C: %ld %lu %lu %ld (%ld)\n", C_s, C_f1, C_f0, C_e, C_c); | ||
31 | #endif | ||
32 | |||
33 | if ((A_c == FP_CLS_INF && C_c == FP_CLS_ZERO) || | ||
34 | (A_c == FP_CLS_ZERO && C_c == FP_CLS_INF)) | ||
35 | ret |= EFLAG_VXIMZ; | ||
36 | |||
37 | FP_MUL_D(T, A, C); | ||
38 | |||
39 | if (T_s != B_s && T_c == FP_CLS_INF && B_c == FP_CLS_INF) | ||
40 | ret |= EFLAG_VXISI; | ||
41 | |||
42 | FP_ADD_D(R, T, B); | ||
43 | |||
44 | #ifdef DEBUG | ||
45 | printk("D: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c); | ||
46 | #endif | ||
47 | |||
48 | return (ret | __FP_PACK_DS(frD, R)); | ||
49 | } | ||
diff --git a/arch/powerpc/math-emu/fmr.c b/arch/powerpc/math-emu/fmr.c new file mode 100644 index 000000000000..28df700c0c7e --- /dev/null +++ b/arch/powerpc/math-emu/fmr.c | |||
@@ -0,0 +1,18 @@ | |||
1 | #include <linux/types.h> | ||
2 | #include <linux/errno.h> | ||
3 | #include <asm/uaccess.h> | ||
4 | |||
5 | int | ||
6 | fmr(u32 *frD, u32 *frB) | ||
7 | { | ||
8 | frD[0] = frB[0]; | ||
9 | frD[1] = frB[1]; | ||
10 | |||
11 | #ifdef DEBUG | ||
12 | printk("%s: D %p, B %p: ", __FUNCTION__, frD, frB); | ||
13 | dump_double(frD); | ||
14 | printk("\n"); | ||
15 | #endif | ||
16 | |||
17 | return 0; | ||
18 | } | ||
diff --git a/arch/powerpc/math-emu/fmsub.c b/arch/powerpc/math-emu/fmsub.c new file mode 100644 index 000000000000..203fd48a6fec --- /dev/null +++ b/arch/powerpc/math-emu/fmsub.c | |||
@@ -0,0 +1,51 @@ | |||
1 | #include <linux/types.h> | ||
2 | #include <linux/errno.h> | ||
3 | #include <asm/uaccess.h> | ||
4 | |||
5 | #include "soft-fp.h" | ||
6 | #include "double.h" | ||
7 | |||
8 | int | ||
9 | fmsub(void *frD, void *frA, void *frB, void *frC) | ||
10 | { | ||
11 | FP_DECL_D(R); | ||
12 | FP_DECL_D(A); | ||
13 | FP_DECL_D(B); | ||
14 | FP_DECL_D(C); | ||
15 | FP_DECL_D(T); | ||
16 | int ret = 0; | ||
17 | |||
18 | #ifdef DEBUG | ||
19 | printk("%s: %p %p %p %p\n", __FUNCTION__, frD, frA, frB, frC); | ||
20 | #endif | ||
21 | |||
22 | __FP_UNPACK_D(A, frA); | ||
23 | __FP_UNPACK_D(B, frB); | ||
24 | __FP_UNPACK_D(C, frC); | ||
25 | |||
26 | #ifdef DEBUG | ||
27 | printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c); | ||
28 | printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c); | ||
29 | printk("C: %ld %lu %lu %ld (%ld)\n", C_s, C_f1, C_f0, C_e, C_c); | ||
30 | #endif | ||
31 | |||
32 | if ((A_c == FP_CLS_INF && C_c == FP_CLS_ZERO) || | ||
33 | (A_c == FP_CLS_ZERO && C_c == FP_CLS_INF)) | ||
34 | ret |= EFLAG_VXIMZ; | ||
35 | |||
36 | FP_MUL_D(T, A, C); | ||
37 | |||
38 | if (B_c != FP_CLS_NAN) | ||
39 | B_s ^= 1; | ||
40 | |||
41 | if (T_s != B_s && T_c == FP_CLS_INF && B_c == FP_CLS_INF) | ||
42 | ret |= EFLAG_VXISI; | ||
43 | |||
44 | FP_ADD_D(R, T, B); | ||
45 | |||
46 | #ifdef DEBUG | ||
47 | printk("D: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c); | ||
48 | #endif | ||
49 | |||
50 | return (ret | __FP_PACK_D(frD, R)); | ||
51 | } | ||
diff --git a/arch/powerpc/math-emu/fmsubs.c b/arch/powerpc/math-emu/fmsubs.c new file mode 100644 index 000000000000..8ce68624c189 --- /dev/null +++ b/arch/powerpc/math-emu/fmsubs.c | |||
@@ -0,0 +1,52 @@ | |||
1 | #include <linux/types.h> | ||
2 | #include <linux/errno.h> | ||
3 | #include <asm/uaccess.h> | ||
4 | |||
5 | #include "soft-fp.h" | ||
6 | #include "double.h" | ||
7 | #include "single.h" | ||
8 | |||
9 | int | ||
10 | fmsubs(void *frD, void *frA, void *frB, void *frC) | ||
11 | { | ||
12 | FP_DECL_D(R); | ||
13 | FP_DECL_D(A); | ||
14 | FP_DECL_D(B); | ||
15 | FP_DECL_D(C); | ||
16 | FP_DECL_D(T); | ||
17 | int ret = 0; | ||
18 | |||
19 | #ifdef DEBUG | ||
20 | printk("%s: %p %p %p %p\n", __FUNCTION__, frD, frA, frB, frC); | ||
21 | #endif | ||
22 | |||
23 | __FP_UNPACK_D(A, frA); | ||
24 | __FP_UNPACK_D(B, frB); | ||
25 | __FP_UNPACK_D(C, frC); | ||
26 | |||
27 | #ifdef DEBUG | ||
28 | printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c); | ||
29 | printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c); | ||
30 | printk("C: %ld %lu %lu %ld (%ld)\n", C_s, C_f1, C_f0, C_e, C_c); | ||
31 | #endif | ||
32 | |||
33 | if ((A_c == FP_CLS_INF && C_c == FP_CLS_ZERO) || | ||
34 | (A_c == FP_CLS_ZERO && C_c == FP_CLS_INF)) | ||
35 | ret |= EFLAG_VXIMZ; | ||
36 | |||
37 | FP_MUL_D(T, A, C); | ||
38 | |||
39 | if (B_c != FP_CLS_NAN) | ||
40 | B_s ^= 1; | ||
41 | |||
42 | if (T_s != B_s && T_c == FP_CLS_INF && B_c == FP_CLS_INF) | ||
43 | ret |= EFLAG_VXISI; | ||
44 | |||
45 | FP_ADD_D(R, T, B); | ||
46 | |||
47 | #ifdef DEBUG | ||
48 | printk("D: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c); | ||
49 | #endif | ||
50 | |||
51 | return (ret | __FP_PACK_DS(frD, R)); | ||
52 | } | ||
diff --git a/arch/powerpc/math-emu/fmul.c b/arch/powerpc/math-emu/fmul.c new file mode 100644 index 000000000000..66c7e79aae2e --- /dev/null +++ b/arch/powerpc/math-emu/fmul.c | |||
@@ -0,0 +1,42 @@ | |||
1 | #include <linux/types.h> | ||
2 | #include <linux/errno.h> | ||
3 | #include <asm/uaccess.h> | ||
4 | |||
5 | #include "soft-fp.h" | ||
6 | #include "double.h" | ||
7 | |||
8 | int | ||
9 | fmul(void *frD, void *frA, void *frB) | ||
10 | { | ||
11 | FP_DECL_D(A); | ||
12 | FP_DECL_D(B); | ||
13 | FP_DECL_D(R); | ||
14 | int ret = 0; | ||
15 | |||
16 | #ifdef DEBUG | ||
17 | printk("%s: %p %p %p\n", __FUNCTION__, frD, frA, frB); | ||
18 | #endif | ||
19 | |||
20 | __FP_UNPACK_D(A, frA); | ||
21 | __FP_UNPACK_D(B, frB); | ||
22 | |||
23 | #ifdef DEBUG | ||
24 | printk("A: %ld %lu %lu %ld (%ld) [%08lx.%08lx %lx]\n", | ||
25 | A_s, A_f1, A_f0, A_e, A_c, A_f1, A_f0, A_e + 1023); | ||
26 | printk("B: %ld %lu %lu %ld (%ld) [%08lx.%08lx %lx]\n", | ||
27 | B_s, B_f1, B_f0, B_e, B_c, B_f1, B_f0, B_e + 1023); | ||
28 | #endif | ||
29 | |||
30 | if ((A_c == FP_CLS_INF && B_c == FP_CLS_ZERO) || | ||
31 | (A_c == FP_CLS_ZERO && B_c == FP_CLS_INF)) | ||
32 | ret |= EFLAG_VXIMZ; | ||
33 | |||
34 | FP_MUL_D(R, A, B); | ||
35 | |||
36 | #ifdef DEBUG | ||
37 | printk("D: %ld %lu %lu %ld (%ld) [%08lx.%08lx %lx]\n", | ||
38 | R_s, R_f1, R_f0, R_e, R_c, R_f1, R_f0, R_e + 1023); | ||
39 | #endif | ||
40 | |||
41 | return (ret | __FP_PACK_D(frD, R)); | ||
42 | } | ||
diff --git a/arch/powerpc/math-emu/fmuls.c b/arch/powerpc/math-emu/fmuls.c new file mode 100644 index 000000000000..26bc4278271c --- /dev/null +++ b/arch/powerpc/math-emu/fmuls.c | |||
@@ -0,0 +1,43 @@ | |||
1 | #include <linux/types.h> | ||
2 | #include <linux/errno.h> | ||
3 | #include <asm/uaccess.h> | ||
4 | |||
5 | #include "soft-fp.h" | ||
6 | #include "double.h" | ||
7 | #include "single.h" | ||
8 | |||
9 | int | ||
10 | fmuls(void *frD, void *frA, void *frB) | ||
11 | { | ||
12 | FP_DECL_D(A); | ||
13 | FP_DECL_D(B); | ||
14 | FP_DECL_D(R); | ||
15 | int ret = 0; | ||
16 | |||
17 | #ifdef DEBUG | ||
18 | printk("%s: %p %p %p\n", __FUNCTION__, frD, frA, frB); | ||
19 | #endif | ||
20 | |||
21 | __FP_UNPACK_D(A, frA); | ||
22 | __FP_UNPACK_D(B, frB); | ||
23 | |||
24 | #ifdef DEBUG | ||
25 | printk("A: %ld %lu %lu %ld (%ld) [%08lx.%08lx %lx]\n", | ||
26 | A_s, A_f1, A_f0, A_e, A_c, A_f1, A_f0, A_e + 1023); | ||
27 | printk("B: %ld %lu %lu %ld (%ld) [%08lx.%08lx %lx]\n", | ||
28 | B_s, B_f1, B_f0, B_e, B_c, B_f1, B_f0, B_e + 1023); | ||
29 | #endif | ||
30 | |||
31 | if ((A_c == FP_CLS_INF && B_c == FP_CLS_ZERO) || | ||
32 | (A_c == FP_CLS_ZERO && B_c == FP_CLS_INF)) | ||
33 | ret |= EFLAG_VXIMZ; | ||
34 | |||
35 | FP_MUL_D(R, A, B); | ||
36 | |||
37 | #ifdef DEBUG | ||
38 | printk("D: %ld %lu %lu %ld (%ld) [%08lx.%08lx %lx]\n", | ||
39 | R_s, R_f1, R_f0, R_e, R_c, R_f1, R_f0, R_e + 1023); | ||
40 | #endif | ||
41 | |||
42 | return (ret | __FP_PACK_DS(frD, R)); | ||
43 | } | ||
diff --git a/arch/powerpc/math-emu/fnabs.c b/arch/powerpc/math-emu/fnabs.c new file mode 100644 index 000000000000..c6b913d179e0 --- /dev/null +++ b/arch/powerpc/math-emu/fnabs.c | |||
@@ -0,0 +1,18 @@ | |||
1 | #include <linux/types.h> | ||
2 | #include <linux/errno.h> | ||
3 | #include <asm/uaccess.h> | ||
4 | |||
5 | int | ||
6 | fnabs(u32 *frD, u32 *frB) | ||
7 | { | ||
8 | frD[0] = frB[0] | 0x80000000; | ||
9 | frD[1] = frB[1]; | ||
10 | |||
11 | #ifdef DEBUG | ||
12 | printk("%s: D %p, B %p: ", __FUNCTION__, frD, frB); | ||
13 | dump_double(frD); | ||
14 | printk("\n"); | ||
15 | #endif | ||
16 | |||
17 | return 0; | ||
18 | } | ||
diff --git a/arch/powerpc/math-emu/fneg.c b/arch/powerpc/math-emu/fneg.c new file mode 100644 index 000000000000..fe9a98deff69 --- /dev/null +++ b/arch/powerpc/math-emu/fneg.c | |||
@@ -0,0 +1,18 @@ | |||
1 | #include <linux/types.h> | ||
2 | #include <linux/errno.h> | ||
3 | #include <asm/uaccess.h> | ||
4 | |||
5 | int | ||
6 | fneg(u32 *frD, u32 *frB) | ||
7 | { | ||
8 | frD[0] = frB[0] ^ 0x80000000; | ||
9 | frD[1] = frB[1]; | ||
10 | |||
11 | #ifdef DEBUG | ||
12 | printk("%s: D %p, B %p: ", __FUNCTION__, frD, frB); | ||
13 | dump_double(frD); | ||
14 | printk("\n"); | ||
15 | #endif | ||
16 | |||
17 | return 0; | ||
18 | } | ||
diff --git a/arch/powerpc/math-emu/fnmadd.c b/arch/powerpc/math-emu/fnmadd.c new file mode 100644 index 000000000000..7f312276d920 --- /dev/null +++ b/arch/powerpc/math-emu/fnmadd.c | |||
@@ -0,0 +1,51 @@ | |||
1 | #include <linux/types.h> | ||
2 | #include <linux/errno.h> | ||
3 | #include <asm/uaccess.h> | ||
4 | |||
5 | #include "soft-fp.h" | ||
6 | #include "double.h" | ||
7 | |||
8 | int | ||
9 | fnmadd(void *frD, void *frA, void *frB, void *frC) | ||
10 | { | ||
11 | FP_DECL_D(R); | ||
12 | FP_DECL_D(A); | ||
13 | FP_DECL_D(B); | ||
14 | FP_DECL_D(C); | ||
15 | FP_DECL_D(T); | ||
16 | int ret = 0; | ||
17 | |||
18 | #ifdef DEBUG | ||
19 | printk("%s: %p %p %p %p\n", __FUNCTION__, frD, frA, frB, frC); | ||
20 | #endif | ||
21 | |||
22 | __FP_UNPACK_D(A, frA); | ||
23 | __FP_UNPACK_D(B, frB); | ||
24 | __FP_UNPACK_D(C, frC); | ||
25 | |||
26 | #ifdef DEBUG | ||
27 | printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c); | ||
28 | printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c); | ||
29 | printk("C: %ld %lu %lu %ld (%ld)\n", C_s, C_f1, C_f0, C_e, C_c); | ||
30 | #endif | ||
31 | |||
32 | if ((A_c == FP_CLS_INF && C_c == FP_CLS_ZERO) || | ||
33 | (A_c == FP_CLS_ZERO && C_c == FP_CLS_INF)) | ||
34 | ret |= EFLAG_VXIMZ; | ||
35 | |||
36 | FP_MUL_D(T, A, C); | ||
37 | |||
38 | if (T_s != B_s && T_c == FP_CLS_INF && B_c == FP_CLS_INF) | ||
39 | ret |= EFLAG_VXISI; | ||
40 | |||
41 | FP_ADD_D(R, T, B); | ||
42 | |||
43 | if (R_c != FP_CLS_NAN) | ||
44 | R_s ^= 1; | ||
45 | |||
46 | #ifdef DEBUG | ||
47 | printk("D: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c); | ||
48 | #endif | ||
49 | |||
50 | return (ret | __FP_PACK_D(frD, R)); | ||
51 | } | ||
diff --git a/arch/powerpc/math-emu/fnmadds.c b/arch/powerpc/math-emu/fnmadds.c new file mode 100644 index 000000000000..65454c9c70bc --- /dev/null +++ b/arch/powerpc/math-emu/fnmadds.c | |||
@@ -0,0 +1,52 @@ | |||
1 | #include <linux/types.h> | ||
2 | #include <linux/errno.h> | ||
3 | #include <asm/uaccess.h> | ||
4 | |||
5 | #include "soft-fp.h" | ||
6 | #include "double.h" | ||
7 | #include "single.h" | ||
8 | |||
9 | int | ||
10 | fnmadds(void *frD, void *frA, void *frB, void *frC) | ||
11 | { | ||
12 | FP_DECL_D(R); | ||
13 | FP_DECL_D(A); | ||
14 | FP_DECL_D(B); | ||
15 | FP_DECL_D(C); | ||
16 | FP_DECL_D(T); | ||
17 | int ret = 0; | ||
18 | |||
19 | #ifdef DEBUG | ||
20 | printk("%s: %p %p %p %p\n", __FUNCTION__, frD, frA, frB, frC); | ||
21 | #endif | ||
22 | |||
23 | __FP_UNPACK_D(A, frA); | ||
24 | __FP_UNPACK_D(B, frB); | ||
25 | __FP_UNPACK_D(C, frC); | ||
26 | |||
27 | #ifdef DEBUG | ||
28 | printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c); | ||
29 | printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c); | ||
30 | printk("C: %ld %lu %lu %ld (%ld)\n", C_s, C_f1, C_f0, C_e, C_c); | ||
31 | #endif | ||
32 | |||
33 | if ((A_c == FP_CLS_INF && C_c == FP_CLS_ZERO) || | ||
34 | (A_c == FP_CLS_ZERO && C_c == FP_CLS_INF)) | ||
35 | ret |= EFLAG_VXIMZ; | ||
36 | |||
37 | FP_MUL_D(T, A, C); | ||
38 | |||
39 | if (T_s != B_s && T_c == FP_CLS_INF && B_c == FP_CLS_INF) | ||
40 | ret |= EFLAG_VXISI; | ||
41 | |||
42 | FP_ADD_D(R, T, B); | ||
43 | |||
44 | if (R_c != FP_CLS_NAN) | ||
45 | R_s ^= 1; | ||
46 | |||
47 | #ifdef DEBUG | ||
48 | printk("D: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c); | ||
49 | #endif | ||
50 | |||
51 | return (ret | __FP_PACK_DS(frD, R)); | ||
52 | } | ||
diff --git a/arch/powerpc/math-emu/fnmsub.c b/arch/powerpc/math-emu/fnmsub.c new file mode 100644 index 000000000000..f1ca7482b5f0 --- /dev/null +++ b/arch/powerpc/math-emu/fnmsub.c | |||
@@ -0,0 +1,54 @@ | |||
1 | #include <linux/types.h> | ||
2 | #include <linux/errno.h> | ||
3 | #include <asm/uaccess.h> | ||
4 | |||
5 | #include "soft-fp.h" | ||
6 | #include "double.h" | ||
7 | |||
8 | int | ||
9 | fnmsub(void *frD, void *frA, void *frB, void *frC) | ||
10 | { | ||
11 | FP_DECL_D(R); | ||
12 | FP_DECL_D(A); | ||
13 | FP_DECL_D(B); | ||
14 | FP_DECL_D(C); | ||
15 | FP_DECL_D(T); | ||
16 | int ret = 0; | ||
17 | |||
18 | #ifdef DEBUG | ||
19 | printk("%s: %p %p %p %p\n", __FUNCTION__, frD, frA, frB, frC); | ||
20 | #endif | ||
21 | |||
22 | __FP_UNPACK_D(A, frA); | ||
23 | __FP_UNPACK_D(B, frB); | ||
24 | __FP_UNPACK_D(C, frC); | ||
25 | |||
26 | #ifdef DEBUG | ||
27 | printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c); | ||
28 | printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c); | ||
29 | printk("C: %ld %lu %lu %ld (%ld)\n", C_s, C_f1, C_f0, C_e, C_c); | ||
30 | #endif | ||
31 | |||
32 | if ((A_c == FP_CLS_INF && C_c == FP_CLS_ZERO) || | ||
33 | (A_c == FP_CLS_ZERO && C_c == FP_CLS_INF)) | ||
34 | ret |= EFLAG_VXIMZ; | ||
35 | |||
36 | FP_MUL_D(T, A, C); | ||
37 | |||
38 | if (B_c != FP_CLS_NAN) | ||
39 | B_s ^= 1; | ||
40 | |||
41 | if (T_s != B_s && T_c == FP_CLS_INF && B_c == FP_CLS_INF) | ||
42 | ret |= EFLAG_VXISI; | ||
43 | |||
44 | FP_ADD_D(R, T, B); | ||
45 | |||
46 | if (R_c != FP_CLS_NAN) | ||
47 | R_s ^= 1; | ||
48 | |||
49 | #ifdef DEBUG | ||
50 | printk("D: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c); | ||
51 | #endif | ||
52 | |||
53 | return (ret | __FP_PACK_D(frD, R)); | ||
54 | } | ||
diff --git a/arch/powerpc/math-emu/fnmsubs.c b/arch/powerpc/math-emu/fnmsubs.c new file mode 100644 index 000000000000..5c9a09a87dc7 --- /dev/null +++ b/arch/powerpc/math-emu/fnmsubs.c | |||
@@ -0,0 +1,55 @@ | |||
1 | #include <linux/types.h> | ||
2 | #include <linux/errno.h> | ||
3 | #include <asm/uaccess.h> | ||
4 | |||
5 | #include "soft-fp.h" | ||
6 | #include "double.h" | ||
7 | #include "single.h" | ||
8 | |||
9 | int | ||
10 | fnmsubs(void *frD, void *frA, void *frB, void *frC) | ||
11 | { | ||
12 | FP_DECL_D(R); | ||
13 | FP_DECL_D(A); | ||
14 | FP_DECL_D(B); | ||
15 | FP_DECL_D(C); | ||
16 | FP_DECL_D(T); | ||
17 | int ret = 0; | ||
18 | |||
19 | #ifdef DEBUG | ||
20 | printk("%s: %p %p %p %p\n", __FUNCTION__, frD, frA, frB, frC); | ||
21 | #endif | ||
22 | |||
23 | __FP_UNPACK_D(A, frA); | ||
24 | __FP_UNPACK_D(B, frB); | ||
25 | __FP_UNPACK_D(C, frC); | ||
26 | |||
27 | #ifdef DEBUG | ||
28 | printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c); | ||
29 | printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c); | ||
30 | printk("C: %ld %lu %lu %ld (%ld)\n", C_s, C_f1, C_f0, C_e, C_c); | ||
31 | #endif | ||
32 | |||
33 | if ((A_c == FP_CLS_INF && C_c == FP_CLS_ZERO) || | ||
34 | (A_c == FP_CLS_ZERO && C_c == FP_CLS_INF)) | ||
35 | ret |= EFLAG_VXIMZ; | ||
36 | |||
37 | FP_MUL_D(T, A, C); | ||
38 | |||
39 | if (B_c != FP_CLS_NAN) | ||
40 | B_s ^= 1; | ||
41 | |||
42 | if (T_s != B_s && T_c == FP_CLS_INF && B_c == FP_CLS_INF) | ||
43 | ret |= EFLAG_VXISI; | ||
44 | |||
45 | FP_ADD_D(R, T, B); | ||
46 | |||
47 | if (R_c != FP_CLS_NAN) | ||
48 | R_s ^= 1; | ||
49 | |||
50 | #ifdef DEBUG | ||
51 | printk("D: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c); | ||
52 | #endif | ||
53 | |||
54 | return (ret | __FP_PACK_DS(frD, R)); | ||
55 | } | ||
diff --git a/arch/powerpc/math-emu/fres.c b/arch/powerpc/math-emu/fres.c new file mode 100644 index 000000000000..ec11e46d20af --- /dev/null +++ b/arch/powerpc/math-emu/fres.c | |||
@@ -0,0 +1,12 @@ | |||
1 | #include <linux/types.h> | ||
2 | #include <linux/errno.h> | ||
3 | #include <asm/uaccess.h> | ||
4 | |||
5 | int | ||
6 | fres(void *frD, void *frB) | ||
7 | { | ||
8 | #ifdef DEBUG | ||
9 | printk("%s: %p %p\n", __FUNCTION__, frD, frB); | ||
10 | #endif | ||
11 | return -ENOSYS; | ||
12 | } | ||
diff --git a/arch/powerpc/math-emu/frsp.c b/arch/powerpc/math-emu/frsp.c new file mode 100644 index 000000000000..d879b2a3d0c9 --- /dev/null +++ b/arch/powerpc/math-emu/frsp.c | |||
@@ -0,0 +1,25 @@ | |||
1 | #include <linux/types.h> | ||
2 | #include <linux/errno.h> | ||
3 | #include <asm/uaccess.h> | ||
4 | |||
5 | #include "soft-fp.h" | ||
6 | #include "double.h" | ||
7 | #include "single.h" | ||
8 | |||
9 | int | ||
10 | frsp(void *frD, void *frB) | ||
11 | { | ||
12 | FP_DECL_D(B); | ||
13 | |||
14 | #ifdef DEBUG | ||
15 | printk("%s: D %p, B %p\n", __FUNCTION__, frD, frB); | ||
16 | #endif | ||
17 | |||
18 | __FP_UNPACK_D(B, frB); | ||
19 | |||
20 | #ifdef DEBUG | ||
21 | printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c); | ||
22 | #endif | ||
23 | |||
24 | return __FP_PACK_DS(frD, B); | ||
25 | } | ||
diff --git a/arch/powerpc/math-emu/frsqrte.c b/arch/powerpc/math-emu/frsqrte.c new file mode 100644 index 000000000000..a11ae1829850 --- /dev/null +++ b/arch/powerpc/math-emu/frsqrte.c | |||
@@ -0,0 +1,12 @@ | |||
1 | #include <linux/types.h> | ||
2 | #include <linux/errno.h> | ||
3 | #include <asm/uaccess.h> | ||
4 | |||
5 | int | ||
6 | frsqrte(void *frD, void *frB) | ||
7 | { | ||
8 | #ifdef DEBUG | ||
9 | printk("%s: %p %p\n", __FUNCTION__, frD, frB); | ||
10 | #endif | ||
11 | return 0; | ||
12 | } | ||
diff --git a/arch/powerpc/math-emu/fsel.c b/arch/powerpc/math-emu/fsel.c new file mode 100644 index 000000000000..e36e6e72819a --- /dev/null +++ b/arch/powerpc/math-emu/fsel.c | |||
@@ -0,0 +1,38 @@ | |||
1 | #include <linux/types.h> | ||
2 | #include <linux/errno.h> | ||
3 | #include <asm/uaccess.h> | ||
4 | |||
5 | #include "soft-fp.h" | ||
6 | #include "double.h" | ||
7 | |||
8 | int | ||
9 | fsel(u32 *frD, void *frA, u32 *frB, u32 *frC) | ||
10 | { | ||
11 | FP_DECL_D(A); | ||
12 | |||
13 | #ifdef DEBUG | ||
14 | printk("%s: %p %p %p %p\n", __FUNCTION__, frD, frA, frB, frC); | ||
15 | #endif | ||
16 | |||
17 | __FP_UNPACK_D(A, frA); | ||
18 | |||
19 | #ifdef DEBUG | ||
20 | printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c); | ||
21 | printk("B: %08x %08x\n", frB[0], frB[1]); | ||
22 | printk("C: %08x %08x\n", frC[0], frC[1]); | ||
23 | #endif | ||
24 | |||
25 | if (A_c == FP_CLS_NAN || (A_c != FP_CLS_ZERO && A_s)) { | ||
26 | frD[0] = frB[0]; | ||
27 | frD[1] = frB[1]; | ||
28 | } else { | ||
29 | frD[0] = frC[0]; | ||
30 | frD[1] = frC[1]; | ||
31 | } | ||
32 | |||
33 | #ifdef DEBUG | ||
34 | printk("D: %08x.%08x\n", frD[0], frD[1]); | ||
35 | #endif | ||
36 | |||
37 | return 0; | ||
38 | } | ||
diff --git a/arch/powerpc/math-emu/fsqrt.c b/arch/powerpc/math-emu/fsqrt.c new file mode 100644 index 000000000000..6f8319f64a8a --- /dev/null +++ b/arch/powerpc/math-emu/fsqrt.c | |||
@@ -0,0 +1,37 @@ | |||
1 | #include <linux/types.h> | ||
2 | #include <linux/errno.h> | ||
3 | #include <asm/uaccess.h> | ||
4 | |||
5 | #include "soft-fp.h" | ||
6 | #include "double.h" | ||
7 | |||
8 | int | ||
9 | fsqrt(void *frD, void *frB) | ||
10 | { | ||
11 | FP_DECL_D(B); | ||
12 | FP_DECL_D(R); | ||
13 | int ret = 0; | ||
14 | |||
15 | #ifdef DEBUG | ||
16 | printk("%s: %p %p %p %p\n", __FUNCTION__, frD, frB); | ||
17 | #endif | ||
18 | |||
19 | __FP_UNPACK_D(B, frB); | ||
20 | |||
21 | #ifdef DEBUG | ||
22 | printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c); | ||
23 | #endif | ||
24 | |||
25 | if (B_s && B_c != FP_CLS_ZERO) | ||
26 | ret |= EFLAG_VXSQRT; | ||
27 | if (B_c == FP_CLS_NAN) | ||
28 | ret |= EFLAG_VXSNAN; | ||
29 | |||
30 | FP_SQRT_D(R, B); | ||
31 | |||
32 | #ifdef DEBUG | ||
33 | printk("R: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c); | ||
34 | #endif | ||
35 | |||
36 | return (ret | __FP_PACK_D(frD, R)); | ||
37 | } | ||
diff --git a/arch/powerpc/math-emu/fsqrts.c b/arch/powerpc/math-emu/fsqrts.c new file mode 100644 index 000000000000..3b2b1cf55c12 --- /dev/null +++ b/arch/powerpc/math-emu/fsqrts.c | |||
@@ -0,0 +1,38 @@ | |||
1 | #include <linux/types.h> | ||
2 | #include <linux/errno.h> | ||
3 | #include <asm/uaccess.h> | ||
4 | |||
5 | #include "soft-fp.h" | ||
6 | #include "double.h" | ||
7 | #include "single.h" | ||
8 | |||
9 | int | ||
10 | fsqrts(void *frD, void *frB) | ||
11 | { | ||
12 | FP_DECL_D(B); | ||
13 | FP_DECL_D(R); | ||
14 | int ret = 0; | ||
15 | |||
16 | #ifdef DEBUG | ||
17 | printk("%s: %p %p %p %p\n", __FUNCTION__, frD, frB); | ||
18 | #endif | ||
19 | |||
20 | __FP_UNPACK_D(B, frB); | ||
21 | |||
22 | #ifdef DEBUG | ||
23 | printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c); | ||
24 | #endif | ||
25 | |||
26 | if (B_s && B_c != FP_CLS_ZERO) | ||
27 | ret |= EFLAG_VXSQRT; | ||
28 | if (B_c == FP_CLS_NAN) | ||
29 | ret |= EFLAG_VXSNAN; | ||
30 | |||
31 | FP_SQRT_D(R, B); | ||
32 | |||
33 | #ifdef DEBUG | ||
34 | printk("R: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c); | ||
35 | #endif | ||
36 | |||
37 | return (ret | __FP_PACK_DS(frD, R)); | ||
38 | } | ||
diff --git a/arch/powerpc/math-emu/fsub.c b/arch/powerpc/math-emu/fsub.c new file mode 100644 index 000000000000..956679042bb2 --- /dev/null +++ b/arch/powerpc/math-emu/fsub.c | |||
@@ -0,0 +1,41 @@ | |||
1 | #include <linux/types.h> | ||
2 | #include <linux/errno.h> | ||
3 | #include <asm/uaccess.h> | ||
4 | |||
5 | #include "soft-fp.h" | ||
6 | #include "double.h" | ||
7 | |||
8 | int | ||
9 | fsub(void *frD, void *frA, void *frB) | ||
10 | { | ||
11 | FP_DECL_D(A); | ||
12 | FP_DECL_D(B); | ||
13 | FP_DECL_D(R); | ||
14 | int ret = 0; | ||
15 | |||
16 | #ifdef DEBUG | ||
17 | printk("%s: %p %p %p\n", __FUNCTION__, frD, frA, frB); | ||
18 | #endif | ||
19 | |||
20 | __FP_UNPACK_D(A, frA); | ||
21 | __FP_UNPACK_D(B, frB); | ||
22 | |||
23 | #ifdef DEBUG | ||
24 | printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c); | ||
25 | printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c); | ||
26 | #endif | ||
27 | |||
28 | if (B_c != FP_CLS_NAN) | ||
29 | B_s ^= 1; | ||
30 | |||
31 | if (A_s != B_s && A_c == FP_CLS_INF && B_c == FP_CLS_INF) | ||
32 | ret |= EFLAG_VXISI; | ||
33 | |||
34 | FP_ADD_D(R, A, B); | ||
35 | |||
36 | #ifdef DEBUG | ||
37 | printk("D: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c); | ||
38 | #endif | ||
39 | |||
40 | return (ret | __FP_PACK_D(frD, R)); | ||
41 | } | ||
diff --git a/arch/powerpc/math-emu/fsubs.c b/arch/powerpc/math-emu/fsubs.c new file mode 100644 index 000000000000..3428117dfe8c --- /dev/null +++ b/arch/powerpc/math-emu/fsubs.c | |||
@@ -0,0 +1,42 @@ | |||
1 | #include <linux/types.h> | ||
2 | #include <linux/errno.h> | ||
3 | #include <asm/uaccess.h> | ||
4 | |||
5 | #include "soft-fp.h" | ||
6 | #include "double.h" | ||
7 | #include "single.h" | ||
8 | |||
9 | int | ||
10 | fsubs(void *frD, void *frA, void *frB) | ||
11 | { | ||
12 | FP_DECL_D(A); | ||
13 | FP_DECL_D(B); | ||
14 | FP_DECL_D(R); | ||
15 | int ret = 0; | ||
16 | |||
17 | #ifdef DEBUG | ||
18 | printk("%s: %p %p %p\n", __FUNCTION__, frD, frA, frB); | ||
19 | #endif | ||
20 | |||
21 | __FP_UNPACK_D(A, frA); | ||
22 | __FP_UNPACK_D(B, frB); | ||
23 | |||
24 | #ifdef DEBUG | ||
25 | printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c); | ||
26 | printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c); | ||
27 | #endif | ||
28 | |||
29 | if (B_c != FP_CLS_NAN) | ||
30 | B_s ^= 1; | ||
31 | |||
32 | if (A_s != B_s && A_c == FP_CLS_INF && B_c == FP_CLS_INF) | ||
33 | ret |= EFLAG_VXISI; | ||
34 | |||
35 | FP_ADD_D(R, A, B); | ||
36 | |||
37 | #ifdef DEBUG | ||
38 | printk("D: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c); | ||
39 | #endif | ||
40 | |||
41 | return (ret | __FP_PACK_DS(frD, R)); | ||
42 | } | ||
diff --git a/arch/powerpc/math-emu/lfd.c b/arch/powerpc/math-emu/lfd.c new file mode 100644 index 000000000000..7d38101c329b --- /dev/null +++ b/arch/powerpc/math-emu/lfd.c | |||
@@ -0,0 +1,19 @@ | |||
1 | #include <linux/types.h> | ||
2 | #include <linux/errno.h> | ||
3 | #include <asm/uaccess.h> | ||
4 | |||
5 | #include "sfp-machine.h" | ||
6 | #include "double.h" | ||
7 | |||
8 | int | ||
9 | lfd(void *frD, void *ea) | ||
10 | { | ||
11 | if (copy_from_user(frD, ea, sizeof(double))) | ||
12 | return -EFAULT; | ||
13 | #ifdef DEBUG | ||
14 | printk("%s: D %p, ea %p: ", __FUNCTION__, frD, ea); | ||
15 | dump_double(frD); | ||
16 | printk("\n"); | ||
17 | #endif | ||
18 | return 0; | ||
19 | } | ||
diff --git a/arch/powerpc/math-emu/lfs.c b/arch/powerpc/math-emu/lfs.c new file mode 100644 index 000000000000..c86dee3d7655 --- /dev/null +++ b/arch/powerpc/math-emu/lfs.c | |||
@@ -0,0 +1,37 @@ | |||
1 | #include <linux/types.h> | ||
2 | #include <linux/errno.h> | ||
3 | #include <asm/uaccess.h> | ||
4 | |||
5 | #include "soft-fp.h" | ||
6 | #include "double.h" | ||
7 | #include "single.h" | ||
8 | |||
9 | int | ||
10 | lfs(void *frD, void *ea) | ||
11 | { | ||
12 | FP_DECL_D(R); | ||
13 | FP_DECL_S(A); | ||
14 | float f; | ||
15 | |||
16 | #ifdef DEBUG | ||
17 | printk("%s: D %p, ea %p\n", __FUNCTION__, frD, ea); | ||
18 | #endif | ||
19 | |||
20 | if (copy_from_user(&f, ea, sizeof(float))) | ||
21 | return -EFAULT; | ||
22 | |||
23 | __FP_UNPACK_S(A, &f); | ||
24 | |||
25 | #ifdef DEBUG | ||
26 | printk("A: %ld %lu %ld (%ld) [%08lx]\n", A_s, A_f, A_e, A_c, | ||
27 | *(unsigned long *)&f); | ||
28 | #endif | ||
29 | |||
30 | FP_CONV(D, S, 2, 1, R, A); | ||
31 | |||
32 | #ifdef DEBUG | ||
33 | printk("R: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c); | ||
34 | #endif | ||
35 | |||
36 | return __FP_PACK_D(frD, R); | ||
37 | } | ||
diff --git a/arch/powerpc/math-emu/math.c b/arch/powerpc/math-emu/math.c new file mode 100644 index 000000000000..589153472761 --- /dev/null +++ b/arch/powerpc/math-emu/math.c | |||
@@ -0,0 +1,483 @@ | |||
1 | /* | ||
2 | * Copyright (C) 1999 Eddie C. Dost (ecd@atecom.com) | ||
3 | */ | ||
4 | |||
5 | #include <linux/config.h> | ||
6 | #include <linux/types.h> | ||
7 | #include <linux/sched.h> | ||
8 | |||
9 | #include <asm/uaccess.h> | ||
10 | #include <asm/reg.h> | ||
11 | |||
12 | #include "sfp-machine.h" | ||
13 | #include "double.h" | ||
14 | |||
15 | #define FLOATFUNC(x) extern int x(void *, void *, void *, void *) | ||
16 | |||
17 | FLOATFUNC(fadd); | ||
18 | FLOATFUNC(fadds); | ||
19 | FLOATFUNC(fdiv); | ||
20 | FLOATFUNC(fdivs); | ||
21 | FLOATFUNC(fmul); | ||
22 | FLOATFUNC(fmuls); | ||
23 | FLOATFUNC(fsub); | ||
24 | FLOATFUNC(fsubs); | ||
25 | |||
26 | FLOATFUNC(fmadd); | ||
27 | FLOATFUNC(fmadds); | ||
28 | FLOATFUNC(fmsub); | ||
29 | FLOATFUNC(fmsubs); | ||
30 | FLOATFUNC(fnmadd); | ||
31 | FLOATFUNC(fnmadds); | ||
32 | FLOATFUNC(fnmsub); | ||
33 | FLOATFUNC(fnmsubs); | ||
34 | |||
35 | FLOATFUNC(fctiw); | ||
36 | FLOATFUNC(fctiwz); | ||
37 | FLOATFUNC(frsp); | ||
38 | |||
39 | FLOATFUNC(fcmpo); | ||
40 | FLOATFUNC(fcmpu); | ||
41 | |||
42 | FLOATFUNC(mcrfs); | ||
43 | FLOATFUNC(mffs); | ||
44 | FLOATFUNC(mtfsb0); | ||
45 | FLOATFUNC(mtfsb1); | ||
46 | FLOATFUNC(mtfsf); | ||
47 | FLOATFUNC(mtfsfi); | ||
48 | |||
49 | FLOATFUNC(lfd); | ||
50 | FLOATFUNC(lfs); | ||
51 | |||
52 | FLOATFUNC(stfd); | ||
53 | FLOATFUNC(stfs); | ||
54 | FLOATFUNC(stfiwx); | ||
55 | |||
56 | FLOATFUNC(fabs); | ||
57 | FLOATFUNC(fmr); | ||
58 | FLOATFUNC(fnabs); | ||
59 | FLOATFUNC(fneg); | ||
60 | |||
61 | /* Optional */ | ||
62 | FLOATFUNC(fres); | ||
63 | FLOATFUNC(frsqrte); | ||
64 | FLOATFUNC(fsel); | ||
65 | FLOATFUNC(fsqrt); | ||
66 | FLOATFUNC(fsqrts); | ||
67 | |||
68 | |||
69 | #define OP31 0x1f /* 31 */ | ||
70 | #define LFS 0x30 /* 48 */ | ||
71 | #define LFSU 0x31 /* 49 */ | ||
72 | #define LFD 0x32 /* 50 */ | ||
73 | #define LFDU 0x33 /* 51 */ | ||
74 | #define STFS 0x34 /* 52 */ | ||
75 | #define STFSU 0x35 /* 53 */ | ||
76 | #define STFD 0x36 /* 54 */ | ||
77 | #define STFDU 0x37 /* 55 */ | ||
78 | #define OP59 0x3b /* 59 */ | ||
79 | #define OP63 0x3f /* 63 */ | ||
80 | |||
81 | /* Opcode 31: */ | ||
82 | /* X-Form: */ | ||
83 | #define LFSX 0x217 /* 535 */ | ||
84 | #define LFSUX 0x237 /* 567 */ | ||
85 | #define LFDX 0x257 /* 599 */ | ||
86 | #define LFDUX 0x277 /* 631 */ | ||
87 | #define STFSX 0x297 /* 663 */ | ||
88 | #define STFSUX 0x2b7 /* 695 */ | ||
89 | #define STFDX 0x2d7 /* 727 */ | ||
90 | #define STFDUX 0x2f7 /* 759 */ | ||
91 | #define STFIWX 0x3d7 /* 983 */ | ||
92 | |||
93 | /* Opcode 59: */ | ||
94 | /* A-Form: */ | ||
95 | #define FDIVS 0x012 /* 18 */ | ||
96 | #define FSUBS 0x014 /* 20 */ | ||
97 | #define FADDS 0x015 /* 21 */ | ||
98 | #define FSQRTS 0x016 /* 22 */ | ||
99 | #define FRES 0x018 /* 24 */ | ||
100 | #define FMULS 0x019 /* 25 */ | ||
101 | #define FMSUBS 0x01c /* 28 */ | ||
102 | #define FMADDS 0x01d /* 29 */ | ||
103 | #define FNMSUBS 0x01e /* 30 */ | ||
104 | #define FNMADDS 0x01f /* 31 */ | ||
105 | |||
106 | /* Opcode 63: */ | ||
107 | /* A-Form: */ | ||
108 | #define FDIV 0x012 /* 18 */ | ||
109 | #define FSUB 0x014 /* 20 */ | ||
110 | #define FADD 0x015 /* 21 */ | ||
111 | #define FSQRT 0x016 /* 22 */ | ||
112 | #define FSEL 0x017 /* 23 */ | ||
113 | #define FMUL 0x019 /* 25 */ | ||
114 | #define FRSQRTE 0x01a /* 26 */ | ||
115 | #define FMSUB 0x01c /* 28 */ | ||
116 | #define FMADD 0x01d /* 29 */ | ||
117 | #define FNMSUB 0x01e /* 30 */ | ||
118 | #define FNMADD 0x01f /* 31 */ | ||
119 | |||
120 | /* X-Form: */ | ||
121 | #define FCMPU 0x000 /* 0 */ | ||
122 | #define FRSP 0x00c /* 12 */ | ||
123 | #define FCTIW 0x00e /* 14 */ | ||
124 | #define FCTIWZ 0x00f /* 15 */ | ||
125 | #define FCMPO 0x020 /* 32 */ | ||
126 | #define MTFSB1 0x026 /* 38 */ | ||
127 | #define FNEG 0x028 /* 40 */ | ||
128 | #define MCRFS 0x040 /* 64 */ | ||
129 | #define MTFSB0 0x046 /* 70 */ | ||
130 | #define FMR 0x048 /* 72 */ | ||
131 | #define MTFSFI 0x086 /* 134 */ | ||
132 | #define FNABS 0x088 /* 136 */ | ||
133 | #define FABS 0x108 /* 264 */ | ||
134 | #define MFFS 0x247 /* 583 */ | ||
135 | #define MTFSF 0x2c7 /* 711 */ | ||
136 | |||
137 | |||
138 | #define AB 2 | ||
139 | #define AC 3 | ||
140 | #define ABC 4 | ||
141 | #define D 5 | ||
142 | #define DU 6 | ||
143 | #define X 7 | ||
144 | #define XA 8 | ||
145 | #define XB 9 | ||
146 | #define XCR 11 | ||
147 | #define XCRB 12 | ||
148 | #define XCRI 13 | ||
149 | #define XCRL 16 | ||
150 | #define XE 14 | ||
151 | #define XEU 15 | ||
152 | #define XFLB 10 | ||
153 | |||
154 | #ifdef CONFIG_MATH_EMULATION | ||
155 | static int | ||
156 | record_exception(struct pt_regs *regs, int eflag) | ||
157 | { | ||
158 | u32 fpscr; | ||
159 | |||
160 | fpscr = __FPU_FPSCR; | ||
161 | |||
162 | if (eflag) { | ||
163 | fpscr |= FPSCR_FX; | ||
164 | if (eflag & EFLAG_OVERFLOW) | ||
165 | fpscr |= FPSCR_OX; | ||
166 | if (eflag & EFLAG_UNDERFLOW) | ||
167 | fpscr |= FPSCR_UX; | ||
168 | if (eflag & EFLAG_DIVZERO) | ||
169 | fpscr |= FPSCR_ZX; | ||
170 | if (eflag & EFLAG_INEXACT) | ||
171 | fpscr |= FPSCR_XX; | ||
172 | if (eflag & EFLAG_VXSNAN) | ||
173 | fpscr |= FPSCR_VXSNAN; | ||
174 | if (eflag & EFLAG_VXISI) | ||
175 | fpscr |= FPSCR_VXISI; | ||
176 | if (eflag & EFLAG_VXIDI) | ||
177 | fpscr |= FPSCR_VXIDI; | ||
178 | if (eflag & EFLAG_VXZDZ) | ||
179 | fpscr |= FPSCR_VXZDZ; | ||
180 | if (eflag & EFLAG_VXIMZ) | ||
181 | fpscr |= FPSCR_VXIMZ; | ||
182 | if (eflag & EFLAG_VXVC) | ||
183 | fpscr |= FPSCR_VXVC; | ||
184 | if (eflag & EFLAG_VXSOFT) | ||
185 | fpscr |= FPSCR_VXSOFT; | ||
186 | if (eflag & EFLAG_VXSQRT) | ||
187 | fpscr |= FPSCR_VXSQRT; | ||
188 | if (eflag & EFLAG_VXCVI) | ||
189 | fpscr |= FPSCR_VXCVI; | ||
190 | } | ||
191 | |||
192 | fpscr &= ~(FPSCR_VX); | ||
193 | if (fpscr & (FPSCR_VXSNAN | FPSCR_VXISI | FPSCR_VXIDI | | ||
194 | FPSCR_VXZDZ | FPSCR_VXIMZ | FPSCR_VXVC | | ||
195 | FPSCR_VXSOFT | FPSCR_VXSQRT | FPSCR_VXCVI)) | ||
196 | fpscr |= FPSCR_VX; | ||
197 | |||
198 | fpscr &= ~(FPSCR_FEX); | ||
199 | if (((fpscr & FPSCR_VX) && (fpscr & FPSCR_VE)) || | ||
200 | ((fpscr & FPSCR_OX) && (fpscr & FPSCR_OE)) || | ||
201 | ((fpscr & FPSCR_UX) && (fpscr & FPSCR_UE)) || | ||
202 | ((fpscr & FPSCR_ZX) && (fpscr & FPSCR_ZE)) || | ||
203 | ((fpscr & FPSCR_XX) && (fpscr & FPSCR_XE))) | ||
204 | fpscr |= FPSCR_FEX; | ||
205 | |||
206 | __FPU_FPSCR = fpscr; | ||
207 | |||
208 | return (fpscr & FPSCR_FEX) ? 1 : 0; | ||
209 | } | ||
210 | #endif /* CONFIG_MATH_EMULATION */ | ||
211 | |||
212 | int | ||
213 | do_mathemu(struct pt_regs *regs) | ||
214 | { | ||
215 | void *op0 = 0, *op1 = 0, *op2 = 0, *op3 = 0; | ||
216 | unsigned long pc = regs->nip; | ||
217 | signed short sdisp; | ||
218 | u32 insn = 0; | ||
219 | int idx = 0; | ||
220 | #ifdef CONFIG_MATH_EMULATION | ||
221 | int (*func)(void *, void *, void *, void *); | ||
222 | int type = 0; | ||
223 | int eflag, trap; | ||
224 | #endif | ||
225 | |||
226 | if (get_user(insn, (u32 *)pc)) | ||
227 | return -EFAULT; | ||
228 | |||
229 | #ifndef CONFIG_MATH_EMULATION | ||
230 | switch (insn >> 26) { | ||
231 | case LFD: | ||
232 | idx = (insn >> 16) & 0x1f; | ||
233 | sdisp = (insn & 0xffff); | ||
234 | op0 = (void *)¤t->thread.fpr[(insn >> 21) & 0x1f]; | ||
235 | op1 = (void *)((idx ? regs->gpr[idx] : 0) + sdisp); | ||
236 | lfd(op0, op1, op2, op3); | ||
237 | break; | ||
238 | case LFDU: | ||
239 | idx = (insn >> 16) & 0x1f; | ||
240 | sdisp = (insn & 0xffff); | ||
241 | op0 = (void *)¤t->thread.fpr[(insn >> 21) & 0x1f]; | ||
242 | op1 = (void *)((idx ? regs->gpr[idx] : 0) + sdisp); | ||
243 | lfd(op0, op1, op2, op3); | ||
244 | regs->gpr[idx] = (unsigned long)op1; | ||
245 | break; | ||
246 | case STFD: | ||
247 | idx = (insn >> 16) & 0x1f; | ||
248 | sdisp = (insn & 0xffff); | ||
249 | op0 = (void *)¤t->thread.fpr[(insn >> 21) & 0x1f]; | ||
250 | op1 = (void *)((idx ? regs->gpr[idx] : 0) + sdisp); | ||
251 | stfd(op0, op1, op2, op3); | ||
252 | break; | ||
253 | case STFDU: | ||
254 | idx = (insn >> 16) & 0x1f; | ||
255 | sdisp = (insn & 0xffff); | ||
256 | op0 = (void *)¤t->thread.fpr[(insn >> 21) & 0x1f]; | ||
257 | op1 = (void *)((idx ? regs->gpr[idx] : 0) + sdisp); | ||
258 | stfd(op0, op1, op2, op3); | ||
259 | regs->gpr[idx] = (unsigned long)op1; | ||
260 | break; | ||
261 | case OP63: | ||
262 | op0 = (void *)¤t->thread.fpr[(insn >> 21) & 0x1f]; | ||
263 | op1 = (void *)¤t->thread.fpr[(insn >> 11) & 0x1f]; | ||
264 | fmr(op0, op1, op2, op3); | ||
265 | break; | ||
266 | default: | ||
267 | goto illegal; | ||
268 | } | ||
269 | #else /* CONFIG_MATH_EMULATION */ | ||
270 | switch (insn >> 26) { | ||
271 | case LFS: func = lfs; type = D; break; | ||
272 | case LFSU: func = lfs; type = DU; break; | ||
273 | case LFD: func = lfd; type = D; break; | ||
274 | case LFDU: func = lfd; type = DU; break; | ||
275 | case STFS: func = stfs; type = D; break; | ||
276 | case STFSU: func = stfs; type = DU; break; | ||
277 | case STFD: func = stfd; type = D; break; | ||
278 | case STFDU: func = stfd; type = DU; break; | ||
279 | |||
280 | case OP31: | ||
281 | switch ((insn >> 1) & 0x3ff) { | ||
282 | case LFSX: func = lfs; type = XE; break; | ||
283 | case LFSUX: func = lfs; type = XEU; break; | ||
284 | case LFDX: func = lfd; type = XE; break; | ||
285 | case LFDUX: func = lfd; type = XEU; break; | ||
286 | case STFSX: func = stfs; type = XE; break; | ||
287 | case STFSUX: func = stfs; type = XEU; break; | ||
288 | case STFDX: func = stfd; type = XE; break; | ||
289 | case STFDUX: func = stfd; type = XEU; break; | ||
290 | case STFIWX: func = stfiwx; type = XE; break; | ||
291 | default: | ||
292 | goto illegal; | ||
293 | } | ||
294 | break; | ||
295 | |||
296 | case OP59: | ||
297 | switch ((insn >> 1) & 0x1f) { | ||
298 | case FDIVS: func = fdivs; type = AB; break; | ||
299 | case FSUBS: func = fsubs; type = AB; break; | ||
300 | case FADDS: func = fadds; type = AB; break; | ||
301 | case FSQRTS: func = fsqrts; type = AB; break; | ||
302 | case FRES: func = fres; type = AB; break; | ||
303 | case FMULS: func = fmuls; type = AC; break; | ||
304 | case FMSUBS: func = fmsubs; type = ABC; break; | ||
305 | case FMADDS: func = fmadds; type = ABC; break; | ||
306 | case FNMSUBS: func = fnmsubs; type = ABC; break; | ||
307 | case FNMADDS: func = fnmadds; type = ABC; break; | ||
308 | default: | ||
309 | goto illegal; | ||
310 | } | ||
311 | break; | ||
312 | |||
313 | case OP63: | ||
314 | if (insn & 0x20) { | ||
315 | switch ((insn >> 1) & 0x1f) { | ||
316 | case FDIV: func = fdiv; type = AB; break; | ||
317 | case FSUB: func = fsub; type = AB; break; | ||
318 | case FADD: func = fadd; type = AB; break; | ||
319 | case FSQRT: func = fsqrt; type = AB; break; | ||
320 | case FSEL: func = fsel; type = ABC; break; | ||
321 | case FMUL: func = fmul; type = AC; break; | ||
322 | case FRSQRTE: func = frsqrte; type = AB; break; | ||
323 | case FMSUB: func = fmsub; type = ABC; break; | ||
324 | case FMADD: func = fmadd; type = ABC; break; | ||
325 | case FNMSUB: func = fnmsub; type = ABC; break; | ||
326 | case FNMADD: func = fnmadd; type = ABC; break; | ||
327 | default: | ||
328 | goto illegal; | ||
329 | } | ||
330 | break; | ||
331 | } | ||
332 | |||
333 | switch ((insn >> 1) & 0x3ff) { | ||
334 | case FCMPU: func = fcmpu; type = XCR; break; | ||
335 | case FRSP: func = frsp; type = XB; break; | ||
336 | case FCTIW: func = fctiw; type = XB; break; | ||
337 | case FCTIWZ: func = fctiwz; type = XB; break; | ||
338 | case FCMPO: func = fcmpo; type = XCR; break; | ||
339 | case MTFSB1: func = mtfsb1; type = XCRB; break; | ||
340 | case FNEG: func = fneg; type = XB; break; | ||
341 | case MCRFS: func = mcrfs; type = XCRL; break; | ||
342 | case MTFSB0: func = mtfsb0; type = XCRB; break; | ||
343 | case FMR: func = fmr; type = XB; break; | ||
344 | case MTFSFI: func = mtfsfi; type = XCRI; break; | ||
345 | case FNABS: func = fnabs; type = XB; break; | ||
346 | case FABS: func = fabs; type = XB; break; | ||
347 | case MFFS: func = mffs; type = X; break; | ||
348 | case MTFSF: func = mtfsf; type = XFLB; break; | ||
349 | default: | ||
350 | goto illegal; | ||
351 | } | ||
352 | break; | ||
353 | |||
354 | default: | ||
355 | goto illegal; | ||
356 | } | ||
357 | |||
358 | switch (type) { | ||
359 | case AB: | ||
360 | op0 = (void *)¤t->thread.fpr[(insn >> 21) & 0x1f]; | ||
361 | op1 = (void *)¤t->thread.fpr[(insn >> 16) & 0x1f]; | ||
362 | op2 = (void *)¤t->thread.fpr[(insn >> 11) & 0x1f]; | ||
363 | break; | ||
364 | |||
365 | case AC: | ||
366 | op0 = (void *)¤t->thread.fpr[(insn >> 21) & 0x1f]; | ||
367 | op1 = (void *)¤t->thread.fpr[(insn >> 16) & 0x1f]; | ||
368 | op2 = (void *)¤t->thread.fpr[(insn >> 6) & 0x1f]; | ||
369 | break; | ||
370 | |||
371 | case ABC: | ||
372 | op0 = (void *)¤t->thread.fpr[(insn >> 21) & 0x1f]; | ||
373 | op1 = (void *)¤t->thread.fpr[(insn >> 16) & 0x1f]; | ||
374 | op2 = (void *)¤t->thread.fpr[(insn >> 11) & 0x1f]; | ||
375 | op3 = (void *)¤t->thread.fpr[(insn >> 6) & 0x1f]; | ||
376 | break; | ||
377 | |||
378 | case D: | ||
379 | idx = (insn >> 16) & 0x1f; | ||
380 | sdisp = (insn & 0xffff); | ||
381 | op0 = (void *)¤t->thread.fpr[(insn >> 21) & 0x1f]; | ||
382 | op1 = (void *)((idx ? regs->gpr[idx] : 0) + sdisp); | ||
383 | break; | ||
384 | |||
385 | case DU: | ||
386 | idx = (insn >> 16) & 0x1f; | ||
387 | if (!idx) | ||
388 | goto illegal; | ||
389 | |||
390 | sdisp = (insn & 0xffff); | ||
391 | op0 = (void *)¤t->thread.fpr[(insn >> 21) & 0x1f]; | ||
392 | op1 = (void *)(regs->gpr[idx] + sdisp); | ||
393 | break; | ||
394 | |||
395 | case X: | ||
396 | op0 = (void *)¤t->thread.fpr[(insn >> 21) & 0x1f]; | ||
397 | break; | ||
398 | |||
399 | case XA: | ||
400 | op0 = (void *)¤t->thread.fpr[(insn >> 21) & 0x1f]; | ||
401 | op1 = (void *)¤t->thread.fpr[(insn >> 16) & 0x1f]; | ||
402 | break; | ||
403 | |||
404 | case XB: | ||
405 | op0 = (void *)¤t->thread.fpr[(insn >> 21) & 0x1f]; | ||
406 | op1 = (void *)¤t->thread.fpr[(insn >> 11) & 0x1f]; | ||
407 | break; | ||
408 | |||
409 | case XE: | ||
410 | idx = (insn >> 16) & 0x1f; | ||
411 | if (!idx) | ||
412 | goto illegal; | ||
413 | |||
414 | op0 = (void *)¤t->thread.fpr[(insn >> 21) & 0x1f]; | ||
415 | op1 = (void *)(regs->gpr[idx] + regs->gpr[(insn >> 11) & 0x1f]); | ||
416 | break; | ||
417 | |||
418 | case XEU: | ||
419 | idx = (insn >> 16) & 0x1f; | ||
420 | op0 = (void *)¤t->thread.fpr[(insn >> 21) & 0x1f]; | ||
421 | op1 = (void *)((idx ? regs->gpr[idx] : 0) | ||
422 | + regs->gpr[(insn >> 11) & 0x1f]); | ||
423 | break; | ||
424 | |||
425 | case XCR: | ||
426 | op0 = (void *)®s->ccr; | ||
427 | op1 = (void *)((insn >> 23) & 0x7); | ||
428 | op2 = (void *)¤t->thread.fpr[(insn >> 16) & 0x1f]; | ||
429 | op3 = (void *)¤t->thread.fpr[(insn >> 11) & 0x1f]; | ||
430 | break; | ||
431 | |||
432 | case XCRL: | ||
433 | op0 = (void *)®s->ccr; | ||
434 | op1 = (void *)((insn >> 23) & 0x7); | ||
435 | op2 = (void *)((insn >> 18) & 0x7); | ||
436 | break; | ||
437 | |||
438 | case XCRB: | ||
439 | op0 = (void *)((insn >> 21) & 0x1f); | ||
440 | break; | ||
441 | |||
442 | case XCRI: | ||
443 | op0 = (void *)((insn >> 23) & 0x7); | ||
444 | op1 = (void *)((insn >> 12) & 0xf); | ||
445 | break; | ||
446 | |||
447 | case XFLB: | ||
448 | op0 = (void *)((insn >> 17) & 0xff); | ||
449 | op1 = (void *)¤t->thread.fpr[(insn >> 11) & 0x1f]; | ||
450 | break; | ||
451 | |||
452 | default: | ||
453 | goto illegal; | ||
454 | } | ||
455 | |||
456 | eflag = func(op0, op1, op2, op3); | ||
457 | |||
458 | if (insn & 1) { | ||
459 | regs->ccr &= ~(0x0f000000); | ||
460 | regs->ccr |= (__FPU_FPSCR >> 4) & 0x0f000000; | ||
461 | } | ||
462 | |||
463 | trap = record_exception(regs, eflag); | ||
464 | if (trap) | ||
465 | return 1; | ||
466 | |||
467 | switch (type) { | ||
468 | case DU: | ||
469 | case XEU: | ||
470 | regs->gpr[idx] = (unsigned long)op1; | ||
471 | break; | ||
472 | |||
473 | default: | ||
474 | break; | ||
475 | } | ||
476 | #endif /* CONFIG_MATH_EMULATION */ | ||
477 | |||
478 | regs->nip += 4; | ||
479 | return 0; | ||
480 | |||
481 | illegal: | ||
482 | return -ENOSYS; | ||
483 | } | ||
diff --git a/arch/powerpc/math-emu/mcrfs.c b/arch/powerpc/math-emu/mcrfs.c new file mode 100644 index 000000000000..106dd912914b --- /dev/null +++ b/arch/powerpc/math-emu/mcrfs.c | |||
@@ -0,0 +1,31 @@ | |||
1 | #include <linux/types.h> | ||
2 | #include <linux/errno.h> | ||
3 | #include <asm/uaccess.h> | ||
4 | |||
5 | #include "soft-fp.h" | ||
6 | |||
7 | int | ||
8 | mcrfs(u32 *ccr, u32 crfD, u32 crfS) | ||
9 | { | ||
10 | u32 value, clear; | ||
11 | |||
12 | #ifdef DEBUG | ||
13 | printk("%s: %p (%08x) %d %d\n", __FUNCTION__, ccr, *ccr, crfD, crfS); | ||
14 | #endif | ||
15 | |||
16 | clear = 15 << ((7 - crfS) << 2); | ||
17 | if (!crfS) | ||
18 | clear = 0x90000000; | ||
19 | |||
20 | value = (__FPU_FPSCR >> ((7 - crfS) << 2)) & 15; | ||
21 | __FPU_FPSCR &= ~(clear); | ||
22 | |||
23 | *ccr &= ~(15 << ((7 - crfD) << 2)); | ||
24 | *ccr |= (value << ((7 - crfD) << 2)); | ||
25 | |||
26 | #ifdef DEBUG | ||
27 | printk("CR: %08x\n", __FUNCTION__, *ccr); | ||
28 | #endif | ||
29 | |||
30 | return 0; | ||
31 | } | ||
diff --git a/arch/powerpc/math-emu/mffs.c b/arch/powerpc/math-emu/mffs.c new file mode 100644 index 000000000000..f477c9170e75 --- /dev/null +++ b/arch/powerpc/math-emu/mffs.c | |||
@@ -0,0 +1,17 @@ | |||
1 | #include <linux/types.h> | ||
2 | #include <linux/errno.h> | ||
3 | #include <asm/uaccess.h> | ||
4 | |||
5 | #include "soft-fp.h" | ||
6 | |||
7 | int | ||
8 | mffs(u32 *frD) | ||
9 | { | ||
10 | frD[1] = __FPU_FPSCR; | ||
11 | |||
12 | #ifdef DEBUG | ||
13 | printk("%s: frD %p: %08x.%08x\n", __FUNCTION__, frD, frD[0], frD[1]); | ||
14 | #endif | ||
15 | |||
16 | return 0; | ||
17 | } | ||
diff --git a/arch/powerpc/math-emu/mtfsb0.c b/arch/powerpc/math-emu/mtfsb0.c new file mode 100644 index 000000000000..99bfd80f4af3 --- /dev/null +++ b/arch/powerpc/math-emu/mtfsb0.c | |||
@@ -0,0 +1,18 @@ | |||
1 | #include <linux/types.h> | ||
2 | #include <linux/errno.h> | ||
3 | #include <asm/uaccess.h> | ||
4 | |||
5 | #include "soft-fp.h" | ||
6 | |||
7 | int | ||
8 | mtfsb0(int crbD) | ||
9 | { | ||
10 | if ((crbD != 1) && (crbD != 2)) | ||
11 | __FPU_FPSCR &= ~(1 << (31 - crbD)); | ||
12 | |||
13 | #ifdef DEBUG | ||
14 | printk("%s: %d %08lx\n", __FUNCTION__, crbD, __FPU_FPSCR); | ||
15 | #endif | ||
16 | |||
17 | return 0; | ||
18 | } | ||
diff --git a/arch/powerpc/math-emu/mtfsb1.c b/arch/powerpc/math-emu/mtfsb1.c new file mode 100644 index 000000000000..3d9e7ed92d2b --- /dev/null +++ b/arch/powerpc/math-emu/mtfsb1.c | |||
@@ -0,0 +1,18 @@ | |||
1 | #include <linux/types.h> | ||
2 | #include <linux/errno.h> | ||
3 | #include <asm/uaccess.h> | ||
4 | |||
5 | #include "soft-fp.h" | ||
6 | |||
7 | int | ||
8 | mtfsb1(int crbD) | ||
9 | { | ||
10 | if ((crbD != 1) && (crbD != 2)) | ||
11 | __FPU_FPSCR |= (1 << (31 - crbD)); | ||
12 | |||
13 | #ifdef DEBUG | ||
14 | printk("%s: %d %08lx\n", __FUNCTION__, crbD, __FPU_FPSCR); | ||
15 | #endif | ||
16 | |||
17 | return 0; | ||
18 | } | ||
diff --git a/arch/powerpc/math-emu/mtfsf.c b/arch/powerpc/math-emu/mtfsf.c new file mode 100644 index 000000000000..d70cf714994c --- /dev/null +++ b/arch/powerpc/math-emu/mtfsf.c | |||
@@ -0,0 +1,45 @@ | |||
1 | #include <linux/types.h> | ||
2 | #include <linux/errno.h> | ||
3 | #include <asm/uaccess.h> | ||
4 | |||
5 | #include "soft-fp.h" | ||
6 | |||
7 | int | ||
8 | mtfsf(unsigned int FM, u32 *frB) | ||
9 | { | ||
10 | u32 mask; | ||
11 | |||
12 | if (FM == 0) | ||
13 | return 0; | ||
14 | |||
15 | if (FM == 0xff) | ||
16 | mask = 0x9fffffff; | ||
17 | else { | ||
18 | mask = 0; | ||
19 | if (FM & (1 << 0)) | ||
20 | mask |= 0x90000000; | ||
21 | if (FM & (1 << 1)) | ||
22 | mask |= 0x0f000000; | ||
23 | if (FM & (1 << 2)) | ||
24 | mask |= 0x00f00000; | ||
25 | if (FM & (1 << 3)) | ||
26 | mask |= 0x000f0000; | ||
27 | if (FM & (1 << 4)) | ||
28 | mask |= 0x0000f000; | ||
29 | if (FM & (1 << 5)) | ||
30 | mask |= 0x00000f00; | ||
31 | if (FM & (1 << 6)) | ||
32 | mask |= 0x000000f0; | ||
33 | if (FM & (1 << 7)) | ||
34 | mask |= 0x0000000f; | ||
35 | } | ||
36 | |||
37 | __FPU_FPSCR &= ~(mask); | ||
38 | __FPU_FPSCR |= (frB[1] & mask); | ||
39 | |||
40 | #ifdef DEBUG | ||
41 | printk("%s: %02x %p: %08lx\n", __FUNCTION__, FM, frB, __FPU_FPSCR); | ||
42 | #endif | ||
43 | |||
44 | return 0; | ||
45 | } | ||
diff --git a/arch/powerpc/math-emu/mtfsfi.c b/arch/powerpc/math-emu/mtfsfi.c new file mode 100644 index 000000000000..71df854baa7e --- /dev/null +++ b/arch/powerpc/math-emu/mtfsfi.c | |||
@@ -0,0 +1,23 @@ | |||
1 | #include <linux/types.h> | ||
2 | #include <linux/errno.h> | ||
3 | #include <asm/uaccess.h> | ||
4 | |||
5 | #include "soft-fp.h" | ||
6 | |||
7 | int | ||
8 | mtfsfi(unsigned int crfD, unsigned int IMM) | ||
9 | { | ||
10 | u32 mask = 0xf; | ||
11 | |||
12 | if (!crfD) | ||
13 | mask = 9; | ||
14 | |||
15 | __FPU_FPSCR &= ~(mask << ((7 - crfD) << 2)); | ||
16 | __FPU_FPSCR |= (IMM & 0xf) << ((7 - crfD) << 2); | ||
17 | |||
18 | #ifdef DEBUG | ||
19 | printk("%s: %d %x: %08lx\n", __FUNCTION__, crfD, IMM, __FPU_FPSCR); | ||
20 | #endif | ||
21 | |||
22 | return 0; | ||
23 | } | ||
diff --git a/arch/powerpc/math-emu/op-1.h b/arch/powerpc/math-emu/op-1.h new file mode 100644 index 000000000000..c92fa95f562e --- /dev/null +++ b/arch/powerpc/math-emu/op-1.h | |||
@@ -0,0 +1,245 @@ | |||
1 | /* | ||
2 | * Basic one-word fraction declaration and manipulation. | ||
3 | */ | ||
4 | |||
5 | #define _FP_FRAC_DECL_1(X) _FP_W_TYPE X##_f | ||
6 | #define _FP_FRAC_COPY_1(D,S) (D##_f = S##_f) | ||
7 | #define _FP_FRAC_SET_1(X,I) (X##_f = I) | ||
8 | #define _FP_FRAC_HIGH_1(X) (X##_f) | ||
9 | #define _FP_FRAC_LOW_1(X) (X##_f) | ||
10 | #define _FP_FRAC_WORD_1(X,w) (X##_f) | ||
11 | |||
12 | #define _FP_FRAC_ADDI_1(X,I) (X##_f += I) | ||
13 | #define _FP_FRAC_SLL_1(X,N) \ | ||
14 | do { \ | ||
15 | if (__builtin_constant_p(N) && (N) == 1) \ | ||
16 | X##_f += X##_f; \ | ||
17 | else \ | ||
18 | X##_f <<= (N); \ | ||
19 | } while (0) | ||
20 | #define _FP_FRAC_SRL_1(X,N) (X##_f >>= N) | ||
21 | |||
22 | /* Right shift with sticky-lsb. */ | ||
23 | #define _FP_FRAC_SRS_1(X,N,sz) __FP_FRAC_SRS_1(X##_f, N, sz) | ||
24 | |||
25 | #define __FP_FRAC_SRS_1(X,N,sz) \ | ||
26 | (X = (X >> (N) | (__builtin_constant_p(N) && (N) == 1 \ | ||
27 | ? X & 1 : (X << (_FP_W_TYPE_SIZE - (N))) != 0))) | ||
28 | |||
29 | #define _FP_FRAC_ADD_1(R,X,Y) (R##_f = X##_f + Y##_f) | ||
30 | #define _FP_FRAC_SUB_1(R,X,Y) (R##_f = X##_f - Y##_f) | ||
31 | #define _FP_FRAC_CLZ_1(z, X) __FP_CLZ(z, X##_f) | ||
32 | |||
33 | /* Predicates */ | ||
34 | #define _FP_FRAC_NEGP_1(X) ((_FP_WS_TYPE)X##_f < 0) | ||
35 | #define _FP_FRAC_ZEROP_1(X) (X##_f == 0) | ||
36 | #define _FP_FRAC_OVERP_1(fs,X) (X##_f & _FP_OVERFLOW_##fs) | ||
37 | #define _FP_FRAC_EQ_1(X, Y) (X##_f == Y##_f) | ||
38 | #define _FP_FRAC_GE_1(X, Y) (X##_f >= Y##_f) | ||
39 | #define _FP_FRAC_GT_1(X, Y) (X##_f > Y##_f) | ||
40 | |||
41 | #define _FP_ZEROFRAC_1 0 | ||
42 | #define _FP_MINFRAC_1 1 | ||
43 | |||
44 | /* | ||
45 | * Unpack the raw bits of a native fp value. Do not classify or | ||
46 | * normalize the data. | ||
47 | */ | ||
48 | |||
49 | #define _FP_UNPACK_RAW_1(fs, X, val) \ | ||
50 | do { \ | ||
51 | union _FP_UNION_##fs _flo; _flo.flt = (val); \ | ||
52 | \ | ||
53 | X##_f = _flo.bits.frac; \ | ||
54 | X##_e = _flo.bits.exp; \ | ||
55 | X##_s = _flo.bits.sign; \ | ||
56 | } while (0) | ||
57 | |||
58 | |||
59 | /* | ||
60 | * Repack the raw bits of a native fp value. | ||
61 | */ | ||
62 | |||
63 | #define _FP_PACK_RAW_1(fs, val, X) \ | ||
64 | do { \ | ||
65 | union _FP_UNION_##fs _flo; \ | ||
66 | \ | ||
67 | _flo.bits.frac = X##_f; \ | ||
68 | _flo.bits.exp = X##_e; \ | ||
69 | _flo.bits.sign = X##_s; \ | ||
70 | \ | ||
71 | (val) = _flo.flt; \ | ||
72 | } while (0) | ||
73 | |||
74 | |||
75 | /* | ||
76 | * Multiplication algorithms: | ||
77 | */ | ||
78 | |||
79 | /* Basic. Assuming the host word size is >= 2*FRACBITS, we can do the | ||
80 | multiplication immediately. */ | ||
81 | |||
82 | #define _FP_MUL_MEAT_1_imm(fs, R, X, Y) \ | ||
83 | do { \ | ||
84 | R##_f = X##_f * Y##_f; \ | ||
85 | /* Normalize since we know where the msb of the multiplicands \ | ||
86 | were (bit B), we know that the msb of the of the product is \ | ||
87 | at either 2B or 2B-1. */ \ | ||
88 | _FP_FRAC_SRS_1(R, _FP_WFRACBITS_##fs-1, 2*_FP_WFRACBITS_##fs); \ | ||
89 | } while (0) | ||
90 | |||
91 | /* Given a 1W * 1W => 2W primitive, do the extended multiplication. */ | ||
92 | |||
93 | #define _FP_MUL_MEAT_1_wide(fs, R, X, Y, doit) \ | ||
94 | do { \ | ||
95 | _FP_W_TYPE _Z_f0, _Z_f1; \ | ||
96 | doit(_Z_f1, _Z_f0, X##_f, Y##_f); \ | ||
97 | /* Normalize since we know where the msb of the multiplicands \ | ||
98 | were (bit B), we know that the msb of the of the product is \ | ||
99 | at either 2B or 2B-1. */ \ | ||
100 | _FP_FRAC_SRS_2(_Z, _FP_WFRACBITS_##fs-1, 2*_FP_WFRACBITS_##fs); \ | ||
101 | R##_f = _Z_f0; \ | ||
102 | } while (0) | ||
103 | |||
104 | /* Finally, a simple widening multiply algorithm. What fun! */ | ||
105 | |||
106 | #define _FP_MUL_MEAT_1_hard(fs, R, X, Y) \ | ||
107 | do { \ | ||
108 | _FP_W_TYPE _xh, _xl, _yh, _yl, _z_f0, _z_f1, _a_f0, _a_f1; \ | ||
109 | \ | ||
110 | /* split the words in half */ \ | ||
111 | _xh = X##_f >> (_FP_W_TYPE_SIZE/2); \ | ||
112 | _xl = X##_f & (((_FP_W_TYPE)1 << (_FP_W_TYPE_SIZE/2)) - 1); \ | ||
113 | _yh = Y##_f >> (_FP_W_TYPE_SIZE/2); \ | ||
114 | _yl = Y##_f & (((_FP_W_TYPE)1 << (_FP_W_TYPE_SIZE/2)) - 1); \ | ||
115 | \ | ||
116 | /* multiply the pieces */ \ | ||
117 | _z_f0 = _xl * _yl; \ | ||
118 | _a_f0 = _xh * _yl; \ | ||
119 | _a_f1 = _xl * _yh; \ | ||
120 | _z_f1 = _xh * _yh; \ | ||
121 | \ | ||
122 | /* reassemble into two full words */ \ | ||
123 | if ((_a_f0 += _a_f1) < _a_f1) \ | ||
124 | _z_f1 += (_FP_W_TYPE)1 << (_FP_W_TYPE_SIZE/2); \ | ||
125 | _a_f1 = _a_f0 >> (_FP_W_TYPE_SIZE/2); \ | ||
126 | _a_f0 = _a_f0 << (_FP_W_TYPE_SIZE/2); \ | ||
127 | _FP_FRAC_ADD_2(_z, _z, _a); \ | ||
128 | \ | ||
129 | /* normalize */ \ | ||
130 | _FP_FRAC_SRS_2(_z, _FP_WFRACBITS_##fs - 1, 2*_FP_WFRACBITS_##fs); \ | ||
131 | R##_f = _z_f0; \ | ||
132 | } while (0) | ||
133 | |||
134 | |||
135 | /* | ||
136 | * Division algorithms: | ||
137 | */ | ||
138 | |||
139 | /* Basic. Assuming the host word size is >= 2*FRACBITS, we can do the | ||
140 | division immediately. Give this macro either _FP_DIV_HELP_imm for | ||
141 | C primitives or _FP_DIV_HELP_ldiv for the ISO function. Which you | ||
142 | choose will depend on what the compiler does with divrem4. */ | ||
143 | |||
144 | #define _FP_DIV_MEAT_1_imm(fs, R, X, Y, doit) \ | ||
145 | do { \ | ||
146 | _FP_W_TYPE _q, _r; \ | ||
147 | X##_f <<= (X##_f < Y##_f \ | ||
148 | ? R##_e--, _FP_WFRACBITS_##fs \ | ||
149 | : _FP_WFRACBITS_##fs - 1); \ | ||
150 | doit(_q, _r, X##_f, Y##_f); \ | ||
151 | R##_f = _q | (_r != 0); \ | ||
152 | } while (0) | ||
153 | |||
154 | /* GCC's longlong.h defines a 2W / 1W => (1W,1W) primitive udiv_qrnnd | ||
155 | that may be useful in this situation. This first is for a primitive | ||
156 | that requires normalization, the second for one that does not. Look | ||
157 | for UDIV_NEEDS_NORMALIZATION to tell which your machine needs. */ | ||
158 | |||
159 | #define _FP_DIV_MEAT_1_udiv_norm(fs, R, X, Y) \ | ||
160 | do { \ | ||
161 | _FP_W_TYPE _nh, _nl, _q, _r; \ | ||
162 | \ | ||
163 | /* Normalize Y -- i.e. make the most significant bit set. */ \ | ||
164 | Y##_f <<= _FP_WFRACXBITS_##fs - 1; \ | ||
165 | \ | ||
166 | /* Shift X op correspondingly high, that is, up one full word. */ \ | ||
167 | if (X##_f <= Y##_f) \ | ||
168 | { \ | ||
169 | _nl = 0; \ | ||
170 | _nh = X##_f; \ | ||
171 | } \ | ||
172 | else \ | ||
173 | { \ | ||
174 | R##_e++; \ | ||
175 | _nl = X##_f << (_FP_W_TYPE_SIZE-1); \ | ||
176 | _nh = X##_f >> 1; \ | ||
177 | } \ | ||
178 | \ | ||
179 | udiv_qrnnd(_q, _r, _nh, _nl, Y##_f); \ | ||
180 | R##_f = _q | (_r != 0); \ | ||
181 | } while (0) | ||
182 | |||
183 | #define _FP_DIV_MEAT_1_udiv(fs, R, X, Y) \ | ||
184 | do { \ | ||
185 | _FP_W_TYPE _nh, _nl, _q, _r; \ | ||
186 | if (X##_f < Y##_f) \ | ||
187 | { \ | ||
188 | R##_e--; \ | ||
189 | _nl = X##_f << _FP_WFRACBITS_##fs; \ | ||
190 | _nh = X##_f >> _FP_WFRACXBITS_##fs; \ | ||
191 | } \ | ||
192 | else \ | ||
193 | { \ | ||
194 | _nl = X##_f << (_FP_WFRACBITS_##fs - 1); \ | ||
195 | _nh = X##_f >> (_FP_WFRACXBITS_##fs + 1); \ | ||
196 | } \ | ||
197 | udiv_qrnnd(_q, _r, _nh, _nl, Y##_f); \ | ||
198 | R##_f = _q | (_r != 0); \ | ||
199 | } while (0) | ||
200 | |||
201 | |||
202 | /* | ||
203 | * Square root algorithms: | ||
204 | * We have just one right now, maybe Newton approximation | ||
205 | * should be added for those machines where division is fast. | ||
206 | */ | ||
207 | |||
208 | #define _FP_SQRT_MEAT_1(R, S, T, X, q) \ | ||
209 | do { \ | ||
210 | while (q) \ | ||
211 | { \ | ||
212 | T##_f = S##_f + q; \ | ||
213 | if (T##_f <= X##_f) \ | ||
214 | { \ | ||
215 | S##_f = T##_f + q; \ | ||
216 | X##_f -= T##_f; \ | ||
217 | R##_f += q; \ | ||
218 | } \ | ||
219 | _FP_FRAC_SLL_1(X, 1); \ | ||
220 | q >>= 1; \ | ||
221 | } \ | ||
222 | } while (0) | ||
223 | |||
224 | /* | ||
225 | * Assembly/disassembly for converting to/from integral types. | ||
226 | * No shifting or overflow handled here. | ||
227 | */ | ||
228 | |||
229 | #define _FP_FRAC_ASSEMBLE_1(r, X, rsize) (r = X##_f) | ||
230 | #define _FP_FRAC_DISASSEMBLE_1(X, r, rsize) (X##_f = r) | ||
231 | |||
232 | |||
233 | /* | ||
234 | * Convert FP values between word sizes | ||
235 | */ | ||
236 | |||
237 | #define _FP_FRAC_CONV_1_1(dfs, sfs, D, S) \ | ||
238 | do { \ | ||
239 | D##_f = S##_f; \ | ||
240 | if (_FP_WFRACBITS_##sfs > _FP_WFRACBITS_##dfs) \ | ||
241 | _FP_FRAC_SRS_1(D, (_FP_WFRACBITS_##sfs-_FP_WFRACBITS_##dfs), \ | ||
242 | _FP_WFRACBITS_##sfs); \ | ||
243 | else \ | ||
244 | D##_f <<= _FP_WFRACBITS_##dfs - _FP_WFRACBITS_##sfs; \ | ||
245 | } while (0) | ||
diff --git a/arch/powerpc/math-emu/op-2.h b/arch/powerpc/math-emu/op-2.h new file mode 100644 index 000000000000..b9b06b4c6ea1 --- /dev/null +++ b/arch/powerpc/math-emu/op-2.h | |||
@@ -0,0 +1,433 @@ | |||
1 | /* | ||
2 | * Basic two-word fraction declaration and manipulation. | ||
3 | */ | ||
4 | |||
5 | #define _FP_FRAC_DECL_2(X) _FP_W_TYPE X##_f0, X##_f1 | ||
6 | #define _FP_FRAC_COPY_2(D,S) (D##_f0 = S##_f0, D##_f1 = S##_f1) | ||
7 | #define _FP_FRAC_SET_2(X,I) __FP_FRAC_SET_2(X, I) | ||
8 | #define _FP_FRAC_HIGH_2(X) (X##_f1) | ||
9 | #define _FP_FRAC_LOW_2(X) (X##_f0) | ||
10 | #define _FP_FRAC_WORD_2(X,w) (X##_f##w) | ||
11 | |||
12 | #define _FP_FRAC_SLL_2(X,N) \ | ||
13 | do { \ | ||
14 | if ((N) < _FP_W_TYPE_SIZE) \ | ||
15 | { \ | ||
16 | if (__builtin_constant_p(N) && (N) == 1) \ | ||
17 | { \ | ||
18 | X##_f1 = X##_f1 + X##_f1 + (((_FP_WS_TYPE)(X##_f0)) < 0); \ | ||
19 | X##_f0 += X##_f0; \ | ||
20 | } \ | ||
21 | else \ | ||
22 | { \ | ||
23 | X##_f1 = X##_f1 << (N) | X##_f0 >> (_FP_W_TYPE_SIZE - (N)); \ | ||
24 | X##_f0 <<= (N); \ | ||
25 | } \ | ||
26 | } \ | ||
27 | else \ | ||
28 | { \ | ||
29 | X##_f1 = X##_f0 << ((N) - _FP_W_TYPE_SIZE); \ | ||
30 | X##_f0 = 0; \ | ||
31 | } \ | ||
32 | } while (0) | ||
33 | |||
34 | #define _FP_FRAC_SRL_2(X,N) \ | ||
35 | do { \ | ||
36 | if ((N) < _FP_W_TYPE_SIZE) \ | ||
37 | { \ | ||
38 | X##_f0 = X##_f0 >> (N) | X##_f1 << (_FP_W_TYPE_SIZE - (N)); \ | ||
39 | X##_f1 >>= (N); \ | ||
40 | } \ | ||
41 | else \ | ||
42 | { \ | ||
43 | X##_f0 = X##_f1 >> ((N) - _FP_W_TYPE_SIZE); \ | ||
44 | X##_f1 = 0; \ | ||
45 | } \ | ||
46 | } while (0) | ||
47 | |||
48 | /* Right shift with sticky-lsb. */ | ||
49 | #define _FP_FRAC_SRS_2(X,N,sz) \ | ||
50 | do { \ | ||
51 | if ((N) < _FP_W_TYPE_SIZE) \ | ||
52 | { \ | ||
53 | X##_f0 = (X##_f1 << (_FP_W_TYPE_SIZE - (N)) | X##_f0 >> (N) | \ | ||
54 | (__builtin_constant_p(N) && (N) == 1 \ | ||
55 | ? X##_f0 & 1 \ | ||
56 | : (X##_f0 << (_FP_W_TYPE_SIZE - (N))) != 0)); \ | ||
57 | X##_f1 >>= (N); \ | ||
58 | } \ | ||
59 | else \ | ||
60 | { \ | ||
61 | X##_f0 = (X##_f1 >> ((N) - _FP_W_TYPE_SIZE) | \ | ||
62 | (((X##_f1 << (sz - (N))) | X##_f0) != 0)); \ | ||
63 | X##_f1 = 0; \ | ||
64 | } \ | ||
65 | } while (0) | ||
66 | |||
67 | #define _FP_FRAC_ADDI_2(X,I) \ | ||
68 | __FP_FRAC_ADDI_2(X##_f1, X##_f0, I) | ||
69 | |||
70 | #define _FP_FRAC_ADD_2(R,X,Y) \ | ||
71 | __FP_FRAC_ADD_2(R##_f1, R##_f0, X##_f1, X##_f0, Y##_f1, Y##_f0) | ||
72 | |||
73 | #define _FP_FRAC_SUB_2(R,X,Y) \ | ||
74 | __FP_FRAC_SUB_2(R##_f1, R##_f0, X##_f1, X##_f0, Y##_f1, Y##_f0) | ||
75 | |||
76 | #define _FP_FRAC_CLZ_2(R,X) \ | ||
77 | do { \ | ||
78 | if (X##_f1) \ | ||
79 | __FP_CLZ(R,X##_f1); \ | ||
80 | else \ | ||
81 | { \ | ||
82 | __FP_CLZ(R,X##_f0); \ | ||
83 | R += _FP_W_TYPE_SIZE; \ | ||
84 | } \ | ||
85 | } while(0) | ||
86 | |||
87 | /* Predicates */ | ||
88 | #define _FP_FRAC_NEGP_2(X) ((_FP_WS_TYPE)X##_f1 < 0) | ||
89 | #define _FP_FRAC_ZEROP_2(X) ((X##_f1 | X##_f0) == 0) | ||
90 | #define _FP_FRAC_OVERP_2(fs,X) (X##_f1 & _FP_OVERFLOW_##fs) | ||
91 | #define _FP_FRAC_EQ_2(X, Y) (X##_f1 == Y##_f1 && X##_f0 == Y##_f0) | ||
92 | #define _FP_FRAC_GT_2(X, Y) \ | ||
93 | ((X##_f1 > Y##_f1) || (X##_f1 == Y##_f1 && X##_f0 > Y##_f0)) | ||
94 | #define _FP_FRAC_GE_2(X, Y) \ | ||
95 | ((X##_f1 > Y##_f1) || (X##_f1 == Y##_f1 && X##_f0 >= Y##_f0)) | ||
96 | |||
97 | #define _FP_ZEROFRAC_2 0, 0 | ||
98 | #define _FP_MINFRAC_2 0, 1 | ||
99 | |||
100 | /* | ||
101 | * Internals | ||
102 | */ | ||
103 | |||
104 | #define __FP_FRAC_SET_2(X,I1,I0) (X##_f0 = I0, X##_f1 = I1) | ||
105 | |||
106 | #define __FP_CLZ_2(R, xh, xl) \ | ||
107 | do { \ | ||
108 | if (xh) \ | ||
109 | __FP_CLZ(R,xl); \ | ||
110 | else \ | ||
111 | { \ | ||
112 | __FP_CLZ(R,xl); \ | ||
113 | R += _FP_W_TYPE_SIZE; \ | ||
114 | } \ | ||
115 | } while(0) | ||
116 | |||
117 | #if 0 | ||
118 | |||
119 | #ifndef __FP_FRAC_ADDI_2 | ||
120 | #define __FP_FRAC_ADDI_2(xh, xl, i) \ | ||
121 | (xh += ((xl += i) < i)) | ||
122 | #endif | ||
123 | #ifndef __FP_FRAC_ADD_2 | ||
124 | #define __FP_FRAC_ADD_2(rh, rl, xh, xl, yh, yl) \ | ||
125 | (rh = xh + yh + ((rl = xl + yl) < xl)) | ||
126 | #endif | ||
127 | #ifndef __FP_FRAC_SUB_2 | ||
128 | #define __FP_FRAC_SUB_2(rh, rl, xh, xl, yh, yl) \ | ||
129 | (rh = xh - yh - ((rl = xl - yl) > xl)) | ||
130 | #endif | ||
131 | |||
132 | #else | ||
133 | |||
134 | #undef __FP_FRAC_ADDI_2 | ||
135 | #define __FP_FRAC_ADDI_2(xh, xl, i) add_ssaaaa(xh, xl, xh, xl, 0, i) | ||
136 | #undef __FP_FRAC_ADD_2 | ||
137 | #define __FP_FRAC_ADD_2 add_ssaaaa | ||
138 | #undef __FP_FRAC_SUB_2 | ||
139 | #define __FP_FRAC_SUB_2 sub_ddmmss | ||
140 | |||
141 | #endif | ||
142 | |||
143 | /* | ||
144 | * Unpack the raw bits of a native fp value. Do not classify or | ||
145 | * normalize the data. | ||
146 | */ | ||
147 | |||
148 | #define _FP_UNPACK_RAW_2(fs, X, val) \ | ||
149 | do { \ | ||
150 | union _FP_UNION_##fs _flo; _flo.flt = (val); \ | ||
151 | \ | ||
152 | X##_f0 = _flo.bits.frac0; \ | ||
153 | X##_f1 = _flo.bits.frac1; \ | ||
154 | X##_e = _flo.bits.exp; \ | ||
155 | X##_s = _flo.bits.sign; \ | ||
156 | } while (0) | ||
157 | |||
158 | |||
159 | /* | ||
160 | * Repack the raw bits of a native fp value. | ||
161 | */ | ||
162 | |||
163 | #define _FP_PACK_RAW_2(fs, val, X) \ | ||
164 | do { \ | ||
165 | union _FP_UNION_##fs _flo; \ | ||
166 | \ | ||
167 | _flo.bits.frac0 = X##_f0; \ | ||
168 | _flo.bits.frac1 = X##_f1; \ | ||
169 | _flo.bits.exp = X##_e; \ | ||
170 | _flo.bits.sign = X##_s; \ | ||
171 | \ | ||
172 | (val) = _flo.flt; \ | ||
173 | } while (0) | ||
174 | |||
175 | |||
176 | /* | ||
177 | * Multiplication algorithms: | ||
178 | */ | ||
179 | |||
180 | /* Given a 1W * 1W => 2W primitive, do the extended multiplication. */ | ||
181 | |||
182 | #define _FP_MUL_MEAT_2_wide(fs, R, X, Y, doit) \ | ||
183 | do { \ | ||
184 | _FP_FRAC_DECL_4(_z); _FP_FRAC_DECL_2(_b); _FP_FRAC_DECL_2(_c); \ | ||
185 | \ | ||
186 | doit(_FP_FRAC_WORD_4(_z,1), _FP_FRAC_WORD_4(_z,0), X##_f0, Y##_f0); \ | ||
187 | doit(_b_f1, _b_f0, X##_f0, Y##_f1); \ | ||
188 | doit(_c_f1, _c_f0, X##_f1, Y##_f0); \ | ||
189 | doit(_FP_FRAC_WORD_4(_z,3), _FP_FRAC_WORD_4(_z,2), X##_f1, Y##_f1); \ | ||
190 | \ | ||
191 | __FP_FRAC_ADD_4(_FP_FRAC_WORD_4(_z,3),_FP_FRAC_WORD_4(_z,2), \ | ||
192 | _FP_FRAC_WORD_4(_z,1),_FP_FRAC_WORD_4(_z,0), \ | ||
193 | 0, _b_f1, _b_f0, 0, \ | ||
194 | _FP_FRAC_WORD_4(_z,3),_FP_FRAC_WORD_4(_z,2), \ | ||
195 | _FP_FRAC_WORD_4(_z,1),_FP_FRAC_WORD_4(_z,0)); \ | ||
196 | __FP_FRAC_ADD_4(_FP_FRAC_WORD_4(_z,3),_FP_FRAC_WORD_4(_z,2), \ | ||
197 | _FP_FRAC_WORD_4(_z,1),_FP_FRAC_WORD_4(_z,0), \ | ||
198 | 0, _c_f1, _c_f0, 0, \ | ||
199 | _FP_FRAC_WORD_4(_z,3),_FP_FRAC_WORD_4(_z,2), \ | ||
200 | _FP_FRAC_WORD_4(_z,1),_FP_FRAC_WORD_4(_z,0)); \ | ||
201 | \ | ||
202 | /* Normalize since we know where the msb of the multiplicands \ | ||
203 | were (bit B), we know that the msb of the of the product is \ | ||
204 | at either 2B or 2B-1. */ \ | ||
205 | _FP_FRAC_SRS_4(_z, _FP_WFRACBITS_##fs-1, 2*_FP_WFRACBITS_##fs); \ | ||
206 | R##_f0 = _FP_FRAC_WORD_4(_z,0); \ | ||
207 | R##_f1 = _FP_FRAC_WORD_4(_z,1); \ | ||
208 | } while (0) | ||
209 | |||
210 | /* This next macro appears to be totally broken. Fortunately nowhere | ||
211 | * seems to use it :-> The problem is that we define _z[4] but | ||
212 | * then use it in _FP_FRAC_SRS_4, which will attempt to access | ||
213 | * _z_f[n] which will cause an error. The fix probably involves | ||
214 | * declaring it with _FP_FRAC_DECL_4, see previous macro. -- PMM 02/1998 | ||
215 | */ | ||
216 | #define _FP_MUL_MEAT_2_gmp(fs, R, X, Y) \ | ||
217 | do { \ | ||
218 | _FP_W_TYPE _x[2], _y[2], _z[4]; \ | ||
219 | _x[0] = X##_f0; _x[1] = X##_f1; \ | ||
220 | _y[0] = Y##_f0; _y[1] = Y##_f1; \ | ||
221 | \ | ||
222 | mpn_mul_n(_z, _x, _y, 2); \ | ||
223 | \ | ||
224 | /* Normalize since we know where the msb of the multiplicands \ | ||
225 | were (bit B), we know that the msb of the of the product is \ | ||
226 | at either 2B or 2B-1. */ \ | ||
227 | _FP_FRAC_SRS_4(_z, _FP_WFRACBITS##_fs-1, 2*_FP_WFRACBITS_##fs); \ | ||
228 | R##_f0 = _z[0]; \ | ||
229 | R##_f1 = _z[1]; \ | ||
230 | } while (0) | ||
231 | |||
232 | |||
233 | /* | ||
234 | * Division algorithms: | ||
235 | * This seems to be giving me difficulties -- PMM | ||
236 | * Look, NetBSD seems to be able to comment algorithms. Can't you? | ||
237 | * I've thrown printks at the problem. | ||
238 | * This now appears to work, but I still don't really know why. | ||
239 | * Also, I don't think the result is properly normalised... | ||
240 | */ | ||
241 | |||
242 | #define _FP_DIV_MEAT_2_udiv_64(fs, R, X, Y) \ | ||
243 | do { \ | ||
244 | extern void _fp_udivmodti4(_FP_W_TYPE q[2], _FP_W_TYPE r[2], \ | ||
245 | _FP_W_TYPE n1, _FP_W_TYPE n0, \ | ||
246 | _FP_W_TYPE d1, _FP_W_TYPE d0); \ | ||
247 | _FP_W_TYPE _n_f3, _n_f2, _n_f1, _n_f0, _r_f1, _r_f0; \ | ||
248 | _FP_W_TYPE _q_f1, _q_f0, _m_f1, _m_f0; \ | ||
249 | _FP_W_TYPE _rmem[2], _qmem[2]; \ | ||
250 | /* I think this check is to ensure that the result is normalised. \ | ||
251 | * Assuming X,Y normalised (ie in [1.0,2.0)) X/Y will be in \ | ||
252 | * [0.5,2.0). Furthermore, it will be less than 1.0 iff X < Y. \ | ||
253 | * In this case we tweak things. (this is based on comments in \ | ||
254 | * the NetBSD FPU emulation code. ) \ | ||
255 | * We know X,Y are normalised because we ensure this as part of \ | ||
256 | * the unpacking process. -- PMM \ | ||
257 | */ \ | ||
258 | if (_FP_FRAC_GT_2(X, Y)) \ | ||
259 | { \ | ||
260 | /* R##_e++; */ \ | ||
261 | _n_f3 = X##_f1 >> 1; \ | ||
262 | _n_f2 = X##_f1 << (_FP_W_TYPE_SIZE - 1) | X##_f0 >> 1; \ | ||
263 | _n_f1 = X##_f0 << (_FP_W_TYPE_SIZE - 1); \ | ||
264 | _n_f0 = 0; \ | ||
265 | } \ | ||
266 | else \ | ||
267 | { \ | ||
268 | R##_e--; \ | ||
269 | _n_f3 = X##_f1; \ | ||
270 | _n_f2 = X##_f0; \ | ||
271 | _n_f1 = _n_f0 = 0; \ | ||
272 | } \ | ||
273 | \ | ||
274 | /* Normalize, i.e. make the most significant bit of the \ | ||
275 | denominator set. CHANGED: - 1 to nothing -- PMM */ \ | ||
276 | _FP_FRAC_SLL_2(Y, _FP_WFRACXBITS_##fs /* -1 */); \ | ||
277 | \ | ||
278 | /* Do the 256/128 bit division given the 128-bit _fp_udivmodtf4 \ | ||
279 | primitive snagged from libgcc2.c. */ \ | ||
280 | \ | ||
281 | _fp_udivmodti4(_qmem, _rmem, _n_f3, _n_f2, 0, Y##_f1); \ | ||
282 | _q_f1 = _qmem[0]; \ | ||
283 | umul_ppmm(_m_f1, _m_f0, _q_f1, Y##_f0); \ | ||
284 | _r_f1 = _rmem[0]; \ | ||
285 | _r_f0 = _n_f1; \ | ||
286 | if (_FP_FRAC_GT_2(_m, _r)) \ | ||
287 | { \ | ||
288 | _q_f1--; \ | ||
289 | _FP_FRAC_ADD_2(_r, _r, Y); \ | ||
290 | if (_FP_FRAC_GE_2(_r, Y) && _FP_FRAC_GT_2(_m, _r)) \ | ||
291 | { \ | ||
292 | _q_f1--; \ | ||
293 | _FP_FRAC_ADD_2(_r, _r, Y); \ | ||
294 | } \ | ||
295 | } \ | ||
296 | _FP_FRAC_SUB_2(_r, _r, _m); \ | ||
297 | \ | ||
298 | _fp_udivmodti4(_qmem, _rmem, _r_f1, _r_f0, 0, Y##_f1); \ | ||
299 | _q_f0 = _qmem[0]; \ | ||
300 | umul_ppmm(_m_f1, _m_f0, _q_f0, Y##_f0); \ | ||
301 | _r_f1 = _rmem[0]; \ | ||
302 | _r_f0 = _n_f0; \ | ||
303 | if (_FP_FRAC_GT_2(_m, _r)) \ | ||
304 | { \ | ||
305 | _q_f0--; \ | ||
306 | _FP_FRAC_ADD_2(_r, _r, Y); \ | ||
307 | if (_FP_FRAC_GE_2(_r, Y) && _FP_FRAC_GT_2(_m, _r)) \ | ||
308 | { \ | ||
309 | _q_f0--; \ | ||
310 | _FP_FRAC_ADD_2(_r, _r, Y); \ | ||
311 | } \ | ||
312 | } \ | ||
313 | _FP_FRAC_SUB_2(_r, _r, _m); \ | ||
314 | \ | ||
315 | R##_f1 = _q_f1; \ | ||
316 | R##_f0 = _q_f0 | ((_r_f1 | _r_f0) != 0); \ | ||
317 | /* adjust so answer is normalized again. I'm not sure what the \ | ||
318 | * final sz param should be. In practice it's never used since \ | ||
319 | * N is 1 which is always going to be < _FP_W_TYPE_SIZE... \ | ||
320 | */ \ | ||
321 | /* _FP_FRAC_SRS_2(R,1,_FP_WFRACBITS_##fs); */ \ | ||
322 | } while (0) | ||
323 | |||
324 | |||
325 | #define _FP_DIV_MEAT_2_gmp(fs, R, X, Y) \ | ||
326 | do { \ | ||
327 | _FP_W_TYPE _x[4], _y[2], _z[4]; \ | ||
328 | _y[0] = Y##_f0; _y[1] = Y##_f1; \ | ||
329 | _x[0] = _x[3] = 0; \ | ||
330 | if (_FP_FRAC_GT_2(X, Y)) \ | ||
331 | { \ | ||
332 | R##_e++; \ | ||
333 | _x[1] = (X##_f0 << (_FP_WFRACBITS-1 - _FP_W_TYPE_SIZE) | \ | ||
334 | X##_f1 >> (_FP_W_TYPE_SIZE - \ | ||
335 | (_FP_WFRACBITS-1 - _FP_W_TYPE_SIZE))); \ | ||
336 | _x[2] = X##_f1 << (_FP_WFRACBITS-1 - _FP_W_TYPE_SIZE); \ | ||
337 | } \ | ||
338 | else \ | ||
339 | { \ | ||
340 | _x[1] = (X##_f0 << (_FP_WFRACBITS - _FP_W_TYPE_SIZE) | \ | ||
341 | X##_f1 >> (_FP_W_TYPE_SIZE - \ | ||
342 | (_FP_WFRACBITS - _FP_W_TYPE_SIZE))); \ | ||
343 | _x[2] = X##_f1 << (_FP_WFRACBITS - _FP_W_TYPE_SIZE); \ | ||
344 | } \ | ||
345 | \ | ||
346 | (void) mpn_divrem (_z, 0, _x, 4, _y, 2); \ | ||
347 | R##_f1 = _z[1]; \ | ||
348 | R##_f0 = _z[0] | ((_x[0] | _x[1]) != 0); \ | ||
349 | } while (0) | ||
350 | |||
351 | |||
352 | /* | ||
353 | * Square root algorithms: | ||
354 | * We have just one right now, maybe Newton approximation | ||
355 | * should be added for those machines where division is fast. | ||
356 | */ | ||
357 | |||
358 | #define _FP_SQRT_MEAT_2(R, S, T, X, q) \ | ||
359 | do { \ | ||
360 | while (q) \ | ||
361 | { \ | ||
362 | T##_f1 = S##_f1 + q; \ | ||
363 | if (T##_f1 <= X##_f1) \ | ||
364 | { \ | ||
365 | S##_f1 = T##_f1 + q; \ | ||
366 | X##_f1 -= T##_f1; \ | ||
367 | R##_f1 += q; \ | ||
368 | } \ | ||
369 | _FP_FRAC_SLL_2(X, 1); \ | ||
370 | q >>= 1; \ | ||
371 | } \ | ||
372 | q = (_FP_W_TYPE)1 << (_FP_W_TYPE_SIZE - 1); \ | ||
373 | while (q) \ | ||
374 | { \ | ||
375 | T##_f0 = S##_f0 + q; \ | ||
376 | T##_f1 = S##_f1; \ | ||
377 | if (T##_f1 < X##_f1 || \ | ||
378 | (T##_f1 == X##_f1 && T##_f0 < X##_f0)) \ | ||
379 | { \ | ||
380 | S##_f0 = T##_f0 + q; \ | ||
381 | if (((_FP_WS_TYPE)T##_f0) < 0 && \ | ||
382 | ((_FP_WS_TYPE)S##_f0) >= 0) \ | ||
383 | S##_f1++; \ | ||
384 | _FP_FRAC_SUB_2(X, X, T); \ | ||
385 | R##_f0 += q; \ | ||
386 | } \ | ||
387 | _FP_FRAC_SLL_2(X, 1); \ | ||
388 | q >>= 1; \ | ||
389 | } \ | ||
390 | } while (0) | ||
391 | |||
392 | |||
393 | /* | ||
394 | * Assembly/disassembly for converting to/from integral types. | ||
395 | * No shifting or overflow handled here. | ||
396 | */ | ||
397 | |||
398 | #define _FP_FRAC_ASSEMBLE_2(r, X, rsize) \ | ||
399 | do { \ | ||
400 | if (rsize <= _FP_W_TYPE_SIZE) \ | ||
401 | r = X##_f0; \ | ||
402 | else \ | ||
403 | { \ | ||
404 | r = X##_f1; \ | ||
405 | r <<= _FP_W_TYPE_SIZE; \ | ||
406 | r += X##_f0; \ | ||
407 | } \ | ||
408 | } while (0) | ||
409 | |||
410 | #define _FP_FRAC_DISASSEMBLE_2(X, r, rsize) \ | ||
411 | do { \ | ||
412 | X##_f0 = r; \ | ||
413 | X##_f1 = (rsize <= _FP_W_TYPE_SIZE ? 0 : r >> _FP_W_TYPE_SIZE); \ | ||
414 | } while (0) | ||
415 | |||
416 | /* | ||
417 | * Convert FP values between word sizes | ||
418 | */ | ||
419 | |||
420 | #define _FP_FRAC_CONV_1_2(dfs, sfs, D, S) \ | ||
421 | do { \ | ||
422 | _FP_FRAC_SRS_2(S, (_FP_WFRACBITS_##sfs - _FP_WFRACBITS_##dfs), \ | ||
423 | _FP_WFRACBITS_##sfs); \ | ||
424 | D##_f = S##_f0; \ | ||
425 | } while (0) | ||
426 | |||
427 | #define _FP_FRAC_CONV_2_1(dfs, sfs, D, S) \ | ||
428 | do { \ | ||
429 | D##_f0 = S##_f; \ | ||
430 | D##_f1 = 0; \ | ||
431 | _FP_FRAC_SLL_2(D, (_FP_WFRACBITS_##dfs - _FP_WFRACBITS_##sfs)); \ | ||
432 | } while (0) | ||
433 | |||
diff --git a/arch/powerpc/math-emu/op-4.h b/arch/powerpc/math-emu/op-4.h new file mode 100644 index 000000000000..fcdd6d064c54 --- /dev/null +++ b/arch/powerpc/math-emu/op-4.h | |||
@@ -0,0 +1,297 @@ | |||
1 | /* | ||
2 | * Basic four-word fraction declaration and manipulation. | ||
3 | * | ||
4 | * When adding quadword support for 32 bit machines, we need | ||
5 | * to be a little careful as double multiply uses some of these | ||
6 | * macros: (in op-2.h) | ||
7 | * _FP_MUL_MEAT_2_wide() uses _FP_FRAC_DECL_4, _FP_FRAC_WORD_4, | ||
8 | * _FP_FRAC_ADD_4, _FP_FRAC_SRS_4 | ||
9 | * _FP_MUL_MEAT_2_gmp() uses _FP_FRAC_SRS_4 (and should use | ||
10 | * _FP_FRAC_DECL_4: it appears to be broken and is not used | ||
11 | * anywhere anyway. ) | ||
12 | * | ||
13 | * I've now fixed all the macros that were here from the sparc64 code. | ||
14 | * [*none* of the shift macros were correct!] -- PMM 02/1998 | ||
15 | * | ||
16 | * The only quadword stuff that remains to be coded is: | ||
17 | * 1) the conversion to/from ints, which requires | ||
18 | * that we check (in op-common.h) that the following do the right thing | ||
19 | * for quadwords: _FP_TO_INT(Q,4,r,X,rsz,rsg), _FP_FROM_INT(Q,4,X,r,rs,rt) | ||
20 | * 2) multiply, divide and sqrt, which require: | ||
21 | * _FP_MUL_MEAT_4_*(R,X,Y), _FP_DIV_MEAT_4_*(R,X,Y), _FP_SQRT_MEAT_4(R,S,T,X,q), | ||
22 | * This also needs _FP_MUL_MEAT_Q and _FP_DIV_MEAT_Q to be defined to | ||
23 | * some suitable _FP_MUL_MEAT_4_* macros in sfp-machine.h. | ||
24 | * [we're free to choose whatever FP_MUL_MEAT_4_* macros we need for | ||
25 | * these; they are used nowhere else. ] | ||
26 | */ | ||
27 | |||
28 | #define _FP_FRAC_DECL_4(X) _FP_W_TYPE X##_f[4] | ||
29 | #define _FP_FRAC_COPY_4(D,S) \ | ||
30 | (D##_f[0] = S##_f[0], D##_f[1] = S##_f[1], \ | ||
31 | D##_f[2] = S##_f[2], D##_f[3] = S##_f[3]) | ||
32 | /* The _FP_FRAC_SET_n(X,I) macro is intended for use with another | ||
33 | * macro such as _FP_ZEROFRAC_n which returns n comma separated values. | ||
34 | * The result is that we get an expansion of __FP_FRAC_SET_n(X,I0,I1,I2,I3) | ||
35 | * which just assigns the In values to the array X##_f[]. | ||
36 | * This is why the number of parameters doesn't appear to match | ||
37 | * at first glance... -- PMM | ||
38 | */ | ||
39 | #define _FP_FRAC_SET_4(X,I) __FP_FRAC_SET_4(X, I) | ||
40 | #define _FP_FRAC_HIGH_4(X) (X##_f[3]) | ||
41 | #define _FP_FRAC_LOW_4(X) (X##_f[0]) | ||
42 | #define _FP_FRAC_WORD_4(X,w) (X##_f[w]) | ||
43 | |||
44 | #define _FP_FRAC_SLL_4(X,N) \ | ||
45 | do { \ | ||
46 | _FP_I_TYPE _up, _down, _skip, _i; \ | ||
47 | _skip = (N) / _FP_W_TYPE_SIZE; \ | ||
48 | _up = (N) % _FP_W_TYPE_SIZE; \ | ||
49 | _down = _FP_W_TYPE_SIZE - _up; \ | ||
50 | for (_i = 3; _i > _skip; --_i) \ | ||
51 | X##_f[_i] = X##_f[_i-_skip] << _up | X##_f[_i-_skip-1] >> _down; \ | ||
52 | /* bugfixed: was X##_f[_i] <<= _up; -- PMM 02/1998 */ \ | ||
53 | X##_f[_i] = X##_f[0] << _up; \ | ||
54 | for (--_i; _i >= 0; --_i) \ | ||
55 | X##_f[_i] = 0; \ | ||
56 | } while (0) | ||
57 | |||
58 | /* This one was broken too */ | ||
59 | #define _FP_FRAC_SRL_4(X,N) \ | ||
60 | do { \ | ||
61 | _FP_I_TYPE _up, _down, _skip, _i; \ | ||
62 | _skip = (N) / _FP_W_TYPE_SIZE; \ | ||
63 | _down = (N) % _FP_W_TYPE_SIZE; \ | ||
64 | _up = _FP_W_TYPE_SIZE - _down; \ | ||
65 | for (_i = 0; _i < 3-_skip; ++_i) \ | ||
66 | X##_f[_i] = X##_f[_i+_skip] >> _down | X##_f[_i+_skip+1] << _up; \ | ||
67 | X##_f[_i] = X##_f[3] >> _down; \ | ||
68 | for (++_i; _i < 4; ++_i) \ | ||
69 | X##_f[_i] = 0; \ | ||
70 | } while (0) | ||
71 | |||
72 | |||
73 | /* Right shift with sticky-lsb. | ||
74 | * What this actually means is that we do a standard right-shift, | ||
75 | * but that if any of the bits that fall off the right hand side | ||
76 | * were one then we always set the LSbit. | ||
77 | */ | ||
78 | #define _FP_FRAC_SRS_4(X,N,size) \ | ||
79 | do { \ | ||
80 | _FP_I_TYPE _up, _down, _skip, _i; \ | ||
81 | _FP_W_TYPE _s; \ | ||
82 | _skip = (N) / _FP_W_TYPE_SIZE; \ | ||
83 | _down = (N) % _FP_W_TYPE_SIZE; \ | ||
84 | _up = _FP_W_TYPE_SIZE - _down; \ | ||
85 | for (_s = _i = 0; _i < _skip; ++_i) \ | ||
86 | _s |= X##_f[_i]; \ | ||
87 | _s |= X##_f[_i] << _up; \ | ||
88 | /* s is now != 0 if we want to set the LSbit */ \ | ||
89 | for (_i = 0; _i < 3-_skip; ++_i) \ | ||
90 | X##_f[_i] = X##_f[_i+_skip] >> _down | X##_f[_i+_skip+1] << _up; \ | ||
91 | X##_f[_i] = X##_f[3] >> _down; \ | ||
92 | for (++_i; _i < 4; ++_i) \ | ||
93 | X##_f[_i] = 0; \ | ||
94 | /* don't fix the LSB until the very end when we're sure f[0] is stable */ \ | ||
95 | X##_f[0] |= (_s != 0); \ | ||
96 | } while (0) | ||
97 | |||
98 | #define _FP_FRAC_ADD_4(R,X,Y) \ | ||
99 | __FP_FRAC_ADD_4(R##_f[3], R##_f[2], R##_f[1], R##_f[0], \ | ||
100 | X##_f[3], X##_f[2], X##_f[1], X##_f[0], \ | ||
101 | Y##_f[3], Y##_f[2], Y##_f[1], Y##_f[0]) | ||
102 | |||
103 | #define _FP_FRAC_SUB_4(R,X,Y) \ | ||
104 | __FP_FRAC_SUB_4(R##_f[3], R##_f[2], R##_f[1], R##_f[0], \ | ||
105 | X##_f[3], X##_f[2], X##_f[1], X##_f[0], \ | ||
106 | Y##_f[3], Y##_f[2], Y##_f[1], Y##_f[0]) | ||
107 | |||
108 | #define _FP_FRAC_ADDI_4(X,I) \ | ||
109 | __FP_FRAC_ADDI_4(X##_f[3], X##_f[2], X##_f[1], X##_f[0], I) | ||
110 | |||
111 | #define _FP_ZEROFRAC_4 0,0,0,0 | ||
112 | #define _FP_MINFRAC_4 0,0,0,1 | ||
113 | |||
114 | #define _FP_FRAC_ZEROP_4(X) ((X##_f[0] | X##_f[1] | X##_f[2] | X##_f[3]) == 0) | ||
115 | #define _FP_FRAC_NEGP_4(X) ((_FP_WS_TYPE)X##_f[3] < 0) | ||
116 | #define _FP_FRAC_OVERP_4(fs,X) (X##_f[0] & _FP_OVERFLOW_##fs) | ||
117 | |||
118 | #define _FP_FRAC_EQ_4(X,Y) \ | ||
119 | (X##_f[0] == Y##_f[0] && X##_f[1] == Y##_f[1] \ | ||
120 | && X##_f[2] == Y##_f[2] && X##_f[3] == Y##_f[3]) | ||
121 | |||
122 | #define _FP_FRAC_GT_4(X,Y) \ | ||
123 | (X##_f[3] > Y##_f[3] || \ | ||
124 | (X##_f[3] == Y##_f[3] && (X##_f[2] > Y##_f[2] || \ | ||
125 | (X##_f[2] == Y##_f[2] && (X##_f[1] > Y##_f[1] || \ | ||
126 | (X##_f[1] == Y##_f[1] && X##_f[0] > Y##_f[0]) \ | ||
127 | )) \ | ||
128 | )) \ | ||
129 | ) | ||
130 | |||
131 | #define _FP_FRAC_GE_4(X,Y) \ | ||
132 | (X##_f[3] > Y##_f[3] || \ | ||
133 | (X##_f[3] == Y##_f[3] && (X##_f[2] > Y##_f[2] || \ | ||
134 | (X##_f[2] == Y##_f[2] && (X##_f[1] > Y##_f[1] || \ | ||
135 | (X##_f[1] == Y##_f[1] && X##_f[0] >= Y##_f[0]) \ | ||
136 | )) \ | ||
137 | )) \ | ||
138 | ) | ||
139 | |||
140 | |||
141 | #define _FP_FRAC_CLZ_4(R,X) \ | ||
142 | do { \ | ||
143 | if (X##_f[3]) \ | ||
144 | { \ | ||
145 | __FP_CLZ(R,X##_f[3]); \ | ||
146 | } \ | ||
147 | else if (X##_f[2]) \ | ||
148 | { \ | ||
149 | __FP_CLZ(R,X##_f[2]); \ | ||
150 | R += _FP_W_TYPE_SIZE; \ | ||
151 | } \ | ||
152 | else if (X##_f[1]) \ | ||
153 | { \ | ||
154 | __FP_CLZ(R,X##_f[2]); \ | ||
155 | R += _FP_W_TYPE_SIZE*2; \ | ||
156 | } \ | ||
157 | else \ | ||
158 | { \ | ||
159 | __FP_CLZ(R,X##_f[0]); \ | ||
160 | R += _FP_W_TYPE_SIZE*3; \ | ||
161 | } \ | ||
162 | } while(0) | ||
163 | |||
164 | |||
165 | #define _FP_UNPACK_RAW_4(fs, X, val) \ | ||
166 | do { \ | ||
167 | union _FP_UNION_##fs _flo; _flo.flt = (val); \ | ||
168 | X##_f[0] = _flo.bits.frac0; \ | ||
169 | X##_f[1] = _flo.bits.frac1; \ | ||
170 | X##_f[2] = _flo.bits.frac2; \ | ||
171 | X##_f[3] = _flo.bits.frac3; \ | ||
172 | X##_e = _flo.bits.exp; \ | ||
173 | X##_s = _flo.bits.sign; \ | ||
174 | } while (0) | ||
175 | |||
176 | #define _FP_PACK_RAW_4(fs, val, X) \ | ||
177 | do { \ | ||
178 | union _FP_UNION_##fs _flo; \ | ||
179 | _flo.bits.frac0 = X##_f[0]; \ | ||
180 | _flo.bits.frac1 = X##_f[1]; \ | ||
181 | _flo.bits.frac2 = X##_f[2]; \ | ||
182 | _flo.bits.frac3 = X##_f[3]; \ | ||
183 | _flo.bits.exp = X##_e; \ | ||
184 | _flo.bits.sign = X##_s; \ | ||
185 | (val) = _flo.flt; \ | ||
186 | } while (0) | ||
187 | |||
188 | |||
189 | /* | ||
190 | * Internals | ||
191 | */ | ||
192 | |||
193 | #define __FP_FRAC_SET_4(X,I3,I2,I1,I0) \ | ||
194 | (X##_f[3] = I3, X##_f[2] = I2, X##_f[1] = I1, X##_f[0] = I0) | ||
195 | |||
196 | #ifndef __FP_FRAC_ADD_4 | ||
197 | #define __FP_FRAC_ADD_4(r3,r2,r1,r0,x3,x2,x1,x0,y3,y2,y1,y0) \ | ||
198 | (r0 = x0 + y0, \ | ||
199 | r1 = x1 + y1 + (r0 < x0), \ | ||
200 | r2 = x2 + y2 + (r1 < x1), \ | ||
201 | r3 = x3 + y3 + (r2 < x2)) | ||
202 | #endif | ||
203 | |||
204 | #ifndef __FP_FRAC_SUB_4 | ||
205 | #define __FP_FRAC_SUB_4(r3,r2,r1,r0,x3,x2,x1,x0,y3,y2,y1,y0) \ | ||
206 | (r0 = x0 - y0, \ | ||
207 | r1 = x1 - y1 - (r0 > x0), \ | ||
208 | r2 = x2 - y2 - (r1 > x1), \ | ||
209 | r3 = x3 - y3 - (r2 > x2)) | ||
210 | #endif | ||
211 | |||
212 | #ifndef __FP_FRAC_ADDI_4 | ||
213 | /* I always wanted to be a lisp programmer :-> */ | ||
214 | #define __FP_FRAC_ADDI_4(x3,x2,x1,x0,i) \ | ||
215 | (x3 += ((x2 += ((x1 += ((x0 += i) < x0)) < x1) < x2))) | ||
216 | #endif | ||
217 | |||
218 | /* Convert FP values between word sizes. This appears to be more | ||
219 | * complicated than I'd have expected it to be, so these might be | ||
220 | * wrong... These macros are in any case somewhat bogus because they | ||
221 | * use information about what various FRAC_n variables look like | ||
222 | * internally [eg, that 2 word vars are X_f0 and x_f1]. But so do | ||
223 | * the ones in op-2.h and op-1.h. | ||
224 | */ | ||
225 | #define _FP_FRAC_CONV_1_4(dfs, sfs, D, S) \ | ||
226 | do { \ | ||
227 | _FP_FRAC_SRS_4(S, (_FP_WFRACBITS_##sfs - _FP_WFRACBITS_##dfs), \ | ||
228 | _FP_WFRACBITS_##sfs); \ | ||
229 | D##_f = S##_f[0]; \ | ||
230 | } while (0) | ||
231 | |||
232 | #define _FP_FRAC_CONV_2_4(dfs, sfs, D, S) \ | ||
233 | do { \ | ||
234 | _FP_FRAC_SRS_4(S, (_FP_WFRACBITS_##sfs - _FP_WFRACBITS_##dfs), \ | ||
235 | _FP_WFRACBITS_##sfs); \ | ||
236 | D##_f0 = S##_f[0]; \ | ||
237 | D##_f1 = S##_f[1]; \ | ||
238 | } while (0) | ||
239 | |||
240 | /* Assembly/disassembly for converting to/from integral types. | ||
241 | * No shifting or overflow handled here. | ||
242 | */ | ||
243 | /* Put the FP value X into r, which is an integer of size rsize. */ | ||
244 | #define _FP_FRAC_ASSEMBLE_4(r, X, rsize) \ | ||
245 | do { \ | ||
246 | if (rsize <= _FP_W_TYPE_SIZE) \ | ||
247 | r = X##_f[0]; \ | ||
248 | else if (rsize <= 2*_FP_W_TYPE_SIZE) \ | ||
249 | { \ | ||
250 | r = X##_f[1]; \ | ||
251 | r <<= _FP_W_TYPE_SIZE; \ | ||
252 | r += X##_f[0]; \ | ||
253 | } \ | ||
254 | else \ | ||
255 | { \ | ||
256 | /* I'm feeling lazy so we deal with int == 3words (implausible)*/ \ | ||
257 | /* and int == 4words as a single case. */ \ | ||
258 | r = X##_f[3]; \ | ||
259 | r <<= _FP_W_TYPE_SIZE; \ | ||
260 | r += X##_f[2]; \ | ||
261 | r <<= _FP_W_TYPE_SIZE; \ | ||
262 | r += X##_f[1]; \ | ||
263 | r <<= _FP_W_TYPE_SIZE; \ | ||
264 | r += X##_f[0]; \ | ||
265 | } \ | ||
266 | } while (0) | ||
267 | |||
268 | /* "No disassemble Number Five!" */ | ||
269 | /* move an integer of size rsize into X's fractional part. We rely on | ||
270 | * the _f[] array consisting of words of size _FP_W_TYPE_SIZE to avoid | ||
271 | * having to mask the values we store into it. | ||
272 | */ | ||
273 | #define _FP_FRAC_DISASSEMBLE_4(X, r, rsize) \ | ||
274 | do { \ | ||
275 | X##_f[0] = r; \ | ||
276 | X##_f[1] = (rsize <= _FP_W_TYPE_SIZE ? 0 : r >> _FP_W_TYPE_SIZE); \ | ||
277 | X##_f[2] = (rsize <= 2*_FP_W_TYPE_SIZE ? 0 : r >> 2*_FP_W_TYPE_SIZE); \ | ||
278 | X##_f[3] = (rsize <= 3*_FP_W_TYPE_SIZE ? 0 : r >> 3*_FP_W_TYPE_SIZE); \ | ||
279 | } while (0) | ||
280 | |||
281 | #define _FP_FRAC_CONV_4_1(dfs, sfs, D, S) \ | ||
282 | do { \ | ||
283 | D##_f[0] = S##_f; \ | ||
284 | D##_f[1] = D##_f[2] = D##_f[3] = 0; \ | ||
285 | _FP_FRAC_SLL_4(D, (_FP_WFRACBITS_##dfs - _FP_WFRACBITS_##sfs)); \ | ||
286 | } while (0) | ||
287 | |||
288 | #define _FP_FRAC_CONV_4_2(dfs, sfs, D, S) \ | ||
289 | do { \ | ||
290 | D##_f[0] = S##_f0; \ | ||
291 | D##_f[1] = S##_f1; \ | ||
292 | D##_f[2] = D##_f[3] = 0; \ | ||
293 | _FP_FRAC_SLL_4(D, (_FP_WFRACBITS_##dfs - _FP_WFRACBITS_##sfs)); \ | ||
294 | } while (0) | ||
295 | |||
296 | /* FIXME! This has to be written */ | ||
297 | #define _FP_SQRT_MEAT_4(R, S, T, X, q) | ||
diff --git a/arch/powerpc/math-emu/op-common.h b/arch/powerpc/math-emu/op-common.h new file mode 100644 index 000000000000..afb82b6498ce --- /dev/null +++ b/arch/powerpc/math-emu/op-common.h | |||
@@ -0,0 +1,688 @@ | |||
1 | #define _FP_DECL(wc, X) \ | ||
2 | _FP_I_TYPE X##_c, X##_s, X##_e; \ | ||
3 | _FP_FRAC_DECL_##wc(X) | ||
4 | |||
5 | /* | ||
6 | * Finish truely unpacking a native fp value by classifying the kind | ||
7 | * of fp value and normalizing both the exponent and the fraction. | ||
8 | */ | ||
9 | |||
10 | #define _FP_UNPACK_CANONICAL(fs, wc, X) \ | ||
11 | do { \ | ||
12 | switch (X##_e) \ | ||
13 | { \ | ||
14 | default: \ | ||
15 | _FP_FRAC_HIGH_##wc(X) |= _FP_IMPLBIT_##fs; \ | ||
16 | _FP_FRAC_SLL_##wc(X, _FP_WORKBITS); \ | ||
17 | X##_e -= _FP_EXPBIAS_##fs; \ | ||
18 | X##_c = FP_CLS_NORMAL; \ | ||
19 | break; \ | ||
20 | \ | ||
21 | case 0: \ | ||
22 | if (_FP_FRAC_ZEROP_##wc(X)) \ | ||
23 | X##_c = FP_CLS_ZERO; \ | ||
24 | else \ | ||
25 | { \ | ||
26 | /* a denormalized number */ \ | ||
27 | _FP_I_TYPE _shift; \ | ||
28 | _FP_FRAC_CLZ_##wc(_shift, X); \ | ||
29 | _shift -= _FP_FRACXBITS_##fs; \ | ||
30 | _FP_FRAC_SLL_##wc(X, (_shift+_FP_WORKBITS)); \ | ||
31 | X##_e -= _FP_EXPBIAS_##fs - 1 + _shift; \ | ||
32 | X##_c = FP_CLS_NORMAL; \ | ||
33 | } \ | ||
34 | break; \ | ||
35 | \ | ||
36 | case _FP_EXPMAX_##fs: \ | ||
37 | if (_FP_FRAC_ZEROP_##wc(X)) \ | ||
38 | X##_c = FP_CLS_INF; \ | ||
39 | else \ | ||
40 | /* we don't differentiate between signaling and quiet nans */ \ | ||
41 | X##_c = FP_CLS_NAN; \ | ||
42 | break; \ | ||
43 | } \ | ||
44 | } while (0) | ||
45 | |||
46 | |||
47 | /* | ||
48 | * Before packing the bits back into the native fp result, take care | ||
49 | * of such mundane things as rounding and overflow. Also, for some | ||
50 | * kinds of fp values, the original parts may not have been fully | ||
51 | * extracted -- but that is ok, we can regenerate them now. | ||
52 | */ | ||
53 | |||
54 | #define _FP_PACK_CANONICAL(fs, wc, X) \ | ||
55 | ({int __ret = 0; \ | ||
56 | switch (X##_c) \ | ||
57 | { \ | ||
58 | case FP_CLS_NORMAL: \ | ||
59 | X##_e += _FP_EXPBIAS_##fs; \ | ||
60 | if (X##_e > 0) \ | ||
61 | { \ | ||
62 | __ret |= _FP_ROUND(wc, X); \ | ||
63 | if (_FP_FRAC_OVERP_##wc(fs, X)) \ | ||
64 | { \ | ||
65 | _FP_FRAC_SRL_##wc(X, (_FP_WORKBITS+1)); \ | ||
66 | X##_e++; \ | ||
67 | } \ | ||
68 | else \ | ||
69 | _FP_FRAC_SRL_##wc(X, _FP_WORKBITS); \ | ||
70 | if (X##_e >= _FP_EXPMAX_##fs) \ | ||
71 | { \ | ||
72 | /* overflow to infinity */ \ | ||
73 | X##_e = _FP_EXPMAX_##fs; \ | ||
74 | _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc); \ | ||
75 | __ret |= EFLAG_OVERFLOW; \ | ||
76 | } \ | ||
77 | } \ | ||
78 | else \ | ||
79 | { \ | ||
80 | /* we've got a denormalized number */ \ | ||
81 | X##_e = -X##_e + 1; \ | ||
82 | if (X##_e <= _FP_WFRACBITS_##fs) \ | ||
83 | { \ | ||
84 | _FP_FRAC_SRS_##wc(X, X##_e, _FP_WFRACBITS_##fs); \ | ||
85 | _FP_FRAC_SLL_##wc(X, 1); \ | ||
86 | if (_FP_FRAC_OVERP_##wc(fs, X)) \ | ||
87 | { \ | ||
88 | X##_e = 1; \ | ||
89 | _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc); \ | ||
90 | } \ | ||
91 | else \ | ||
92 | { \ | ||
93 | X##_e = 0; \ | ||
94 | _FP_FRAC_SRL_##wc(X, _FP_WORKBITS+1); \ | ||
95 | __ret |= EFLAG_UNDERFLOW; \ | ||
96 | } \ | ||
97 | } \ | ||
98 | else \ | ||
99 | { \ | ||
100 | /* underflow to zero */ \ | ||
101 | X##_e = 0; \ | ||
102 | _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc); \ | ||
103 | __ret |= EFLAG_UNDERFLOW; \ | ||
104 | } \ | ||
105 | } \ | ||
106 | break; \ | ||
107 | \ | ||
108 | case FP_CLS_ZERO: \ | ||
109 | X##_e = 0; \ | ||
110 | _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc); \ | ||
111 | break; \ | ||
112 | \ | ||
113 | case FP_CLS_INF: \ | ||
114 | X##_e = _FP_EXPMAX_##fs; \ | ||
115 | _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc); \ | ||
116 | break; \ | ||
117 | \ | ||
118 | case FP_CLS_NAN: \ | ||
119 | X##_e = _FP_EXPMAX_##fs; \ | ||
120 | if (!_FP_KEEPNANFRACP) \ | ||
121 | { \ | ||
122 | _FP_FRAC_SET_##wc(X, _FP_NANFRAC_##fs); \ | ||
123 | X##_s = 0; \ | ||
124 | } \ | ||
125 | else \ | ||
126 | _FP_FRAC_HIGH_##wc(X) |= _FP_QNANBIT_##fs; \ | ||
127 | break; \ | ||
128 | } \ | ||
129 | __ret; \ | ||
130 | }) | ||
131 | |||
132 | |||
133 | /* | ||
134 | * Main addition routine. The input values should be cooked. | ||
135 | */ | ||
136 | |||
137 | #define _FP_ADD(fs, wc, R, X, Y) \ | ||
138 | do { \ | ||
139 | switch (_FP_CLS_COMBINE(X##_c, Y##_c)) \ | ||
140 | { \ | ||
141 | case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NORMAL): \ | ||
142 | { \ | ||
143 | /* shift the smaller number so that its exponent matches the larger */ \ | ||
144 | _FP_I_TYPE diff = X##_e - Y##_e; \ | ||
145 | \ | ||
146 | if (diff < 0) \ | ||
147 | { \ | ||
148 | diff = -diff; \ | ||
149 | if (diff <= _FP_WFRACBITS_##fs) \ | ||
150 | _FP_FRAC_SRS_##wc(X, diff, _FP_WFRACBITS_##fs); \ | ||
151 | else if (!_FP_FRAC_ZEROP_##wc(X)) \ | ||
152 | _FP_FRAC_SET_##wc(X, _FP_MINFRAC_##wc); \ | ||
153 | else \ | ||
154 | _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc); \ | ||
155 | R##_e = Y##_e; \ | ||
156 | } \ | ||
157 | else \ | ||
158 | { \ | ||
159 | if (diff > 0) \ | ||
160 | { \ | ||
161 | if (diff <= _FP_WFRACBITS_##fs) \ | ||
162 | _FP_FRAC_SRS_##wc(Y, diff, _FP_WFRACBITS_##fs); \ | ||
163 | else if (!_FP_FRAC_ZEROP_##wc(Y)) \ | ||
164 | _FP_FRAC_SET_##wc(Y, _FP_MINFRAC_##wc); \ | ||
165 | else \ | ||
166 | _FP_FRAC_SET_##wc(Y, _FP_ZEROFRAC_##wc); \ | ||
167 | } \ | ||
168 | R##_e = X##_e; \ | ||
169 | } \ | ||
170 | \ | ||
171 | R##_c = FP_CLS_NORMAL; \ | ||
172 | \ | ||
173 | if (X##_s == Y##_s) \ | ||
174 | { \ | ||
175 | R##_s = X##_s; \ | ||
176 | _FP_FRAC_ADD_##wc(R, X, Y); \ | ||
177 | if (_FP_FRAC_OVERP_##wc(fs, R)) \ | ||
178 | { \ | ||
179 | _FP_FRAC_SRS_##wc(R, 1, _FP_WFRACBITS_##fs); \ | ||
180 | R##_e++; \ | ||
181 | } \ | ||
182 | } \ | ||
183 | else \ | ||
184 | { \ | ||
185 | R##_s = X##_s; \ | ||
186 | _FP_FRAC_SUB_##wc(R, X, Y); \ | ||
187 | if (_FP_FRAC_ZEROP_##wc(R)) \ | ||
188 | { \ | ||
189 | /* return an exact zero */ \ | ||
190 | if (FP_ROUNDMODE == FP_RND_MINF) \ | ||
191 | R##_s |= Y##_s; \ | ||
192 | else \ | ||
193 | R##_s &= Y##_s; \ | ||
194 | R##_c = FP_CLS_ZERO; \ | ||
195 | } \ | ||
196 | else \ | ||
197 | { \ | ||
198 | if (_FP_FRAC_NEGP_##wc(R)) \ | ||
199 | { \ | ||
200 | _FP_FRAC_SUB_##wc(R, Y, X); \ | ||
201 | R##_s = Y##_s; \ | ||
202 | } \ | ||
203 | \ | ||
204 | /* renormalize after subtraction */ \ | ||
205 | _FP_FRAC_CLZ_##wc(diff, R); \ | ||
206 | diff -= _FP_WFRACXBITS_##fs; \ | ||
207 | if (diff) \ | ||
208 | { \ | ||
209 | R##_e -= diff; \ | ||
210 | _FP_FRAC_SLL_##wc(R, diff); \ | ||
211 | } \ | ||
212 | } \ | ||
213 | } \ | ||
214 | break; \ | ||
215 | } \ | ||
216 | \ | ||
217 | case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NAN): \ | ||
218 | _FP_CHOOSENAN(fs, wc, R, X, Y); \ | ||
219 | break; \ | ||
220 | \ | ||
221 | case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_ZERO): \ | ||
222 | R##_e = X##_e; \ | ||
223 | case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NORMAL): \ | ||
224 | case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_INF): \ | ||
225 | case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_ZERO): \ | ||
226 | _FP_FRAC_COPY_##wc(R, X); \ | ||
227 | R##_s = X##_s; \ | ||
228 | R##_c = X##_c; \ | ||
229 | break; \ | ||
230 | \ | ||
231 | case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NORMAL): \ | ||
232 | R##_e = Y##_e; \ | ||
233 | case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NAN): \ | ||
234 | case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NAN): \ | ||
235 | case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NAN): \ | ||
236 | _FP_FRAC_COPY_##wc(R, Y); \ | ||
237 | R##_s = Y##_s; \ | ||
238 | R##_c = Y##_c; \ | ||
239 | break; \ | ||
240 | \ | ||
241 | case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_INF): \ | ||
242 | if (X##_s != Y##_s) \ | ||
243 | { \ | ||
244 | /* +INF + -INF => NAN */ \ | ||
245 | _FP_FRAC_SET_##wc(R, _FP_NANFRAC_##fs); \ | ||
246 | R##_s = X##_s ^ Y##_s; \ | ||
247 | R##_c = FP_CLS_NAN; \ | ||
248 | break; \ | ||
249 | } \ | ||
250 | /* FALLTHRU */ \ | ||
251 | \ | ||
252 | case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NORMAL): \ | ||
253 | case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_ZERO): \ | ||
254 | R##_s = X##_s; \ | ||
255 | R##_c = FP_CLS_INF; \ | ||
256 | break; \ | ||
257 | \ | ||
258 | case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_INF): \ | ||
259 | case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_INF): \ | ||
260 | R##_s = Y##_s; \ | ||
261 | R##_c = FP_CLS_INF; \ | ||
262 | break; \ | ||
263 | \ | ||
264 | case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_ZERO): \ | ||
265 | /* make sure the sign is correct */ \ | ||
266 | if (FP_ROUNDMODE == FP_RND_MINF) \ | ||
267 | R##_s = X##_s | Y##_s; \ | ||
268 | else \ | ||
269 | R##_s = X##_s & Y##_s; \ | ||
270 | R##_c = FP_CLS_ZERO; \ | ||
271 | break; \ | ||
272 | \ | ||
273 | default: \ | ||
274 | abort(); \ | ||
275 | } \ | ||
276 | } while (0) | ||
277 | |||
278 | |||
279 | /* | ||
280 | * Main negation routine. FIXME -- when we care about setting exception | ||
281 | * bits reliably, this will not do. We should examine all of the fp classes. | ||
282 | */ | ||
283 | |||
284 | #define _FP_NEG(fs, wc, R, X) \ | ||
285 | do { \ | ||
286 | _FP_FRAC_COPY_##wc(R, X); \ | ||
287 | R##_c = X##_c; \ | ||
288 | R##_e = X##_e; \ | ||
289 | R##_s = 1 ^ X##_s; \ | ||
290 | } while (0) | ||
291 | |||
292 | |||
293 | /* | ||
294 | * Main multiplication routine. The input values should be cooked. | ||
295 | */ | ||
296 | |||
297 | #define _FP_MUL(fs, wc, R, X, Y) \ | ||
298 | do { \ | ||
299 | R##_s = X##_s ^ Y##_s; \ | ||
300 | switch (_FP_CLS_COMBINE(X##_c, Y##_c)) \ | ||
301 | { \ | ||
302 | case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NORMAL): \ | ||
303 | R##_c = FP_CLS_NORMAL; \ | ||
304 | R##_e = X##_e + Y##_e + 1; \ | ||
305 | \ | ||
306 | _FP_MUL_MEAT_##fs(R,X,Y); \ | ||
307 | \ | ||
308 | if (_FP_FRAC_OVERP_##wc(fs, R)) \ | ||
309 | _FP_FRAC_SRS_##wc(R, 1, _FP_WFRACBITS_##fs); \ | ||
310 | else \ | ||
311 | R##_e--; \ | ||
312 | break; \ | ||
313 | \ | ||
314 | case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NAN): \ | ||
315 | _FP_CHOOSENAN(fs, wc, R, X, Y); \ | ||
316 | break; \ | ||
317 | \ | ||
318 | case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NORMAL): \ | ||
319 | case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_INF): \ | ||
320 | case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_ZERO): \ | ||
321 | R##_s = X##_s; \ | ||
322 | \ | ||
323 | case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_INF): \ | ||
324 | case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NORMAL): \ | ||
325 | case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NORMAL): \ | ||
326 | case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_ZERO): \ | ||
327 | _FP_FRAC_COPY_##wc(R, X); \ | ||
328 | R##_c = X##_c; \ | ||
329 | break; \ | ||
330 | \ | ||
331 | case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NAN): \ | ||
332 | case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NAN): \ | ||
333 | case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NAN): \ | ||
334 | R##_s = Y##_s; \ | ||
335 | \ | ||
336 | case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_INF): \ | ||
337 | case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_ZERO): \ | ||
338 | _FP_FRAC_COPY_##wc(R, Y); \ | ||
339 | R##_c = Y##_c; \ | ||
340 | break; \ | ||
341 | \ | ||
342 | case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_ZERO): \ | ||
343 | case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_INF): \ | ||
344 | R##_c = FP_CLS_NAN; \ | ||
345 | _FP_FRAC_SET_##wc(R, _FP_NANFRAC_##fs); \ | ||
346 | break; \ | ||
347 | \ | ||
348 | default: \ | ||
349 | abort(); \ | ||
350 | } \ | ||
351 | } while (0) | ||
352 | |||
353 | |||
354 | /* | ||
355 | * Main division routine. The input values should be cooked. | ||
356 | */ | ||
357 | |||
358 | #define _FP_DIV(fs, wc, R, X, Y) \ | ||
359 | do { \ | ||
360 | R##_s = X##_s ^ Y##_s; \ | ||
361 | switch (_FP_CLS_COMBINE(X##_c, Y##_c)) \ | ||
362 | { \ | ||
363 | case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NORMAL): \ | ||
364 | R##_c = FP_CLS_NORMAL; \ | ||
365 | R##_e = X##_e - Y##_e; \ | ||
366 | \ | ||
367 | _FP_DIV_MEAT_##fs(R,X,Y); \ | ||
368 | break; \ | ||
369 | \ | ||
370 | case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NAN): \ | ||
371 | _FP_CHOOSENAN(fs, wc, R, X, Y); \ | ||
372 | break; \ | ||
373 | \ | ||
374 | case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NORMAL): \ | ||
375 | case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_INF): \ | ||
376 | case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_ZERO): \ | ||
377 | R##_s = X##_s; \ | ||
378 | _FP_FRAC_COPY_##wc(R, X); \ | ||
379 | R##_c = X##_c; \ | ||
380 | break; \ | ||
381 | \ | ||
382 | case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NAN): \ | ||
383 | case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NAN): \ | ||
384 | case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NAN): \ | ||
385 | R##_s = Y##_s; \ | ||
386 | _FP_FRAC_COPY_##wc(R, Y); \ | ||
387 | R##_c = Y##_c; \ | ||
388 | break; \ | ||
389 | \ | ||
390 | case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_INF): \ | ||
391 | case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_INF): \ | ||
392 | case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NORMAL): \ | ||
393 | R##_c = FP_CLS_ZERO; \ | ||
394 | break; \ | ||
395 | \ | ||
396 | case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_ZERO): \ | ||
397 | case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_ZERO): \ | ||
398 | case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NORMAL): \ | ||
399 | R##_c = FP_CLS_INF; \ | ||
400 | break; \ | ||
401 | \ | ||
402 | case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_INF): \ | ||
403 | case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_ZERO): \ | ||
404 | R##_c = FP_CLS_NAN; \ | ||
405 | _FP_FRAC_SET_##wc(R, _FP_NANFRAC_##fs); \ | ||
406 | break; \ | ||
407 | \ | ||
408 | default: \ | ||
409 | abort(); \ | ||
410 | } \ | ||
411 | } while (0) | ||
412 | |||
413 | |||
414 | /* | ||
415 | * Main differential comparison routine. The inputs should be raw not | ||
416 | * cooked. The return is -1,0,1 for normal values, 2 otherwise. | ||
417 | */ | ||
418 | |||
419 | #define _FP_CMP(fs, wc, ret, X, Y, un) \ | ||
420 | do { \ | ||
421 | /* NANs are unordered */ \ | ||
422 | if ((X##_e == _FP_EXPMAX_##fs && !_FP_FRAC_ZEROP_##wc(X)) \ | ||
423 | || (Y##_e == _FP_EXPMAX_##fs && !_FP_FRAC_ZEROP_##wc(Y))) \ | ||
424 | { \ | ||
425 | ret = un; \ | ||
426 | } \ | ||
427 | else \ | ||
428 | { \ | ||
429 | int __x_zero = (!X##_e && _FP_FRAC_ZEROP_##wc(X)) ? 1 : 0; \ | ||
430 | int __y_zero = (!Y##_e && _FP_FRAC_ZEROP_##wc(Y)) ? 1 : 0; \ | ||
431 | \ | ||
432 | if (__x_zero && __y_zero) \ | ||
433 | ret = 0; \ | ||
434 | else if (__x_zero) \ | ||
435 | ret = Y##_s ? 1 : -1; \ | ||
436 | else if (__y_zero) \ | ||
437 | ret = X##_s ? -1 : 1; \ | ||
438 | else if (X##_s != Y##_s) \ | ||
439 | ret = X##_s ? -1 : 1; \ | ||
440 | else if (X##_e > Y##_e) \ | ||
441 | ret = X##_s ? -1 : 1; \ | ||
442 | else if (X##_e < Y##_e) \ | ||
443 | ret = X##_s ? 1 : -1; \ | ||
444 | else if (_FP_FRAC_GT_##wc(X, Y)) \ | ||
445 | ret = X##_s ? -1 : 1; \ | ||
446 | else if (_FP_FRAC_GT_##wc(Y, X)) \ | ||
447 | ret = X##_s ? 1 : -1; \ | ||
448 | else \ | ||
449 | ret = 0; \ | ||
450 | } \ | ||
451 | } while (0) | ||
452 | |||
453 | |||
454 | /* Simplification for strict equality. */ | ||
455 | |||
456 | #define _FP_CMP_EQ(fs, wc, ret, X, Y) \ | ||
457 | do { \ | ||
458 | /* NANs are unordered */ \ | ||
459 | if ((X##_e == _FP_EXPMAX_##fs && !_FP_FRAC_ZEROP_##wc(X)) \ | ||
460 | || (Y##_e == _FP_EXPMAX_##fs && !_FP_FRAC_ZEROP_##wc(Y))) \ | ||
461 | { \ | ||
462 | ret = 1; \ | ||
463 | } \ | ||
464 | else \ | ||
465 | { \ | ||
466 | ret = !(X##_e == Y##_e \ | ||
467 | && _FP_FRAC_EQ_##wc(X, Y) \ | ||
468 | && (X##_s == Y##_s || !X##_e && _FP_FRAC_ZEROP_##wc(X))); \ | ||
469 | } \ | ||
470 | } while (0) | ||
471 | |||
472 | /* | ||
473 | * Main square root routine. The input value should be cooked. | ||
474 | */ | ||
475 | |||
476 | #define _FP_SQRT(fs, wc, R, X) \ | ||
477 | do { \ | ||
478 | _FP_FRAC_DECL_##wc(T); _FP_FRAC_DECL_##wc(S); \ | ||
479 | _FP_W_TYPE q; \ | ||
480 | switch (X##_c) \ | ||
481 | { \ | ||
482 | case FP_CLS_NAN: \ | ||
483 | R##_s = 0; \ | ||
484 | R##_c = FP_CLS_NAN; \ | ||
485 | _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc); \ | ||
486 | break; \ | ||
487 | case FP_CLS_INF: \ | ||
488 | if (X##_s) \ | ||
489 | { \ | ||
490 | R##_s = 0; \ | ||
491 | R##_c = FP_CLS_NAN; /* sNAN */ \ | ||
492 | } \ | ||
493 | else \ | ||
494 | { \ | ||
495 | R##_s = 0; \ | ||
496 | R##_c = FP_CLS_INF; /* sqrt(+inf) = +inf */ \ | ||
497 | } \ | ||
498 | break; \ | ||
499 | case FP_CLS_ZERO: \ | ||
500 | R##_s = X##_s; \ | ||
501 | R##_c = FP_CLS_ZERO; /* sqrt(+-0) = +-0 */ \ | ||
502 | break; \ | ||
503 | case FP_CLS_NORMAL: \ | ||
504 | R##_s = 0; \ | ||
505 | if (X##_s) \ | ||
506 | { \ | ||
507 | R##_c = FP_CLS_NAN; /* sNAN */ \ | ||
508 | break; \ | ||
509 | } \ | ||
510 | R##_c = FP_CLS_NORMAL; \ | ||
511 | if (X##_e & 1) \ | ||
512 | _FP_FRAC_SLL_##wc(X, 1); \ | ||
513 | R##_e = X##_e >> 1; \ | ||
514 | _FP_FRAC_SET_##wc(S, _FP_ZEROFRAC_##wc); \ | ||
515 | _FP_FRAC_SET_##wc(R, _FP_ZEROFRAC_##wc); \ | ||
516 | q = _FP_OVERFLOW_##fs; \ | ||
517 | _FP_FRAC_SLL_##wc(X, 1); \ | ||
518 | _FP_SQRT_MEAT_##wc(R, S, T, X, q); \ | ||
519 | _FP_FRAC_SRL_##wc(R, 1); \ | ||
520 | } \ | ||
521 | } while (0) | ||
522 | |||
523 | /* | ||
524 | * Convert from FP to integer | ||
525 | */ | ||
526 | |||
527 | /* "When a NaN, infinity, large positive argument >= 2147483648.0, or | ||
528 | * large negative argument <= -2147483649.0 is converted to an integer, | ||
529 | * the invalid_current bit...should be set and fp_exception_IEEE_754 should | ||
530 | * be raised. If the floating point invalid trap is disabled, no trap occurs | ||
531 | * and a numerical result is generated: if the sign bit of the operand | ||
532 | * is 0, the result is 2147483647; if the sign bit of the operand is 1, | ||
533 | * the result is -2147483648." | ||
534 | * Similarly for conversion to extended ints, except that the boundaries | ||
535 | * are >= 2^63, <= -(2^63 + 1), and the results are 2^63 + 1 for s=0 and | ||
536 | * -2^63 for s=1. | ||
537 | * -- SPARC Architecture Manual V9, Appendix B, which specifies how | ||
538 | * SPARCs resolve implementation dependencies in the IEEE-754 spec. | ||
539 | * I don't believe that the code below follows this. I'm not even sure | ||
540 | * it's right! | ||
541 | * It doesn't cope with needing to convert to an n bit integer when there | ||
542 | * is no n bit integer type. Fortunately gcc provides long long so this | ||
543 | * isn't a problem for sparc32. | ||
544 | * I have, however, fixed its NaN handling to conform as above. | ||
545 | * -- PMM 02/1998 | ||
546 | * NB: rsigned is not 'is r declared signed?' but 'should the value stored | ||
547 | * in r be signed or unsigned?'. r is always(?) declared unsigned. | ||
548 | * Comments below are mine, BTW -- PMM | ||
549 | */ | ||
550 | #define _FP_TO_INT(fs, wc, r, X, rsize, rsigned) \ | ||
551 | do { \ | ||
552 | switch (X##_c) \ | ||
553 | { \ | ||
554 | case FP_CLS_NORMAL: \ | ||
555 | if (X##_e < 0) \ | ||
556 | { \ | ||
557 | /* case FP_CLS_NAN: see above! */ \ | ||
558 | case FP_CLS_ZERO: \ | ||
559 | r = 0; \ | ||
560 | } \ | ||
561 | else if (X##_e >= rsize - (rsigned != 0)) \ | ||
562 | { /* overflow */ \ | ||
563 | case FP_CLS_NAN: \ | ||
564 | case FP_CLS_INF: \ | ||
565 | if (rsigned) \ | ||
566 | { \ | ||
567 | r = 1; \ | ||
568 | r <<= rsize - 1; \ | ||
569 | r -= 1 - X##_s; \ | ||
570 | } \ | ||
571 | else \ | ||
572 | { \ | ||
573 | r = 0; \ | ||
574 | if (!X##_s) \ | ||
575 | r = ~r; \ | ||
576 | } \ | ||
577 | } \ | ||
578 | else \ | ||
579 | { \ | ||
580 | if (_FP_W_TYPE_SIZE*wc < rsize) \ | ||
581 | { \ | ||
582 | _FP_FRAC_ASSEMBLE_##wc(r, X, rsize); \ | ||
583 | r <<= X##_e - _FP_WFRACBITS_##fs; \ | ||
584 | } \ | ||
585 | else \ | ||
586 | { \ | ||
587 | if (X##_e >= _FP_WFRACBITS_##fs) \ | ||
588 | _FP_FRAC_SLL_##wc(X, (X##_e - _FP_WFRACBITS_##fs + 1));\ | ||
589 | else \ | ||
590 | _FP_FRAC_SRL_##wc(X, (_FP_WFRACBITS_##fs - X##_e - 1));\ | ||
591 | _FP_FRAC_ASSEMBLE_##wc(r, X, rsize); \ | ||
592 | } \ | ||
593 | if (rsigned && X##_s) \ | ||
594 | r = -r; \ | ||
595 | } \ | ||
596 | break; \ | ||
597 | } \ | ||
598 | } while (0) | ||
599 | |||
600 | #define _FP_FROM_INT(fs, wc, X, r, rsize, rtype) \ | ||
601 | do { \ | ||
602 | if (r) \ | ||
603 | { \ | ||
604 | X##_c = FP_CLS_NORMAL; \ | ||
605 | \ | ||
606 | if ((X##_s = (r < 0))) \ | ||
607 | r = -r; \ | ||
608 | /* Note that `r' is now considered unsigned, so we don't have \ | ||
609 | to worry about the single signed overflow case. */ \ | ||
610 | \ | ||
611 | if (rsize <= _FP_W_TYPE_SIZE) \ | ||
612 | __FP_CLZ(X##_e, r); \ | ||
613 | else \ | ||
614 | __FP_CLZ_2(X##_e, (_FP_W_TYPE)(r >> _FP_W_TYPE_SIZE), \ | ||
615 | (_FP_W_TYPE)r); \ | ||
616 | if (rsize < _FP_W_TYPE_SIZE) \ | ||
617 | X##_e -= (_FP_W_TYPE_SIZE - rsize); \ | ||
618 | X##_e = rsize - X##_e - 1; \ | ||
619 | \ | ||
620 | if (_FP_FRACBITS_##fs < rsize && _FP_WFRACBITS_##fs < X##_e) \ | ||
621 | __FP_FRAC_SRS_1(r, (X##_e - _FP_WFRACBITS_##fs), rsize); \ | ||
622 | r &= ~((_FP_W_TYPE)1 << X##_e); \ | ||
623 | _FP_FRAC_DISASSEMBLE_##wc(X, ((unsigned rtype)r), rsize); \ | ||
624 | _FP_FRAC_SLL_##wc(X, (_FP_WFRACBITS_##fs - X##_e - 1)); \ | ||
625 | } \ | ||
626 | else \ | ||
627 | { \ | ||
628 | X##_c = FP_CLS_ZERO, X##_s = 0; \ | ||
629 | } \ | ||
630 | } while (0) | ||
631 | |||
632 | |||
633 | #define FP_CONV(dfs,sfs,dwc,swc,D,S) \ | ||
634 | do { \ | ||
635 | _FP_FRAC_CONV_##dwc##_##swc(dfs, sfs, D, S); \ | ||
636 | D##_e = S##_e; \ | ||
637 | D##_c = S##_c; \ | ||
638 | D##_s = S##_s; \ | ||
639 | } while (0) | ||
640 | |||
641 | /* | ||
642 | * Helper primitives. | ||
643 | */ | ||
644 | |||
645 | /* Count leading zeros in a word. */ | ||
646 | |||
647 | #ifndef __FP_CLZ | ||
648 | #if _FP_W_TYPE_SIZE < 64 | ||
649 | /* this is just to shut the compiler up about shifts > word length -- PMM 02/1998 */ | ||
650 | #define __FP_CLZ(r, x) \ | ||
651 | do { \ | ||
652 | _FP_W_TYPE _t = (x); \ | ||
653 | r = _FP_W_TYPE_SIZE - 1; \ | ||
654 | if (_t > 0xffff) r -= 16; \ | ||
655 | if (_t > 0xffff) _t >>= 16; \ | ||
656 | if (_t > 0xff) r -= 8; \ | ||
657 | if (_t > 0xff) _t >>= 8; \ | ||
658 | if (_t & 0xf0) r -= 4; \ | ||
659 | if (_t & 0xf0) _t >>= 4; \ | ||
660 | if (_t & 0xc) r -= 2; \ | ||
661 | if (_t & 0xc) _t >>= 2; \ | ||
662 | if (_t & 0x2) r -= 1; \ | ||
663 | } while (0) | ||
664 | #else /* not _FP_W_TYPE_SIZE < 64 */ | ||
665 | #define __FP_CLZ(r, x) \ | ||
666 | do { \ | ||
667 | _FP_W_TYPE _t = (x); \ | ||
668 | r = _FP_W_TYPE_SIZE - 1; \ | ||
669 | if (_t > 0xffffffff) r -= 32; \ | ||
670 | if (_t > 0xffffffff) _t >>= 32; \ | ||
671 | if (_t > 0xffff) r -= 16; \ | ||
672 | if (_t > 0xffff) _t >>= 16; \ | ||
673 | if (_t > 0xff) r -= 8; \ | ||
674 | if (_t > 0xff) _t >>= 8; \ | ||
675 | if (_t & 0xf0) r -= 4; \ | ||
676 | if (_t & 0xf0) _t >>= 4; \ | ||
677 | if (_t & 0xc) r -= 2; \ | ||
678 | if (_t & 0xc) _t >>= 2; \ | ||
679 | if (_t & 0x2) r -= 1; \ | ||
680 | } while (0) | ||
681 | #endif /* not _FP_W_TYPE_SIZE < 64 */ | ||
682 | #endif /* ndef __FP_CLZ */ | ||
683 | |||
684 | #define _FP_DIV_HELP_imm(q, r, n, d) \ | ||
685 | do { \ | ||
686 | q = n / d, r = n % d; \ | ||
687 | } while (0) | ||
688 | |||
diff --git a/arch/powerpc/math-emu/sfp-machine.h b/arch/powerpc/math-emu/sfp-machine.h new file mode 100644 index 000000000000..4b17d83cfcdd --- /dev/null +++ b/arch/powerpc/math-emu/sfp-machine.h | |||
@@ -0,0 +1,377 @@ | |||
1 | /* Machine-dependent software floating-point definitions. PPC version. | ||
2 | Copyright (C) 1997 Free Software Foundation, Inc. | ||
3 | This file is part of the GNU C Library. | ||
4 | |||
5 | The GNU C Library is free software; you can redistribute it and/or | ||
6 | modify it under the terms of the GNU Library General Public License as | ||
7 | published by the Free Software Foundation; either version 2 of the | ||
8 | License, or (at your option) any later version. | ||
9 | |||
10 | The GNU C Library is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Library General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Library General Public | ||
16 | License along with the GNU C Library; see the file COPYING.LIB. If | ||
17 | not, write to the Free Software Foundation, Inc., | ||
18 | 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
19 | |||
20 | Actually, this is a PPC (32bit) version, written based on the | ||
21 | i386, sparc, and sparc64 versions, by me, | ||
22 | Peter Maydell (pmaydell@chiark.greenend.org.uk). | ||
23 | Comments are by and large also mine, although they may be inaccurate. | ||
24 | |||
25 | In picking out asm fragments I've gone with the lowest common | ||
26 | denominator, which also happens to be the hardware I have :-> | ||
27 | That is, a SPARC without hardware multiply and divide. | ||
28 | */ | ||
29 | |||
30 | /* basic word size definitions */ | ||
31 | #define _FP_W_TYPE_SIZE 32 | ||
32 | #define _FP_W_TYPE unsigned long | ||
33 | #define _FP_WS_TYPE signed long | ||
34 | #define _FP_I_TYPE long | ||
35 | |||
36 | #define __ll_B ((UWtype) 1 << (W_TYPE_SIZE / 2)) | ||
37 | #define __ll_lowpart(t) ((UWtype) (t) & (__ll_B - 1)) | ||
38 | #define __ll_highpart(t) ((UWtype) (t) >> (W_TYPE_SIZE / 2)) | ||
39 | |||
40 | /* You can optionally code some things like addition in asm. For | ||
41 | * example, i386 defines __FP_FRAC_ADD_2 as asm. If you don't | ||
42 | * then you get a fragment of C code [if you change an #ifdef 0 | ||
43 | * in op-2.h] or a call to add_ssaaaa (see below). | ||
44 | * Good places to look for asm fragments to use are gcc and glibc. | ||
45 | * gcc's longlong.h is useful. | ||
46 | */ | ||
47 | |||
48 | /* We need to know how to multiply and divide. If the host word size | ||
49 | * is >= 2*fracbits you can use FP_MUL_MEAT_n_imm(t,R,X,Y) which | ||
50 | * codes the multiply with whatever gcc does to 'a * b'. | ||
51 | * _FP_MUL_MEAT_n_wide(t,R,X,Y,f) is used when you have an asm | ||
52 | * function that can multiply two 1W values and get a 2W result. | ||
53 | * Otherwise you're stuck with _FP_MUL_MEAT_n_hard(t,R,X,Y) which | ||
54 | * does bitshifting to avoid overflow. | ||
55 | * For division there is FP_DIV_MEAT_n_imm(t,R,X,Y,f) for word size | ||
56 | * >= 2*fracbits, where f is either _FP_DIV_HELP_imm or | ||
57 | * _FP_DIV_HELP_ldiv (see op-1.h). | ||
58 | * _FP_DIV_MEAT_udiv() is if you have asm to do 2W/1W => (1W, 1W). | ||
59 | * [GCC and glibc have longlong.h which has the asm macro udiv_qrnnd | ||
60 | * to do this.] | ||
61 | * In general, 'n' is the number of words required to hold the type, | ||
62 | * and 't' is either S, D or Q for single/double/quad. | ||
63 | * -- PMM | ||
64 | */ | ||
65 | /* Example: SPARC64: | ||
66 | * #define _FP_MUL_MEAT_S(R,X,Y) _FP_MUL_MEAT_1_imm(S,R,X,Y) | ||
67 | * #define _FP_MUL_MEAT_D(R,X,Y) _FP_MUL_MEAT_1_wide(D,R,X,Y,umul_ppmm) | ||
68 | * #define _FP_MUL_MEAT_Q(R,X,Y) _FP_MUL_MEAT_2_wide(Q,R,X,Y,umul_ppmm) | ||
69 | * | ||
70 | * #define _FP_DIV_MEAT_S(R,X,Y) _FP_DIV_MEAT_1_imm(S,R,X,Y,_FP_DIV_HELP_imm) | ||
71 | * #define _FP_DIV_MEAT_D(R,X,Y) _FP_DIV_MEAT_1_udiv(D,R,X,Y) | ||
72 | * #define _FP_DIV_MEAT_Q(R,X,Y) _FP_DIV_MEAT_2_udiv_64(Q,R,X,Y) | ||
73 | * | ||
74 | * Example: i386: | ||
75 | * #define _FP_MUL_MEAT_S(R,X,Y) _FP_MUL_MEAT_1_wide(S,R,X,Y,_i386_mul_32_64) | ||
76 | * #define _FP_MUL_MEAT_D(R,X,Y) _FP_MUL_MEAT_2_wide(D,R,X,Y,_i386_mul_32_64) | ||
77 | * | ||
78 | * #define _FP_DIV_MEAT_S(R,X,Y) _FP_DIV_MEAT_1_udiv(S,R,X,Y,_i386_div_64_32) | ||
79 | * #define _FP_DIV_MEAT_D(R,X,Y) _FP_DIV_MEAT_2_udiv_64(D,R,X,Y) | ||
80 | */ | ||
81 | |||
82 | #define _FP_MUL_MEAT_S(R,X,Y) _FP_MUL_MEAT_1_wide(S,R,X,Y,umul_ppmm) | ||
83 | #define _FP_MUL_MEAT_D(R,X,Y) _FP_MUL_MEAT_2_wide(D,R,X,Y,umul_ppmm) | ||
84 | |||
85 | #define _FP_DIV_MEAT_S(R,X,Y) _FP_DIV_MEAT_1_udiv(S,R,X,Y) | ||
86 | #define _FP_DIV_MEAT_D(R,X,Y) _FP_DIV_MEAT_2_udiv_64(D,R,X,Y) | ||
87 | |||
88 | /* These macros define what NaN looks like. They're supposed to expand to | ||
89 | * a comma-separated set of 32bit unsigned ints that encode NaN. | ||
90 | */ | ||
91 | #define _FP_NANFRAC_S _FP_QNANBIT_S | ||
92 | #define _FP_NANFRAC_D _FP_QNANBIT_D, 0 | ||
93 | #define _FP_NANFRAC_Q _FP_QNANBIT_Q, 0, 0, 0 | ||
94 | |||
95 | #define _FP_KEEPNANFRACP 1 | ||
96 | |||
97 | /* This macro appears to be called when both X and Y are NaNs, and | ||
98 | * has to choose one and copy it to R. i386 goes for the larger of the | ||
99 | * two, sparc64 just picks Y. I don't understand this at all so I'll | ||
100 | * go with sparc64 because it's shorter :-> -- PMM | ||
101 | */ | ||
102 | #define _FP_CHOOSENAN(fs, wc, R, X, Y) \ | ||
103 | do { \ | ||
104 | R##_s = Y##_s; \ | ||
105 | _FP_FRAC_COPY_##wc(R,Y); \ | ||
106 | R##_c = FP_CLS_NAN; \ | ||
107 | } while (0) | ||
108 | |||
109 | |||
110 | extern void fp_unpack_d(long *, unsigned long *, unsigned long *, | ||
111 | long *, long *, void *); | ||
112 | extern int fp_pack_d(void *, long, unsigned long, unsigned long, long, long); | ||
113 | extern int fp_pack_ds(void *, long, unsigned long, unsigned long, long, long); | ||
114 | |||
115 | #define __FP_UNPACK_RAW_1(fs, X, val) \ | ||
116 | do { \ | ||
117 | union _FP_UNION_##fs *_flo = \ | ||
118 | (union _FP_UNION_##fs *)val; \ | ||
119 | \ | ||
120 | X##_f = _flo->bits.frac; \ | ||
121 | X##_e = _flo->bits.exp; \ | ||
122 | X##_s = _flo->bits.sign; \ | ||
123 | } while (0) | ||
124 | |||
125 | #define __FP_UNPACK_RAW_2(fs, X, val) \ | ||
126 | do { \ | ||
127 | union _FP_UNION_##fs *_flo = \ | ||
128 | (union _FP_UNION_##fs *)val; \ | ||
129 | \ | ||
130 | X##_f0 = _flo->bits.frac0; \ | ||
131 | X##_f1 = _flo->bits.frac1; \ | ||
132 | X##_e = _flo->bits.exp; \ | ||
133 | X##_s = _flo->bits.sign; \ | ||
134 | } while (0) | ||
135 | |||
136 | #define __FP_UNPACK_S(X,val) \ | ||
137 | do { \ | ||
138 | __FP_UNPACK_RAW_1(S,X,val); \ | ||
139 | _FP_UNPACK_CANONICAL(S,1,X); \ | ||
140 | } while (0) | ||
141 | |||
142 | #define __FP_UNPACK_D(X,val) \ | ||
143 | fp_unpack_d(&X##_s, &X##_f1, &X##_f0, &X##_e, &X##_c, val) | ||
144 | |||
145 | #define __FP_PACK_RAW_1(fs, val, X) \ | ||
146 | do { \ | ||
147 | union _FP_UNION_##fs *_flo = \ | ||
148 | (union _FP_UNION_##fs *)val; \ | ||
149 | \ | ||
150 | _flo->bits.frac = X##_f; \ | ||
151 | _flo->bits.exp = X##_e; \ | ||
152 | _flo->bits.sign = X##_s; \ | ||
153 | } while (0) | ||
154 | |||
155 | #define __FP_PACK_RAW_2(fs, val, X) \ | ||
156 | do { \ | ||
157 | union _FP_UNION_##fs *_flo = \ | ||
158 | (union _FP_UNION_##fs *)val; \ | ||
159 | \ | ||
160 | _flo->bits.frac0 = X##_f0; \ | ||
161 | _flo->bits.frac1 = X##_f1; \ | ||
162 | _flo->bits.exp = X##_e; \ | ||
163 | _flo->bits.sign = X##_s; \ | ||
164 | } while (0) | ||
165 | |||
166 | #include <linux/kernel.h> | ||
167 | #include <linux/sched.h> | ||
168 | |||
169 | #define __FPU_FPSCR (current->thread.fpscr.val) | ||
170 | |||
171 | /* We only actually write to the destination register | ||
172 | * if exceptions signalled (if any) will not trap. | ||
173 | */ | ||
174 | #define __FPU_ENABLED_EXC \ | ||
175 | ({ \ | ||
176 | (__FPU_FPSCR >> 3) & 0x1f; \ | ||
177 | }) | ||
178 | |||
179 | #define __FPU_TRAP_P(bits) \ | ||
180 | ((__FPU_ENABLED_EXC & (bits)) != 0) | ||
181 | |||
182 | #define __FP_PACK_S(val,X) \ | ||
183 | ({ int __exc = _FP_PACK_CANONICAL(S,1,X); \ | ||
184 | if(!__exc || !__FPU_TRAP_P(__exc)) \ | ||
185 | __FP_PACK_RAW_1(S,val,X); \ | ||
186 | __exc; \ | ||
187 | }) | ||
188 | |||
189 | #define __FP_PACK_D(val,X) \ | ||
190 | fp_pack_d(val, X##_s, X##_f1, X##_f0, X##_e, X##_c) | ||
191 | |||
192 | #define __FP_PACK_DS(val,X) \ | ||
193 | fp_pack_ds(val, X##_s, X##_f1, X##_f0, X##_e, X##_c) | ||
194 | |||
195 | /* Obtain the current rounding mode. */ | ||
196 | #define FP_ROUNDMODE \ | ||
197 | ({ \ | ||
198 | __FPU_FPSCR & 0x3; \ | ||
199 | }) | ||
200 | |||
201 | /* the asm fragments go here: all these are taken from glibc-2.0.5's | ||
202 | * stdlib/longlong.h | ||
203 | */ | ||
204 | |||
205 | #include <linux/types.h> | ||
206 | #include <asm/byteorder.h> | ||
207 | |||
208 | /* add_ssaaaa is used in op-2.h and should be equivalent to | ||
209 | * #define add_ssaaaa(sh,sl,ah,al,bh,bl) (sh = ah+bh+ (( sl = al+bl) < al)) | ||
210 | * add_ssaaaa(high_sum, low_sum, high_addend_1, low_addend_1, | ||
211 | * high_addend_2, low_addend_2) adds two UWtype integers, composed by | ||
212 | * HIGH_ADDEND_1 and LOW_ADDEND_1, and HIGH_ADDEND_2 and LOW_ADDEND_2 | ||
213 | * respectively. The result is placed in HIGH_SUM and LOW_SUM. Overflow | ||
214 | * (i.e. carry out) is not stored anywhere, and is lost. | ||
215 | */ | ||
216 | #define add_ssaaaa(sh, sl, ah, al, bh, bl) \ | ||
217 | do { \ | ||
218 | if (__builtin_constant_p (bh) && (bh) == 0) \ | ||
219 | __asm__ ("{a%I4|add%I4c} %1,%3,%4\n\t{aze|addze} %0,%2" \ | ||
220 | : "=r" ((USItype)(sh)), \ | ||
221 | "=&r" ((USItype)(sl)) \ | ||
222 | : "%r" ((USItype)(ah)), \ | ||
223 | "%r" ((USItype)(al)), \ | ||
224 | "rI" ((USItype)(bl))); \ | ||
225 | else if (__builtin_constant_p (bh) && (bh) ==~(USItype) 0) \ | ||
226 | __asm__ ("{a%I4|add%I4c} %1,%3,%4\n\t{ame|addme} %0,%2" \ | ||
227 | : "=r" ((USItype)(sh)), \ | ||
228 | "=&r" ((USItype)(sl)) \ | ||
229 | : "%r" ((USItype)(ah)), \ | ||
230 | "%r" ((USItype)(al)), \ | ||
231 | "rI" ((USItype)(bl))); \ | ||
232 | else \ | ||
233 | __asm__ ("{a%I5|add%I5c} %1,%4,%5\n\t{ae|adde} %0,%2,%3" \ | ||
234 | : "=r" ((USItype)(sh)), \ | ||
235 | "=&r" ((USItype)(sl)) \ | ||
236 | : "%r" ((USItype)(ah)), \ | ||
237 | "r" ((USItype)(bh)), \ | ||
238 | "%r" ((USItype)(al)), \ | ||
239 | "rI" ((USItype)(bl))); \ | ||
240 | } while (0) | ||
241 | |||
242 | /* sub_ddmmss is used in op-2.h and udivmodti4.c and should be equivalent to | ||
243 | * #define sub_ddmmss(sh, sl, ah, al, bh, bl) (sh = ah-bh - ((sl = al-bl) > al)) | ||
244 | * sub_ddmmss(high_difference, low_difference, high_minuend, low_minuend, | ||
245 | * high_subtrahend, low_subtrahend) subtracts two two-word UWtype integers, | ||
246 | * composed by HIGH_MINUEND_1 and LOW_MINUEND_1, and HIGH_SUBTRAHEND_2 and | ||
247 | * LOW_SUBTRAHEND_2 respectively. The result is placed in HIGH_DIFFERENCE | ||
248 | * and LOW_DIFFERENCE. Overflow (i.e. carry out) is not stored anywhere, | ||
249 | * and is lost. | ||
250 | */ | ||
251 | #define sub_ddmmss(sh, sl, ah, al, bh, bl) \ | ||
252 | do { \ | ||
253 | if (__builtin_constant_p (ah) && (ah) == 0) \ | ||
254 | __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{sfze|subfze} %0,%2" \ | ||
255 | : "=r" ((USItype)(sh)), \ | ||
256 | "=&r" ((USItype)(sl)) \ | ||
257 | : "r" ((USItype)(bh)), \ | ||
258 | "rI" ((USItype)(al)), \ | ||
259 | "r" ((USItype)(bl))); \ | ||
260 | else if (__builtin_constant_p (ah) && (ah) ==~(USItype) 0) \ | ||
261 | __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{sfme|subfme} %0,%2" \ | ||
262 | : "=r" ((USItype)(sh)), \ | ||
263 | "=&r" ((USItype)(sl)) \ | ||
264 | : "r" ((USItype)(bh)), \ | ||
265 | "rI" ((USItype)(al)), \ | ||
266 | "r" ((USItype)(bl))); \ | ||
267 | else if (__builtin_constant_p (bh) && (bh) == 0) \ | ||
268 | __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{ame|addme} %0,%2" \ | ||
269 | : "=r" ((USItype)(sh)), \ | ||
270 | "=&r" ((USItype)(sl)) \ | ||
271 | : "r" ((USItype)(ah)), \ | ||
272 | "rI" ((USItype)(al)), \ | ||
273 | "r" ((USItype)(bl))); \ | ||
274 | else if (__builtin_constant_p (bh) && (bh) ==~(USItype) 0) \ | ||
275 | __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{aze|addze} %0,%2" \ | ||
276 | : "=r" ((USItype)(sh)), \ | ||
277 | "=&r" ((USItype)(sl)) \ | ||
278 | : "r" ((USItype)(ah)), \ | ||
279 | "rI" ((USItype)(al)), \ | ||
280 | "r" ((USItype)(bl))); \ | ||
281 | else \ | ||
282 | __asm__ ("{sf%I4|subf%I4c} %1,%5,%4\n\t{sfe|subfe} %0,%3,%2" \ | ||
283 | : "=r" ((USItype)(sh)), \ | ||
284 | "=&r" ((USItype)(sl)) \ | ||
285 | : "r" ((USItype)(ah)), \ | ||
286 | "r" ((USItype)(bh)), \ | ||
287 | "rI" ((USItype)(al)), \ | ||
288 | "r" ((USItype)(bl))); \ | ||
289 | } while (0) | ||
290 | |||
291 | /* asm fragments for mul and div */ | ||
292 | |||
293 | /* umul_ppmm(high_prod, low_prod, multipler, multiplicand) multiplies two | ||
294 | * UWtype integers MULTIPLER and MULTIPLICAND, and generates a two UWtype | ||
295 | * word product in HIGH_PROD and LOW_PROD. | ||
296 | */ | ||
297 | #define umul_ppmm(ph, pl, m0, m1) \ | ||
298 | do { \ | ||
299 | USItype __m0 = (m0), __m1 = (m1); \ | ||
300 | __asm__ ("mulhwu %0,%1,%2" \ | ||
301 | : "=r" ((USItype)(ph)) \ | ||
302 | : "%r" (__m0), \ | ||
303 | "r" (__m1)); \ | ||
304 | (pl) = __m0 * __m1; \ | ||
305 | } while (0) | ||
306 | |||
307 | /* udiv_qrnnd(quotient, remainder, high_numerator, low_numerator, | ||
308 | * denominator) divides a UDWtype, composed by the UWtype integers | ||
309 | * HIGH_NUMERATOR and LOW_NUMERATOR, by DENOMINATOR and places the quotient | ||
310 | * in QUOTIENT and the remainder in REMAINDER. HIGH_NUMERATOR must be less | ||
311 | * than DENOMINATOR for correct operation. If, in addition, the most | ||
312 | * significant bit of DENOMINATOR must be 1, then the pre-processor symbol | ||
313 | * UDIV_NEEDS_NORMALIZATION is defined to 1. | ||
314 | */ | ||
315 | #define udiv_qrnnd(q, r, n1, n0, d) \ | ||
316 | do { \ | ||
317 | UWtype __d1, __d0, __q1, __q0, __r1, __r0, __m; \ | ||
318 | __d1 = __ll_highpart (d); \ | ||
319 | __d0 = __ll_lowpart (d); \ | ||
320 | \ | ||
321 | __r1 = (n1) % __d1; \ | ||
322 | __q1 = (n1) / __d1; \ | ||
323 | __m = (UWtype) __q1 * __d0; \ | ||
324 | __r1 = __r1 * __ll_B | __ll_highpart (n0); \ | ||
325 | if (__r1 < __m) \ | ||
326 | { \ | ||
327 | __q1--, __r1 += (d); \ | ||
328 | if (__r1 >= (d)) /* we didn't get carry when adding to __r1 */ \ | ||
329 | if (__r1 < __m) \ | ||
330 | __q1--, __r1 += (d); \ | ||
331 | } \ | ||
332 | __r1 -= __m; \ | ||
333 | \ | ||
334 | __r0 = __r1 % __d1; \ | ||
335 | __q0 = __r1 / __d1; \ | ||
336 | __m = (UWtype) __q0 * __d0; \ | ||
337 | __r0 = __r0 * __ll_B | __ll_lowpart (n0); \ | ||
338 | if (__r0 < __m) \ | ||
339 | { \ | ||
340 | __q0--, __r0 += (d); \ | ||
341 | if (__r0 >= (d)) \ | ||
342 | if (__r0 < __m) \ | ||
343 | __q0--, __r0 += (d); \ | ||
344 | } \ | ||
345 | __r0 -= __m; \ | ||
346 | \ | ||
347 | (q) = (UWtype) __q1 * __ll_B | __q0; \ | ||
348 | (r) = __r0; \ | ||
349 | } while (0) | ||
350 | |||
351 | #define UDIV_NEEDS_NORMALIZATION 1 | ||
352 | |||
353 | #define abort() \ | ||
354 | return 0 | ||
355 | |||
356 | #ifdef __BIG_ENDIAN | ||
357 | #define __BYTE_ORDER __BIG_ENDIAN | ||
358 | #else | ||
359 | #define __BYTE_ORDER __LITTLE_ENDIAN | ||
360 | #endif | ||
361 | |||
362 | /* Exception flags. */ | ||
363 | #define EFLAG_INVALID (1 << (31 - 2)) | ||
364 | #define EFLAG_OVERFLOW (1 << (31 - 3)) | ||
365 | #define EFLAG_UNDERFLOW (1 << (31 - 4)) | ||
366 | #define EFLAG_DIVZERO (1 << (31 - 5)) | ||
367 | #define EFLAG_INEXACT (1 << (31 - 6)) | ||
368 | |||
369 | #define EFLAG_VXSNAN (1 << (31 - 7)) | ||
370 | #define EFLAG_VXISI (1 << (31 - 8)) | ||
371 | #define EFLAG_VXIDI (1 << (31 - 9)) | ||
372 | #define EFLAG_VXZDZ (1 << (31 - 10)) | ||
373 | #define EFLAG_VXIMZ (1 << (31 - 11)) | ||
374 | #define EFLAG_VXVC (1 << (31 - 12)) | ||
375 | #define EFLAG_VXSOFT (1 << (31 - 21)) | ||
376 | #define EFLAG_VXSQRT (1 << (31 - 22)) | ||
377 | #define EFLAG_VXCVI (1 << (31 - 23)) | ||
diff --git a/arch/powerpc/math-emu/single.h b/arch/powerpc/math-emu/single.h new file mode 100644 index 000000000000..f19d99451815 --- /dev/null +++ b/arch/powerpc/math-emu/single.h | |||
@@ -0,0 +1,66 @@ | |||
1 | /* | ||
2 | * Definitions for IEEE Single Precision | ||
3 | */ | ||
4 | |||
5 | #if _FP_W_TYPE_SIZE < 32 | ||
6 | #error "Here's a nickel kid. Go buy yourself a real computer." | ||
7 | #endif | ||
8 | |||
9 | #define _FP_FRACBITS_S 24 | ||
10 | #define _FP_FRACXBITS_S (_FP_W_TYPE_SIZE - _FP_FRACBITS_S) | ||
11 | #define _FP_WFRACBITS_S (_FP_WORKBITS + _FP_FRACBITS_S) | ||
12 | #define _FP_WFRACXBITS_S (_FP_W_TYPE_SIZE - _FP_WFRACBITS_S) | ||
13 | #define _FP_EXPBITS_S 8 | ||
14 | #define _FP_EXPBIAS_S 127 | ||
15 | #define _FP_EXPMAX_S 255 | ||
16 | #define _FP_QNANBIT_S ((_FP_W_TYPE)1 << (_FP_FRACBITS_S-2)) | ||
17 | #define _FP_IMPLBIT_S ((_FP_W_TYPE)1 << (_FP_FRACBITS_S-1)) | ||
18 | #define _FP_OVERFLOW_S ((_FP_W_TYPE)1 << (_FP_WFRACBITS_S)) | ||
19 | |||
20 | /* The implementation of _FP_MUL_MEAT_S and _FP_DIV_MEAT_S should be | ||
21 | chosen by the target machine. */ | ||
22 | |||
23 | union _FP_UNION_S | ||
24 | { | ||
25 | float flt; | ||
26 | struct { | ||
27 | #if __BYTE_ORDER == __BIG_ENDIAN | ||
28 | unsigned sign : 1; | ||
29 | unsigned exp : _FP_EXPBITS_S; | ||
30 | unsigned frac : _FP_FRACBITS_S - (_FP_IMPLBIT_S != 0); | ||
31 | #else | ||
32 | unsigned frac : _FP_FRACBITS_S - (_FP_IMPLBIT_S != 0); | ||
33 | unsigned exp : _FP_EXPBITS_S; | ||
34 | unsigned sign : 1; | ||
35 | #endif | ||
36 | } bits __attribute__((packed)); | ||
37 | }; | ||
38 | |||
39 | #define FP_DECL_S(X) _FP_DECL(1,X) | ||
40 | #define FP_UNPACK_RAW_S(X,val) _FP_UNPACK_RAW_1(S,X,val) | ||
41 | #define FP_PACK_RAW_S(val,X) _FP_PACK_RAW_1(S,val,X) | ||
42 | |||
43 | #define FP_UNPACK_S(X,val) \ | ||
44 | do { \ | ||
45 | _FP_UNPACK_RAW_1(S,X,val); \ | ||
46 | _FP_UNPACK_CANONICAL(S,1,X); \ | ||
47 | } while (0) | ||
48 | |||
49 | #define FP_PACK_S(val,X) \ | ||
50 | do { \ | ||
51 | _FP_PACK_CANONICAL(S,1,X); \ | ||
52 | _FP_PACK_RAW_1(S,val,X); \ | ||
53 | } while (0) | ||
54 | |||
55 | #define FP_NEG_S(R,X) _FP_NEG(S,1,R,X) | ||
56 | #define FP_ADD_S(R,X,Y) _FP_ADD(S,1,R,X,Y) | ||
57 | #define FP_SUB_S(R,X,Y) _FP_SUB(S,1,R,X,Y) | ||
58 | #define FP_MUL_S(R,X,Y) _FP_MUL(S,1,R,X,Y) | ||
59 | #define FP_DIV_S(R,X,Y) _FP_DIV(S,1,R,X,Y) | ||
60 | #define FP_SQRT_S(R,X) _FP_SQRT(S,1,R,X) | ||
61 | |||
62 | #define FP_CMP_S(r,X,Y,un) _FP_CMP(S,1,r,X,Y,un) | ||
63 | #define FP_CMP_EQ_S(r,X,Y) _FP_CMP_EQ(S,1,r,X,Y) | ||
64 | |||
65 | #define FP_TO_INT_S(r,X,rsz,rsg) _FP_TO_INT(S,1,r,X,rsz,rsg) | ||
66 | #define FP_FROM_INT_S(X,r,rs,rt) _FP_FROM_INT(S,1,X,r,rs,rt) | ||
diff --git a/arch/powerpc/math-emu/soft-fp.h b/arch/powerpc/math-emu/soft-fp.h new file mode 100644 index 000000000000..cca39598f873 --- /dev/null +++ b/arch/powerpc/math-emu/soft-fp.h | |||
@@ -0,0 +1,104 @@ | |||
1 | #ifndef SOFT_FP_H | ||
2 | #define SOFT_FP_H | ||
3 | |||
4 | #include "sfp-machine.h" | ||
5 | |||
6 | #define _FP_WORKBITS 3 | ||
7 | #define _FP_WORK_LSB ((_FP_W_TYPE)1 << 3) | ||
8 | #define _FP_WORK_ROUND ((_FP_W_TYPE)1 << 2) | ||
9 | #define _FP_WORK_GUARD ((_FP_W_TYPE)1 << 1) | ||
10 | #define _FP_WORK_STICKY ((_FP_W_TYPE)1 << 0) | ||
11 | |||
12 | #ifndef FP_RND_NEAREST | ||
13 | # define FP_RND_NEAREST 0 | ||
14 | # define FP_RND_ZERO 1 | ||
15 | # define FP_RND_PINF 2 | ||
16 | # define FP_RND_MINF 3 | ||
17 | #ifndef FP_ROUNDMODE | ||
18 | # define FP_ROUNDMODE FP_RND_NEAREST | ||
19 | #endif | ||
20 | #endif | ||
21 | |||
22 | #define _FP_ROUND_NEAREST(wc, X) \ | ||
23 | ({ int __ret = 0; \ | ||
24 | int __frac = _FP_FRAC_LOW_##wc(X) & 15; \ | ||
25 | if (__frac & 7) { \ | ||
26 | __ret = EFLAG_INEXACT; \ | ||
27 | if ((__frac & 7) != _FP_WORK_ROUND) \ | ||
28 | _FP_FRAC_ADDI_##wc(X, _FP_WORK_ROUND); \ | ||
29 | else if (__frac & _FP_WORK_LSB) \ | ||
30 | _FP_FRAC_ADDI_##wc(X, _FP_WORK_ROUND); \ | ||
31 | } \ | ||
32 | __ret; \ | ||
33 | }) | ||
34 | |||
35 | #define _FP_ROUND_ZERO(wc, X) \ | ||
36 | ({ int __ret = 0; \ | ||
37 | if (_FP_FRAC_LOW_##wc(X) & 7) \ | ||
38 | __ret = EFLAG_INEXACT; \ | ||
39 | __ret; \ | ||
40 | }) | ||
41 | |||
42 | #define _FP_ROUND_PINF(wc, X) \ | ||
43 | ({ int __ret = EFLAG_INEXACT; \ | ||
44 | if (!X##_s && (_FP_FRAC_LOW_##wc(X) & 7)) \ | ||
45 | _FP_FRAC_ADDI_##wc(X, _FP_WORK_LSB); \ | ||
46 | else __ret = 0; \ | ||
47 | __ret; \ | ||
48 | }) | ||
49 | |||
50 | #define _FP_ROUND_MINF(wc, X) \ | ||
51 | ({ int __ret = EFLAG_INEXACT; \ | ||
52 | if (X##_s && (_FP_FRAC_LOW_##wc(X) & 7)) \ | ||
53 | _FP_FRAC_ADDI_##wc(X, _FP_WORK_LSB); \ | ||
54 | else __ret = 0; \ | ||
55 | __ret; \ | ||
56 | }) | ||
57 | |||
58 | #define _FP_ROUND(wc, X) \ | ||
59 | ({ int __ret = 0; \ | ||
60 | switch (FP_ROUNDMODE) \ | ||
61 | { \ | ||
62 | case FP_RND_NEAREST: \ | ||
63 | __ret |= _FP_ROUND_NEAREST(wc,X); \ | ||
64 | break; \ | ||
65 | case FP_RND_ZERO: \ | ||
66 | __ret |= _FP_ROUND_ZERO(wc,X); \ | ||
67 | break; \ | ||
68 | case FP_RND_PINF: \ | ||
69 | __ret |= _FP_ROUND_PINF(wc,X); \ | ||
70 | break; \ | ||
71 | case FP_RND_MINF: \ | ||
72 | __ret |= _FP_ROUND_MINF(wc,X); \ | ||
73 | break; \ | ||
74 | }; \ | ||
75 | __ret; \ | ||
76 | }) | ||
77 | |||
78 | #define FP_CLS_NORMAL 0 | ||
79 | #define FP_CLS_ZERO 1 | ||
80 | #define FP_CLS_INF 2 | ||
81 | #define FP_CLS_NAN 3 | ||
82 | |||
83 | #define _FP_CLS_COMBINE(x,y) (((x) << 2) | (y)) | ||
84 | |||
85 | #include "op-1.h" | ||
86 | #include "op-2.h" | ||
87 | #include "op-4.h" | ||
88 | #include "op-common.h" | ||
89 | |||
90 | /* Sigh. Silly things longlong.h needs. */ | ||
91 | #define UWtype _FP_W_TYPE | ||
92 | #define W_TYPE_SIZE _FP_W_TYPE_SIZE | ||
93 | |||
94 | typedef int SItype __attribute__((mode(SI))); | ||
95 | typedef int DItype __attribute__((mode(DI))); | ||
96 | typedef unsigned int USItype __attribute__((mode(SI))); | ||
97 | typedef unsigned int UDItype __attribute__((mode(DI))); | ||
98 | #if _FP_W_TYPE_SIZE == 32 | ||
99 | typedef unsigned int UHWtype __attribute__((mode(HI))); | ||
100 | #elif _FP_W_TYPE_SIZE == 64 | ||
101 | typedef USItype UHWtype; | ||
102 | #endif | ||
103 | |||
104 | #endif | ||
diff --git a/arch/powerpc/math-emu/stfd.c b/arch/powerpc/math-emu/stfd.c new file mode 100644 index 000000000000..3f8c2558a9e8 --- /dev/null +++ b/arch/powerpc/math-emu/stfd.c | |||
@@ -0,0 +1,20 @@ | |||
1 | #include <linux/types.h> | ||
2 | #include <linux/errno.h> | ||
3 | #include <asm/uaccess.h> | ||
4 | |||
5 | int | ||
6 | stfd(void *frS, void *ea) | ||
7 | { | ||
8 | #if 0 | ||
9 | #ifdef DEBUG | ||
10 | printk("%s: S %p, ea %p: ", __FUNCTION__, frS, ea); | ||
11 | dump_double(frS); | ||
12 | printk("\n"); | ||
13 | #endif | ||
14 | #endif | ||
15 | |||
16 | if (copy_to_user(ea, frS, sizeof(double))) | ||
17 | return -EFAULT; | ||
18 | |||
19 | return 0; | ||
20 | } | ||
diff --git a/arch/powerpc/math-emu/stfiwx.c b/arch/powerpc/math-emu/stfiwx.c new file mode 100644 index 000000000000..95caaeec6a08 --- /dev/null +++ b/arch/powerpc/math-emu/stfiwx.c | |||
@@ -0,0 +1,16 @@ | |||
1 | #include <linux/types.h> | ||
2 | #include <linux/errno.h> | ||
3 | #include <asm/uaccess.h> | ||
4 | |||
5 | int | ||
6 | stfiwx(u32 *frS, void *ea) | ||
7 | { | ||
8 | #ifdef DEBUG | ||
9 | printk("%s: %p %p\n", __FUNCTION__, frS, ea); | ||
10 | #endif | ||
11 | |||
12 | if (copy_to_user(ea, &frS[1], sizeof(frS[1]))) | ||
13 | return -EFAULT; | ||
14 | |||
15 | return 0; | ||
16 | } | ||
diff --git a/arch/powerpc/math-emu/stfs.c b/arch/powerpc/math-emu/stfs.c new file mode 100644 index 000000000000..e87ca23c6dc3 --- /dev/null +++ b/arch/powerpc/math-emu/stfs.c | |||
@@ -0,0 +1,41 @@ | |||
1 | #include <linux/types.h> | ||
2 | #include <linux/errno.h> | ||
3 | #include <asm/uaccess.h> | ||
4 | |||
5 | #include "soft-fp.h" | ||
6 | #include "double.h" | ||
7 | #include "single.h" | ||
8 | |||
9 | int | ||
10 | stfs(void *frS, void *ea) | ||
11 | { | ||
12 | FP_DECL_D(A); | ||
13 | FP_DECL_S(R); | ||
14 | float f; | ||
15 | int err; | ||
16 | |||
17 | #ifdef DEBUG | ||
18 | printk("%s: S %p, ea %p\n", __FUNCTION__, frS, ea); | ||
19 | #endif | ||
20 | |||
21 | __FP_UNPACK_D(A, frS); | ||
22 | |||
23 | #ifdef DEBUG | ||
24 | printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c); | ||
25 | #endif | ||
26 | |||
27 | FP_CONV(S, D, 1, 2, R, A); | ||
28 | |||
29 | #ifdef DEBUG | ||
30 | printk("R: %ld %lu %ld (%ld)\n", R_s, R_f, R_e, R_c); | ||
31 | #endif | ||
32 | |||
33 | err = _FP_PACK_CANONICAL(S, 1, R); | ||
34 | if (!err || !__FPU_TRAP_P(err)) { | ||
35 | __FP_PACK_RAW_1(S, &f, R); | ||
36 | if (copy_to_user(ea, &f, sizeof(float))) | ||
37 | return -EFAULT; | ||
38 | } | ||
39 | |||
40 | return err; | ||
41 | } | ||
diff --git a/arch/powerpc/math-emu/types.c b/arch/powerpc/math-emu/types.c new file mode 100644 index 000000000000..e1ed15d829db --- /dev/null +++ b/arch/powerpc/math-emu/types.c | |||
@@ -0,0 +1,51 @@ | |||
1 | #include "soft-fp.h" | ||
2 | #include "double.h" | ||
3 | #include "single.h" | ||
4 | |||
5 | void | ||
6 | fp_unpack_d(long *_s, unsigned long *_f1, unsigned long *_f0, | ||
7 | long *_e, long *_c, void *val) | ||
8 | { | ||
9 | FP_DECL_D(X); | ||
10 | |||
11 | __FP_UNPACK_RAW_2(D, X, val); | ||
12 | |||
13 | _FP_UNPACK_CANONICAL(D, 2, X); | ||
14 | |||
15 | *_s = X_s; | ||
16 | *_f1 = X_f1; | ||
17 | *_f0 = X_f0; | ||
18 | *_e = X_e; | ||
19 | *_c = X_c; | ||
20 | } | ||
21 | |||
22 | int | ||
23 | fp_pack_d(void *val, long X_s, unsigned long X_f1, | ||
24 | unsigned long X_f0, long X_e, long X_c) | ||
25 | { | ||
26 | int exc; | ||
27 | |||
28 | exc = _FP_PACK_CANONICAL(D, 2, X); | ||
29 | if (!exc || !__FPU_TRAP_P(exc)) | ||
30 | __FP_PACK_RAW_2(D, val, X); | ||
31 | return exc; | ||
32 | } | ||
33 | |||
34 | int | ||
35 | fp_pack_ds(void *val, long X_s, unsigned long X_f1, | ||
36 | unsigned long X_f0, long X_e, long X_c) | ||
37 | { | ||
38 | FP_DECL_S(__X); | ||
39 | int exc; | ||
40 | |||
41 | FP_CONV(S, D, 1, 2, __X, X); | ||
42 | exc = _FP_PACK_CANONICAL(S, 1, __X); | ||
43 | if (!exc || !__FPU_TRAP_P(exc)) { | ||
44 | _FP_UNPACK_CANONICAL(S, 1, __X); | ||
45 | FP_CONV(D, S, 2, 1, X, __X); | ||
46 | exc |= _FP_PACK_CANONICAL(D, 2, X); | ||
47 | if (!exc || !__FPU_TRAP_P(exc)) | ||
48 | __FP_PACK_RAW_2(D, val, X); | ||
49 | } | ||
50 | return exc; | ||
51 | } | ||
diff --git a/arch/powerpc/math-emu/udivmodti4.c b/arch/powerpc/math-emu/udivmodti4.c new file mode 100644 index 000000000000..7e112dc1e2f2 --- /dev/null +++ b/arch/powerpc/math-emu/udivmodti4.c | |||
@@ -0,0 +1,191 @@ | |||
1 | /* This has so very few changes over libgcc2's __udivmoddi4 it isn't funny. */ | ||
2 | |||
3 | #include "soft-fp.h" | ||
4 | |||
5 | #undef count_leading_zeros | ||
6 | #define count_leading_zeros __FP_CLZ | ||
7 | |||
8 | void | ||
9 | _fp_udivmodti4(_FP_W_TYPE q[2], _FP_W_TYPE r[2], | ||
10 | _FP_W_TYPE n1, _FP_W_TYPE n0, | ||
11 | _FP_W_TYPE d1, _FP_W_TYPE d0) | ||
12 | { | ||
13 | _FP_W_TYPE q0, q1, r0, r1; | ||
14 | _FP_I_TYPE b, bm; | ||
15 | |||
16 | if (d1 == 0) | ||
17 | { | ||
18 | #if !UDIV_NEEDS_NORMALIZATION | ||
19 | if (d0 > n1) | ||
20 | { | ||
21 | /* 0q = nn / 0D */ | ||
22 | |||
23 | udiv_qrnnd (q0, n0, n1, n0, d0); | ||
24 | q1 = 0; | ||
25 | |||
26 | /* Remainder in n0. */ | ||
27 | } | ||
28 | else | ||
29 | { | ||
30 | /* qq = NN / 0d */ | ||
31 | |||
32 | if (d0 == 0) | ||
33 | d0 = 1 / d0; /* Divide intentionally by zero. */ | ||
34 | |||
35 | udiv_qrnnd (q1, n1, 0, n1, d0); | ||
36 | udiv_qrnnd (q0, n0, n1, n0, d0); | ||
37 | |||
38 | /* Remainder in n0. */ | ||
39 | } | ||
40 | |||
41 | r0 = n0; | ||
42 | r1 = 0; | ||
43 | |||
44 | #else /* UDIV_NEEDS_NORMALIZATION */ | ||
45 | |||
46 | if (d0 > n1) | ||
47 | { | ||
48 | /* 0q = nn / 0D */ | ||
49 | |||
50 | count_leading_zeros (bm, d0); | ||
51 | |||
52 | if (bm != 0) | ||
53 | { | ||
54 | /* Normalize, i.e. make the most significant bit of the | ||
55 | denominator set. */ | ||
56 | |||
57 | d0 = d0 << bm; | ||
58 | n1 = (n1 << bm) | (n0 >> (_FP_W_TYPE_SIZE - bm)); | ||
59 | n0 = n0 << bm; | ||
60 | } | ||
61 | |||
62 | udiv_qrnnd (q0, n0, n1, n0, d0); | ||
63 | q1 = 0; | ||
64 | |||
65 | /* Remainder in n0 >> bm. */ | ||
66 | } | ||
67 | else | ||
68 | { | ||
69 | /* qq = NN / 0d */ | ||
70 | |||
71 | if (d0 == 0) | ||
72 | d0 = 1 / d0; /* Divide intentionally by zero. */ | ||
73 | |||
74 | count_leading_zeros (bm, d0); | ||
75 | |||
76 | if (bm == 0) | ||
77 | { | ||
78 | /* From (n1 >= d0) /\ (the most significant bit of d0 is set), | ||
79 | conclude (the most significant bit of n1 is set) /\ (the | ||
80 | leading quotient digit q1 = 1). | ||
81 | |||
82 | This special case is necessary, not an optimization. | ||
83 | (Shifts counts of SI_TYPE_SIZE are undefined.) */ | ||
84 | |||
85 | n1 -= d0; | ||
86 | q1 = 1; | ||
87 | } | ||
88 | else | ||
89 | { | ||
90 | _FP_W_TYPE n2; | ||
91 | |||
92 | /* Normalize. */ | ||
93 | |||
94 | b = _FP_W_TYPE_SIZE - bm; | ||
95 | |||
96 | d0 = d0 << bm; | ||
97 | n2 = n1 >> b; | ||
98 | n1 = (n1 << bm) | (n0 >> b); | ||
99 | n0 = n0 << bm; | ||
100 | |||
101 | udiv_qrnnd (q1, n1, n2, n1, d0); | ||
102 | } | ||
103 | |||
104 | /* n1 != d0... */ | ||
105 | |||
106 | udiv_qrnnd (q0, n0, n1, n0, d0); | ||
107 | |||
108 | /* Remainder in n0 >> bm. */ | ||
109 | } | ||
110 | |||
111 | r0 = n0 >> bm; | ||
112 | r1 = 0; | ||
113 | #endif /* UDIV_NEEDS_NORMALIZATION */ | ||
114 | } | ||
115 | else | ||
116 | { | ||
117 | if (d1 > n1) | ||
118 | { | ||
119 | /* 00 = nn / DD */ | ||
120 | |||
121 | q0 = 0; | ||
122 | q1 = 0; | ||
123 | |||
124 | /* Remainder in n1n0. */ | ||
125 | r0 = n0; | ||
126 | r1 = n1; | ||
127 | } | ||
128 | else | ||
129 | { | ||
130 | /* 0q = NN / dd */ | ||
131 | |||
132 | count_leading_zeros (bm, d1); | ||
133 | if (bm == 0) | ||
134 | { | ||
135 | /* From (n1 >= d1) /\ (the most significant bit of d1 is set), | ||
136 | conclude (the most significant bit of n1 is set) /\ (the | ||
137 | quotient digit q0 = 0 or 1). | ||
138 | |||
139 | This special case is necessary, not an optimization. */ | ||
140 | |||
141 | /* The condition on the next line takes advantage of that | ||
142 | n1 >= d1 (true due to program flow). */ | ||
143 | if (n1 > d1 || n0 >= d0) | ||
144 | { | ||
145 | q0 = 1; | ||
146 | sub_ddmmss (n1, n0, n1, n0, d1, d0); | ||
147 | } | ||
148 | else | ||
149 | q0 = 0; | ||
150 | |||
151 | q1 = 0; | ||
152 | |||
153 | r0 = n0; | ||
154 | r1 = n1; | ||
155 | } | ||
156 | else | ||
157 | { | ||
158 | _FP_W_TYPE m1, m0, n2; | ||
159 | |||
160 | /* Normalize. */ | ||
161 | |||
162 | b = _FP_W_TYPE_SIZE - bm; | ||
163 | |||
164 | d1 = (d1 << bm) | (d0 >> b); | ||
165 | d0 = d0 << bm; | ||
166 | n2 = n1 >> b; | ||
167 | n1 = (n1 << bm) | (n0 >> b); | ||
168 | n0 = n0 << bm; | ||
169 | |||
170 | udiv_qrnnd (q0, n1, n2, n1, d1); | ||
171 | umul_ppmm (m1, m0, q0, d0); | ||
172 | |||
173 | if (m1 > n1 || (m1 == n1 && m0 > n0)) | ||
174 | { | ||
175 | q0--; | ||
176 | sub_ddmmss (m1, m0, m1, m0, d1, d0); | ||
177 | } | ||
178 | |||
179 | q1 = 0; | ||
180 | |||
181 | /* Remainder in (n1n0 - m1m0) >> bm. */ | ||
182 | sub_ddmmss (n1, n0, n1, n0, m1, m0); | ||
183 | r0 = (n1 << b) | (n0 >> bm); | ||
184 | r1 = n1 >> bm; | ||
185 | } | ||
186 | } | ||
187 | } | ||
188 | |||
189 | q[0] = q0; q[1] = q1; | ||
190 | r[0] = r0, r[1] = r1; | ||
191 | } | ||