|
@@ -104,3 +104,114 @@ u32 vfp_single_normaliseround(int sd, struct vfp_single *vs, u32 fpscr, u32 exce
|
|
|
exponent -= shift;
|
|
|
significand <<= shift;
|
|
|
}
|
|
|
+
|
|
|
+#ifdef DEBUG
|
|
|
+ vs->exponent = exponent;
|
|
|
+ vs->significand = significand;
|
|
|
+ vfp_single_dump("pack: normalised", vs);
|
|
|
+#endif
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Tiny number?
|
|
|
+ */
|
|
|
+ underflow = exponent < 0;
|
|
|
+ if (underflow) {
|
|
|
+ significand = vfp_shiftright32jamming(significand, -exponent);
|
|
|
+ exponent = 0;
|
|
|
+#ifdef DEBUG
|
|
|
+ vs->exponent = exponent;
|
|
|
+ vs->significand = significand;
|
|
|
+ vfp_single_dump("pack: tiny number", vs);
|
|
|
+#endif
|
|
|
+ if (!(significand & ((1 << (VFP_SINGLE_LOW_BITS + 1)) - 1)))
|
|
|
+ underflow = 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Select rounding increment.
|
|
|
+ */
|
|
|
+ incr = 0;
|
|
|
+ rmode = fpscr & FPSCR_RMODE_MASK;
|
|
|
+
|
|
|
+ if (rmode == FPSCR_ROUND_NEAREST) {
|
|
|
+ incr = 1 << VFP_SINGLE_LOW_BITS;
|
|
|
+ if ((significand & (1 << (VFP_SINGLE_LOW_BITS + 1))) == 0)
|
|
|
+ incr -= 1;
|
|
|
+ } else if (rmode == FPSCR_ROUND_TOZERO) {
|
|
|
+ incr = 0;
|
|
|
+ } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vs->sign != 0))
|
|
|
+ incr = (1 << (VFP_SINGLE_LOW_BITS + 1)) - 1;
|
|
|
+
|
|
|
+ pr_debug("VFP: rounding increment = 0x%08x\n", incr);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Is our rounding going to overflow?
|
|
|
+ */
|
|
|
+ if ((significand + incr) < significand) {
|
|
|
+ exponent += 1;
|
|
|
+ significand = (significand >> 1) | (significand & 1);
|
|
|
+ incr >>= 1;
|
|
|
+#ifdef DEBUG
|
|
|
+ vs->exponent = exponent;
|
|
|
+ vs->significand = significand;
|
|
|
+ vfp_single_dump("pack: overflow", vs);
|
|
|
+#endif
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * If any of the low bits (which will be shifted out of the
|
|
|
+ * number) are non-zero, the result is inexact.
|
|
|
+ */
|
|
|
+ if (significand & ((1 << (VFP_SINGLE_LOW_BITS + 1)) - 1))
|
|
|
+ exceptions |= FPSCR_IXC;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Do our rounding.
|
|
|
+ */
|
|
|
+ significand += incr;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Infinity?
|
|
|
+ */
|
|
|
+ if (exponent >= 254) {
|
|
|
+ exceptions |= FPSCR_OFC | FPSCR_IXC;
|
|
|
+ if (incr == 0) {
|
|
|
+ vs->exponent = 253;
|
|
|
+ vs->significand = 0x7fffffff;
|
|
|
+ } else {
|
|
|
+ vs->exponent = 255; /* infinity */
|
|
|
+ vs->significand = 0;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ if (significand >> (VFP_SINGLE_LOW_BITS + 1) == 0)
|
|
|
+ exponent = 0;
|
|
|
+ if (exponent || significand > 0x80000000)
|
|
|
+ underflow = 0;
|
|
|
+ if (underflow)
|
|
|
+ exceptions |= FPSCR_UFC;
|
|
|
+ vs->exponent = exponent;
|
|
|
+ vs->significand = significand >> 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ pack:
|
|
|
+ vfp_single_dump("pack: final", vs);
|
|
|
+ {
|
|
|
+ s32 d = vfp_single_pack(vs);
|
|
|
+#ifdef DEBUG
|
|
|
+ pr_debug("VFP: %s: d(s%d)=%08x exceptions=%08x\n", func,
|
|
|
+ sd, d, exceptions);
|
|
|
+#endif
|
|
|
+ vfp_put_float(d, sd);
|
|
|
+ }
|
|
|
+
|
|
|
+ return exceptions;
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Propagate the NaN, setting exceptions if it is signalling.
|
|
|
+ * 'n' is always a NaN. 'm' may be a number, NaN or infinity.
|
|
|
+ */
|
|
|
+static u32
|
|
|
+vfp_propagate_nan(struct vfp_single *vsd, struct vfp_single *vsn,
|
|
|
+ struct vfp_single *vsm, u32 fpscr)
|
|
|
+{
|