|
@@ -910,3 +910,151 @@ static u32 vfp_double_fnmsc(int dd, int dn, int dm, u32 fpscr)
|
|
|
return vfp_double_multiply_accumulate(dd, dn, dm, fpscr, NEG_SUBTRACT | NEG_MULTIPLY, "fnmsc");
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * sd = sn * sm
|
|
|
+ */
|
|
|
+static u32 vfp_double_fmul(int dd, int dn, int dm, u32 fpscr)
|
|
|
+{
|
|
|
+ struct vfp_double vdd, vdn, vdm;
|
|
|
+ u32 exceptions;
|
|
|
+
|
|
|
+ vfp_double_unpack(&vdn, vfp_get_double(dn));
|
|
|
+ if (vdn.exponent == 0 && vdn.significand)
|
|
|
+ vfp_double_normalise_denormal(&vdn);
|
|
|
+
|
|
|
+ vfp_double_unpack(&vdm, vfp_get_double(dm));
|
|
|
+ if (vdm.exponent == 0 && vdm.significand)
|
|
|
+ vfp_double_normalise_denormal(&vdm);
|
|
|
+
|
|
|
+ exceptions = vfp_double_multiply(&vdd, &vdn, &vdm, fpscr);
|
|
|
+ return vfp_double_normaliseround(dd, &vdd, fpscr, exceptions, "fmul");
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * sd = -(sn * sm)
|
|
|
+ */
|
|
|
+static u32 vfp_double_fnmul(int dd, int dn, int dm, u32 fpscr)
|
|
|
+{
|
|
|
+ struct vfp_double vdd, vdn, vdm;
|
|
|
+ u32 exceptions;
|
|
|
+
|
|
|
+ vfp_double_unpack(&vdn, vfp_get_double(dn));
|
|
|
+ if (vdn.exponent == 0 && vdn.significand)
|
|
|
+ vfp_double_normalise_denormal(&vdn);
|
|
|
+
|
|
|
+ vfp_double_unpack(&vdm, vfp_get_double(dm));
|
|
|
+ if (vdm.exponent == 0 && vdm.significand)
|
|
|
+ vfp_double_normalise_denormal(&vdm);
|
|
|
+
|
|
|
+ exceptions = vfp_double_multiply(&vdd, &vdn, &vdm, fpscr);
|
|
|
+ vdd.sign = vfp_sign_negate(vdd.sign);
|
|
|
+
|
|
|
+ return vfp_double_normaliseround(dd, &vdd, fpscr, exceptions, "fnmul");
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * sd = sn + sm
|
|
|
+ */
|
|
|
+static u32 vfp_double_fadd(int dd, int dn, int dm, u32 fpscr)
|
|
|
+{
|
|
|
+ struct vfp_double vdd, vdn, vdm;
|
|
|
+ u32 exceptions;
|
|
|
+
|
|
|
+ vfp_double_unpack(&vdn, vfp_get_double(dn));
|
|
|
+ if (vdn.exponent == 0 && vdn.significand)
|
|
|
+ vfp_double_normalise_denormal(&vdn);
|
|
|
+
|
|
|
+ vfp_double_unpack(&vdm, vfp_get_double(dm));
|
|
|
+ if (vdm.exponent == 0 && vdm.significand)
|
|
|
+ vfp_double_normalise_denormal(&vdm);
|
|
|
+
|
|
|
+ exceptions = vfp_double_add(&vdd, &vdn, &vdm, fpscr);
|
|
|
+
|
|
|
+ return vfp_double_normaliseround(dd, &vdd, fpscr, exceptions, "fadd");
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * sd = sn - sm
|
|
|
+ */
|
|
|
+static u32 vfp_double_fsub(int dd, int dn, int dm, u32 fpscr)
|
|
|
+{
|
|
|
+ struct vfp_double vdd, vdn, vdm;
|
|
|
+ u32 exceptions;
|
|
|
+
|
|
|
+ vfp_double_unpack(&vdn, vfp_get_double(dn));
|
|
|
+ if (vdn.exponent == 0 && vdn.significand)
|
|
|
+ vfp_double_normalise_denormal(&vdn);
|
|
|
+
|
|
|
+ vfp_double_unpack(&vdm, vfp_get_double(dm));
|
|
|
+ if (vdm.exponent == 0 && vdm.significand)
|
|
|
+ vfp_double_normalise_denormal(&vdm);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Subtraction is like addition, but with a negated operand.
|
|
|
+ */
|
|
|
+ vdm.sign = vfp_sign_negate(vdm.sign);
|
|
|
+
|
|
|
+ exceptions = vfp_double_add(&vdd, &vdn, &vdm, fpscr);
|
|
|
+
|
|
|
+ return vfp_double_normaliseround(dd, &vdd, fpscr, exceptions, "fsub");
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * sd = sn / sm
|
|
|
+ */
|
|
|
+static u32 vfp_double_fdiv(int dd, int dn, int dm, u32 fpscr)
|
|
|
+{
|
|
|
+ struct vfp_double vdd, vdn, vdm;
|
|
|
+ u32 exceptions = 0;
|
|
|
+ int tm, tn;
|
|
|
+
|
|
|
+ vfp_double_unpack(&vdn, vfp_get_double(dn));
|
|
|
+ vfp_double_unpack(&vdm, vfp_get_double(dm));
|
|
|
+
|
|
|
+ vdd.sign = vdn.sign ^ vdm.sign;
|
|
|
+
|
|
|
+ tn = vfp_double_type(&vdn);
|
|
|
+ tm = vfp_double_type(&vdm);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Is n a NAN?
|
|
|
+ */
|
|
|
+ if (tn & VFP_NAN)
|
|
|
+ goto vdn_nan;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Is m a NAN?
|
|
|
+ */
|
|
|
+ if (tm & VFP_NAN)
|
|
|
+ goto vdm_nan;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * If n and m are infinity, the result is invalid
|
|
|
+ * If n and m are zero, the result is invalid
|
|
|
+ */
|
|
|
+ if (tm & tn & (VFP_INFINITY|VFP_ZERO))
|
|
|
+ goto invalid;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * If n is infinity, the result is infinity
|
|
|
+ */
|
|
|
+ if (tn & VFP_INFINITY)
|
|
|
+ goto infinity;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * If m is zero, raise div0 exceptions
|
|
|
+ */
|
|
|
+ if (tm & VFP_ZERO)
|
|
|
+ goto divzero;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * If m is infinity, or n is zero, the result is zero
|
|
|
+ */
|
|
|
+ if (tm & VFP_INFINITY || tn & VFP_ZERO)
|
|
|
+ goto zero;
|
|
|
+
|
|
|
+ if (tn & VFP_DENORMAL)
|
|
|
+ vfp_double_normalise_denormal(&vdn);
|
|
|
+ if (tm & VFP_DENORMAL)
|
|
|
+ vfp_double_normalise_denormal(&vdm);
|
|
|
+
|