/* * Our task is to calculate the square root of a floating point number x0. * This number x normally has the form: * * exp * x = mant * 2 (where 1 <= mant < 2 and exp is an integer) * * This can be left as it stands, or the mantissa can be doubled and the * exponent decremented: * * exp-1 * x = (2 * mant) * 2 (where 2 <= 2 * mant < 4) * * If the exponent `exp' is even, the square root of the number is best * handled using the first form, and is by definition equal to: * * exp/2 * sqrt(x) = sqrt(mant) * 2 * * If exp is odd, on the other hand, it is convenient to use the second * form, giving: * * (exp-1)/2 * sqrt(x) = sqrt(2 * mant) * 2 * * In the first case, we have * * 1 <= mant < 2 * * and therefore * * sqrt(1) <= sqrt(mant) < sqrt(2) * * while in the second case we have * * 2 <= 2*mant < 4 * * and therefore * * sqrt(2) <= sqrt(2*mant) < sqrt(4) * * so that in any case, we are sure that * * sqrt(1) <= sqrt(n * mant) < sqrt(4), n = 1 or 2 * * or * * 1 <= sqrt(n * mant) < 2, n = 1 or 2. * * This root is therefore a properly formed mantissa for a floating * point number. The exponent of sqrt(x) is either exp/2 or (exp-1)/2 * as above. This leaves us with the problem of finding the square root * of a fixed-point number in the range [1..4). * * Though it may not be instantly obvious, the following square root * algorithm works for any integer x of an even number of bits, provided * that no overflows occur: * * let q = 0 * for k = NBITS-1 to 0 step -1 do -- for each digit in the answer... * x *= 2 -- multiply by radix, for next digit * if x >= 2q + 2^k then -- if adding 2^k does not * x -= 2q + 2^k -- exceed the correct root, * q += 2^k -- add 2^k and adjust x * fi * done * sqrt = q / 2^(NBITS/2) -- (and any remainder is in x) * * If NBITS is odd (so that k is initially even), we can just add another * zero bit at the top of x. Doing so means that q is not going to acquire * a 1 bit in the first trip around the loop (since x0 < 2^NBITS). If the * final value in x is not needed, or can be off by a factor of 2, this is * equivalant to moving the `x *= 2' step to the bottom of the loop: * * for k = NBITS-1 to 0 step -1 do if ... fi; x *= 2; done * * and the result q will then be sqrt(x0) * 2^floor(NBITS / 2). * (Since the algorithm is destructive on x, we will call x's initial * value, for which q is some power of two times its square root, x0.) * * If we insert a loop invariant y = 2q, we can then rewrite this using * C notation as: * * q = y = 0; x = x0; * for (k = NBITS; --k >= 0;) { * #if (NBITS is even) * x *= 2; * #endif * t = y + (1 << k); * if (x >= t) { * x -= t; * q += 1 << k; * y += 1 << (k + 1); * } * #if (NBITS is odd) * x *= 2; * #endif * } * * If x0 is fixed point, rather than an integer, we can simply alter the * scale factor between q and sqrt(x0). As it happens, we can easily arrange * for the scale factor to be 2**0 or 1, so that sqrt(x0) == q. * * In our case, however, x0 (and therefore x, y, q, and t) are multiword * integers, which adds some complication. But note that q is built one * bit at a time, from the top down, and is not used itself in the loop * (we use 2q as held in y instead). This means we can build our answer * in an integer, one word at a time, which saves a bit of work. Also, * since 1 << k is always a `new' bit in q, 1 << k and 1 << (k+1) are * `new' bits in y and we can set them with an `or' operation rather than * a full-blown multiword add. * * We are almost done, except for one snag. We must prove that none of our * intermediate calculations can overflow. We know that x0 is in [1..4) * and therefore the square root in q will be in [1..2), but what about x, * y, and t? * * We know that y = 2q at the beginning of each loop. (The relation only * fails temporarily while y and q are being updated.) Since q < 2, y < 4. * The sum in t can, in our case, be as much as y+(1<<1) = y+2 < 6, and. * Furthermore, we can prove with a bit of work that x never exceeds y by * more than 2, so that even after doubling, 0 <= x < 8. (This is left as * an exercise to the reader, mostly because I have become tired of working * on this comment.) * * If our floating point mantissas (which are of the form 1.frac) occupy * B+1 bits, our largest intermediary needs at most B+3 bits, or two extra. * In fact, we want even one more bit (for a carry, to avoid compares), or * three extra. There is a comment in fpu_emu.h reminding maintainers of * this, so we have some justification in assuming it. */ struct fpn * fpu_sqrt(struct fpemu *fe) { struct fpn *x = &fe->fe_f1; u_int bit, q, tt; u_int x0, x1, x2, x3; u_int y0, y1, y2, y3; u_int d0, d1, d2, d3; int e; FPU_DECL_CARRY; /* * Take care of special cases first. In order: * * sqrt(NaN) = NaN * sqrt(+0) = +0 * sqrt(-0) = -0 * sqrt(x < 0) = NaN (including sqrt(-Inf)) * sqrt(+Inf) = +Inf * * Then all that remains are numbers with mantissas in [1..2). */ DPRINTF(FPE_REG, ("fpu_sqer:\n")); DUMPFPN(FPE_REG, x); DPRINTF(FPE_REG, ("=>\n")); if (ISNAN(x)) { fe->fe_cx |= FPSCR_VXSNAN; DUMPFPN(FPE_REG, x); return (x); } if (ISZERO(x)) { fe->fe_cx |= FPSCR_ZX; x->fp_class = FPC_INF; DUMPFPN(FPE_REG, x); return (x); } if (x->fp_sign) { return (fpu_newnan(fe)); } if (ISINF(x)) { fe->fe_cx |= FPSCR_VXSQRT; DUMPFPN(FPE_REG, 0); return (0); } /* * Calculate result exponent. As noted above, this may involve * doubling the mantissa. We will also need to double x each * time around the loop, so we define a macro for this here, and * we break out the multiword mantissa. */ #ifdef FPU_SHL1_BY_ADD #define DOUBLE_X { \ FPU_ADDS(x3, x3, x3); FPU_ADDCS(x2, x2, x2); \ FPU_ADDCS(x1, x1, x1); FPU_ADDC(x0, x0, x0); \ } #else #define DOUBLE_X { \ x0 = (x0 << 1) | (x1 >> 31); x1 = (x1 << 1) | (x2 >> 31); \ x2 = (x2 << 1) | (x3 >> 31); x3 <<= 1; \ } #endif #if (FP_NMANT & 1) != 0 # define ODD_DOUBLE DOUBLE_X # define EVEN_DOUBLE /* nothing */ #else # define ODD_DOUBLE /* nothing */ # define EVEN_DOUBLE DOUBLE_X #endif x0 = x->fp_mant[0]; x1 = x->fp_mant[1]; x2 = x->fp_mant[2]; x3 = x->fp_mant[3]; e = x->fp_exp; if (e & 1) /* exponent is odd; use sqrt(2mant) */ DOUBLE_X; /* THE FOLLOWING ASSUMES THAT RIGHT SHIFT DOES SIGN EXTENSION */ x->fp_exp = e >> 1; /* calculates (e&1 ? (e-1)/2 : e/2 */ /* * Now calculate the mantissa root. Since x is now in [1..4), * we know that the first trip around the loop will definitely * set the top bit in q, so we can do that manually and start * the loop at the next bit down instead. We must be sure to * double x correctly while doing the `known q=1.0'. * * We do this one mantissa-word at a time, as noted above, to * save work. To avoid `(1U << 31) << 1', we also do the top bit * outside of each per-word loop. * * The calculation `t = y + bit' breaks down into `t0 = y0, ..., * t3 = y3, t? |= bit' for the appropriate word. Since the bit * is always a `new' one, this means that three of the `t?'s are * just the corresponding `y?'; we use `#define's here for this. * The variable `tt' holds the actual `t?' variable. */ /* calculate q0 */ #define t0 tt bit = FP_1; EVEN_DOUBLE; /* if (x >= (t0 = y0 | bit)) { */ /* always true */ q = bit; x0 -= bit; y0 = bit << 1; /* } */ ODD_DOUBLE; while ((bit >>= 1) != 0) { /* for remaining bits in q0 */ EVEN_DOUBLE; t0 = y0 | bit; /* t = y + bit */ if (x0 >= t0) { /* if x >= t then */ x0 -= t0; /* x -= t */ q |= bit; /* q += bit */ y0 |= bit << 1; /* y += bit << 1 */ } ODD_DOUBLE; } x->fp_mant[0] = q; #undef t0 /* calculate q1. note (y0&1)==0. */ #define t0 y0 #define t1 tt q = 0; y1 = 0; bit = 1 << 31; EVEN_DOUBLE; t1 = bit; FPU_SUBS(d1, x1, t1); FPU_SUBC(d0, x0, t0); /* d = x - t */ if ((int)d0 >= 0) { /* if d >= 0 (i.e., x >= t) then */ x0 = d0, x1 = d1; /* x -= t */ q = bit; /* q += bit */ y0 |= 1; /* y += bit << 1 */ } ODD_DOUBLE; while ((bit >>= 1) != 0) { /* for remaining bits in q1 */ EVEN_DOUBLE; /* as before */ t1 = y1 | bit; FPU_SUBS(d1, x1, t1); FPU_SUBC(d0, x0, t0); if ((int)d0 >= 0) { x0 = d0, x1 = d1; q |= bit; y1 |= bit << 1; } ODD_DOUBLE; } x->fp_mant[1] = q; #undef t1 /* calculate q2. note (y1&1)==0; y0 (aka t0) is fixed. */ #define t1 y1 #define t2 tt q = 0; y2 = 0; bit = 1 << 31; EVEN_DOUBLE; t2 = bit; FPU_SUBS(d2, x2, t2); FPU_SUBCS(d1, x1, t1); FPU_SUBC(d0, x0, t0); if ((int)d0 >= 0) { x0 = d0, x1 = d1, x2 = d2; q |= bit; y1 |= 1; /* now t1, y1 are set in concrete */ } ODD_DOUBLE; while ((bit >>= 1) != 0) { EVEN_DOUBLE; t2 = y2 | bit; FPU_SUBS(d2, x2, t2); FPU_SUBCS(d1, x1, t1); FPU_SUBC(d0, x0, t0); if ((int)d0 >= 0) { x0 = d0, x1 = d1, x2 = d2; q |= bit; y2 |= bit << 1; } ODD_DOUBLE; } x->fp_mant[2] = q; #undef t2 /* calculate q3. y0, t0, y1, t1 all fixed; y2, t2, almost done. */ #define t2 y2 #define t3 tt q = 0; y3 = 0; bit = 1 << 31; EVEN_DOUBLE; t3 = bit; FPU_SUBS(d3, x3, t3); FPU_SUBCS(d2, x2, t2); FPU_SUBCS(d1, x1, t1); FPU_SUBC(d0, x0, t0); ODD_DOUBLE; if ((int)d0 >= 0) { x0 = d0, x1 = d1, x2 = d2; q |= bit; y2 |= 1; } while ((bit >>= 1) != 0) { EVEN_DOUBLE; t3 = y3 | bit; FPU_SUBS(d3, x3, t3); FPU_SUBCS(d2, x2, t2); FPU_SUBCS(d1, x1, t1); FPU_SUBC(d0, x0, t0); if ((int)d0 >= 0) { x0 = d0, x1 = d1, x2 = d2; q |= bit; y3 |= bit << 1; } ODD_DOUBLE; } x->fp_mant[3] = q; /* * The result, which includes guard and round bits, is exact iff * x is now zero; any nonzero bits in x represent sticky bits. */ x->fp_sticky = x0 | x1 | x2 | x3; DUMPFPN(FPE_REG, x); return (x); }
/* * Perform a compare instruction (with or without unordered exception). * This updates the fcc field in the fsr. * * If either operand is NaN, the result is unordered. For cmpe, this * causes an NV exception. Everything else is ordered: * |Inf| > |numbers| > |0|. * We already arranged for fp_class(Inf) > fp_class(numbers) > fp_class(0), * so we get this directly. Note, however, that two zeros compare equal * regardless of sign, while everything else depends on sign. * * Incidentally, two Infs of the same sign compare equal (per the 80387 * manual---it would be nice if the SPARC documentation were more * complete). */ void fpu_compare(struct fpemu *fe, int cmpe) { register struct fpn *a, *b; register int cc, r3, r2, r1, r0; FPU_DECL_CARRY a = &fe->fe_f1; b = &fe->fe_f2; if (ISNAN(a) || ISNAN(b)) { /* * In any case, we already got an exception for signalling * NaNs; here we may replace that one with an identical * exception, but so what?. */ if (cmpe) fe->fe_cx = FSR_NV; cc = FSR_CC_UO; goto done; } /* * Must handle both-zero early to avoid sign goofs. Otherwise, * at most one is 0, and if the signs differ we are done. */ if (ISZERO(a) && ISZERO(b)) { cc = FSR_CC_EQ; goto done; } if (a->fp_sign) { /* a < 0 (or -0) */ if (!b->fp_sign) { /* b >= 0 (or if a = -0, b > 0) */ cc = FSR_CC_LT; goto done; } } else { /* a > 0 (or +0) */ if (b->fp_sign) { /* b <= -0 (or if a = +0, b < 0) */ cc = FSR_CC_GT; goto done; } } /* * Now the signs are the same (but may both be negative). All * we have left are these cases: * * |a| < |b| [classes or values differ] * |a| > |b| [classes or values differ] * |a| == |b| [classes and values identical] * * We define `diff' here to expand these as: * * |a| < |b|, a,b >= 0: a < b => FSR_CC_LT * |a| < |b|, a,b < 0: a > b => FSR_CC_GT * |a| > |b|, a,b >= 0: a > b => FSR_CC_GT * |a| > |b|, a,b < 0: a < b => FSR_CC_LT */ #define opposite_cc(cc) ((cc) == FSR_CC_LT ? FSR_CC_GT : FSR_CC_LT) #define diff(magnitude) (a->fp_sign ? opposite_cc(magnitude) : (magnitude)) if (a->fp_class < b->fp_class) { /* |a| < |b| */ cc = diff(FSR_CC_LT); goto done; } if (a->fp_class > b->fp_class) { /* |a| > |b| */ cc = diff(FSR_CC_GT); goto done; } /* now none can be 0: only Inf and numbers remain */ if (ISINF(a)) { /* |Inf| = |Inf| */ cc = FSR_CC_EQ; goto done; } /* * Only numbers remain. To compare two numbers in magnitude, we * simply subtract their mantissas. */ FPU_SUBS(r3, a->fp_mant[0], b->fp_mant[0]); FPU_SUBCS(r2, a->fp_mant[1], b->fp_mant[1]); FPU_SUBCS(r1, a->fp_mant[2], b->fp_mant[2]); FPU_SUBC(r0, a->fp_mant[3], b->fp_mant[3]); if (r0 < 0) /* underflow: |a| < |b| */ cc = diff(FSR_CC_LT); else if ((r0 | r1 | r2 | r3) != 0) /* |a| > |b| */ cc = diff(FSR_CC_GT); else cc = FSR_CC_EQ; /* |a| == |b| */ done: fe->fe_fsr = (fe->fe_fsr & ~FSR_FCC) | (cc << FSR_FCC_SHIFT); }
struct fpn * fpu_add(struct fpemu *fe) { struct fpn *x = &fe->fe_f1, *y = &fe->fe_f2, *r; u_int r0, r1, r2, r3; int rd; /* * Put the `heavier' operand on the right (see fpu_emu.h). * Then we will have one of the following cases, taken in the * following order: * * - y = NaN. Implied: if only one is a signalling NaN, y is. * The result is y. * - y = Inf. Implied: x != NaN (is 0, number, or Inf: the NaN * case was taken care of earlier). * If x = -y, the result is NaN. Otherwise the result * is y (an Inf of whichever sign). * - y is 0. Implied: x = 0. * If x and y differ in sign (one positive, one negative), * the result is +0 except when rounding to -Inf. If same: * +0 + +0 = +0; -0 + -0 = -0. * - x is 0. Implied: y != 0. * Result is y. * - other. Implied: both x and y are numbers. * Do addition a la Hennessey & Patterson. */ DPRINTF(FPE_REG, ("fpu_add:\n")); DUMPFPN(FPE_REG, x); DUMPFPN(FPE_REG, y); DPRINTF(FPE_REG, ("=>\n")); ORDER(x, y); if (ISNAN(y)) { fe->fe_cx |= FPSCR_VXSNAN; DUMPFPN(FPE_REG, y); return (y); } if (ISINF(y)) { if (ISINF(x) && x->fp_sign != y->fp_sign) { fe->fe_cx |= FPSCR_VXISI; return (fpu_newnan(fe)); } DUMPFPN(FPE_REG, y); return (y); } rd = ((fe->fe_fpscr) & FPSCR_RN); if (ISZERO(y)) { if (rd != FSR_RD_RM) /* only -0 + -0 gives -0 */ y->fp_sign &= x->fp_sign; else /* any -0 operand gives -0 */ y->fp_sign |= x->fp_sign; DUMPFPN(FPE_REG, y); return (y); } if (ISZERO(x)) { DUMPFPN(FPE_REG, y); return (y); } /* * We really have two numbers to add, although their signs may * differ. Make the exponents match, by shifting the smaller * number right (e.g., 1.011 => 0.1011) and increasing its * exponent (2^3 => 2^4). Note that we do not alter the exponents * of x and y here. */ r = &fe->fe_f3; r->fp_class = FPC_NUM; if (x->fp_exp == y->fp_exp) { r->fp_exp = x->fp_exp; r->fp_sticky = 0; } else { if (x->fp_exp < y->fp_exp) { /* * Try to avoid subtract case iii (see below). * This also guarantees that x->fp_sticky = 0. */ SWAP(x, y); } /* now x->fp_exp > y->fp_exp */ r->fp_exp = x->fp_exp; r->fp_sticky = fpu_shr(y, x->fp_exp - y->fp_exp); } r->fp_sign = x->fp_sign; if (x->fp_sign == y->fp_sign) { FPU_DECL_CARRY /* * The signs match, so we simply add the numbers. The result * may be `supernormal' (as big as 1.111...1 + 1.111...1, or * 11.111...0). If so, a single bit shift-right will fix it * (but remember to adjust the exponent). */ /* r->fp_mant = x->fp_mant + y->fp_mant */ FPU_ADDS(r->fp_mant[3], x->fp_mant[3], y->fp_mant[3]); FPU_ADDCS(r->fp_mant[2], x->fp_mant[2], y->fp_mant[2]); FPU_ADDCS(r->fp_mant[1], x->fp_mant[1], y->fp_mant[1]); FPU_ADDC(r0, x->fp_mant[0], y->fp_mant[0]); if ((r->fp_mant[0] = r0) >= FP_2) { (void) fpu_shr(r, 1); r->fp_exp++; } } else { FPU_DECL_CARRY /* * The signs differ, so things are rather more difficult. * H&P would have us negate the negative operand and add; * this is the same as subtracting the negative operand. * This is quite a headache. Instead, we will subtract * y from x, regardless of whether y itself is the negative * operand. When this is done one of three conditions will * hold, depending on the magnitudes of x and y: * case i) |x| > |y|. The result is just x - y, * with x's sign, but it may need to be normalized. * case ii) |x| = |y|. The result is 0 (maybe -0) * so must be fixed up. * case iii) |x| < |y|. We goofed; the result should * be (y - x), with the same sign as y. * We could compare |x| and |y| here and avoid case iii, * but that would take just as much work as the subtract. * We can tell case iii has occurred by an overflow. * * N.B.: since x->fp_exp >= y->fp_exp, x->fp_sticky = 0. */ /* r->fp_mant = x->fp_mant - y->fp_mant */ FPU_SET_CARRY(y->fp_sticky); FPU_SUBCS(r3, x->fp_mant[3], y->fp_mant[3]); FPU_SUBCS(r2, x->fp_mant[2], y->fp_mant[2]); FPU_SUBCS(r1, x->fp_mant[1], y->fp_mant[1]); FPU_SUBC(r0, x->fp_mant[0], y->fp_mant[0]); if (r0 < FP_2) { /* cases i and ii */ if ((r0 | r1 | r2 | r3) == 0) { /* case ii */ r->fp_class = FPC_ZERO; r->fp_sign = rd == FSR_RD_RM; return (r); } } else { /* * Oops, case iii. This can only occur when the * exponents were equal, in which case neither * x nor y have sticky bits set. Flip the sign * (to y's sign) and negate the result to get y - x. */ #ifdef DIAGNOSTIC if (x->fp_exp != y->fp_exp || r->fp_sticky) panic("fpu_add"); #endif r->fp_sign = y->fp_sign; FPU_SUBS(r3, 0, r3); FPU_SUBCS(r2, 0, r2); FPU_SUBCS(r1, 0, r1); FPU_SUBC(r0, 0, r0); } r->fp_mant[3] = r3; r->fp_mant[2] = r2; r->fp_mant[1] = r1; r->fp_mant[0] = r0; if (r0 < FP_1) fpu_norm(r); } DUMPFPN(FPE_REG, r); return (r); }