|
|
1.1 ! root 1: /* $NetBSD: fpu_add.c,v 1.9 2013/03/26 11:30:20 isaki Exp $ */ ! 2: ! 3: /* ! 4: * Copyright (c) 1992, 1993 ! 5: * The Regents of the University of California. All rights reserved. ! 6: * ! 7: * This software was developed by the Computer Systems Engineering group ! 8: * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and ! 9: * contributed to Berkeley. ! 10: * ! 11: * All advertising materials mentioning features or use of this software ! 12: * must display the following acknowledgement: ! 13: * This product includes software developed by the University of ! 14: * California, Lawrence Berkeley Laboratory. ! 15: * ! 16: * Redistribution and use in source and binary forms, with or without ! 17: * modification, are permitted provided that the following conditions ! 18: * are met: ! 19: * 1. Redistributions of source code must retain the above copyright ! 20: * notice, this list of conditions and the following disclaimer. ! 21: * 2. Redistributions in binary form must reproduce the above copyright ! 22: * notice, this list of conditions and the following disclaimer in the ! 23: * documentation and/or other materials provided with the distribution. ! 24: * 3. Neither the name of the University nor the names of its contributors ! 25: * may be used to endorse or promote products derived from this software ! 26: * without specific prior written permission. ! 27: * ! 28: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ! 29: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! 30: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! 31: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE ! 32: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! 33: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! 34: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 35: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! 36: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! 37: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! 38: * SUCH DAMAGE. ! 39: * ! 40: * @(#)fpu_add.c 8.1 (Berkeley) 6/11/93 ! 41: */ ! 42: ! 43: /* ! 44: * Perform an FPU add (return x + y). ! 45: * ! 46: * To subtract, negate y and call add. ! 47: */ ! 48: ! 49: #include "fpu_arith.h" ! 50: #include "fpu_emulate.h" ! 51: ! 52: struct fpn * ! 53: fpu_add(struct fpemu *fe) ! 54: { ! 55: struct fpn *x = &fe->fe_f1, *y = &fe->fe_f2, *r; ! 56: uint32_t r0, r1, r2; ! 57: int rd; ! 58: ! 59: /* ! 60: * Put the `heavier' operand on the right (see fpu_emu.h). ! 61: * Then we will have one of the following cases, taken in the ! 62: * following order: ! 63: * ! 64: * - y = NaN. Implied: if only one is a signalling NaN, y is. ! 65: * The result is y. ! 66: * - y = Inf. Implied: x != NaN (is 0, number, or Inf: the NaN ! 67: * case was taken care of earlier). ! 68: * If x = -y, the result is NaN. Otherwise the result ! 69: * is y (an Inf of whichever sign). ! 70: * - y is 0. Implied: x = 0. ! 71: * If x and y differ in sign (one positive, one negative), ! 72: * the result is +0 except when rounding to -Inf. If same: ! 73: * +0 + +0 = +0; -0 + -0 = -0. ! 74: * - x is 0. Implied: y != 0. ! 75: * Result is y. ! 76: * - other. Implied: both x and y are numbers. ! 77: * Do addition a la Hennessey & Patterson. ! 78: */ ! 79: ORDER(x, y); ! 80: if (ISNAN(y)) ! 81: return (y); ! 82: if (ISINF(y)) { ! 83: if (ISINF(x) && x->fp_sign != y->fp_sign) ! 84: return (fpu_newnan(fe)); ! 85: return (y); ! 86: } ! 87: rd = (fe->fe_fpcr & FPCR_ROUND); ! 88: if (ISZERO(y)) { ! 89: if (rd != FPCR_MINF) /* only -0 + -0 gives -0 */ ! 90: y->fp_sign &= x->fp_sign; ! 91: else /* any -0 operand gives -0 */ ! 92: y->fp_sign |= x->fp_sign; ! 93: return (y); ! 94: } ! 95: if (ISZERO(x)) ! 96: return (y); ! 97: /* ! 98: * We really have two numbers to add, although their signs may ! 99: * differ. Make the exponents match, by shifting the smaller ! 100: * number right (e.g., 1.011 => 0.1011) and increasing its ! 101: * exponent (2^3 => 2^4). Note that we do not alter the exponents ! 102: * of x and y here. ! 103: */ ! 104: r = &fe->fe_f3; ! 105: r->fp_class = FPC_NUM; ! 106: if (x->fp_exp == y->fp_exp) { ! 107: r->fp_exp = x->fp_exp; ! 108: r->fp_sticky = 0; ! 109: } else { ! 110: if (x->fp_exp < y->fp_exp) { ! 111: /* ! 112: * Try to avoid subtract case iii (see below). ! 113: * This also guarantees that x->fp_sticky = 0. ! 114: */ ! 115: SWAP(x, y); ! 116: } ! 117: /* now x->fp_exp > y->fp_exp */ ! 118: r->fp_exp = x->fp_exp; ! 119: r->fp_sticky = fpu_shr(y, x->fp_exp - y->fp_exp); ! 120: } ! 121: r->fp_sign = x->fp_sign; ! 122: if (x->fp_sign == y->fp_sign) { ! 123: FPU_DECL_CARRY ! 124: ! 125: /* ! 126: * The signs match, so we simply add the numbers. The result ! 127: * may be `supernormal' (as big as 1.111...1 + 1.111...1, or ! 128: * 11.111...0). If so, a single bit shift-right will fix it ! 129: * (but remember to adjust the exponent). ! 130: */ ! 131: /* r->fp_mant = x->fp_mant + y->fp_mant */ ! 132: FPU_ADDS(r->fp_mant[2], x->fp_mant[2], y->fp_mant[2]); ! 133: FPU_ADDCS(r->fp_mant[1], x->fp_mant[1], y->fp_mant[1]); ! 134: FPU_ADDC(r0, x->fp_mant[0], y->fp_mant[0]); ! 135: if ((r->fp_mant[0] = r0) >= FP_2) { ! 136: (void) fpu_shr(r, 1); ! 137: r->fp_exp++; ! 138: } ! 139: } else { ! 140: FPU_DECL_CARRY ! 141: ! 142: /* ! 143: * The signs differ, so things are rather more difficult. ! 144: * H&P would have us negate the negative operand and add; ! 145: * this is the same as subtracting the negative operand. ! 146: * This is quite a headache. Instead, we will subtract ! 147: * y from x, regardless of whether y itself is the negative ! 148: * operand. When this is done one of three conditions will ! 149: * hold, depending on the magnitudes of x and y: ! 150: * case i) |x| > |y|. The result is just x - y, ! 151: * with x's sign, but it may need to be normalized. ! 152: * case ii) |x| = |y|. The result is 0 (maybe -0) ! 153: * so must be fixed up. ! 154: * case iii) |x| < |y|. We goofed; the result should ! 155: * be (y - x), with the same sign as y. ! 156: * We could compare |x| and |y| here and avoid case iii, ! 157: * but that would take just as much work as the subtract. ! 158: * We can tell case iii has occurred by an overflow. ! 159: * ! 160: * N.B.: since x->fp_exp >= y->fp_exp, x->fp_sticky = 0. ! 161: */ ! 162: /* r->fp_mant = x->fp_mant - y->fp_mant */ ! 163: FPU_SET_CARRY(y->fp_sticky); ! 164: FPU_SUBCS(r2, x->fp_mant[2], y->fp_mant[2]); ! 165: FPU_SUBCS(r1, x->fp_mant[1], y->fp_mant[1]); ! 166: FPU_SUBC(r0, x->fp_mant[0], y->fp_mant[0]); ! 167: if (r0 < FP_2) { ! 168: /* cases i and ii */ ! 169: if ((r0 | r1 | r2) == 0) { ! 170: /* case ii */ ! 171: r->fp_class = FPC_ZERO; ! 172: r->fp_sign = (rd == FPCR_MINF); ! 173: return (r); ! 174: } ! 175: } else { ! 176: /* ! 177: * Oops, case iii. This can only occur when the ! 178: * exponents were equal, in which case neither ! 179: * x nor y have sticky bits set. Flip the sign ! 180: * (to y's sign) and negate the result to get y - x. ! 181: */ ! 182: #ifdef DIAGNOSTIC ! 183: if (x->fp_exp != y->fp_exp || r->fp_sticky) ! 184: panic("fpu_add"); ! 185: #endif ! 186: r->fp_sign = y->fp_sign; ! 187: FPU_SUBS(r2, 0, r2); ! 188: FPU_SUBCS(r1, 0, r1); ! 189: FPU_SUBC(r0, 0, r0); ! 190: } ! 191: r->fp_mant[2] = r2; ! 192: r->fp_mant[1] = r1; ! 193: r->fp_mant[0] = r0; ! 194: if (r0 < FP_1) ! 195: fpu_norm(r); ! 196: } ! 197: return (r); ! 198: } ! 199: ! 200: #if defined(XM6i_FPE) ! 201: struct fpn * ! 202: fpu_sub(struct fpemu *fe) ! 203: { ! 204: if (ISNAN(&fe->fe_f1)) ! 205: return &fe->fe_f1; ! 206: if (ISNAN(&fe->fe_f2)) ! 207: return &fe->fe_f2; ! 208: ! 209: fe->fe_f2.fp_sign = !fe->fe_f2.fp_sign; ! 210: return fpu_add(fe); ! 211: } ! 212: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.