diff options
Diffstat (limited to 'arch/mips/math-emu/ieee754sp.c')
-rw-r--r-- | arch/mips/math-emu/ieee754sp.c | 196 |
1 files changed, 196 insertions, 0 deletions
diff --git a/arch/mips/math-emu/ieee754sp.c b/arch/mips/math-emu/ieee754sp.c new file mode 100644 index 000000000..0b6267bc8 --- /dev/null +++ b/arch/mips/math-emu/ieee754sp.c | |||
@@ -0,0 +1,196 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0-only | ||
2 | /* IEEE754 floating point arithmetic | ||
3 | * single precision | ||
4 | */ | ||
5 | /* | ||
6 | * MIPS floating point support | ||
7 | * Copyright (C) 1994-2000 Algorithmics Ltd. | ||
8 | */ | ||
9 | |||
10 | #include <linux/compiler.h> | ||
11 | |||
12 | #include "ieee754sp.h" | ||
13 | |||
14 | int ieee754sp_class(union ieee754sp x) | ||
15 | { | ||
16 | COMPXSP; | ||
17 | EXPLODEXSP; | ||
18 | return xc; | ||
19 | } | ||
20 | |||
21 | static inline int ieee754sp_isnan(union ieee754sp x) | ||
22 | { | ||
23 | return ieee754_class_nan(ieee754sp_class(x)); | ||
24 | } | ||
25 | |||
26 | static inline int ieee754sp_issnan(union ieee754sp x) | ||
27 | { | ||
28 | int qbit; | ||
29 | |||
30 | assert(ieee754sp_isnan(x)); | ||
31 | qbit = (SPMANT(x) & SP_MBIT(SP_FBITS - 1)) == SP_MBIT(SP_FBITS - 1); | ||
32 | return ieee754_csr.nan2008 ^ qbit; | ||
33 | } | ||
34 | |||
35 | |||
36 | /* | ||
37 | * Raise the Invalid Operation IEEE 754 exception | ||
38 | * and convert the signaling NaN supplied to a quiet NaN. | ||
39 | */ | ||
40 | union ieee754sp __cold ieee754sp_nanxcpt(union ieee754sp r) | ||
41 | { | ||
42 | assert(ieee754sp_issnan(r)); | ||
43 | |||
44 | ieee754_setcx(IEEE754_INVALID_OPERATION); | ||
45 | if (ieee754_csr.nan2008) { | ||
46 | SPMANT(r) |= SP_MBIT(SP_FBITS - 1); | ||
47 | } else { | ||
48 | SPMANT(r) &= ~SP_MBIT(SP_FBITS - 1); | ||
49 | if (!ieee754sp_isnan(r)) | ||
50 | SPMANT(r) |= SP_MBIT(SP_FBITS - 2); | ||
51 | } | ||
52 | |||
53 | return r; | ||
54 | } | ||
55 | |||
56 | static unsigned int ieee754sp_get_rounding(int sn, unsigned int xm) | ||
57 | { | ||
58 | /* inexact must round of 3 bits | ||
59 | */ | ||
60 | if (xm & (SP_MBIT(3) - 1)) { | ||
61 | switch (ieee754_csr.rm) { | ||
62 | case FPU_CSR_RZ: | ||
63 | break; | ||
64 | case FPU_CSR_RN: | ||
65 | xm += 0x3 + ((xm >> 3) & 1); | ||
66 | /* xm += (xm&0x8)?0x4:0x3 */ | ||
67 | break; | ||
68 | case FPU_CSR_RU: /* toward +Infinity */ | ||
69 | if (!sn) /* ?? */ | ||
70 | xm += 0x8; | ||
71 | break; | ||
72 | case FPU_CSR_RD: /* toward -Infinity */ | ||
73 | if (sn) /* ?? */ | ||
74 | xm += 0x8; | ||
75 | break; | ||
76 | } | ||
77 | } | ||
78 | return xm; | ||
79 | } | ||
80 | |||
81 | |||
82 | /* generate a normal/denormal number with over,under handling | ||
83 | * sn is sign | ||
84 | * xe is an unbiased exponent | ||
85 | * xm is 3bit extended precision value. | ||
86 | */ | ||
87 | union ieee754sp ieee754sp_format(int sn, int xe, unsigned int xm) | ||
88 | { | ||
89 | assert(xm); /* we don't gen exact zeros (probably should) */ | ||
90 | |||
91 | assert((xm >> (SP_FBITS + 1 + 3)) == 0); /* no excess */ | ||
92 | assert(xm & (SP_HIDDEN_BIT << 3)); | ||
93 | |||
94 | if (xe < SP_EMIN) { | ||
95 | /* strip lower bits */ | ||
96 | int es = SP_EMIN - xe; | ||
97 | |||
98 | if (ieee754_csr.nod) { | ||
99 | ieee754_setcx(IEEE754_UNDERFLOW); | ||
100 | ieee754_setcx(IEEE754_INEXACT); | ||
101 | |||
102 | switch(ieee754_csr.rm) { | ||
103 | case FPU_CSR_RN: | ||
104 | case FPU_CSR_RZ: | ||
105 | return ieee754sp_zero(sn); | ||
106 | case FPU_CSR_RU: /* toward +Infinity */ | ||
107 | if (sn == 0) | ||
108 | return ieee754sp_min(0); | ||
109 | else | ||
110 | return ieee754sp_zero(1); | ||
111 | case FPU_CSR_RD: /* toward -Infinity */ | ||
112 | if (sn == 0) | ||
113 | return ieee754sp_zero(0); | ||
114 | else | ||
115 | return ieee754sp_min(1); | ||
116 | } | ||
117 | } | ||
118 | |||
119 | if (xe == SP_EMIN - 1 && | ||
120 | ieee754sp_get_rounding(sn, xm) >> (SP_FBITS + 1 + 3)) | ||
121 | { | ||
122 | /* Not tiny after rounding */ | ||
123 | ieee754_setcx(IEEE754_INEXACT); | ||
124 | xm = ieee754sp_get_rounding(sn, xm); | ||
125 | xm >>= 1; | ||
126 | /* Clear grs bits */ | ||
127 | xm &= ~(SP_MBIT(3) - 1); | ||
128 | xe++; | ||
129 | } else { | ||
130 | /* sticky right shift es bits | ||
131 | */ | ||
132 | xm = XSPSRS(xm, es); | ||
133 | xe += es; | ||
134 | assert((xm & (SP_HIDDEN_BIT << 3)) == 0); | ||
135 | assert(xe == SP_EMIN); | ||
136 | } | ||
137 | } | ||
138 | if (xm & (SP_MBIT(3) - 1)) { | ||
139 | ieee754_setcx(IEEE754_INEXACT); | ||
140 | if ((xm & (SP_HIDDEN_BIT << 3)) == 0) { | ||
141 | ieee754_setcx(IEEE754_UNDERFLOW); | ||
142 | } | ||
143 | |||
144 | /* inexact must round of 3 bits | ||
145 | */ | ||
146 | xm = ieee754sp_get_rounding(sn, xm); | ||
147 | /* adjust exponent for rounding add overflowing | ||
148 | */ | ||
149 | if (xm >> (SP_FBITS + 1 + 3)) { | ||
150 | /* add causes mantissa overflow */ | ||
151 | xm >>= 1; | ||
152 | xe++; | ||
153 | } | ||
154 | } | ||
155 | /* strip grs bits */ | ||
156 | xm >>= 3; | ||
157 | |||
158 | assert((xm >> (SP_FBITS + 1)) == 0); /* no excess */ | ||
159 | assert(xe >= SP_EMIN); | ||
160 | |||
161 | if (xe > SP_EMAX) { | ||
162 | ieee754_setcx(IEEE754_OVERFLOW); | ||
163 | ieee754_setcx(IEEE754_INEXACT); | ||
164 | /* -O can be table indexed by (rm,sn) */ | ||
165 | switch (ieee754_csr.rm) { | ||
166 | case FPU_CSR_RN: | ||
167 | return ieee754sp_inf(sn); | ||
168 | case FPU_CSR_RZ: | ||
169 | return ieee754sp_max(sn); | ||
170 | case FPU_CSR_RU: /* toward +Infinity */ | ||
171 | if (sn == 0) | ||
172 | return ieee754sp_inf(0); | ||
173 | else | ||
174 | return ieee754sp_max(1); | ||
175 | case FPU_CSR_RD: /* toward -Infinity */ | ||
176 | if (sn == 0) | ||
177 | return ieee754sp_max(0); | ||
178 | else | ||
179 | return ieee754sp_inf(1); | ||
180 | } | ||
181 | } | ||
182 | /* gen norm/denorm/zero */ | ||
183 | |||
184 | if ((xm & SP_HIDDEN_BIT) == 0) { | ||
185 | /* we underflow (tiny/zero) */ | ||
186 | assert(xe == SP_EMIN); | ||
187 | if (ieee754_csr.mx & IEEE754_UNDERFLOW) | ||
188 | ieee754_setcx(IEEE754_UNDERFLOW); | ||
189 | return buildsp(sn, SP_EMIN - 1 + SP_EBIAS, xm); | ||
190 | } else { | ||
191 | assert((xm >> (SP_FBITS + 1)) == 0); /* no excess */ | ||
192 | assert(xm & SP_HIDDEN_BIT); | ||
193 | |||
194 | return buildsp(sn, xe + SP_EBIAS, xm & ~SP_HIDDEN_BIT); | ||
195 | } | ||
196 | } | ||