|
@@ -254,3 +254,195 @@ static u32 vfp_double_fabs(int dd, int unused, int dm, u32 fpscr)
|
|
|
}
|
|
|
|
|
|
static u32 vfp_double_fcpy(int dd, int unused, int dm, u32 fpscr)
|
|
|
+{
|
|
|
+ vfp_put_double(vfp_get_double(dm), dd);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static u32 vfp_double_fneg(int dd, int unused, int dm, u32 fpscr)
|
|
|
+{
|
|
|
+ vfp_put_double(vfp_double_packed_negate(vfp_get_double(dm)), dd);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static u32 vfp_double_fsqrt(int dd, int unused, int dm, u32 fpscr)
|
|
|
+{
|
|
|
+ struct vfp_double vdm, vdd;
|
|
|
+ int ret, tm;
|
|
|
+
|
|
|
+ vfp_double_unpack(&vdm, vfp_get_double(dm));
|
|
|
+ tm = vfp_double_type(&vdm);
|
|
|
+ if (tm & (VFP_NAN|VFP_INFINITY)) {
|
|
|
+ struct vfp_double *vdp = &vdd;
|
|
|
+
|
|
|
+ if (tm & VFP_NAN)
|
|
|
+ ret = vfp_propagate_nan(vdp, &vdm, NULL, fpscr);
|
|
|
+ else if (vdm.sign == 0) {
|
|
|
+ sqrt_copy:
|
|
|
+ vdp = &vdm;
|
|
|
+ ret = 0;
|
|
|
+ } else {
|
|
|
+ sqrt_invalid:
|
|
|
+ vdp = &vfp_double_default_qnan;
|
|
|
+ ret = FPSCR_IOC;
|
|
|
+ }
|
|
|
+ vfp_put_double(vfp_double_pack(vdp), dd);
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * sqrt(+/- 0) == +/- 0
|
|
|
+ */
|
|
|
+ if (tm & VFP_ZERO)
|
|
|
+ goto sqrt_copy;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Normalise a denormalised number
|
|
|
+ */
|
|
|
+ if (tm & VFP_DENORMAL)
|
|
|
+ vfp_double_normalise_denormal(&vdm);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * sqrt(<0) = invalid
|
|
|
+ */
|
|
|
+ if (vdm.sign)
|
|
|
+ goto sqrt_invalid;
|
|
|
+
|
|
|
+ vfp_double_dump("sqrt", &vdm);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Estimate the square root.
|
|
|
+ */
|
|
|
+ vdd.sign = 0;
|
|
|
+ vdd.exponent = ((vdm.exponent - 1023) >> 1) + 1023;
|
|
|
+ vdd.significand = (u64)vfp_estimate_sqrt_significand(vdm.exponent, vdm.significand >> 32) << 31;
|
|
|
+
|
|
|
+ vfp_double_dump("sqrt estimate1", &vdd);
|
|
|
+
|
|
|
+ vdm.significand >>= 1 + (vdm.exponent & 1);
|
|
|
+ vdd.significand += 2 + vfp_estimate_div128to64(vdm.significand, 0, vdd.significand);
|
|
|
+
|
|
|
+ vfp_double_dump("sqrt estimate2", &vdd);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * And now adjust.
|
|
|
+ */
|
|
|
+ if ((vdd.significand & VFP_DOUBLE_LOW_BITS_MASK) <= 5) {
|
|
|
+ if (vdd.significand < 2) {
|
|
|
+ vdd.significand = ~0ULL;
|
|
|
+ } else {
|
|
|
+ u64 termh, terml, remh, reml;
|
|
|
+ vdm.significand <<= 2;
|
|
|
+ mul64to128(&termh, &terml, vdd.significand, vdd.significand);
|
|
|
+ sub128(&remh, &reml, vdm.significand, 0, termh, terml);
|
|
|
+ while ((s64)remh < 0) {
|
|
|
+ vdd.significand -= 1;
|
|
|
+ shift64left(&termh, &terml, vdd.significand);
|
|
|
+ terml |= 1;
|
|
|
+ add128(&remh, &reml, remh, reml, termh, terml);
|
|
|
+ }
|
|
|
+ vdd.significand |= (remh | reml) != 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ vdd.significand = vfp_shiftright64jamming(vdd.significand, 1);
|
|
|
+
|
|
|
+ return vfp_double_normaliseround(dd, &vdd, fpscr, 0, "fsqrt");
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Equal := ZC
|
|
|
+ * Less than := N
|
|
|
+ * Greater than := C
|
|
|
+ * Unordered := CV
|
|
|
+ */
|
|
|
+static u32 vfp_compare(int dd, int signal_on_qnan, int dm, u32 fpscr)
|
|
|
+{
|
|
|
+ s64 d, m;
|
|
|
+ u32 ret = 0;
|
|
|
+
|
|
|
+ m = vfp_get_double(dm);
|
|
|
+ if (vfp_double_packed_exponent(m) == 2047 && vfp_double_packed_mantissa(m)) {
|
|
|
+ ret |= FPSCR_C | FPSCR_V;
|
|
|
+ if (signal_on_qnan || !(vfp_double_packed_mantissa(m) & (1ULL << (VFP_DOUBLE_MANTISSA_BITS - 1))))
|
|
|
+ /*
|
|
|
+ * Signalling NaN, or signalling on quiet NaN
|
|
|
+ */
|
|
|
+ ret |= FPSCR_IOC;
|
|
|
+ }
|
|
|
+
|
|
|
+ d = vfp_get_double(dd);
|
|
|
+ if (vfp_double_packed_exponent(d) == 2047 && vfp_double_packed_mantissa(d)) {
|
|
|
+ ret |= FPSCR_C | FPSCR_V;
|
|
|
+ if (signal_on_qnan || !(vfp_double_packed_mantissa(d) & (1ULL << (VFP_DOUBLE_MANTISSA_BITS - 1))))
|
|
|
+ /*
|
|
|
+ * Signalling NaN, or signalling on quiet NaN
|
|
|
+ */
|
|
|
+ ret |= FPSCR_IOC;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (ret == 0) {
|
|
|
+ if (d == m || vfp_double_packed_abs(d | m) == 0) {
|
|
|
+ /*
|
|
|
+ * equal
|
|
|
+ */
|
|
|
+ ret |= FPSCR_Z | FPSCR_C;
|
|
|
+ } else if (vfp_double_packed_sign(d ^ m)) {
|
|
|
+ /*
|
|
|
+ * different signs
|
|
|
+ */
|
|
|
+ if (vfp_double_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_double_packed_sign(d) != 0) ^ (d < m)) {
|
|
|
+ /*
|
|
|
+ * d < m
|
|
|
+ */
|
|
|
+ ret |= FPSCR_N;
|
|
|
+ } else if ((vfp_double_packed_sign(d) != 0) ^ (d > m)) {
|
|
|
+ /*
|
|
|
+ * d > m
|
|
|
+ */
|
|
|
+ ret |= FPSCR_C;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+static u32 vfp_double_fcmp(int dd, int unused, int dm, u32 fpscr)
|
|
|
+{
|
|
|
+ return vfp_compare(dd, 0, dm, fpscr);
|
|
|
+}
|
|
|
+
|
|
|
+static u32 vfp_double_fcmpe(int dd, int unused, int dm, u32 fpscr)
|
|
|
+{
|
|
|
+ return vfp_compare(dd, 1, dm, fpscr);
|
|
|
+}
|
|
|
+
|
|
|
+static u32 vfp_double_fcmpz(int dd, int unused, int dm, u32 fpscr)
|
|
|
+{
|
|
|
+ return vfp_compare(dd, 0, VFP_REG_ZERO, fpscr);
|
|
|
+}
|
|
|
+
|
|
|
+static u32 vfp_double_fcmpez(int dd, int unused, int dm, u32 fpscr)
|
|
|
+{
|
|
|
+ return vfp_compare(dd, 1, VFP_REG_ZERO, fpscr);
|
|
|
+}
|
|
|
+
|
|
|
+static u32 vfp_double_fcvts(int sd, int unused, int dm, u32 fpscr)
|
|
|
+{
|
|
|
+ struct vfp_double vdm;
|
|
|
+ struct vfp_single vsd;
|
|
|
+ int tm;
|
|
|
+ u32 exceptions = 0;
|
|
|
+
|
|
|
+ vfp_double_unpack(&vdm, vfp_get_double(dm));
|
|
|
+
|
|
|
+ tm = vfp_double_type(&vdm);
|