|
@@ -724,3 +724,92 @@ static struct op fops_ext[32] = {
|
|
|
|
|
|
|
|
|
|
|
|
+
|
|
|
+static u32
|
|
|
+vfp_single_fadd_nonnumber(struct vfp_single *vsd, struct vfp_single *vsn,
|
|
|
+ struct vfp_single *vsm, u32 fpscr)
|
|
|
+{
|
|
|
+ struct vfp_single *vsp;
|
|
|
+ u32 exceptions = 0;
|
|
|
+ int tn, tm;
|
|
|
+
|
|
|
+ tn = vfp_single_type(vsn);
|
|
|
+ tm = vfp_single_type(vsm);
|
|
|
+
|
|
|
+ if (tn & tm & VFP_INFINITY) {
|
|
|
+ /*
|
|
|
+ * Two infinities. Are they different signs?
|
|
|
+ */
|
|
|
+ if (vsn->sign ^ vsm->sign) {
|
|
|
+ /*
|
|
|
+ * different signs -> invalid
|
|
|
+ */
|
|
|
+ exceptions = FPSCR_IOC;
|
|
|
+ vsp = &vfp_single_default_qnan;
|
|
|
+ } else {
|
|
|
+ /*
|
|
|
+ * same signs -> valid
|
|
|
+ */
|
|
|
+ vsp = vsn;
|
|
|
+ }
|
|
|
+ } else if (tn & VFP_INFINITY && tm & VFP_NUMBER) {
|
|
|
+ /*
|
|
|
+ * One infinity and one number -> infinity
|
|
|
+ */
|
|
|
+ vsp = vsn;
|
|
|
+ } else {
|
|
|
+ /*
|
|
|
+ * 'n' is a NaN of some type
|
|
|
+ */
|
|
|
+ return vfp_propagate_nan(vsd, vsn, vsm, fpscr);
|
|
|
+ }
|
|
|
+ *vsd = *vsp;
|
|
|
+ return exceptions;
|
|
|
+}
|
|
|
+
|
|
|
+static u32
|
|
|
+vfp_single_add(struct vfp_single *vsd, struct vfp_single *vsn,
|
|
|
+ struct vfp_single *vsm, u32 fpscr)
|
|
|
+{
|
|
|
+ u32 exp_diff, m_sig;
|
|
|
+
|
|
|
+ if (vsn->significand & 0x80000000 ||
|
|
|
+ vsm->significand & 0x80000000) {
|
|
|
+ pr_info("VFP: bad FP values in %s\n", __func__);
|
|
|
+ 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;
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Is 'n' an infinity or a NaN? Note that 'm' may be a number,
|
|
|
+ * infinity or a NaN here.
|
|
|
+ */
|
|
|
+ if (vsn->exponent == 255)
|
|
|
+ return vfp_single_fadd_nonnumber(vsd, vsn, vsm, fpscr);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * We have two proper numbers, where 'vsn' is the larger magnitude.
|
|
|
+ *
|
|
|
+ * Copy 'n' to 'd' before doing the arithmetic.
|
|
|
+ */
|
|
|
+ *vsd = *vsn;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Align both numbers.
|
|
|
+ */
|
|
|
+ exp_diff = vsn->exponent - vsm->exponent;
|
|
|
+ m_sig = vfp_shiftright32jamming(vsm->significand, exp_diff);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * If the signs are different, we are really subtracting.
|