|
|
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.