Merge tag 'usb-5.11-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb
[linux/fpc-iii.git] / arch / arm / nwfpe / fpa11_cprt.c
bloba8c142e45e543ed452930407509662ed6406c953
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 NetWinder Floating Point Emulator
4 (c) Rebel.COM, 1998,1999
5 (c) Philip Blundell, 1999, 2001
7 Direct questions, comments to Scott Bambrough <scottb@netwinder.org>
9 */
11 #include "fpa11.h"
12 #include "fpopcode.h"
13 #include "fpa11.inl"
14 #include "fpmodule.h"
15 #include "fpmodule.inl"
16 #include "softfloat.h"
18 unsigned int PerformFLT(const unsigned int opcode);
19 unsigned int PerformFIX(const unsigned int opcode);
21 static unsigned int PerformComparison(const unsigned int opcode);
23 unsigned int EmulateCPRT(const unsigned int opcode)
26 if (opcode & 0x800000) {
27 /* This is some variant of a comparison (PerformComparison
28 will sort out which one). Since most of the other CPRT
29 instructions are oddball cases of some sort or other it
30 makes sense to pull this out into a fast path. */
31 return PerformComparison(opcode);
34 /* Hint to GCC that we'd like a jump table rather than a load of CMPs */
35 switch ((opcode & 0x700000) >> 20) {
36 case FLT_CODE >> 20:
37 return PerformFLT(opcode);
38 break;
39 case FIX_CODE >> 20:
40 return PerformFIX(opcode);
41 break;
43 case WFS_CODE >> 20:
44 writeFPSR(readRegister(getRd(opcode)));
45 break;
46 case RFS_CODE >> 20:
47 writeRegister(getRd(opcode), readFPSR());
48 break;
50 default:
51 return 0;
54 return 1;
57 unsigned int PerformFLT(const unsigned int opcode)
59 FPA11 *fpa11 = GET_FPA11();
60 struct roundingData roundData;
62 roundData.mode = SetRoundingMode(opcode);
63 roundData.precision = SetRoundingPrecision(opcode);
64 roundData.exception = 0;
66 switch (opcode & MASK_ROUNDING_PRECISION) {
67 case ROUND_SINGLE:
69 fpa11->fType[getFn(opcode)] = typeSingle;
70 fpa11->fpreg[getFn(opcode)].fSingle = int32_to_float32(&roundData, readRegister(getRd(opcode)));
72 break;
74 case ROUND_DOUBLE:
76 fpa11->fType[getFn(opcode)] = typeDouble;
77 fpa11->fpreg[getFn(opcode)].fDouble = int32_to_float64(readRegister(getRd(opcode)));
79 break;
81 #ifdef CONFIG_FPE_NWFPE_XP
82 case ROUND_EXTENDED:
84 fpa11->fType[getFn(opcode)] = typeExtended;
85 fpa11->fpreg[getFn(opcode)].fExtended = int32_to_floatx80(readRegister(getRd(opcode)));
87 break;
88 #endif
90 default:
91 return 0;
94 if (roundData.exception)
95 float_raise(roundData.exception);
97 return 1;
100 unsigned int PerformFIX(const unsigned int opcode)
102 FPA11 *fpa11 = GET_FPA11();
103 unsigned int Fn = getFm(opcode);
104 struct roundingData roundData;
106 roundData.mode = SetRoundingMode(opcode);
107 roundData.precision = SetRoundingPrecision(opcode);
108 roundData.exception = 0;
110 switch (fpa11->fType[Fn]) {
111 case typeSingle:
113 writeRegister(getRd(opcode), float32_to_int32(&roundData, fpa11->fpreg[Fn].fSingle));
115 break;
117 case typeDouble:
119 writeRegister(getRd(opcode), float64_to_int32(&roundData, fpa11->fpreg[Fn].fDouble));
121 break;
123 #ifdef CONFIG_FPE_NWFPE_XP
124 case typeExtended:
126 writeRegister(getRd(opcode), floatx80_to_int32(&roundData, fpa11->fpreg[Fn].fExtended));
128 break;
129 #endif
131 default:
132 return 0;
135 if (roundData.exception)
136 float_raise(roundData.exception);
138 return 1;
141 /* This instruction sets the flags N, Z, C, V in the FPSR. */
142 static unsigned int PerformComparison(const unsigned int opcode)
144 FPA11 *fpa11 = GET_FPA11();
145 unsigned int Fn = getFn(opcode), Fm = getFm(opcode);
146 int e_flag = opcode & 0x400000; /* 1 if CxFE */
147 int n_flag = opcode & 0x200000; /* 1 if CNxx */
148 unsigned int flags = 0;
150 #ifdef CONFIG_FPE_NWFPE_XP
151 floatx80 rFn, rFm;
153 /* Check for unordered condition and convert all operands to 80-bit
154 format.
155 ?? Might be some mileage in avoiding this conversion if possible.
156 Eg, if both operands are 32-bit, detect this and do a 32-bit
157 comparison (cheaper than an 80-bit one). */
158 switch (fpa11->fType[Fn]) {
159 case typeSingle:
160 //printk("single.\n");
161 if (float32_is_nan(fpa11->fpreg[Fn].fSingle))
162 goto unordered;
163 rFn = float32_to_floatx80(fpa11->fpreg[Fn].fSingle);
164 break;
166 case typeDouble:
167 //printk("double.\n");
168 if (float64_is_nan(fpa11->fpreg[Fn].fDouble))
169 goto unordered;
170 rFn = float64_to_floatx80(fpa11->fpreg[Fn].fDouble);
171 break;
173 case typeExtended:
174 //printk("extended.\n");
175 if (floatx80_is_nan(fpa11->fpreg[Fn].fExtended))
176 goto unordered;
177 rFn = fpa11->fpreg[Fn].fExtended;
178 break;
180 default:
181 return 0;
184 if (CONSTANT_FM(opcode)) {
185 //printk("Fm is a constant: #%d.\n",Fm);
186 rFm = getExtendedConstant(Fm);
187 if (floatx80_is_nan(rFm))
188 goto unordered;
189 } else {
190 //printk("Fm = r%d which contains a ",Fm);
191 switch (fpa11->fType[Fm]) {
192 case typeSingle:
193 //printk("single.\n");
194 if (float32_is_nan(fpa11->fpreg[Fm].fSingle))
195 goto unordered;
196 rFm = float32_to_floatx80(fpa11->fpreg[Fm].fSingle);
197 break;
199 case typeDouble:
200 //printk("double.\n");
201 if (float64_is_nan(fpa11->fpreg[Fm].fDouble))
202 goto unordered;
203 rFm = float64_to_floatx80(fpa11->fpreg[Fm].fDouble);
204 break;
206 case typeExtended:
207 //printk("extended.\n");
208 if (floatx80_is_nan(fpa11->fpreg[Fm].fExtended))
209 goto unordered;
210 rFm = fpa11->fpreg[Fm].fExtended;
211 break;
213 default:
214 return 0;
218 if (n_flag)
219 rFm.high ^= 0x8000;
221 /* test for less than condition */
222 if (floatx80_lt(rFn, rFm))
223 flags |= CC_NEGATIVE;
225 /* test for equal condition */
226 if (floatx80_eq(rFn, rFm))
227 flags |= CC_ZERO;
229 /* test for greater than or equal condition */
230 if (floatx80_lt(rFm, rFn))
231 flags |= CC_CARRY;
233 #else
234 if (CONSTANT_FM(opcode)) {
235 /* Fm is a constant. Do the comparison in whatever precision
236 Fn happens to be stored in. */
237 if (fpa11->fType[Fn] == typeSingle) {
238 float32 rFm = getSingleConstant(Fm);
239 float32 rFn = fpa11->fpreg[Fn].fSingle;
241 if (float32_is_nan(rFn))
242 goto unordered;
244 if (n_flag)
245 rFm ^= 0x80000000;
247 /* test for less than condition */
248 if (float32_lt_nocheck(rFn, rFm))
249 flags |= CC_NEGATIVE;
251 /* test for equal condition */
252 if (float32_eq_nocheck(rFn, rFm))
253 flags |= CC_ZERO;
255 /* test for greater than or equal condition */
256 if (float32_lt_nocheck(rFm, rFn))
257 flags |= CC_CARRY;
258 } else {
259 float64 rFm = getDoubleConstant(Fm);
260 float64 rFn = fpa11->fpreg[Fn].fDouble;
262 if (float64_is_nan(rFn))
263 goto unordered;
265 if (n_flag)
266 rFm ^= 0x8000000000000000ULL;
268 /* test for less than condition */
269 if (float64_lt_nocheck(rFn, rFm))
270 flags |= CC_NEGATIVE;
272 /* test for equal condition */
273 if (float64_eq_nocheck(rFn, rFm))
274 flags |= CC_ZERO;
276 /* test for greater than or equal condition */
277 if (float64_lt_nocheck(rFm, rFn))
278 flags |= CC_CARRY;
280 } else {
281 /* Both operands are in registers. */
282 if (fpa11->fType[Fn] == typeSingle
283 && fpa11->fType[Fm] == typeSingle) {
284 float32 rFm = fpa11->fpreg[Fm].fSingle;
285 float32 rFn = fpa11->fpreg[Fn].fSingle;
287 if (float32_is_nan(rFn)
288 || float32_is_nan(rFm))
289 goto unordered;
291 if (n_flag)
292 rFm ^= 0x80000000;
294 /* test for less than condition */
295 if (float32_lt_nocheck(rFn, rFm))
296 flags |= CC_NEGATIVE;
298 /* test for equal condition */
299 if (float32_eq_nocheck(rFn, rFm))
300 flags |= CC_ZERO;
302 /* test for greater than or equal condition */
303 if (float32_lt_nocheck(rFm, rFn))
304 flags |= CC_CARRY;
305 } else {
306 /* Promote 32-bit operand to 64 bits. */
307 float64 rFm, rFn;
309 rFm = (fpa11->fType[Fm] == typeSingle) ?
310 float32_to_float64(fpa11->fpreg[Fm].fSingle)
311 : fpa11->fpreg[Fm].fDouble;
313 rFn = (fpa11->fType[Fn] == typeSingle) ?
314 float32_to_float64(fpa11->fpreg[Fn].fSingle)
315 : fpa11->fpreg[Fn].fDouble;
317 if (float64_is_nan(rFn)
318 || float64_is_nan(rFm))
319 goto unordered;
321 if (n_flag)
322 rFm ^= 0x8000000000000000ULL;
324 /* test for less than condition */
325 if (float64_lt_nocheck(rFn, rFm))
326 flags |= CC_NEGATIVE;
328 /* test for equal condition */
329 if (float64_eq_nocheck(rFn, rFm))
330 flags |= CC_ZERO;
332 /* test for greater than or equal condition */
333 if (float64_lt_nocheck(rFm, rFn))
334 flags |= CC_CARRY;
338 #endif
340 writeConditionCodes(flags);
342 return 1;
344 unordered:
345 /* ?? The FPA data sheet is pretty vague about this, in particular
346 about whether the non-E comparisons can ever raise exceptions.
347 This implementation is based on a combination of what it says in
348 the data sheet, observation of how the Acorn emulator actually
349 behaves (and how programs expect it to) and guesswork. */
350 flags |= CC_OVERFLOW;
351 flags &= ~(CC_ZERO | CC_NEGATIVE);
353 if (BIT_AC & readFPSR())
354 flags |= CC_CARRY;
356 if (e_flag)
357 float_raise(float_flag_invalid);
359 writeConditionCodes(flags);
360 return 1;