0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033 #include <linux/kernel.h>
0034 #include <linux/bitops.h>
0035
0036 #include <asm/div64.h>
0037 #include <asm/vfp.h>
0038
0039 #include "vfpinstr.h"
0040 #include "vfp.h"
0041
0042 static struct vfp_single vfp_single_default_qnan = {
0043 .exponent = 255,
0044 .sign = 0,
0045 .significand = VFP_SINGLE_SIGNIFICAND_QNAN,
0046 };
0047
0048 static void vfp_single_dump(const char *str, struct vfp_single *s)
0049 {
0050 pr_debug("VFP: %s: sign=%d exponent=%d significand=%08x\n",
0051 str, s->sign != 0, s->exponent, s->significand);
0052 }
0053
0054 static void vfp_single_normalise_denormal(struct vfp_single *vs)
0055 {
0056 int bits = 31 - fls(vs->significand);
0057
0058 vfp_single_dump("normalise_denormal: in", vs);
0059
0060 if (bits) {
0061 vs->exponent -= bits - 1;
0062 vs->significand <<= bits;
0063 }
0064
0065 vfp_single_dump("normalise_denormal: out", vs);
0066 }
0067
0068 #ifndef DEBUG
0069 #define vfp_single_normaliseround(sd,vsd,fpscr,except,func) __vfp_single_normaliseround(sd,vsd,fpscr,except)
0070 u32 __vfp_single_normaliseround(int sd, struct vfp_single *vs, u32 fpscr, u32 exceptions)
0071 #else
0072 u32 vfp_single_normaliseround(int sd, struct vfp_single *vs, u32 fpscr, u32 exceptions, const char *func)
0073 #endif
0074 {
0075 u32 significand, incr, rmode;
0076 int exponent, shift, underflow;
0077
0078 vfp_single_dump("pack: in", vs);
0079
0080
0081
0082
0083 if (vs->exponent == 255 && (vs->significand == 0 || exceptions))
0084 goto pack;
0085
0086
0087
0088
0089 if (vs->significand == 0) {
0090 vs->exponent = 0;
0091 goto pack;
0092 }
0093
0094 exponent = vs->exponent;
0095 significand = vs->significand;
0096
0097
0098
0099
0100
0101
0102 shift = 32 - fls(significand);
0103 if (shift < 32 && shift) {
0104 exponent -= shift;
0105 significand <<= shift;
0106 }
0107
0108 #ifdef DEBUG
0109 vs->exponent = exponent;
0110 vs->significand = significand;
0111 vfp_single_dump("pack: normalised", vs);
0112 #endif
0113
0114
0115
0116
0117 underflow = exponent < 0;
0118 if (underflow) {
0119 significand = vfp_shiftright32jamming(significand, -exponent);
0120 exponent = 0;
0121 #ifdef DEBUG
0122 vs->exponent = exponent;
0123 vs->significand = significand;
0124 vfp_single_dump("pack: tiny number", vs);
0125 #endif
0126 if (!(significand & ((1 << (VFP_SINGLE_LOW_BITS + 1)) - 1)))
0127 underflow = 0;
0128 }
0129
0130
0131
0132
0133 incr = 0;
0134 rmode = fpscr & FPSCR_RMODE_MASK;
0135
0136 if (rmode == FPSCR_ROUND_NEAREST) {
0137 incr = 1 << VFP_SINGLE_LOW_BITS;
0138 if ((significand & (1 << (VFP_SINGLE_LOW_BITS + 1))) == 0)
0139 incr -= 1;
0140 } else if (rmode == FPSCR_ROUND_TOZERO) {
0141 incr = 0;
0142 } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vs->sign != 0))
0143 incr = (1 << (VFP_SINGLE_LOW_BITS + 1)) - 1;
0144
0145 pr_debug("VFP: rounding increment = 0x%08x\n", incr);
0146
0147
0148
0149
0150 if ((significand + incr) < significand) {
0151 exponent += 1;
0152 significand = (significand >> 1) | (significand & 1);
0153 incr >>= 1;
0154 #ifdef DEBUG
0155 vs->exponent = exponent;
0156 vs->significand = significand;
0157 vfp_single_dump("pack: overflow", vs);
0158 #endif
0159 }
0160
0161
0162
0163
0164
0165 if (significand & ((1 << (VFP_SINGLE_LOW_BITS + 1)) - 1))
0166 exceptions |= FPSCR_IXC;
0167
0168
0169
0170
0171 significand += incr;
0172
0173
0174
0175
0176 if (exponent >= 254) {
0177 exceptions |= FPSCR_OFC | FPSCR_IXC;
0178 if (incr == 0) {
0179 vs->exponent = 253;
0180 vs->significand = 0x7fffffff;
0181 } else {
0182 vs->exponent = 255;
0183 vs->significand = 0;
0184 }
0185 } else {
0186 if (significand >> (VFP_SINGLE_LOW_BITS + 1) == 0)
0187 exponent = 0;
0188 if (exponent || significand > 0x80000000)
0189 underflow = 0;
0190 if (underflow)
0191 exceptions |= FPSCR_UFC;
0192 vs->exponent = exponent;
0193 vs->significand = significand >> 1;
0194 }
0195
0196 pack:
0197 vfp_single_dump("pack: final", vs);
0198 {
0199 s32 d = vfp_single_pack(vs);
0200 #ifdef DEBUG
0201 pr_debug("VFP: %s: d(s%d)=%08x exceptions=%08x\n", func,
0202 sd, d, exceptions);
0203 #endif
0204 vfp_put_float(d, sd);
0205 }
0206
0207 return exceptions;
0208 }
0209
0210
0211
0212
0213
0214 static u32
0215 vfp_propagate_nan(struct vfp_single *vsd, struct vfp_single *vsn,
0216 struct vfp_single *vsm, u32 fpscr)
0217 {
0218 struct vfp_single *nan;
0219 int tn, tm = 0;
0220
0221 tn = vfp_single_type(vsn);
0222
0223 if (vsm)
0224 tm = vfp_single_type(vsm);
0225
0226 if (fpscr & FPSCR_DEFAULT_NAN)
0227
0228
0229
0230 nan = &vfp_single_default_qnan;
0231 else {
0232
0233
0234
0235
0236
0237 if (tn == VFP_SNAN || (tm != VFP_SNAN && tn == VFP_QNAN))
0238 nan = vsn;
0239 else
0240 nan = vsm;
0241
0242
0243
0244 nan->significand |= VFP_SINGLE_SIGNIFICAND_QNAN;
0245 }
0246
0247 *vsd = *nan;
0248
0249
0250
0251
0252 return tn == VFP_SNAN || tm == VFP_SNAN ? FPSCR_IOC : VFP_NAN_FLAG;
0253 }
0254
0255
0256
0257
0258
0259 static u32 vfp_single_fabs(int sd, int unused, s32 m, u32 fpscr)
0260 {
0261 vfp_put_float(vfp_single_packed_abs(m), sd);
0262 return 0;
0263 }
0264
0265 static u32 vfp_single_fcpy(int sd, int unused, s32 m, u32 fpscr)
0266 {
0267 vfp_put_float(m, sd);
0268 return 0;
0269 }
0270
0271 static u32 vfp_single_fneg(int sd, int unused, s32 m, u32 fpscr)
0272 {
0273 vfp_put_float(vfp_single_packed_negate(m), sd);
0274 return 0;
0275 }
0276
0277 static const u16 sqrt_oddadjust[] = {
0278 0x0004, 0x0022, 0x005d, 0x00b1, 0x011d, 0x019f, 0x0236, 0x02e0,
0279 0x039c, 0x0468, 0x0545, 0x0631, 0x072b, 0x0832, 0x0946, 0x0a67
0280 };
0281
0282 static const u16 sqrt_evenadjust[] = {
0283 0x0a2d, 0x08af, 0x075a, 0x0629, 0x051a, 0x0429, 0x0356, 0x029e,
0284 0x0200, 0x0179, 0x0109, 0x00af, 0x0068, 0x0034, 0x0012, 0x0002
0285 };
0286
0287 u32 vfp_estimate_sqrt_significand(u32 exponent, u32 significand)
0288 {
0289 int index;
0290 u32 z, a;
0291
0292 if ((significand & 0xc0000000) != 0x40000000) {
0293 pr_warn("VFP: estimate_sqrt: invalid significand\n");
0294 }
0295
0296 a = significand << 1;
0297 index = (a >> 27) & 15;
0298 if (exponent & 1) {
0299 z = 0x4000 + (a >> 17) - sqrt_oddadjust[index];
0300 z = ((a / z) << 14) + (z << 15);
0301 a >>= 1;
0302 } else {
0303 z = 0x8000 + (a >> 17) - sqrt_evenadjust[index];
0304 z = a / z + z;
0305 z = (z >= 0x20000) ? 0xffff8000 : (z << 15);
0306 if (z <= a)
0307 return (s32)a >> 1;
0308 }
0309 {
0310 u64 v = (u64)a << 31;
0311 do_div(v, z);
0312 return v + (z >> 1);
0313 }
0314 }
0315
0316 static u32 vfp_single_fsqrt(int sd, int unused, s32 m, u32 fpscr)
0317 {
0318 struct vfp_single vsm, vsd;
0319 int ret, tm;
0320
0321 vfp_single_unpack(&vsm, m);
0322 tm = vfp_single_type(&vsm);
0323 if (tm & (VFP_NAN|VFP_INFINITY)) {
0324 struct vfp_single *vsp = &vsd;
0325
0326 if (tm & VFP_NAN)
0327 ret = vfp_propagate_nan(vsp, &vsm, NULL, fpscr);
0328 else if (vsm.sign == 0) {
0329 sqrt_copy:
0330 vsp = &vsm;
0331 ret = 0;
0332 } else {
0333 sqrt_invalid:
0334 vsp = &vfp_single_default_qnan;
0335 ret = FPSCR_IOC;
0336 }
0337 vfp_put_float(vfp_single_pack(vsp), sd);
0338 return ret;
0339 }
0340
0341
0342
0343
0344 if (tm & VFP_ZERO)
0345 goto sqrt_copy;
0346
0347
0348
0349
0350 if (tm & VFP_DENORMAL)
0351 vfp_single_normalise_denormal(&vsm);
0352
0353
0354
0355
0356 if (vsm.sign)
0357 goto sqrt_invalid;
0358
0359 vfp_single_dump("sqrt", &vsm);
0360
0361
0362
0363
0364 vsd.sign = 0;
0365 vsd.exponent = ((vsm.exponent - 127) >> 1) + 127;
0366 vsd.significand = vfp_estimate_sqrt_significand(vsm.exponent, vsm.significand) + 2;
0367
0368 vfp_single_dump("sqrt estimate", &vsd);
0369
0370
0371
0372
0373 if ((vsd.significand & VFP_SINGLE_LOW_BITS_MASK) <= 5) {
0374 if (vsd.significand < 2) {
0375 vsd.significand = 0xffffffff;
0376 } else {
0377 u64 term;
0378 s64 rem;
0379 vsm.significand <<= !(vsm.exponent & 1);
0380 term = (u64)vsd.significand * vsd.significand;
0381 rem = ((u64)vsm.significand << 32) - term;
0382
0383 pr_debug("VFP: term=%016llx rem=%016llx\n", term, rem);
0384
0385 while (rem < 0) {
0386 vsd.significand -= 1;
0387 rem += ((u64)vsd.significand << 1) | 1;
0388 }
0389 vsd.significand |= rem != 0;
0390 }
0391 }
0392 vsd.significand = vfp_shiftright32jamming(vsd.significand, 1);
0393
0394 return vfp_single_normaliseround(sd, &vsd, fpscr, 0, "fsqrt");
0395 }
0396
0397
0398
0399
0400
0401
0402
0403 static u32 vfp_compare(int sd, int signal_on_qnan, s32 m, u32 fpscr)
0404 {
0405 s32 d;
0406 u32 ret = 0;
0407
0408 d = vfp_get_float(sd);
0409 if (vfp_single_packed_exponent(m) == 255 && vfp_single_packed_mantissa(m)) {
0410 ret |= FPSCR_C | FPSCR_V;
0411 if (signal_on_qnan || !(vfp_single_packed_mantissa(m) & (1 << (VFP_SINGLE_MANTISSA_BITS - 1))))
0412
0413
0414
0415 ret |= FPSCR_IOC;
0416 }
0417
0418 if (vfp_single_packed_exponent(d) == 255 && vfp_single_packed_mantissa(d)) {
0419 ret |= FPSCR_C | FPSCR_V;
0420 if (signal_on_qnan || !(vfp_single_packed_mantissa(d) & (1 << (VFP_SINGLE_MANTISSA_BITS - 1))))
0421
0422
0423
0424 ret |= FPSCR_IOC;
0425 }
0426
0427 if (ret == 0) {
0428 if (d == m || vfp_single_packed_abs(d | m) == 0) {
0429
0430
0431
0432 ret |= FPSCR_Z | FPSCR_C;
0433 } else if (vfp_single_packed_sign(d ^ m)) {
0434
0435
0436
0437 if (vfp_single_packed_sign(d))
0438
0439
0440
0441 ret |= FPSCR_N;
0442 else
0443
0444
0445
0446 ret |= FPSCR_C;
0447 } else if ((vfp_single_packed_sign(d) != 0) ^ (d < m)) {
0448
0449
0450
0451 ret |= FPSCR_N;
0452 } else if ((vfp_single_packed_sign(d) != 0) ^ (d > m)) {
0453
0454
0455
0456 ret |= FPSCR_C;
0457 }
0458 }
0459 return ret;
0460 }
0461
0462 static u32 vfp_single_fcmp(int sd, int unused, s32 m, u32 fpscr)
0463 {
0464 return vfp_compare(sd, 0, m, fpscr);
0465 }
0466
0467 static u32 vfp_single_fcmpe(int sd, int unused, s32 m, u32 fpscr)
0468 {
0469 return vfp_compare(sd, 1, m, fpscr);
0470 }
0471
0472 static u32 vfp_single_fcmpz(int sd, int unused, s32 m, u32 fpscr)
0473 {
0474 return vfp_compare(sd, 0, 0, fpscr);
0475 }
0476
0477 static u32 vfp_single_fcmpez(int sd, int unused, s32 m, u32 fpscr)
0478 {
0479 return vfp_compare(sd, 1, 0, fpscr);
0480 }
0481
0482 static u32 vfp_single_fcvtd(int dd, int unused, s32 m, u32 fpscr)
0483 {
0484 struct vfp_single vsm;
0485 struct vfp_double vdd;
0486 int tm;
0487 u32 exceptions = 0;
0488
0489 vfp_single_unpack(&vsm, m);
0490
0491 tm = vfp_single_type(&vsm);
0492
0493
0494
0495
0496 if (tm == VFP_SNAN)
0497 exceptions = FPSCR_IOC;
0498
0499 if (tm & VFP_DENORMAL)
0500 vfp_single_normalise_denormal(&vsm);
0501
0502 vdd.sign = vsm.sign;
0503 vdd.significand = (u64)vsm.significand << 32;
0504
0505
0506
0507
0508 if (tm & (VFP_INFINITY|VFP_NAN)) {
0509 vdd.exponent = 2047;
0510 if (tm == VFP_QNAN)
0511 vdd.significand |= VFP_DOUBLE_SIGNIFICAND_QNAN;
0512 goto pack_nan;
0513 } else if (tm & VFP_ZERO)
0514 vdd.exponent = 0;
0515 else
0516 vdd.exponent = vsm.exponent + (1023 - 127);
0517
0518 return vfp_double_normaliseround(dd, &vdd, fpscr, exceptions, "fcvtd");
0519
0520 pack_nan:
0521 vfp_put_double(vfp_double_pack(&vdd), dd);
0522 return exceptions;
0523 }
0524
0525 static u32 vfp_single_fuito(int sd, int unused, s32 m, u32 fpscr)
0526 {
0527 struct vfp_single vs;
0528
0529 vs.sign = 0;
0530 vs.exponent = 127 + 31 - 1;
0531 vs.significand = (u32)m;
0532
0533 return vfp_single_normaliseround(sd, &vs, fpscr, 0, "fuito");
0534 }
0535
0536 static u32 vfp_single_fsito(int sd, int unused, s32 m, u32 fpscr)
0537 {
0538 struct vfp_single vs;
0539
0540 vs.sign = (m & 0x80000000) >> 16;
0541 vs.exponent = 127 + 31 - 1;
0542 vs.significand = vs.sign ? -m : m;
0543
0544 return vfp_single_normaliseround(sd, &vs, fpscr, 0, "fsito");
0545 }
0546
0547 static u32 vfp_single_ftoui(int sd, int unused, s32 m, u32 fpscr)
0548 {
0549 struct vfp_single vsm;
0550 u32 d, exceptions = 0;
0551 int rmode = fpscr & FPSCR_RMODE_MASK;
0552 int tm;
0553
0554 vfp_single_unpack(&vsm, m);
0555 vfp_single_dump("VSM", &vsm);
0556
0557
0558
0559
0560 tm = vfp_single_type(&vsm);
0561 if (tm & VFP_DENORMAL)
0562 exceptions |= FPSCR_IDC;
0563
0564 if (tm & VFP_NAN)
0565 vsm.sign = 0;
0566
0567 if (vsm.exponent >= 127 + 32) {
0568 d = vsm.sign ? 0 : 0xffffffff;
0569 exceptions = FPSCR_IOC;
0570 } else if (vsm.exponent >= 127 - 1) {
0571 int shift = 127 + 31 - vsm.exponent;
0572 u32 rem, incr = 0;
0573
0574
0575
0576
0577 d = (vsm.significand << 1) >> shift;
0578 rem = vsm.significand << (33 - shift);
0579
0580 if (rmode == FPSCR_ROUND_NEAREST) {
0581 incr = 0x80000000;
0582 if ((d & 1) == 0)
0583 incr -= 1;
0584 } else if (rmode == FPSCR_ROUND_TOZERO) {
0585 incr = 0;
0586 } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vsm.sign != 0)) {
0587 incr = ~0;
0588 }
0589
0590 if ((rem + incr) < rem) {
0591 if (d < 0xffffffff)
0592 d += 1;
0593 else
0594 exceptions |= FPSCR_IOC;
0595 }
0596
0597 if (d && vsm.sign) {
0598 d = 0;
0599 exceptions |= FPSCR_IOC;
0600 } else if (rem)
0601 exceptions |= FPSCR_IXC;
0602 } else {
0603 d = 0;
0604 if (vsm.exponent | vsm.significand) {
0605 exceptions |= FPSCR_IXC;
0606 if (rmode == FPSCR_ROUND_PLUSINF && vsm.sign == 0)
0607 d = 1;
0608 else if (rmode == FPSCR_ROUND_MINUSINF && vsm.sign) {
0609 d = 0;
0610 exceptions |= FPSCR_IOC;
0611 }
0612 }
0613 }
0614
0615 pr_debug("VFP: ftoui: d(s%d)=%08x exceptions=%08x\n", sd, d, exceptions);
0616
0617 vfp_put_float(d, sd);
0618
0619 return exceptions;
0620 }
0621
0622 static u32 vfp_single_ftouiz(int sd, int unused, s32 m, u32 fpscr)
0623 {
0624 return vfp_single_ftoui(sd, unused, m, FPSCR_ROUND_TOZERO);
0625 }
0626
0627 static u32 vfp_single_ftosi(int sd, int unused, s32 m, u32 fpscr)
0628 {
0629 struct vfp_single vsm;
0630 u32 d, exceptions = 0;
0631 int rmode = fpscr & FPSCR_RMODE_MASK;
0632 int tm;
0633
0634 vfp_single_unpack(&vsm, m);
0635 vfp_single_dump("VSM", &vsm);
0636
0637
0638
0639
0640 tm = vfp_single_type(&vsm);
0641 if (vfp_single_type(&vsm) & VFP_DENORMAL)
0642 exceptions |= FPSCR_IDC;
0643
0644 if (tm & VFP_NAN) {
0645 d = 0;
0646 exceptions |= FPSCR_IOC;
0647 } else if (vsm.exponent >= 127 + 32) {
0648
0649
0650
0651 d = 0x7fffffff;
0652 if (vsm.sign)
0653 d = ~d;
0654 exceptions |= FPSCR_IOC;
0655 } else if (vsm.exponent >= 127 - 1) {
0656 int shift = 127 + 31 - vsm.exponent;
0657 u32 rem, incr = 0;
0658
0659
0660 d = (vsm.significand << 1) >> shift;
0661 rem = vsm.significand << (33 - shift);
0662
0663 if (rmode == FPSCR_ROUND_NEAREST) {
0664 incr = 0x80000000;
0665 if ((d & 1) == 0)
0666 incr -= 1;
0667 } else if (rmode == FPSCR_ROUND_TOZERO) {
0668 incr = 0;
0669 } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vsm.sign != 0)) {
0670 incr = ~0;
0671 }
0672
0673 if ((rem + incr) < rem && d < 0xffffffff)
0674 d += 1;
0675 if (d > 0x7fffffff + (vsm.sign != 0)) {
0676 d = 0x7fffffff + (vsm.sign != 0);
0677 exceptions |= FPSCR_IOC;
0678 } else if (rem)
0679 exceptions |= FPSCR_IXC;
0680
0681 if (vsm.sign)
0682 d = -d;
0683 } else {
0684 d = 0;
0685 if (vsm.exponent | vsm.significand) {
0686 exceptions |= FPSCR_IXC;
0687 if (rmode == FPSCR_ROUND_PLUSINF && vsm.sign == 0)
0688 d = 1;
0689 else if (rmode == FPSCR_ROUND_MINUSINF && vsm.sign)
0690 d = -1;
0691 }
0692 }
0693
0694 pr_debug("VFP: ftosi: d(s%d)=%08x exceptions=%08x\n", sd, d, exceptions);
0695
0696 vfp_put_float((s32)d, sd);
0697
0698 return exceptions;
0699 }
0700
0701 static u32 vfp_single_ftosiz(int sd, int unused, s32 m, u32 fpscr)
0702 {
0703 return vfp_single_ftosi(sd, unused, m, FPSCR_ROUND_TOZERO);
0704 }
0705
0706 static struct op fops_ext[32] = {
0707 [FEXT_TO_IDX(FEXT_FCPY)] = { vfp_single_fcpy, 0 },
0708 [FEXT_TO_IDX(FEXT_FABS)] = { vfp_single_fabs, 0 },
0709 [FEXT_TO_IDX(FEXT_FNEG)] = { vfp_single_fneg, 0 },
0710 [FEXT_TO_IDX(FEXT_FSQRT)] = { vfp_single_fsqrt, 0 },
0711 [FEXT_TO_IDX(FEXT_FCMP)] = { vfp_single_fcmp, OP_SCALAR },
0712 [FEXT_TO_IDX(FEXT_FCMPE)] = { vfp_single_fcmpe, OP_SCALAR },
0713 [FEXT_TO_IDX(FEXT_FCMPZ)] = { vfp_single_fcmpz, OP_SCALAR },
0714 [FEXT_TO_IDX(FEXT_FCMPEZ)] = { vfp_single_fcmpez, OP_SCALAR },
0715 [FEXT_TO_IDX(FEXT_FCVT)] = { vfp_single_fcvtd, OP_SCALAR|OP_DD },
0716 [FEXT_TO_IDX(FEXT_FUITO)] = { vfp_single_fuito, OP_SCALAR },
0717 [FEXT_TO_IDX(FEXT_FSITO)] = { vfp_single_fsito, OP_SCALAR },
0718 [FEXT_TO_IDX(FEXT_FTOUI)] = { vfp_single_ftoui, OP_SCALAR },
0719 [FEXT_TO_IDX(FEXT_FTOUIZ)] = { vfp_single_ftouiz, OP_SCALAR },
0720 [FEXT_TO_IDX(FEXT_FTOSI)] = { vfp_single_ftosi, OP_SCALAR },
0721 [FEXT_TO_IDX(FEXT_FTOSIZ)] = { vfp_single_ftosiz, OP_SCALAR },
0722 };
0723
0724
0725
0726
0727
0728 static u32
0729 vfp_single_fadd_nonnumber(struct vfp_single *vsd, struct vfp_single *vsn,
0730 struct vfp_single *vsm, u32 fpscr)
0731 {
0732 struct vfp_single *vsp;
0733 u32 exceptions = 0;
0734 int tn, tm;
0735
0736 tn = vfp_single_type(vsn);
0737 tm = vfp_single_type(vsm);
0738
0739 if (tn & tm & VFP_INFINITY) {
0740
0741
0742
0743 if (vsn->sign ^ vsm->sign) {
0744
0745
0746
0747 exceptions = FPSCR_IOC;
0748 vsp = &vfp_single_default_qnan;
0749 } else {
0750
0751
0752
0753 vsp = vsn;
0754 }
0755 } else if (tn & VFP_INFINITY && tm & VFP_NUMBER) {
0756
0757
0758
0759 vsp = vsn;
0760 } else {
0761
0762
0763
0764 return vfp_propagate_nan(vsd, vsn, vsm, fpscr);
0765 }
0766 *vsd = *vsp;
0767 return exceptions;
0768 }
0769
0770 static u32
0771 vfp_single_add(struct vfp_single *vsd, struct vfp_single *vsn,
0772 struct vfp_single *vsm, u32 fpscr)
0773 {
0774 u32 exp_diff, m_sig;
0775
0776 if (vsn->significand & 0x80000000 ||
0777 vsm->significand & 0x80000000) {
0778 pr_info("VFP: bad FP values in %s\n", __func__);
0779 vfp_single_dump("VSN", vsn);
0780 vfp_single_dump("VSM", vsm);
0781 }
0782
0783
0784
0785
0786
0787
0788 if (vsn->exponent < vsm->exponent) {
0789 struct vfp_single *t = vsn;
0790 vsn = vsm;
0791 vsm = t;
0792 }
0793
0794
0795
0796
0797
0798 if (vsn->exponent == 255)
0799 return vfp_single_fadd_nonnumber(vsd, vsn, vsm, fpscr);
0800
0801
0802
0803
0804
0805
0806 *vsd = *vsn;
0807
0808
0809
0810
0811 exp_diff = vsn->exponent - vsm->exponent;
0812 m_sig = vfp_shiftright32jamming(vsm->significand, exp_diff);
0813
0814
0815
0816
0817 if (vsn->sign ^ vsm->sign) {
0818 m_sig = vsn->significand - m_sig;
0819 if ((s32)m_sig < 0) {
0820 vsd->sign = vfp_sign_negate(vsd->sign);
0821 m_sig = -m_sig;
0822 } else if (m_sig == 0) {
0823 vsd->sign = (fpscr & FPSCR_RMODE_MASK) ==
0824 FPSCR_ROUND_MINUSINF ? 0x8000 : 0;
0825 }
0826 } else {
0827 m_sig = vsn->significand + m_sig;
0828 }
0829 vsd->significand = m_sig;
0830
0831 return 0;
0832 }
0833
0834 static u32
0835 vfp_single_multiply(struct vfp_single *vsd, struct vfp_single *vsn, struct vfp_single *vsm, u32 fpscr)
0836 {
0837 vfp_single_dump("VSN", vsn);
0838 vfp_single_dump("VSM", vsm);
0839
0840
0841
0842
0843
0844
0845 if (vsn->exponent < vsm->exponent) {
0846 struct vfp_single *t = vsn;
0847 vsn = vsm;
0848 vsm = t;
0849 pr_debug("VFP: swapping M <-> N\n");
0850 }
0851
0852 vsd->sign = vsn->sign ^ vsm->sign;
0853
0854
0855
0856
0857 if (vsn->exponent == 255) {
0858 if (vsn->significand || (vsm->exponent == 255 && vsm->significand))
0859 return vfp_propagate_nan(vsd, vsn, vsm, fpscr);
0860 if ((vsm->exponent | vsm->significand) == 0) {
0861 *vsd = vfp_single_default_qnan;
0862 return FPSCR_IOC;
0863 }
0864 vsd->exponent = vsn->exponent;
0865 vsd->significand = 0;
0866 return 0;
0867 }
0868
0869
0870
0871
0872
0873 if ((vsm->exponent | vsm->significand) == 0) {
0874 vsd->exponent = 0;
0875 vsd->significand = 0;
0876 return 0;
0877 }
0878
0879
0880
0881
0882
0883
0884 vsd->exponent = vsn->exponent + vsm->exponent - 127 + 2;
0885 vsd->significand = vfp_hi64to32jamming((u64)vsn->significand * vsm->significand);
0886
0887 vfp_single_dump("VSD", vsd);
0888 return 0;
0889 }
0890
0891 #define NEG_MULTIPLY (1 << 0)
0892 #define NEG_SUBTRACT (1 << 1)
0893
0894 static u32
0895 vfp_single_multiply_accumulate(int sd, int sn, s32 m, u32 fpscr, u32 negate, char *func)
0896 {
0897 struct vfp_single vsd, vsp, vsn, vsm;
0898 u32 exceptions;
0899 s32 v;
0900
0901 v = vfp_get_float(sn);
0902 pr_debug("VFP: s%u = %08x\n", sn, v);
0903 vfp_single_unpack(&vsn, v);
0904 if (vsn.exponent == 0 && vsn.significand)
0905 vfp_single_normalise_denormal(&vsn);
0906
0907 vfp_single_unpack(&vsm, m);
0908 if (vsm.exponent == 0 && vsm.significand)
0909 vfp_single_normalise_denormal(&vsm);
0910
0911 exceptions = vfp_single_multiply(&vsp, &vsn, &vsm, fpscr);
0912 if (negate & NEG_MULTIPLY)
0913 vsp.sign = vfp_sign_negate(vsp.sign);
0914
0915 v = vfp_get_float(sd);
0916 pr_debug("VFP: s%u = %08x\n", sd, v);
0917 vfp_single_unpack(&vsn, v);
0918 if (vsn.exponent == 0 && vsn.significand)
0919 vfp_single_normalise_denormal(&vsn);
0920 if (negate & NEG_SUBTRACT)
0921 vsn.sign = vfp_sign_negate(vsn.sign);
0922
0923 exceptions |= vfp_single_add(&vsd, &vsn, &vsp, fpscr);
0924
0925 return vfp_single_normaliseround(sd, &vsd, fpscr, exceptions, func);
0926 }
0927
0928
0929
0930
0931
0932
0933
0934
0935 static u32 vfp_single_fmac(int sd, int sn, s32 m, u32 fpscr)
0936 {
0937 return vfp_single_multiply_accumulate(sd, sn, m, fpscr, 0, "fmac");
0938 }
0939
0940
0941
0942
0943 static u32 vfp_single_fnmac(int sd, int sn, s32 m, u32 fpscr)
0944 {
0945 return vfp_single_multiply_accumulate(sd, sn, m, fpscr, NEG_MULTIPLY, "fnmac");
0946 }
0947
0948
0949
0950
0951 static u32 vfp_single_fmsc(int sd, int sn, s32 m, u32 fpscr)
0952 {
0953 return vfp_single_multiply_accumulate(sd, sn, m, fpscr, NEG_SUBTRACT, "fmsc");
0954 }
0955
0956
0957
0958
0959 static u32 vfp_single_fnmsc(int sd, int sn, s32 m, u32 fpscr)
0960 {
0961 return vfp_single_multiply_accumulate(sd, sn, m, fpscr, NEG_SUBTRACT | NEG_MULTIPLY, "fnmsc");
0962 }
0963
0964
0965
0966
0967 static u32 vfp_single_fmul(int sd, int sn, s32 m, u32 fpscr)
0968 {
0969 struct vfp_single vsd, vsn, vsm;
0970 u32 exceptions;
0971 s32 n = vfp_get_float(sn);
0972
0973 pr_debug("VFP: s%u = %08x\n", sn, n);
0974
0975 vfp_single_unpack(&vsn, n);
0976 if (vsn.exponent == 0 && vsn.significand)
0977 vfp_single_normalise_denormal(&vsn);
0978
0979 vfp_single_unpack(&vsm, m);
0980 if (vsm.exponent == 0 && vsm.significand)
0981 vfp_single_normalise_denormal(&vsm);
0982
0983 exceptions = vfp_single_multiply(&vsd, &vsn, &vsm, fpscr);
0984 return vfp_single_normaliseround(sd, &vsd, fpscr, exceptions, "fmul");
0985 }
0986
0987
0988
0989
0990 static u32 vfp_single_fnmul(int sd, int sn, s32 m, u32 fpscr)
0991 {
0992 struct vfp_single vsd, vsn, vsm;
0993 u32 exceptions;
0994 s32 n = vfp_get_float(sn);
0995
0996 pr_debug("VFP: s%u = %08x\n", sn, n);
0997
0998 vfp_single_unpack(&vsn, n);
0999 if (vsn.exponent == 0 && vsn.significand)
1000 vfp_single_normalise_denormal(&vsn);
1001
1002 vfp_single_unpack(&vsm, m);
1003 if (vsm.exponent == 0 && vsm.significand)
1004 vfp_single_normalise_denormal(&vsm);
1005
1006 exceptions = vfp_single_multiply(&vsd, &vsn, &vsm, fpscr);
1007 vsd.sign = vfp_sign_negate(vsd.sign);
1008 return vfp_single_normaliseround(sd, &vsd, fpscr, exceptions, "fnmul");
1009 }
1010
1011
1012
1013
1014 static u32 vfp_single_fadd(int sd, int sn, s32 m, u32 fpscr)
1015 {
1016 struct vfp_single vsd, vsn, vsm;
1017 u32 exceptions;
1018 s32 n = vfp_get_float(sn);
1019
1020 pr_debug("VFP: s%u = %08x\n", sn, n);
1021
1022
1023
1024
1025 vfp_single_unpack(&vsn, n);
1026 if (vsn.exponent == 0 && vsn.significand)
1027 vfp_single_normalise_denormal(&vsn);
1028
1029 vfp_single_unpack(&vsm, m);
1030 if (vsm.exponent == 0 && vsm.significand)
1031 vfp_single_normalise_denormal(&vsm);
1032
1033 exceptions = vfp_single_add(&vsd, &vsn, &vsm, fpscr);
1034
1035 return vfp_single_normaliseround(sd, &vsd, fpscr, exceptions, "fadd");
1036 }
1037
1038
1039
1040
1041 static u32 vfp_single_fsub(int sd, int sn, s32 m, u32 fpscr)
1042 {
1043
1044
1045
1046 return vfp_single_fadd(sd, sn, vfp_single_packed_negate(m), fpscr);
1047 }
1048
1049
1050
1051
1052 static u32 vfp_single_fdiv(int sd, int sn, s32 m, u32 fpscr)
1053 {
1054 struct vfp_single vsd, vsn, vsm;
1055 u32 exceptions = 0;
1056 s32 n = vfp_get_float(sn);
1057 int tm, tn;
1058
1059 pr_debug("VFP: s%u = %08x\n", sn, n);
1060
1061 vfp_single_unpack(&vsn, n);
1062 vfp_single_unpack(&vsm, m);
1063
1064 vsd.sign = vsn.sign ^ vsm.sign;
1065
1066 tn = vfp_single_type(&vsn);
1067 tm = vfp_single_type(&vsm);
1068
1069
1070
1071
1072 if (tn & VFP_NAN)
1073 goto vsn_nan;
1074
1075
1076
1077
1078 if (tm & VFP_NAN)
1079 goto vsm_nan;
1080
1081
1082
1083
1084
1085 if (tm & tn & (VFP_INFINITY|VFP_ZERO))
1086 goto invalid;
1087
1088
1089
1090
1091 if (tn & VFP_INFINITY)
1092 goto infinity;
1093
1094
1095
1096
1097 if (tm & VFP_ZERO)
1098 goto divzero;
1099
1100
1101
1102
1103 if (tm & VFP_INFINITY || tn & VFP_ZERO)
1104 goto zero;
1105
1106 if (tn & VFP_DENORMAL)
1107 vfp_single_normalise_denormal(&vsn);
1108 if (tm & VFP_DENORMAL)
1109 vfp_single_normalise_denormal(&vsm);
1110
1111
1112
1113
1114 vsd.exponent = vsn.exponent - vsm.exponent + 127 - 1;
1115 vsm.significand <<= 1;
1116 if (vsm.significand <= (2 * vsn.significand)) {
1117 vsn.significand >>= 1;
1118 vsd.exponent++;
1119 }
1120 {
1121 u64 significand = (u64)vsn.significand << 32;
1122 do_div(significand, vsm.significand);
1123 vsd.significand = significand;
1124 }
1125 if ((vsd.significand & 0x3f) == 0)
1126 vsd.significand |= ((u64)vsm.significand * vsd.significand != (u64)vsn.significand << 32);
1127
1128 return vfp_single_normaliseround(sd, &vsd, fpscr, 0, "fdiv");
1129
1130 vsn_nan:
1131 exceptions = vfp_propagate_nan(&vsd, &vsn, &vsm, fpscr);
1132 pack:
1133 vfp_put_float(vfp_single_pack(&vsd), sd);
1134 return exceptions;
1135
1136 vsm_nan:
1137 exceptions = vfp_propagate_nan(&vsd, &vsm, &vsn, fpscr);
1138 goto pack;
1139
1140 zero:
1141 vsd.exponent = 0;
1142 vsd.significand = 0;
1143 goto pack;
1144
1145 divzero:
1146 exceptions = FPSCR_DZC;
1147 infinity:
1148 vsd.exponent = 255;
1149 vsd.significand = 0;
1150 goto pack;
1151
1152 invalid:
1153 vfp_put_float(vfp_single_pack(&vfp_single_default_qnan), sd);
1154 return FPSCR_IOC;
1155 }
1156
1157 static struct op fops[16] = {
1158 [FOP_TO_IDX(FOP_FMAC)] = { vfp_single_fmac, 0 },
1159 [FOP_TO_IDX(FOP_FNMAC)] = { vfp_single_fnmac, 0 },
1160 [FOP_TO_IDX(FOP_FMSC)] = { vfp_single_fmsc, 0 },
1161 [FOP_TO_IDX(FOP_FNMSC)] = { vfp_single_fnmsc, 0 },
1162 [FOP_TO_IDX(FOP_FMUL)] = { vfp_single_fmul, 0 },
1163 [FOP_TO_IDX(FOP_FNMUL)] = { vfp_single_fnmul, 0 },
1164 [FOP_TO_IDX(FOP_FADD)] = { vfp_single_fadd, 0 },
1165 [FOP_TO_IDX(FOP_FSUB)] = { vfp_single_fsub, 0 },
1166 [FOP_TO_IDX(FOP_FDIV)] = { vfp_single_fdiv, 0 },
1167 };
1168
1169 #define FREG_BANK(x) ((x) & 0x18)
1170 #define FREG_IDX(x) ((x) & 7)
1171
1172 u32 vfp_single_cpdo(u32 inst, u32 fpscr)
1173 {
1174 u32 op = inst & FOP_MASK;
1175 u32 exceptions = 0;
1176 unsigned int dest;
1177 unsigned int sn = vfp_get_sn(inst);
1178 unsigned int sm = vfp_get_sm(inst);
1179 unsigned int vecitr, veclen, vecstride;
1180 struct op *fop;
1181
1182 vecstride = 1 + ((fpscr & FPSCR_STRIDE_MASK) == FPSCR_STRIDE_MASK);
1183
1184 fop = (op == FOP_EXT) ? &fops_ext[FEXT_TO_IDX(inst)] : &fops[FOP_TO_IDX(op)];
1185
1186
1187
1188
1189
1190
1191
1192 if (fop->flags & OP_DD)
1193 dest = vfp_get_dd(inst);
1194 else
1195 dest = vfp_get_sd(inst);
1196
1197
1198
1199
1200
1201 if ((fop->flags & OP_SCALAR) || FREG_BANK(dest) == 0)
1202 veclen = 0;
1203 else
1204 veclen = fpscr & FPSCR_LENGTH_MASK;
1205
1206 pr_debug("VFP: vecstride=%u veclen=%u\n", vecstride,
1207 (veclen >> FPSCR_LENGTH_BIT) + 1);
1208
1209 if (!fop->fn)
1210 goto invalid;
1211
1212 for (vecitr = 0; vecitr <= veclen; vecitr += 1 << FPSCR_LENGTH_BIT) {
1213 s32 m = vfp_get_float(sm);
1214 u32 except;
1215 char type;
1216
1217 type = fop->flags & OP_DD ? 'd' : 's';
1218 if (op == FOP_EXT)
1219 pr_debug("VFP: itr%d (%c%u) = op[%u] (s%u=%08x)\n",
1220 vecitr >> FPSCR_LENGTH_BIT, type, dest, sn,
1221 sm, m);
1222 else
1223 pr_debug("VFP: itr%d (%c%u) = (s%u) op[%u] (s%u=%08x)\n",
1224 vecitr >> FPSCR_LENGTH_BIT, type, dest, sn,
1225 FOP_TO_IDX(op), sm, m);
1226
1227 except = fop->fn(dest, sn, m, fpscr);
1228 pr_debug("VFP: itr%d: exceptions=%08x\n",
1229 vecitr >> FPSCR_LENGTH_BIT, except);
1230
1231 exceptions |= except;
1232
1233
1234
1235
1236
1237 dest = FREG_BANK(dest) + ((FREG_IDX(dest) + vecstride) & 7);
1238 sn = FREG_BANK(sn) + ((FREG_IDX(sn) + vecstride) & 7);
1239 if (FREG_BANK(sm) != 0)
1240 sm = FREG_BANK(sm) + ((FREG_IDX(sm) + vecstride) & 7);
1241 }
1242 return exceptions;
1243
1244 invalid:
1245 return (u32)-1;
1246 }