|
@@ -331,3 +331,193 @@ static u32 vfp_single_fsqrt(int sd, int unused, s32 m, u32 fpscr)
|
|
|
ret = 0;
|
|
|
} else {
|
|
|
sqrt_invalid:
|
|
|
+ vsp = &vfp_single_default_qnan;
|
|
|
+ ret = FPSCR_IOC;
|
|
|
+ }
|
|
|
+ vfp_put_float(vfp_single_pack(vsp), sd);
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * sqrt(+/- 0) == +/- 0
|
|
|
+ */
|
|
|
+ if (tm & VFP_ZERO)
|
|
|
+ goto sqrt_copy;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Normalise a denormalised number
|
|
|
+ */
|
|
|
+ if (tm & VFP_DENORMAL)
|
|
|
+ vfp_single_normalise_denormal(&vsm);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * sqrt(<0) = invalid
|
|
|
+ */
|
|
|
+ if (vsm.sign)
|
|
|
+ goto sqrt_invalid;
|
|
|
+
|
|
|
+ vfp_single_dump("sqrt", &vsm);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Estimate the square root.
|
|
|
+ */
|
|
|
+ vsd.sign = 0;
|
|
|
+ vsd.exponent = ((vsm.exponent - 127) >> 1) + 127;
|
|
|
+ vsd.significand = vfp_estimate_sqrt_significand(vsm.exponent, vsm.significand) + 2;
|
|
|
+
|
|
|
+ vfp_single_dump("sqrt estimate", &vsd);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * And now adjust.
|
|
|
+ */
|
|
|
+ if ((vsd.significand & VFP_SINGLE_LOW_BITS_MASK) <= 5) {
|
|
|
+ if (vsd.significand < 2) {
|
|
|
+ vsd.significand = 0xffffffff;
|
|
|
+ } else {
|
|
|
+ u64 term;
|
|
|
+ s64 rem;
|
|
|
+ vsm.significand <<= !(vsm.exponent & 1);
|
|
|
+ term = (u64)vsd.significand * vsd.significand;
|
|
|
+ rem = ((u64)vsm.significand << 32) - term;
|
|
|
+
|
|
|
+ pr_debug("VFP: term=%016llx rem=%016llx\n", term, rem);
|
|
|
+
|
|
|
+ while (rem < 0) {
|
|
|
+ vsd.significand -= 1;
|
|
|
+ rem += ((u64)vsd.significand << 1) | 1;
|
|
|
+ }
|
|
|
+ vsd.significand |= rem != 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ vsd.significand = vfp_shiftright32jamming(vsd.significand, 1);
|
|
|
+
|
|
|
+ return vfp_single_normaliseround(sd, &vsd, fpscr, 0, "fsqrt");
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Equal := ZC
|
|
|
+ * Less than := N
|
|
|
+ * Greater than := C
|
|
|
+ * Unordered := CV
|
|
|
+ */
|
|
|
+static u32 vfp_compare(int sd, int signal_on_qnan, s32 m, u32 fpscr)
|
|
|
+{
|
|
|
+ s32 d;
|
|
|
+ u32 ret = 0;
|
|
|
+
|
|
|
+ d = vfp_get_float(sd);
|
|
|
+ if (vfp_single_packed_exponent(m) == 255 && vfp_single_packed_mantissa(m)) {
|
|
|
+ ret |= FPSCR_C | FPSCR_V;
|
|
|
+ if (signal_on_qnan || !(vfp_single_packed_mantissa(m) & (1 << (VFP_SINGLE_MANTISSA_BITS - 1))))
|
|
|
+ /*
|
|
|
+ * Signalling NaN, or signalling on quiet NaN
|
|
|
+ */
|
|
|
+ ret |= FPSCR_IOC;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (vfp_single_packed_exponent(d) == 255 && vfp_single_packed_mantissa(d)) {
|
|
|
+ ret |= FPSCR_C | FPSCR_V;
|
|
|
+ if (signal_on_qnan || !(vfp_single_packed_mantissa(d) & (1 << (VFP_SINGLE_MANTISSA_BITS - 1))))
|
|
|
+ /*
|
|
|
+ * Signalling NaN, or signalling on quiet NaN
|
|
|
+ */
|
|
|
+ ret |= FPSCR_IOC;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (ret == 0) {
|
|
|
+ if (d == m || vfp_single_packed_abs(d | m) == 0) {
|
|
|
+ /*
|
|
|
+ * equal
|
|
|
+ */
|
|
|
+ ret |= FPSCR_Z | FPSCR_C;
|
|
|
+ } else if (vfp_single_packed_sign(d ^ m)) {
|
|
|
+ /*
|
|
|
+ * different signs
|
|
|
+ */
|
|
|
+ if (vfp_single_packed_sign(d))
|
|
|
+ /*
|
|
|
+ * d is negative, so d < m
|
|
|
+ */
|
|
|
+ ret |= FPSCR_N;
|
|
|
+ else
|
|
|
+ /*
|
|
|
+ * d is positive, so d > m
|
|
|
+ */
|
|
|
+ ret |= FPSCR_C;
|
|
|
+ } else if ((vfp_single_packed_sign(d) != 0) ^ (d < m)) {
|
|
|
+ /*
|
|
|
+ * d < m
|
|
|
+ */
|
|
|
+ ret |= FPSCR_N;
|
|
|
+ } else if ((vfp_single_packed_sign(d) != 0) ^ (d > m)) {
|
|
|
+ /*
|
|
|
+ * d > m
|
|
|
+ */
|
|
|
+ ret |= FPSCR_C;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+static u32 vfp_single_fcmp(int sd, int unused, s32 m, u32 fpscr)
|
|
|
+{
|
|
|
+ return vfp_compare(sd, 0, m, fpscr);
|
|
|
+}
|
|
|
+
|
|
|
+static u32 vfp_single_fcmpe(int sd, int unused, s32 m, u32 fpscr)
|
|
|
+{
|
|
|
+ return vfp_compare(sd, 1, m, fpscr);
|
|
|
+}
|
|
|
+
|
|
|
+static u32 vfp_single_fcmpz(int sd, int unused, s32 m, u32 fpscr)
|
|
|
+{
|
|
|
+ return vfp_compare(sd, 0, 0, fpscr);
|
|
|
+}
|
|
|
+
|
|
|
+static u32 vfp_single_fcmpez(int sd, int unused, s32 m, u32 fpscr)
|
|
|
+{
|
|
|
+ return vfp_compare(sd, 1, 0, fpscr);
|
|
|
+}
|
|
|
+
|
|
|
+static u32 vfp_single_fcvtd(int dd, int unused, s32 m, u32 fpscr)
|
|
|
+{
|
|
|
+ struct vfp_single vsm;
|
|
|
+ struct vfp_double vdd;
|
|
|
+ int tm;
|
|
|
+ u32 exceptions = 0;
|
|
|
+
|
|
|
+ vfp_single_unpack(&vsm, m);
|
|
|
+
|
|
|
+ tm = vfp_single_type(&vsm);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * If we have a signalling NaN, signal invalid operation.
|
|
|
+ */
|
|
|
+ if (tm == VFP_SNAN)
|
|
|
+ exceptions = FPSCR_IOC;
|
|
|
+
|
|
|
+ if (tm & VFP_DENORMAL)
|
|
|
+ vfp_single_normalise_denormal(&vsm);
|
|
|
+
|
|
|
+ vdd.sign = vsm.sign;
|
|
|
+ vdd.significand = (u64)vsm.significand << 32;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * If we have an infinity or NaN, the exponent must be 2047.
|
|
|
+ */
|
|
|
+ if (tm & (VFP_INFINITY|VFP_NAN)) {
|
|
|
+ vdd.exponent = 2047;
|
|
|
+ if (tm == VFP_QNAN)
|
|
|
+ vdd.significand |= VFP_DOUBLE_SIGNIFICAND_QNAN;
|
|
|
+ goto pack_nan;
|
|
|
+ } else if (tm & VFP_ZERO)
|
|
|
+ vdd.exponent = 0;
|
|
|
+ else
|
|
|
+ vdd.exponent = vsm.exponent + (1023 - 127);
|
|
|
+
|
|
|
+ return vfp_double_normaliseround(dd, &vdd, fpscr, exceptions, "fcvtd");
|
|
|
+
|
|
|
+ pack_nan:
|
|
|
+ vfp_put_double(vfp_double_pack(&vdd), dd);
|
|
|
+ return exceptions;
|
|
|
+}
|