|
@@ -215,3 +215,119 @@ static u32
|
|
vfp_propagate_nan(struct vfp_single *vsd, struct vfp_single *vsn,
|
|
vfp_propagate_nan(struct vfp_single *vsd, struct vfp_single *vsn,
|
|
struct vfp_single *vsm, u32 fpscr)
|
|
struct vfp_single *vsm, u32 fpscr)
|
|
{
|
|
{
|
|
|
|
+ struct vfp_single *nan;
|
|
|
|
+ int tn, tm = 0;
|
|
|
|
+
|
|
|
|
+ tn = vfp_single_type(vsn);
|
|
|
|
+
|
|
|
|
+ if (vsm)
|
|
|
|
+ tm = vfp_single_type(vsm);
|
|
|
|
+
|
|
|
|
+ if (fpscr & FPSCR_DEFAULT_NAN)
|
|
|
|
+ /*
|
|
|
|
+ * Default NaN mode - always returns a quiet NaN
|
|
|
|
+ */
|
|
|
|
+ nan = &vfp_single_default_qnan;
|
|
|
|
+ else {
|
|
|
|
+ /*
|
|
|
|
+ * Contemporary mode - select the first signalling
|
|
|
|
+ * NAN, or if neither are signalling, the first
|
|
|
|
+ * quiet NAN.
|
|
|
|
+ */
|
|
|
|
+ if (tn == VFP_SNAN || (tm != VFP_SNAN && tn == VFP_QNAN))
|
|
|
|
+ nan = vsn;
|
|
|
|
+ else
|
|
|
|
+ nan = vsm;
|
|
|
|
+ /*
|
|
|
|
+ * Make the NaN quiet.
|
|
|
|
+ */
|
|
|
|
+ nan->significand |= VFP_SINGLE_SIGNIFICAND_QNAN;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ *vsd = *nan;
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * If one was a signalling NAN, raise invalid operation.
|
|
|
|
+ */
|
|
|
|
+ return tn == VFP_SNAN || tm == VFP_SNAN ? FPSCR_IOC : VFP_NAN_FLAG;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+/*
|
|
|
|
+ * Extended operations
|
|
|
|
+ */
|
|
|
|
+static u32 vfp_single_fabs(int sd, int unused, s32 m, u32 fpscr)
|
|
|
|
+{
|
|
|
|
+ vfp_put_float(vfp_single_packed_abs(m), sd);
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static u32 vfp_single_fcpy(int sd, int unused, s32 m, u32 fpscr)
|
|
|
|
+{
|
|
|
|
+ vfp_put_float(m, sd);
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static u32 vfp_single_fneg(int sd, int unused, s32 m, u32 fpscr)
|
|
|
|
+{
|
|
|
|
+ vfp_put_float(vfp_single_packed_negate(m), sd);
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static const u16 sqrt_oddadjust[] = {
|
|
|
|
+ 0x0004, 0x0022, 0x005d, 0x00b1, 0x011d, 0x019f, 0x0236, 0x02e0,
|
|
|
|
+ 0x039c, 0x0468, 0x0545, 0x0631, 0x072b, 0x0832, 0x0946, 0x0a67
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+static const u16 sqrt_evenadjust[] = {
|
|
|
|
+ 0x0a2d, 0x08af, 0x075a, 0x0629, 0x051a, 0x0429, 0x0356, 0x029e,
|
|
|
|
+ 0x0200, 0x0179, 0x0109, 0x00af, 0x0068, 0x0034, 0x0012, 0x0002
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+u32 vfp_estimate_sqrt_significand(u32 exponent, u32 significand)
|
|
|
|
+{
|
|
|
|
+ int index;
|
|
|
|
+ u32 z, a;
|
|
|
|
+
|
|
|
|
+ if ((significand & 0xc0000000) != 0x40000000) {
|
|
|
|
+ printk(KERN_WARNING "VFP: estimate_sqrt: invalid significand\n");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ a = significand << 1;
|
|
|
|
+ index = (a >> 27) & 15;
|
|
|
|
+ if (exponent & 1) {
|
|
|
|
+ z = 0x4000 + (a >> 17) - sqrt_oddadjust[index];
|
|
|
|
+ z = ((a / z) << 14) + (z << 15);
|
|
|
|
+ a >>= 1;
|
|
|
|
+ } else {
|
|
|
|
+ z = 0x8000 + (a >> 17) - sqrt_evenadjust[index];
|
|
|
|
+ z = a / z + z;
|
|
|
|
+ z = (z >= 0x20000) ? 0xffff8000 : (z << 15);
|
|
|
|
+ if (z <= a)
|
|
|
|
+ return (s32)a >> 1;
|
|
|
|
+ }
|
|
|
|
+ {
|
|
|
|
+ u64 v = (u64)a << 31;
|
|
|
|
+ do_div(v, z);
|
|
|
|
+ return v + (z >> 1);
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static u32 vfp_single_fsqrt(int sd, int unused, s32 m, u32 fpscr)
|
|
|
|
+{
|
|
|
|
+ struct vfp_single vsm, vsd;
|
|
|
|
+ int ret, tm;
|
|
|
|
+
|
|
|
|
+ vfp_single_unpack(&vsm, m);
|
|
|
|
+ tm = vfp_single_type(&vsm);
|
|
|
|
+ if (tm & (VFP_NAN|VFP_INFINITY)) {
|
|
|
|
+ struct vfp_single *vsp = &vsd;
|
|
|
|
+
|
|
|
|
+ if (tm & VFP_NAN)
|
|
|
|
+ ret = vfp_propagate_nan(vsp, &vsm, NULL, fpscr);
|
|
|
|
+ else if (vsm.sign == 0) {
|
|
|
|
+ sqrt_copy:
|
|
|
|
+ vsp = &vsm;
|
|
|
|
+ ret = 0;
|
|
|
|
+ } else {
|
|
|
|
+ sqrt_invalid:
|