1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright (c) 1988 by Sun Microsystems, Inc. 24 */ 25 26 #ident "%Z%%M% %I% %E% SMI" /* SunOS-4.1 1.8 88/12/06 */ 27 28 #include <sys/fpu/fpu_simulator.h> 29 #include <sys/fpu/globals.h> 30 31 static void 32 true_add(px, py, pz) 33 unpacked *px, *py, *pz; 34 { 35 unsigned c; 36 unpacked *pt; 37 38 if ((int) px->fpclass <= (int) py->fpclass) { /* Reverse. */ 39 pt = py; 40 py = px; 41 px = pt; 42 } 43 /* Now class(x) >= class(y). */ 44 switch (px->fpclass) { 45 case fp_quiet: /* NaN + x -> NaN */ 46 case fp_signaling: /* NaN + x -> NaN */ 47 case fp_infinity: /* Inf + x -> Inf */ 48 case fp_zero: /* 0 + 0 -> 0 */ 49 *pz = *px; 50 return; 51 default: 52 if (py->fpclass == fp_zero) { 53 *pz = *px; 54 return; 55 } 56 } 57 /* Now z is normal or subnormal. */ 58 /* Now y is normal or subnormal. */ 59 if (px->exponent < py->exponent) { /* Reverse. */ 60 pt = py; 61 py = px; 62 px = pt; 63 } 64 /* Now class(x) >= class(y). */ 65 pz->fpclass = px->fpclass; 66 pz->sign = px->sign; 67 pz->exponent = px->exponent; 68 pz->rounded = pz->sticky = 0; 69 70 if (px->exponent != py->exponent) { /* pre-alignment required */ 71 fpu_rightshift(py, pz->exponent - py->exponent); 72 pz->rounded = py->rounded; 73 pz->sticky = py->sticky; 74 } 75 c = 0; 76 c = fpu_add3wc(&(pz->significand[3]), px->significand[3], 77 py->significand[3], c); 78 c = fpu_add3wc(&(pz->significand[2]), px->significand[2], 79 py->significand[2], c); 80 c = fpu_add3wc(&(pz->significand[1]), px->significand[1], 81 py->significand[1], c); 82 c = fpu_add3wc(&(pz->significand[0]), px->significand[0], 83 py->significand[0], c); 84 85 /* Handle carry out of msb. */ 86 if (pz->significand[0] >= 0x20000) { 87 fpu_rightshift(pz, 1); /* Carried out bit. */ 88 pz->exponent++; /* Renormalize. */ 89 } 90 } 91 92 static void 93 true_sub(pfpsd, px, py, pz) 94 fp_simd_type *pfpsd; /* Pointer to simulator data */ 95 unpacked *px, *py, *pz; 96 { 97 unsigned *z, g, s, r, c; 98 unpacked *pt; 99 100 if ((int) px->fpclass <= (int) py->fpclass) { /* Reverse. */ 101 pt = py; 102 py = px; 103 px = pt; 104 } 105 /* Now class(x) >= class(y). */ 106 *pz = *px; /* Tentative difference: x. */ 107 switch (pz->fpclass) { 108 case fp_quiet: /* NaN - x -> NaN */ 109 case fp_signaling: /* NaN - x -> NaN */ 110 return; 111 case fp_infinity: /* Inf - x -> Inf */ 112 if (py->fpclass == fp_infinity) { 113 fpu_error_nan(pfpsd, pz); /* Inf - Inf -> NaN */ 114 pz->fpclass = fp_quiet; 115 } 116 return; 117 case fp_zero: /* 0 - 0 -> 0 */ 118 pz->sign = (pfpsd->fp_direction == fp_negative); 119 return; 120 default: 121 if (py->fpclass == fp_zero) 122 return; 123 } 124 125 /* x and y are both normal or subnormal. */ 126 127 if (px->exponent < py->exponent) { /* Reverse. */ 128 pt = py; 129 py = px; 130 px = pt; 131 } 132 /* Now exp(x) >= exp(y). */ 133 pz->fpclass = px->fpclass; 134 pz->sign = px->sign; 135 pz->exponent = px->exponent; 136 pz->rounded = 0; 137 pz->sticky = 0; 138 z = pz->significand; 139 140 if (px->exponent == py->exponent) { /* no pre-alignment required */ 141 c = 0; 142 c = fpu_sub3wc(&z[3], px->significand[3], 143 py->significand[3], c); 144 c = fpu_sub3wc(&z[2], px->significand[2], 145 py->significand[2], c); 146 c = fpu_sub3wc(&z[1], px->significand[1], 147 py->significand[1], c); 148 c = fpu_sub3wc(&z[0], px->significand[0], 149 py->significand[0], c); 150 if ((z[0]|z[1]|z[2]|z[3]) == 0) { /* exact zero result */ 151 pz->sign = (pfpsd->fp_direction == fp_negative); 152 pz->fpclass = fp_zero; 153 return; 154 } 155 if (z[0] >= 0x20000) { /* sign reversal occurred */ 156 pz->sign = py->sign; 157 c = 0; 158 c = fpu_neg2wc(&z[3], z[3], c); 159 c = fpu_neg2wc(&z[2], z[2], c); 160 c = fpu_neg2wc(&z[1], z[1], c); 161 c = fpu_neg2wc(&z[0], z[0], c); 162 } 163 fpu_normalize(pz); 164 return; 165 } else { /* pre-alignment required */ 166 fpu_rightshift(py, pz->exponent - py->exponent - 1); 167 r = py->rounded; /* rounded bit */ 168 s = py->sticky; /* sticky bit */ 169 fpu_rightshift(py, 1); 170 g = py->rounded; /* guard bit */ 171 if (s != 0) r = (r == 0); 172 if ((r|s) != 0) g = (g == 0); /* guard and rounded bits of z */ 173 c = ((g|r|s) != 0); 174 c = fpu_sub3wc(&z[3], px->significand[3], 175 py->significand[3], c); 176 c = fpu_sub3wc(&z[2], px->significand[2], 177 py->significand[2], c); 178 c = fpu_sub3wc(&z[1], px->significand[1], 179 py->significand[1], c); 180 c = fpu_sub3wc(&z[0], px->significand[0], 181 py->significand[0], c); 182 183 if (z[0] >= 0x10000) { /* don't need post-shifted */ 184 pz->sticky = s|r; 185 pz->rounded = g; 186 } else { /* post-shifted left 1 bit */ 187 pz->sticky = s; 188 pz->rounded = r; 189 pz->significand[0] = (z[0]<<1)|((z[1]&0x80000000)>>31); 190 pz->significand[1] = (z[1]<<1)|((z[2]&0x80000000)>>31); 191 pz->significand[2] = (z[2]<<1)|((z[3]&0x80000000)>>31); 192 pz->significand[3] = (z[3]<<1)|g; 193 pz->exponent -= 1; 194 if (z[0] < 0x10000) fpu_normalize(pz); 195 } 196 return; 197 } 198 } 199 200 void 201 _fp_add(pfpsd, px, py, pz) 202 fp_simd_type *pfpsd; 203 unpacked *px, *py, *pz; 204 { 205 if (px->sign == py->sign) 206 true_add(px, py, pz); 207 else 208 true_sub(pfpsd, px, py, pz); 209 } 210 211 void 212 _fp_sub(pfpsd, px, py, pz) 213 fp_simd_type *pfpsd; 214 unpacked *px, *py, *pz; 215 { 216 if (py->fpclass < fp_quiet) py->sign = 1 - py->sign; 217 if (px->sign == py->sign) 218 true_add(px, py, pz); 219 else 220 true_sub(pfpsd, px, py, pz); 221 } 222