Branch data Line data Source code
1 : : /*
2 : : * linux/arch/arm/vfp/vfpdouble.c
3 : : *
4 : : * This code is derived in part from John R. Housers softfloat library, which
5 : : * carries the following notice:
6 : : *
7 : : * ===========================================================================
8 : : * This C source file is part of the SoftFloat IEC/IEEE Floating-point
9 : : * Arithmetic Package, Release 2.
10 : : *
11 : : * Written by John R. Hauser. This work was made possible in part by the
12 : : * International Computer Science Institute, located at Suite 600, 1947 Center
13 : : * Street, Berkeley, California 94704. Funding was partially provided by the
14 : : * National Science Foundation under grant MIP-9311980. The original version
15 : : * of this code was written as part of a project to build a fixed-point vector
16 : : * processor in collaboration with the University of California at Berkeley,
17 : : * overseen by Profs. Nelson Morgan and John Wawrzynek. More information
18 : : * is available through the web page `http://HTTP.CS.Berkeley.EDU/~jhauser/
19 : : * arithmetic/softfloat.html'.
20 : : *
21 : : * THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort
22 : : * has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
23 : : * TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO
24 : : * PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY
25 : : * AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE.
26 : : *
27 : : * Derivative works are acceptable, even for commercial purposes, so long as
28 : : * (1) they include prominent notice that the work is derivative, and (2) they
29 : : * include prominent notice akin to these three paragraphs for those parts of
30 : : * this code that are retained.
31 : : * ===========================================================================
32 : : */
33 : : #include <linux/kernel.h>
34 : : #include <linux/bitops.h>
35 : :
36 : : #include <asm/div64.h>
37 : : #include <asm/vfp.h>
38 : :
39 : : #include "vfpinstr.h"
40 : : #include "vfp.h"
41 : :
42 : : static struct vfp_double vfp_double_default_qnan = {
43 : : .exponent = 2047,
44 : : .sign = 0,
45 : : .significand = VFP_DOUBLE_SIGNIFICAND_QNAN,
46 : : };
47 : :
48 : : static void vfp_double_dump(const char *str, struct vfp_double *d)
49 : : {
50 : : pr_debug("VFP: %s: sign=%d exponent=%d significand=%016llx\n",
51 : : str, d->sign != 0, d->exponent, d->significand);
52 : : }
53 : :
54 : 0 : static void vfp_double_normalise_denormal(struct vfp_double *vd)
55 : : {
56 : 0 : int bits = 31 - fls(vd->significand >> 32);
57 [ # # ]: 0 : if (bits == 31)
58 : 0 : bits = 63 - fls(vd->significand);
59 : :
60 : : vfp_double_dump("normalise_denormal: in", vd);
61 : :
62 [ # # ]: 0 : if (bits) {
63 : 0 : vd->exponent -= bits - 1;
64 : 0 : vd->significand <<= bits;
65 : : }
66 : :
67 : : vfp_double_dump("normalise_denormal: out", vd);
68 : 0 : }
69 : :
70 : 0 : u32 vfp_double_normaliseround(int dd, struct vfp_double *vd, u32 fpscr, u32 exceptions, const char *func)
71 : : {
72 : : u64 significand, incr;
73 : : int exponent, shift, underflow;
74 : : u32 rmode;
75 : :
76 : : vfp_double_dump("pack: in", vd);
77 : :
78 : : /*
79 : : * Infinities and NaNs are a special case.
80 : : */
81 [ # # # # : 0 : if (vd->exponent == 2047 && (vd->significand == 0 || exceptions))
# # ]
82 : : goto pack;
83 : :
84 : : /*
85 : : * Special-case zero.
86 : : */
87 [ # # ]: 0 : if (vd->significand == 0) {
88 : 0 : vd->exponent = 0;
89 : 0 : goto pack;
90 : : }
91 : :
92 : 0 : exponent = vd->exponent;
93 : : significand = vd->significand;
94 : :
95 : 0 : shift = 32 - fls(significand >> 32);
96 [ # # ]: 0 : if (shift == 32)
97 : 0 : shift = 64 - fls(significand);
98 [ # # ]: 0 : if (shift) {
99 : 0 : exponent -= shift;
100 : 0 : significand <<= shift;
101 : : }
102 : :
103 : : #ifdef DEBUG
104 : : vd->exponent = exponent;
105 : : vd->significand = significand;
106 : : vfp_double_dump("pack: normalised", vd);
107 : : #endif
108 : :
109 : : /*
110 : : * Tiny number?
111 : : */
112 : 0 : underflow = exponent < 0;
113 [ # # ]: 0 : if (underflow) {
114 : 0 : significand = vfp_shiftright64jamming(significand, -exponent);
115 : : exponent = 0;
116 : : #ifdef DEBUG
117 : : vd->exponent = exponent;
118 : : vd->significand = significand;
119 : : vfp_double_dump("pack: tiny number", vd);
120 : : #endif
121 [ # # ]: 0 : if (!(significand & ((1ULL << (VFP_DOUBLE_LOW_BITS + 1)) - 1)))
122 : : underflow = 0;
123 : : }
124 : :
125 : : /*
126 : : * Select rounding increment.
127 : : */
128 : : incr = 0;
129 : 0 : rmode = fpscr & FPSCR_RMODE_MASK;
130 : :
131 [ # # ]: 0 : if (rmode == FPSCR_ROUND_NEAREST) {
132 : : incr = 1ULL << VFP_DOUBLE_LOW_BITS;
133 [ # # ]: 0 : if ((significand & (1ULL << (VFP_DOUBLE_LOW_BITS + 1))) == 0)
134 : : incr -= 1;
135 [ # # ]: 0 : } else if (rmode == FPSCR_ROUND_TOZERO) {
136 : : incr = 0;
137 [ # # ]: 0 : } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vd->sign != 0))
138 : : incr = (1ULL << (VFP_DOUBLE_LOW_BITS + 1)) - 1;
139 : :
140 : : pr_debug("VFP: rounding increment = 0x%08llx\n", incr);
141 : :
142 : : /*
143 : : * Is our rounding going to overflow?
144 : : */
145 [ # # ]: 0 : if ((significand + incr) < significand) {
146 : 0 : exponent += 1;
147 : 0 : significand = (significand >> 1) | (significand & 1);
148 : 0 : incr >>= 1;
149 : : #ifdef DEBUG
150 : : vd->exponent = exponent;
151 : : vd->significand = significand;
152 : : vfp_double_dump("pack: overflow", vd);
153 : : #endif
154 : : }
155 : :
156 : : /*
157 : : * If any of the low bits (which will be shifted out of the
158 : : * number) are non-zero, the result is inexact.
159 : : */
160 [ # # ]: 0 : if (significand & ((1 << (VFP_DOUBLE_LOW_BITS + 1)) - 1))
161 : 0 : exceptions |= FPSCR_IXC;
162 : :
163 : : /*
164 : : * Do our rounding.
165 : : */
166 : 0 : significand += incr;
167 : :
168 : : /*
169 : : * Infinity?
170 : : */
171 [ # # ]: 0 : if (exponent >= 2046) {
172 : 0 : exceptions |= FPSCR_OFC | FPSCR_IXC;
173 [ # # ]: 0 : if (incr == 0) {
174 : 0 : vd->exponent = 2045;
175 : 0 : vd->significand = 0x7fffffffffffffffULL;
176 : : } else {
177 : 0 : vd->exponent = 2047; /* infinity */
178 : 0 : vd->significand = 0;
179 : : }
180 : : } else {
181 [ # # ]: 0 : if (significand >> (VFP_DOUBLE_LOW_BITS + 1) == 0)
182 : : exponent = 0;
183 [ # # ]: 0 : if (exponent || significand > 0x8000000000000000ULL)
184 : : underflow = 0;
185 [ # # ]: 0 : if (underflow)
186 : 0 : exceptions |= FPSCR_UFC;
187 : 0 : vd->exponent = exponent;
188 : 0 : vd->significand = significand >> 1;
189 : : }
190 : :
191 : : pack:
192 : : vfp_double_dump("pack: final", vd);
193 : : {
194 : : s64 d = vfp_double_pack(vd);
195 : : pr_debug("VFP: %s: d(d%d)=%016llx exceptions=%08x\n", func,
196 : : dd, d, exceptions);
197 : 0 : vfp_put_double(d, dd);
198 : : }
199 : 0 : return exceptions;
200 : : }
201 : :
202 : : /*
203 : : * Propagate the NaN, setting exceptions if it is signalling.
204 : : * 'n' is always a NaN. 'm' may be a number, NaN or infinity.
205 : : */
206 : : static u32
207 : 0 : vfp_propagate_nan(struct vfp_double *vdd, struct vfp_double *vdn,
208 : : struct vfp_double *vdm, u32 fpscr)
209 : : {
210 : : struct vfp_double *nan;
211 : : int tn, tm = 0;
212 : :
213 : : tn = vfp_double_type(vdn);
214 : :
215 [ # # ]: 0 : if (vdm)
216 : : tm = vfp_double_type(vdm);
217 : :
218 [ # # ]: 0 : if (fpscr & FPSCR_DEFAULT_NAN)
219 : : /*
220 : : * Default NaN mode - always returns a quiet NaN
221 : : */
222 : : nan = &vfp_double_default_qnan;
223 : : else {
224 : : /*
225 : : * Contemporary mode - select the first signalling
226 : : * NAN, or if neither are signalling, the first
227 : : * quiet NAN.
228 : : */
229 [ # # # # ]: 0 : if (tn == VFP_SNAN || (tm != VFP_SNAN && tn == VFP_QNAN))
230 : : nan = vdn;
231 : : else
232 : : nan = vdm;
233 : : /*
234 : : * Make the NaN quiet.
235 : : */
236 : 0 : nan->significand |= VFP_DOUBLE_SIGNIFICAND_QNAN;
237 : : }
238 : :
239 : 0 : *vdd = *nan;
240 : :
241 : : /*
242 : : * If one was a signalling NAN, raise invalid operation.
243 : : */
244 [ # # ]: 0 : return tn == VFP_SNAN || tm == VFP_SNAN ? FPSCR_IOC : VFP_NAN_FLAG;
245 : : }
246 : :
247 : : /*
248 : : * Extended operations
249 : : */
250 : 0 : static u32 vfp_double_fabs(int dd, int unused, int dm, u32 fpscr)
251 : : {
252 : 0 : vfp_put_double(vfp_double_packed_abs(vfp_get_double(dm)), dd);
253 : 0 : return 0;
254 : : }
255 : :
256 : 0 : static u32 vfp_double_fcpy(int dd, int unused, int dm, u32 fpscr)
257 : : {
258 : 0 : vfp_put_double(vfp_get_double(dm), dd);
259 : 0 : return 0;
260 : : }
261 : :
262 : 0 : static u32 vfp_double_fneg(int dd, int unused, int dm, u32 fpscr)
263 : : {
264 : 0 : vfp_put_double(vfp_double_packed_negate(vfp_get_double(dm)), dd);
265 : 0 : return 0;
266 : : }
267 : :
268 : 0 : static u32 vfp_double_fsqrt(int dd, int unused, int dm, u32 fpscr)
269 : : {
270 : : struct vfp_double vdm, vdd;
271 : : int ret, tm;
272 : :
273 : 0 : vfp_double_unpack(&vdm, vfp_get_double(dm));
274 : : tm = vfp_double_type(&vdm);
275 [ # # ]: 0 : if (tm & (VFP_NAN|VFP_INFINITY)) {
276 : : struct vfp_double *vdp = &vdd;
277 : :
278 [ # # ]: 0 : if (tm & VFP_NAN)
279 : 0 : ret = vfp_propagate_nan(vdp, &vdm, NULL, fpscr);
280 [ # # ]: 0 : else if (vdm.sign == 0) {
281 : : sqrt_copy:
282 : : vdp = &vdm;
283 : : ret = 0;
284 : : } else {
285 : : sqrt_invalid:
286 : : vdp = &vfp_double_default_qnan;
287 : : ret = FPSCR_IOC;
288 : : }
289 : 0 : vfp_put_double(vfp_double_pack(vdp), dd);
290 : 0 : return ret;
291 : : }
292 : :
293 : : /*
294 : : * sqrt(+/- 0) == +/- 0
295 : : */
296 [ # # ]: 0 : if (tm & VFP_ZERO)
297 : : goto sqrt_copy;
298 : :
299 : : /*
300 : : * Normalise a denormalised number
301 : : */
302 [ # # ]: 0 : if (tm & VFP_DENORMAL)
303 : 0 : vfp_double_normalise_denormal(&vdm);
304 : :
305 : : /*
306 : : * sqrt(<0) = invalid
307 : : */
308 [ # # ]: 0 : if (vdm.sign)
309 : : goto sqrt_invalid;
310 : :
311 : : vfp_double_dump("sqrt", &vdm);
312 : :
313 : : /*
314 : : * Estimate the square root.
315 : : */
316 : 0 : vdd.sign = 0;
317 : 0 : vdd.exponent = ((vdm.exponent - 1023) >> 1) + 1023;
318 : 0 : vdd.significand = (u64)vfp_estimate_sqrt_significand(vdm.exponent, vdm.significand >> 32) << 31;
319 : :
320 : : vfp_double_dump("sqrt estimate1", &vdd);
321 : :
322 : 0 : vdm.significand >>= 1 + (vdm.exponent & 1);
323 : 0 : vdd.significand += 2 + vfp_estimate_div128to64(vdm.significand, 0, vdd.significand);
324 : :
325 : : vfp_double_dump("sqrt estimate2", &vdd);
326 : :
327 : : /*
328 : : * And now adjust.
329 : : */
330 [ # # ]: 0 : if ((vdd.significand & VFP_DOUBLE_LOW_BITS_MASK) <= 5) {
331 [ # # ]: 0 : if (vdd.significand < 2) {
332 : 0 : vdd.significand = ~0ULL;
333 : : } else {
334 : : u64 termh, terml, remh, reml;
335 : 0 : vdm.significand <<= 2;
336 : 0 : mul64to128(&termh, &terml, vdd.significand, vdd.significand);
337 : 0 : sub128(&remh, &reml, vdm.significand, 0, termh, terml);
338 [ # # ]: 0 : while ((s64)remh < 0) {
339 : 0 : vdd.significand -= 1;
340 : : shift64left(&termh, &terml, vdd.significand);
341 : 0 : terml |= 1;
342 : : add128(&remh, &reml, remh, reml, termh, terml);
343 : : }
344 : 0 : vdd.significand |= (remh | reml) != 0;
345 : : }
346 : : }
347 : 0 : vdd.significand = vfp_shiftright64jamming(vdd.significand, 1);
348 : :
349 : 0 : return vfp_double_normaliseround(dd, &vdd, fpscr, 0, "fsqrt");
350 : : }
351 : :
352 : : /*
353 : : * Equal := ZC
354 : : * Less than := N
355 : : * Greater than := C
356 : : * Unordered := CV
357 : : */
358 : 0 : static u32 vfp_compare(int dd, int signal_on_qnan, int dm, u32 fpscr)
359 : : {
360 : : s64 d, m;
361 : : u32 ret = 0;
362 : :
363 : 0 : m = vfp_get_double(dm);
364 [ # # # # ]: 0 : if (vfp_double_packed_exponent(m) == 2047 && vfp_double_packed_mantissa(m)) {
365 : : ret |= FPSCR_C | FPSCR_V;
366 [ # # # # ]: 0 : if (signal_on_qnan || !(vfp_double_packed_mantissa(m) & (1ULL << (VFP_DOUBLE_MANTISSA_BITS - 1))))
367 : : /*
368 : : * Signalling NaN, or signalling on quiet NaN
369 : : */
370 : : ret |= FPSCR_IOC;
371 : : }
372 : :
373 : 0 : d = vfp_get_double(dd);
374 [ # # # # ]: 0 : if (vfp_double_packed_exponent(d) == 2047 && vfp_double_packed_mantissa(d)) {
375 : 0 : ret |= FPSCR_C | FPSCR_V;
376 [ # # # # ]: 0 : if (signal_on_qnan || !(vfp_double_packed_mantissa(d) & (1ULL << (VFP_DOUBLE_MANTISSA_BITS - 1))))
377 : : /*
378 : : * Signalling NaN, or signalling on quiet NaN
379 : : */
380 : : ret |= FPSCR_IOC;
381 : : }
382 : :
383 [ # # ]: 0 : if (ret == 0) {
384 [ # # # # ]: 0 : if (d == m || vfp_double_packed_abs(d | m) == 0) {
385 : : /*
386 : : * equal
387 : : */
388 : 0 : ret |= FPSCR_Z | FPSCR_C;
389 [ # # ]: 0 : } else if (vfp_double_packed_sign(d ^ m)) {
390 : : /*
391 : : * different signs
392 : : */
393 [ # # ]: 0 : if (vfp_double_packed_sign(d))
394 : : /*
395 : : * d is negative, so d < m
396 : : */
397 : 0 : ret |= FPSCR_N;
398 : : else
399 : : /*
400 : : * d is positive, so d > m
401 : : */
402 : 0 : ret |= FPSCR_C;
403 [ # # ]: 0 : } else if ((vfp_double_packed_sign(d) != 0) ^ (d < m)) {
404 : : /*
405 : : * d < m
406 : : */
407 : 0 : ret |= FPSCR_N;
408 [ # # ]: 0 : } else if ((vfp_double_packed_sign(d) != 0) ^ (d > m)) {
409 : : /*
410 : : * d > m
411 : : */
412 : 0 : ret |= FPSCR_C;
413 : : }
414 : : }
415 : :
416 : 0 : return ret;
417 : : }
418 : :
419 : 0 : static u32 vfp_double_fcmp(int dd, int unused, int dm, u32 fpscr)
420 : : {
421 : 0 : return vfp_compare(dd, 0, dm, fpscr);
422 : : }
423 : :
424 : 0 : static u32 vfp_double_fcmpe(int dd, int unused, int dm, u32 fpscr)
425 : : {
426 : 0 : return vfp_compare(dd, 1, dm, fpscr);
427 : : }
428 : :
429 : 0 : static u32 vfp_double_fcmpz(int dd, int unused, int dm, u32 fpscr)
430 : : {
431 : 0 : return vfp_compare(dd, 0, VFP_REG_ZERO, fpscr);
432 : : }
433 : :
434 : 0 : static u32 vfp_double_fcmpez(int dd, int unused, int dm, u32 fpscr)
435 : : {
436 : 0 : return vfp_compare(dd, 1, VFP_REG_ZERO, fpscr);
437 : : }
438 : :
439 : 0 : static u32 vfp_double_fcvts(int sd, int unused, int dm, u32 fpscr)
440 : : {
441 : : struct vfp_double vdm;
442 : : struct vfp_single vsd;
443 : : int tm;
444 : : u32 exceptions = 0;
445 : :
446 : 0 : vfp_double_unpack(&vdm, vfp_get_double(dm));
447 : :
448 : : tm = vfp_double_type(&vdm);
449 : :
450 : : /*
451 : : * If we have a signalling NaN, signal invalid operation.
452 : : */
453 [ # # ]: 0 : if (tm == VFP_SNAN)
454 : : exceptions = FPSCR_IOC;
455 : :
456 [ # # ]: 0 : if (tm & VFP_DENORMAL)
457 : 0 : vfp_double_normalise_denormal(&vdm);
458 : :
459 : 0 : vsd.sign = vdm.sign;
460 : 0 : vsd.significand = vfp_hi64to32jamming(vdm.significand);
461 : :
462 : : /*
463 : : * If we have an infinity or a NaN, the exponent must be 255
464 : : */
465 [ # # ]: 0 : if (tm & (VFP_INFINITY|VFP_NAN)) {
466 : 0 : vsd.exponent = 255;
467 [ # # ]: 0 : if (tm == VFP_QNAN)
468 : 0 : vsd.significand |= VFP_SINGLE_SIGNIFICAND_QNAN;
469 : : goto pack_nan;
470 [ # # ]: 0 : } else if (tm & VFP_ZERO)
471 : 0 : vsd.exponent = 0;
472 : : else
473 : 0 : vsd.exponent = vdm.exponent - (1023 - 127);
474 : :
475 : 0 : return vfp_single_normaliseround(sd, &vsd, fpscr, exceptions, "fcvts");
476 : :
477 : : pack_nan:
478 : 0 : vfp_put_float(vfp_single_pack(&vsd), sd);
479 : 0 : return exceptions;
480 : : }
481 : :
482 : 0 : static u32 vfp_double_fuito(int dd, int unused, int dm, u32 fpscr)
483 : : {
484 : : struct vfp_double vdm;
485 : 0 : u32 m = vfp_get_float(dm);
486 : :
487 : 0 : vdm.sign = 0;
488 : 0 : vdm.exponent = 1023 + 63 - 1;
489 : 0 : vdm.significand = (u64)m;
490 : :
491 : 0 : return vfp_double_normaliseround(dd, &vdm, fpscr, 0, "fuito");
492 : : }
493 : :
494 : 0 : static u32 vfp_double_fsito(int dd, int unused, int dm, u32 fpscr)
495 : : {
496 : : struct vfp_double vdm;
497 : 0 : u32 m = vfp_get_float(dm);
498 : :
499 : 0 : vdm.sign = (m & 0x80000000) >> 16;
500 : 0 : vdm.exponent = 1023 + 63 - 1;
501 [ # # ]: 0 : vdm.significand = vdm.sign ? -m : m;
502 : :
503 : 0 : return vfp_double_normaliseround(dd, &vdm, fpscr, 0, "fsito");
504 : : }
505 : :
506 : 0 : static u32 vfp_double_ftoui(int sd, int unused, int dm, u32 fpscr)
507 : : {
508 : : struct vfp_double vdm;
509 : : u32 d, exceptions = 0;
510 : 0 : int rmode = fpscr & FPSCR_RMODE_MASK;
511 : : int tm;
512 : :
513 : 0 : vfp_double_unpack(&vdm, vfp_get_double(dm));
514 : :
515 : : /*
516 : : * Do we have a denormalised number?
517 : : */
518 : : tm = vfp_double_type(&vdm);
519 [ # # ]: 0 : if (tm & VFP_DENORMAL)
520 : : exceptions |= FPSCR_IDC;
521 : :
522 [ # # ]: 0 : if (tm & VFP_NAN)
523 : : vdm.sign = 0;
524 : :
525 [ # # ]: 0 : if (vdm.exponent >= 1023 + 32) {
526 [ # # ]: 0 : d = vdm.sign ? 0 : 0xffffffff;
527 : : exceptions = FPSCR_IOC;
528 [ # # ]: 0 : } else if (vdm.exponent >= 1023 - 1) {
529 : 0 : int shift = 1023 + 63 - vdm.exponent;
530 : : u64 rem, incr = 0;
531 : :
532 : : /*
533 : : * 2^0 <= m < 2^32-2^8
534 : : */
535 : 0 : d = (vdm.significand << 1) >> shift;
536 : 0 : rem = vdm.significand << (65 - shift);
537 : :
538 [ # # ]: 0 : if (rmode == FPSCR_ROUND_NEAREST) {
539 : : incr = 0x8000000000000000ULL;
540 [ # # ]: 0 : if ((d & 1) == 0)
541 : : incr -= 1;
542 [ # # ]: 0 : } else if (rmode == FPSCR_ROUND_TOZERO) {
543 : : incr = 0;
544 [ # # ]: 0 : } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vdm.sign != 0)) {
545 : : incr = ~0ULL;
546 : : }
547 : :
548 [ # # ]: 0 : if ((rem + incr) < rem) {
549 [ # # ]: 0 : if (d < 0xffffffff)
550 : 0 : d += 1;
551 : : else
552 : 0 : exceptions |= FPSCR_IOC;
553 : : }
554 : :
555 [ # # # # ]: 0 : if (d && vdm.sign) {
556 : : d = 0;
557 : 0 : exceptions |= FPSCR_IOC;
558 [ # # ]: 0 : } else if (rem)
559 : 0 : exceptions |= FPSCR_IXC;
560 : : } else {
561 : : d = 0;
562 [ # # ]: 0 : if (vdm.exponent | vdm.significand) {
563 : 0 : exceptions |= FPSCR_IXC;
564 [ # # # # ]: 0 : if (rmode == FPSCR_ROUND_PLUSINF && vdm.sign == 0)
565 : : d = 1;
566 [ # # # # ]: 0 : else if (rmode == FPSCR_ROUND_MINUSINF && vdm.sign) {
567 : : d = 0;
568 : 0 : exceptions |= FPSCR_IOC;
569 : : }
570 : : }
571 : : }
572 : :
573 : : pr_debug("VFP: ftoui: d(s%d)=%08x exceptions=%08x\n", sd, d, exceptions);
574 : :
575 : 0 : vfp_put_float(d, sd);
576 : :
577 : 0 : return exceptions;
578 : : }
579 : :
580 : 0 : static u32 vfp_double_ftouiz(int sd, int unused, int dm, u32 fpscr)
581 : : {
582 : 0 : return vfp_double_ftoui(sd, unused, dm, FPSCR_ROUND_TOZERO);
583 : : }
584 : :
585 : 0 : static u32 vfp_double_ftosi(int sd, int unused, int dm, u32 fpscr)
586 : : {
587 : : struct vfp_double vdm;
588 : : u32 d, exceptions = 0;
589 : 0 : int rmode = fpscr & FPSCR_RMODE_MASK;
590 : : int tm;
591 : :
592 : 0 : vfp_double_unpack(&vdm, vfp_get_double(dm));
593 : : vfp_double_dump("VDM", &vdm);
594 : :
595 : : /*
596 : : * Do we have denormalised number?
597 : : */
598 : : tm = vfp_double_type(&vdm);
599 [ # # ]: 0 : if (tm & VFP_DENORMAL)
600 : : exceptions |= FPSCR_IDC;
601 : :
602 [ # # ]: 0 : if (tm & VFP_NAN) {
603 : : d = 0;
604 : 0 : exceptions |= FPSCR_IOC;
605 [ # # ]: 0 : } else if (vdm.exponent >= 1023 + 32) {
606 : : d = 0x7fffffff;
607 [ # # ]: 0 : if (vdm.sign)
608 : : d = ~d;
609 : 0 : exceptions |= FPSCR_IOC;
610 [ # # ]: 0 : } else if (vdm.exponent >= 1023 - 1) {
611 : 0 : int shift = 1023 + 63 - vdm.exponent; /* 58 */
612 : : u64 rem, incr = 0;
613 : :
614 : 0 : d = (vdm.significand << 1) >> shift;
615 : 0 : rem = vdm.significand << (65 - shift);
616 : :
617 [ # # ]: 0 : if (rmode == FPSCR_ROUND_NEAREST) {
618 : : incr = 0x8000000000000000ULL;
619 [ # # ]: 0 : if ((d & 1) == 0)
620 : : incr -= 1;
621 [ # # ]: 0 : } else if (rmode == FPSCR_ROUND_TOZERO) {
622 : : incr = 0;
623 [ # # ]: 0 : } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vdm.sign != 0)) {
624 : : incr = ~0ULL;
625 : : }
626 : :
627 [ # # # # ]: 0 : if ((rem + incr) < rem && d < 0xffffffff)
628 : 0 : d += 1;
629 [ # # # # ]: 0 : if (d > 0x7fffffff + (vdm.sign != 0)) {
630 [ # # ]: 0 : d = 0x7fffffff + (vdm.sign != 0);
631 : 0 : exceptions |= FPSCR_IOC;
632 [ # # ]: 0 : } else if (rem)
633 : 0 : exceptions |= FPSCR_IXC;
634 : :
635 [ # # ]: 0 : if (vdm.sign)
636 : 0 : d = -d;
637 : : } else {
638 : : d = 0;
639 [ # # ]: 0 : if (vdm.exponent | vdm.significand) {
640 : 0 : exceptions |= FPSCR_IXC;
641 [ # # # # ]: 0 : if (rmode == FPSCR_ROUND_PLUSINF && vdm.sign == 0)
642 : : d = 1;
643 [ # # # # ]: 0 : else if (rmode == FPSCR_ROUND_MINUSINF && vdm.sign)
644 : : d = -1;
645 : : }
646 : : }
647 : :
648 : : pr_debug("VFP: ftosi: d(s%d)=%08x exceptions=%08x\n", sd, d, exceptions);
649 : :
650 : 0 : vfp_put_float((s32)d, sd);
651 : :
652 : 0 : return exceptions;
653 : : }
654 : :
655 : 0 : static u32 vfp_double_ftosiz(int dd, int unused, int dm, u32 fpscr)
656 : : {
657 : 0 : return vfp_double_ftosi(dd, unused, dm, FPSCR_ROUND_TOZERO);
658 : : }
659 : :
660 : :
661 : : static struct op fops_ext[32] = {
662 : : [FEXT_TO_IDX(FEXT_FCPY)] = { vfp_double_fcpy, 0 },
663 : : [FEXT_TO_IDX(FEXT_FABS)] = { vfp_double_fabs, 0 },
664 : : [FEXT_TO_IDX(FEXT_FNEG)] = { vfp_double_fneg, 0 },
665 : : [FEXT_TO_IDX(FEXT_FSQRT)] = { vfp_double_fsqrt, 0 },
666 : : [FEXT_TO_IDX(FEXT_FCMP)] = { vfp_double_fcmp, OP_SCALAR },
667 : : [FEXT_TO_IDX(FEXT_FCMPE)] = { vfp_double_fcmpe, OP_SCALAR },
668 : : [FEXT_TO_IDX(FEXT_FCMPZ)] = { vfp_double_fcmpz, OP_SCALAR },
669 : : [FEXT_TO_IDX(FEXT_FCMPEZ)] = { vfp_double_fcmpez, OP_SCALAR },
670 : : [FEXT_TO_IDX(FEXT_FCVT)] = { vfp_double_fcvts, OP_SCALAR|OP_SD },
671 : : [FEXT_TO_IDX(FEXT_FUITO)] = { vfp_double_fuito, OP_SCALAR|OP_SM },
672 : : [FEXT_TO_IDX(FEXT_FSITO)] = { vfp_double_fsito, OP_SCALAR|OP_SM },
673 : : [FEXT_TO_IDX(FEXT_FTOUI)] = { vfp_double_ftoui, OP_SCALAR|OP_SD },
674 : : [FEXT_TO_IDX(FEXT_FTOUIZ)] = { vfp_double_ftouiz, OP_SCALAR|OP_SD },
675 : : [FEXT_TO_IDX(FEXT_FTOSI)] = { vfp_double_ftosi, OP_SCALAR|OP_SD },
676 : : [FEXT_TO_IDX(FEXT_FTOSIZ)] = { vfp_double_ftosiz, OP_SCALAR|OP_SD },
677 : : };
678 : :
679 : :
680 : :
681 : :
682 : : static u32
683 : 0 : vfp_double_fadd_nonnumber(struct vfp_double *vdd, struct vfp_double *vdn,
684 : : struct vfp_double *vdm, u32 fpscr)
685 : : {
686 : : struct vfp_double *vdp;
687 : : u32 exceptions = 0;
688 : : int tn, tm;
689 : :
690 : : tn = vfp_double_type(vdn);
691 : : tm = vfp_double_type(vdm);
692 : :
693 [ # # ]: 0 : if (tn & tm & VFP_INFINITY) {
694 : : /*
695 : : * Two infinities. Are they different signs?
696 : : */
697 [ # # ]: 0 : if (vdn->sign ^ vdm->sign) {
698 : : /*
699 : : * different signs -> invalid
700 : : */
701 : : exceptions = FPSCR_IOC;
702 : : vdp = &vfp_double_default_qnan;
703 : : } else {
704 : : /*
705 : : * same signs -> valid
706 : : */
707 : : vdp = vdn;
708 : : }
709 [ # # # # ]: 0 : } else if (tn & VFP_INFINITY && tm & VFP_NUMBER) {
710 : : /*
711 : : * One infinity and one number -> infinity
712 : : */
713 : : vdp = vdn;
714 : : } else {
715 : : /*
716 : : * 'n' is a NaN of some type
717 : : */
718 : 0 : return vfp_propagate_nan(vdd, vdn, vdm, fpscr);
719 : : }
720 : 0 : *vdd = *vdp;
721 : 0 : return exceptions;
722 : : }
723 : :
724 : : static u32
725 : 0 : vfp_double_add(struct vfp_double *vdd, struct vfp_double *vdn,
726 : : struct vfp_double *vdm, u32 fpscr)
727 : : {
728 : : u32 exp_diff;
729 : : u64 m_sig;
730 : :
731 [ # # # # ]: 0 : if (vdn->significand & (1ULL << 63) ||
732 : 0 : vdm->significand & (1ULL << 63)) {
733 : 0 : pr_info("VFP: bad FP values in %s\n", __func__);
734 : : vfp_double_dump("VDN", vdn);
735 : : vfp_double_dump("VDM", vdm);
736 : : }
737 : :
738 : : /*
739 : : * Ensure that 'n' is the largest magnitude number. Note that
740 : : * if 'n' and 'm' have equal exponents, we do not swap them.
741 : : * This ensures that NaN propagation works correctly.
742 : : */
743 [ # # ]: 0 : if (vdn->exponent < vdm->exponent) {
744 : : struct vfp_double *t = vdn;
745 : : vdn = vdm;
746 : : vdm = t;
747 : : }
748 : :
749 : : /*
750 : : * Is 'n' an infinity or a NaN? Note that 'm' may be a number,
751 : : * infinity or a NaN here.
752 : : */
753 [ # # ]: 0 : if (vdn->exponent == 2047)
754 : 0 : return vfp_double_fadd_nonnumber(vdd, vdn, vdm, fpscr);
755 : :
756 : : /*
757 : : * We have two proper numbers, where 'vdn' is the larger magnitude.
758 : : *
759 : : * Copy 'n' to 'd' before doing the arithmetic.
760 : : */
761 : 0 : *vdd = *vdn;
762 : :
763 : : /*
764 : : * Align 'm' with the result.
765 : : */
766 : 0 : exp_diff = vdn->exponent - vdm->exponent;
767 : 0 : m_sig = vfp_shiftright64jamming(vdm->significand, exp_diff);
768 : :
769 : : /*
770 : : * If the signs are different, we are really subtracting.
771 : : */
772 [ # # ]: 0 : if (vdn->sign ^ vdm->sign) {
773 : 0 : m_sig = vdn->significand - m_sig;
774 [ # # ]: 0 : if ((s64)m_sig < 0) {
775 : 0 : vdd->sign = vfp_sign_negate(vdd->sign);
776 : 0 : m_sig = -m_sig;
777 [ # # ]: 0 : } else if (m_sig == 0) {
778 [ # # ]: 0 : vdd->sign = (fpscr & FPSCR_RMODE_MASK) ==
779 : : FPSCR_ROUND_MINUSINF ? 0x8000 : 0;
780 : : }
781 : : } else {
782 : 0 : m_sig += vdn->significand;
783 : : }
784 : 0 : vdd->significand = m_sig;
785 : :
786 : 0 : return 0;
787 : : }
788 : :
789 : : static u32
790 : 0 : vfp_double_multiply(struct vfp_double *vdd, struct vfp_double *vdn,
791 : : struct vfp_double *vdm, u32 fpscr)
792 : : {
793 : : vfp_double_dump("VDN", vdn);
794 : : vfp_double_dump("VDM", vdm);
795 : :
796 : : /*
797 : : * Ensure that 'n' is the largest magnitude number. Note that
798 : : * if 'n' and 'm' have equal exponents, we do not swap them.
799 : : * This ensures that NaN propagation works correctly.
800 : : */
801 [ # # ]: 0 : if (vdn->exponent < vdm->exponent) {
802 : : struct vfp_double *t = vdn;
803 : : vdn = vdm;
804 : : vdm = t;
805 : : pr_debug("VFP: swapping M <-> N\n");
806 : : }
807 : :
808 : 0 : vdd->sign = vdn->sign ^ vdm->sign;
809 : :
810 : : /*
811 : : * If 'n' is an infinity or NaN, handle it. 'm' may be anything.
812 : : */
813 [ # # ]: 0 : if (vdn->exponent == 2047) {
814 [ # # # # : 0 : if (vdn->significand || (vdm->exponent == 2047 && vdm->significand))
# # ]
815 : 0 : return vfp_propagate_nan(vdd, vdn, vdm, fpscr);
816 [ # # ]: 0 : if ((vdm->exponent | vdm->significand) == 0) {
817 : 0 : *vdd = vfp_double_default_qnan;
818 : 0 : return FPSCR_IOC;
819 : : }
820 : 0 : vdd->exponent = vdn->exponent;
821 : 0 : vdd->significand = 0;
822 : 0 : return 0;
823 : : }
824 : :
825 : : /*
826 : : * If 'm' is zero, the result is always zero. In this case,
827 : : * 'n' may be zero or a number, but it doesn't matter which.
828 : : */
829 [ # # ]: 0 : if ((vdm->exponent | vdm->significand) == 0) {
830 : 0 : vdd->exponent = 0;
831 : 0 : vdd->significand = 0;
832 : 0 : return 0;
833 : : }
834 : :
835 : : /*
836 : : * We add 2 to the destination exponent for the same reason
837 : : * as the addition case - though this time we have +1 from
838 : : * each input operand.
839 : : */
840 : 0 : vdd->exponent = vdn->exponent + vdm->exponent - 1023 + 2;
841 : 0 : vdd->significand = vfp_hi64multiply64(vdn->significand, vdm->significand);
842 : :
843 : : vfp_double_dump("VDD", vdd);
844 : 0 : return 0;
845 : : }
846 : :
847 : : #define NEG_MULTIPLY (1 << 0)
848 : : #define NEG_SUBTRACT (1 << 1)
849 : :
850 : : static u32
851 : 0 : vfp_double_multiply_accumulate(int dd, int dn, int dm, u32 fpscr, u32 negate, char *func)
852 : : {
853 : : struct vfp_double vdd, vdp, vdn, vdm;
854 : : u32 exceptions;
855 : :
856 : 0 : vfp_double_unpack(&vdn, vfp_get_double(dn));
857 [ # # # # ]: 0 : if (vdn.exponent == 0 && vdn.significand)
858 : 0 : vfp_double_normalise_denormal(&vdn);
859 : :
860 : 0 : vfp_double_unpack(&vdm, vfp_get_double(dm));
861 [ # # # # ]: 0 : if (vdm.exponent == 0 && vdm.significand)
862 : 0 : vfp_double_normalise_denormal(&vdm);
863 : :
864 : 0 : exceptions = vfp_double_multiply(&vdp, &vdn, &vdm, fpscr);
865 [ # # ]: 0 : if (negate & NEG_MULTIPLY)
866 : 0 : vdp.sign = vfp_sign_negate(vdp.sign);
867 : :
868 : 0 : vfp_double_unpack(&vdn, vfp_get_double(dd));
869 [ # # # # ]: 0 : if (vdn.exponent == 0 && vdn.significand)
870 : 0 : vfp_double_normalise_denormal(&vdn);
871 [ # # ]: 0 : if (negate & NEG_SUBTRACT)
872 : 0 : vdn.sign = vfp_sign_negate(vdn.sign);
873 : :
874 : 0 : exceptions |= vfp_double_add(&vdd, &vdn, &vdp, fpscr);
875 : :
876 : 0 : return vfp_double_normaliseround(dd, &vdd, fpscr, exceptions, func);
877 : : }
878 : :
879 : : /*
880 : : * Standard operations
881 : : */
882 : :
883 : : /*
884 : : * sd = sd + (sn * sm)
885 : : */
886 : 0 : static u32 vfp_double_fmac(int dd, int dn, int dm, u32 fpscr)
887 : : {
888 : 0 : return vfp_double_multiply_accumulate(dd, dn, dm, fpscr, 0, "fmac");
889 : : }
890 : :
891 : : /*
892 : : * sd = sd - (sn * sm)
893 : : */
894 : 0 : static u32 vfp_double_fnmac(int dd, int dn, int dm, u32 fpscr)
895 : : {
896 : 0 : return vfp_double_multiply_accumulate(dd, dn, dm, fpscr, NEG_MULTIPLY, "fnmac");
897 : : }
898 : :
899 : : /*
900 : : * sd = -sd + (sn * sm)
901 : : */
902 : 0 : static u32 vfp_double_fmsc(int dd, int dn, int dm, u32 fpscr)
903 : : {
904 : 0 : return vfp_double_multiply_accumulate(dd, dn, dm, fpscr, NEG_SUBTRACT, "fmsc");
905 : : }
906 : :
907 : : /*
908 : : * sd = -sd - (sn * sm)
909 : : */
910 : 0 : static u32 vfp_double_fnmsc(int dd, int dn, int dm, u32 fpscr)
911 : : {
912 : 0 : return vfp_double_multiply_accumulate(dd, dn, dm, fpscr, NEG_SUBTRACT | NEG_MULTIPLY, "fnmsc");
913 : : }
914 : :
915 : : /*
916 : : * sd = sn * sm
917 : : */
918 : 0 : static u32 vfp_double_fmul(int dd, int dn, int dm, u32 fpscr)
919 : : {
920 : : struct vfp_double vdd, vdn, vdm;
921 : : u32 exceptions;
922 : :
923 : 0 : vfp_double_unpack(&vdn, vfp_get_double(dn));
924 [ # # # # ]: 0 : if (vdn.exponent == 0 && vdn.significand)
925 : 0 : vfp_double_normalise_denormal(&vdn);
926 : :
927 : 0 : vfp_double_unpack(&vdm, vfp_get_double(dm));
928 [ # # # # ]: 0 : if (vdm.exponent == 0 && vdm.significand)
929 : 0 : vfp_double_normalise_denormal(&vdm);
930 : :
931 : 0 : exceptions = vfp_double_multiply(&vdd, &vdn, &vdm, fpscr);
932 : 0 : return vfp_double_normaliseround(dd, &vdd, fpscr, exceptions, "fmul");
933 : : }
934 : :
935 : : /*
936 : : * sd = -(sn * sm)
937 : : */
938 : 0 : static u32 vfp_double_fnmul(int dd, int dn, int dm, u32 fpscr)
939 : : {
940 : : struct vfp_double vdd, vdn, vdm;
941 : : u32 exceptions;
942 : :
943 : 0 : vfp_double_unpack(&vdn, vfp_get_double(dn));
944 [ # # # # ]: 0 : if (vdn.exponent == 0 && vdn.significand)
945 : 0 : vfp_double_normalise_denormal(&vdn);
946 : :
947 : 0 : vfp_double_unpack(&vdm, vfp_get_double(dm));
948 [ # # # # ]: 0 : if (vdm.exponent == 0 && vdm.significand)
949 : 0 : vfp_double_normalise_denormal(&vdm);
950 : :
951 : 0 : exceptions = vfp_double_multiply(&vdd, &vdn, &vdm, fpscr);
952 : 0 : vdd.sign = vfp_sign_negate(vdd.sign);
953 : :
954 : 0 : return vfp_double_normaliseround(dd, &vdd, fpscr, exceptions, "fnmul");
955 : : }
956 : :
957 : : /*
958 : : * sd = sn + sm
959 : : */
960 : 0 : static u32 vfp_double_fadd(int dd, int dn, int dm, u32 fpscr)
961 : : {
962 : : struct vfp_double vdd, vdn, vdm;
963 : : u32 exceptions;
964 : :
965 : 0 : vfp_double_unpack(&vdn, vfp_get_double(dn));
966 [ # # # # ]: 0 : if (vdn.exponent == 0 && vdn.significand)
967 : 0 : vfp_double_normalise_denormal(&vdn);
968 : :
969 : 0 : vfp_double_unpack(&vdm, vfp_get_double(dm));
970 [ # # # # ]: 0 : if (vdm.exponent == 0 && vdm.significand)
971 : 0 : vfp_double_normalise_denormal(&vdm);
972 : :
973 : 0 : exceptions = vfp_double_add(&vdd, &vdn, &vdm, fpscr);
974 : :
975 : 0 : return vfp_double_normaliseround(dd, &vdd, fpscr, exceptions, "fadd");
976 : : }
977 : :
978 : : /*
979 : : * sd = sn - sm
980 : : */
981 : 0 : static u32 vfp_double_fsub(int dd, int dn, int dm, u32 fpscr)
982 : : {
983 : : struct vfp_double vdd, vdn, vdm;
984 : : u32 exceptions;
985 : :
986 : 0 : vfp_double_unpack(&vdn, vfp_get_double(dn));
987 [ # # # # ]: 0 : if (vdn.exponent == 0 && vdn.significand)
988 : 0 : vfp_double_normalise_denormal(&vdn);
989 : :
990 : 0 : vfp_double_unpack(&vdm, vfp_get_double(dm));
991 [ # # # # ]: 0 : if (vdm.exponent == 0 && vdm.significand)
992 : 0 : vfp_double_normalise_denormal(&vdm);
993 : :
994 : : /*
995 : : * Subtraction is like addition, but with a negated operand.
996 : : */
997 : 0 : vdm.sign = vfp_sign_negate(vdm.sign);
998 : :
999 : 0 : exceptions = vfp_double_add(&vdd, &vdn, &vdm, fpscr);
1000 : :
1001 : 0 : return vfp_double_normaliseround(dd, &vdd, fpscr, exceptions, "fsub");
1002 : : }
1003 : :
1004 : : /*
1005 : : * sd = sn / sm
1006 : : */
1007 : 0 : static u32 vfp_double_fdiv(int dd, int dn, int dm, u32 fpscr)
1008 : : {
1009 : : struct vfp_double vdd, vdn, vdm;
1010 : : u32 exceptions = 0;
1011 : : int tm, tn;
1012 : :
1013 : 0 : vfp_double_unpack(&vdn, vfp_get_double(dn));
1014 : 0 : vfp_double_unpack(&vdm, vfp_get_double(dm));
1015 : :
1016 : 0 : vdd.sign = vdn.sign ^ vdm.sign;
1017 : :
1018 : : tn = vfp_double_type(&vdn);
1019 : : tm = vfp_double_type(&vdm);
1020 : :
1021 : : /*
1022 : : * Is n a NAN?
1023 : : */
1024 [ # # ]: 0 : if (tn & VFP_NAN)
1025 : : goto vdn_nan;
1026 : :
1027 : : /*
1028 : : * Is m a NAN?
1029 : : */
1030 [ # # ]: 0 : if (tm & VFP_NAN)
1031 : : goto vdm_nan;
1032 : :
1033 : : /*
1034 : : * If n and m are infinity, the result is invalid
1035 : : * If n and m are zero, the result is invalid
1036 : : */
1037 [ # # ]: 0 : if (tm & tn & (VFP_INFINITY|VFP_ZERO))
1038 : : goto invalid;
1039 : :
1040 : : /*
1041 : : * If n is infinity, the result is infinity
1042 : : */
1043 [ # # ]: 0 : if (tn & VFP_INFINITY)
1044 : : goto infinity;
1045 : :
1046 : : /*
1047 : : * If m is zero, raise div0 exceptions
1048 : : */
1049 [ # # ]: 0 : if (tm & VFP_ZERO)
1050 : : goto divzero;
1051 : :
1052 : : /*
1053 : : * If m is infinity, or n is zero, the result is zero
1054 : : */
1055 [ # # # # ]: 0 : if (tm & VFP_INFINITY || tn & VFP_ZERO)
1056 : : goto zero;
1057 : :
1058 [ # # ]: 0 : if (tn & VFP_DENORMAL)
1059 : 0 : vfp_double_normalise_denormal(&vdn);
1060 [ # # ]: 0 : if (tm & VFP_DENORMAL)
1061 : 0 : vfp_double_normalise_denormal(&vdm);
1062 : :
1063 : : /*
1064 : : * Ok, we have two numbers, we can perform division.
1065 : : */
1066 : 0 : vdd.exponent = vdn.exponent - vdm.exponent + 1023 - 1;
1067 : 0 : vdm.significand <<= 1;
1068 [ # # ]: 0 : if (vdm.significand <= (2 * vdn.significand)) {
1069 : 0 : vdn.significand >>= 1;
1070 : 0 : vdd.exponent++;
1071 : : }
1072 : 0 : vdd.significand = vfp_estimate_div128to64(vdn.significand, 0, vdm.significand);
1073 [ # # ]: 0 : if ((vdd.significand & 0x1ff) <= 2) {
1074 : : u64 termh, terml, remh, reml;
1075 : 0 : mul64to128(&termh, &terml, vdm.significand, vdd.significand);
1076 : 0 : sub128(&remh, &reml, vdn.significand, 0, termh, terml);
1077 [ # # ]: 0 : while ((s64)remh < 0) {
1078 : 0 : vdd.significand -= 1;
1079 : 0 : add128(&remh, &reml, remh, reml, 0, vdm.significand);
1080 : : }
1081 : 0 : vdd.significand |= (reml != 0);
1082 : : }
1083 : 0 : return vfp_double_normaliseround(dd, &vdd, fpscr, 0, "fdiv");
1084 : :
1085 : : vdn_nan:
1086 : 0 : exceptions = vfp_propagate_nan(&vdd, &vdn, &vdm, fpscr);
1087 : : pack:
1088 : 0 : vfp_put_double(vfp_double_pack(&vdd), dd);
1089 : 0 : return exceptions;
1090 : :
1091 : : vdm_nan:
1092 : 0 : exceptions = vfp_propagate_nan(&vdd, &vdm, &vdn, fpscr);
1093 : 0 : goto pack;
1094 : :
1095 : : zero:
1096 : 0 : vdd.exponent = 0;
1097 : 0 : vdd.significand = 0;
1098 : 0 : goto pack;
1099 : :
1100 : : divzero:
1101 : : exceptions = FPSCR_DZC;
1102 : : infinity:
1103 : 0 : vdd.exponent = 2047;
1104 : 0 : vdd.significand = 0;
1105 : 0 : goto pack;
1106 : :
1107 : : invalid:
1108 : 0 : vfp_put_double(vfp_double_pack(&vfp_double_default_qnan), dd);
1109 : 0 : return FPSCR_IOC;
1110 : : }
1111 : :
1112 : : static struct op fops[16] = {
1113 : : [FOP_TO_IDX(FOP_FMAC)] = { vfp_double_fmac, 0 },
1114 : : [FOP_TO_IDX(FOP_FNMAC)] = { vfp_double_fnmac, 0 },
1115 : : [FOP_TO_IDX(FOP_FMSC)] = { vfp_double_fmsc, 0 },
1116 : : [FOP_TO_IDX(FOP_FNMSC)] = { vfp_double_fnmsc, 0 },
1117 : : [FOP_TO_IDX(FOP_FMUL)] = { vfp_double_fmul, 0 },
1118 : : [FOP_TO_IDX(FOP_FNMUL)] = { vfp_double_fnmul, 0 },
1119 : : [FOP_TO_IDX(FOP_FADD)] = { vfp_double_fadd, 0 },
1120 : : [FOP_TO_IDX(FOP_FSUB)] = { vfp_double_fsub, 0 },
1121 : : [FOP_TO_IDX(FOP_FDIV)] = { vfp_double_fdiv, 0 },
1122 : : };
1123 : :
1124 : : #define FREG_BANK(x) ((x) & 0x0c)
1125 : : #define FREG_IDX(x) ((x) & 3)
1126 : :
1127 : 0 : u32 vfp_double_cpdo(u32 inst, u32 fpscr)
1128 : : {
1129 : 0 : u32 op = inst & FOP_MASK;
1130 : : u32 exceptions = 0;
1131 : : unsigned int dest;
1132 : 0 : unsigned int dn = vfp_get_dn(inst);
1133 : : unsigned int dm;
1134 : : unsigned int vecitr, veclen, vecstride;
1135 : : struct op *fop;
1136 : :
1137 [ # # ]: 0 : vecstride = (1 + ((fpscr & FPSCR_STRIDE_MASK) == FPSCR_STRIDE_MASK));
1138 : :
1139 [ # # ]: 0 : fop = (op == FOP_EXT) ? &fops_ext[FEXT_TO_IDX(inst)] : &fops[FOP_TO_IDX(op)];
1140 : :
1141 : : /*
1142 : : * fcvtds takes an sN register number as destination, not dN.
1143 : : * It also always operates on scalars.
1144 : : */
1145 [ # # ]: 0 : if (fop->flags & OP_SD)
1146 : 0 : dest = vfp_get_sd(inst);
1147 : : else
1148 : 0 : dest = vfp_get_dd(inst);
1149 : :
1150 : : /*
1151 : : * f[us]ito takes a sN operand, not a dN operand.
1152 : : */
1153 [ # # ]: 0 : if (fop->flags & OP_SM)
1154 : 0 : dm = vfp_get_sm(inst);
1155 : : else
1156 : 0 : dm = vfp_get_dm(inst);
1157 : :
1158 : : /*
1159 : : * If destination bank is zero, vector length is always '1'.
1160 : : * ARM DDI0100F C5.1.3, C5.3.2.
1161 : : */
1162 [ # # # # ]: 0 : if ((fop->flags & OP_SCALAR) || (FREG_BANK(dest) == 0))
1163 : : veclen = 0;
1164 : : else
1165 : 0 : veclen = fpscr & FPSCR_LENGTH_MASK;
1166 : :
1167 : : pr_debug("VFP: vecstride=%u veclen=%u\n", vecstride,
1168 : : (veclen >> FPSCR_LENGTH_BIT) + 1);
1169 : :
1170 [ # # ]: 0 : if (!fop->fn)
1171 : : goto invalid;
1172 : :
1173 [ # # ]: 0 : for (vecitr = 0; vecitr <= veclen; vecitr += 1 << FPSCR_LENGTH_BIT) {
1174 : : u32 except;
1175 : : char type;
1176 : :
1177 : : type = fop->flags & OP_SD ? 's' : 'd';
1178 : : if (op == FOP_EXT)
1179 : : pr_debug("VFP: itr%d (%c%u) = op[%u] (d%u)\n",
1180 : : vecitr >> FPSCR_LENGTH_BIT,
1181 : : type, dest, dn, dm);
1182 : : else
1183 : : pr_debug("VFP: itr%d (%c%u) = (d%u) op[%u] (d%u)\n",
1184 : : vecitr >> FPSCR_LENGTH_BIT,
1185 : : type, dest, dn, FOP_TO_IDX(op), dm);
1186 : :
1187 : 0 : except = fop->fn(dest, dn, dm, fpscr);
1188 : : pr_debug("VFP: itr%d: exceptions=%08x\n",
1189 : : vecitr >> FPSCR_LENGTH_BIT, except);
1190 : :
1191 : 0 : exceptions |= except;
1192 : :
1193 : : /*
1194 : : * CHECK: It appears to be undefined whether we stop when
1195 : : * we encounter an exception. We continue.
1196 : : */
1197 : 0 : dest = FREG_BANK(dest) + ((FREG_IDX(dest) + vecstride) & 3);
1198 : 0 : dn = FREG_BANK(dn) + ((FREG_IDX(dn) + vecstride) & 3);
1199 [ # # ]: 0 : if (FREG_BANK(dm) != 0)
1200 : 0 : dm = FREG_BANK(dm) + ((FREG_IDX(dm) + vecstride) & 3);
1201 : : }
1202 : 0 : return exceptions;
1203 : :
1204 : : invalid:
1205 : : return ~0;
1206 : : }
|