|
@@ -813,3 +813,93 @@ vfp_single_add(struct vfp_single *vsd, struct vfp_single *vsn,
|
|
|
|
|
|
/*
|
|
|
* If the signs are different, we are really subtracting.
|
|
|
+ */
|
|
|
+ if (vsn->sign ^ vsm->sign) {
|
|
|
+ m_sig = vsn->significand - m_sig;
|
|
|
+ if ((s32)m_sig < 0) {
|
|
|
+ vsd->sign = vfp_sign_negate(vsd->sign);
|
|
|
+ m_sig = -m_sig;
|
|
|
+ } else if (m_sig == 0) {
|
|
|
+ vsd->sign = (fpscr & FPSCR_RMODE_MASK) ==
|
|
|
+ FPSCR_ROUND_MINUSINF ? 0x8000 : 0;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ m_sig = vsn->significand + m_sig;
|
|
|
+ }
|
|
|
+ vsd->significand = m_sig;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static u32
|
|
|
+vfp_single_multiply(struct vfp_single *vsd, struct vfp_single *vsn, struct vfp_single *vsm, u32 fpscr)
|
|
|
+{
|
|
|
+ vfp_single_dump("VSN", vsn);
|
|
|
+ vfp_single_dump("VSM", vsm);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Ensure that 'n' is the largest magnitude number. Note that
|
|
|
+ * if 'n' and 'm' have equal exponents, we do not swap them.
|
|
|
+ * This ensures that NaN propagation works correctly.
|
|
|
+ */
|
|
|
+ if (vsn->exponent < vsm->exponent) {
|
|
|
+ struct vfp_single *t = vsn;
|
|
|
+ vsn = vsm;
|
|
|
+ vsm = t;
|
|
|
+ pr_debug("VFP: swapping M <-> N\n");
|
|
|
+ }
|
|
|
+
|
|
|
+ vsd->sign = vsn->sign ^ vsm->sign;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * If 'n' is an infinity or NaN, handle it. 'm' may be anything.
|
|
|
+ */
|
|
|
+ if (vsn->exponent == 255) {
|
|
|
+ if (vsn->significand || (vsm->exponent == 255 && vsm->significand))
|
|
|
+ return vfp_propagate_nan(vsd, vsn, vsm, fpscr);
|
|
|
+ if ((vsm->exponent | vsm->significand) == 0) {
|
|
|
+ *vsd = vfp_single_default_qnan;
|
|
|
+ return FPSCR_IOC;
|
|
|
+ }
|
|
|
+ vsd->exponent = vsn->exponent;
|
|
|
+ vsd->significand = 0;
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * If 'm' is zero, the result is always zero. In this case,
|
|
|
+ * 'n' may be zero or a number, but it doesn't matter which.
|
|
|
+ */
|
|
|
+ if ((vsm->exponent | vsm->significand) == 0) {
|
|
|
+ vsd->exponent = 0;
|
|
|
+ vsd->significand = 0;
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * We add 2 to the destination exponent for the same reason as
|
|
|
+ * the addition case - though this time we have +1 from each
|
|
|
+ * input operand.
|
|
|
+ */
|
|
|
+ vsd->exponent = vsn->exponent + vsm->exponent - 127 + 2;
|
|
|
+ vsd->significand = vfp_hi64to32jamming((u64)vsn->significand * vsm->significand);
|
|
|
+
|
|
|
+ vfp_single_dump("VSD", vsd);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+#define NEG_MULTIPLY (1 << 0)
|
|
|
+#define NEG_SUBTRACT (1 << 1)
|
|
|
+
|
|
|
+static u32
|
|
|
+vfp_single_multiply_accumulate(int sd, int sn, s32 m, u32 fpscr, u32 negate, char *func)
|
|
|
+{
|
|
|
+ struct vfp_single vsd, vsp, vsn, vsm;
|
|
|
+ u32 exceptions;
|
|
|
+ s32 v;
|
|
|
+
|
|
|
+ v = vfp_get_float(sn);
|
|
|
+ pr_debug("VFP: s%u = %08x\n", sn, v);
|
|
|
+ vfp_single_unpack(&vsn, v);
|
|
|
+ if (vsn.exponent == 0 && vsn.significand)
|
|
|
+ vfp_single_normalise_denormal(&vsn);
|