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 1988,2003 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* Utility functions for Sparc FPU simulator. */ 30 31 #include <sys/fpu/fpu_simulator.h> 32 #include <sys/fpu/globals.h> 33 34 void 35 _fp_read_vfreg( 36 FPU_REGS_TYPE *pf, /* Old freg value. */ 37 uint_t n, /* Want to read register n. */ 38 fp_simd_type *pfpsd) 39 { 40 *pf = pfpsd->fp_current_pfregs->fpu_fr.fpu_regs[n]; 41 } 42 43 void 44 _fp_write_vfreg( 45 FPU_REGS_TYPE *pf, /* New freg value. */ 46 uint_t n, /* Want to read register n. */ 47 fp_simd_type *pfpsd) 48 { 49 pfpsd->fp_current_pfregs->fpu_fr.fpu_regs[n] = *pf; 50 } 51 52 void 53 _fp_read_vdreg( 54 FPU_DREGS_TYPE *pd, /* Old dreg value. */ 55 uint_t n, /* Want to read register n. */ 56 fp_simd_type *pfpsd) 57 { 58 *pd = pfpsd->fp_current_pfregs->fpu_fr.fpu_dregs[n]; 59 } 60 61 void 62 _fp_write_vdreg( 63 FPU_DREGS_TYPE *pd, /* New dreg value. */ 64 uint_t n, /* Want to read register n. */ 65 fp_simd_type *pfpsd) 66 { 67 pfpsd->fp_current_pfregs->fpu_fr.fpu_dregs[n] = *pd; 68 } 69 70 /* 71 * Normalize a number. Does not affect zeros, infs, or NaNs. 72 * The number will be normalized to 113 bit extended: 73 * 0x0001####, 0x########, 0x########, 0x########. 74 */ 75 void 76 fpu_normalize(unpacked *pu) 77 { 78 uint_t U, u0, u1, u2, u3, m, n, k; 79 u0 = pu->significand[0]; 80 u1 = pu->significand[1]; 81 u2 = pu->significand[2]; 82 u3 = pu->significand[3]; 83 if ((*pu).fpclass == fp_normal) { 84 if ((u0|u1|u2|u3) == 0) { 85 (*pu).fpclass = fp_zero; 86 return; 87 } 88 while (u0 == 0) { 89 u0 = u1; u1 = u2; u2 = u3; u3 = 0; 90 (*pu).exponent = (*pu).exponent - 32; 91 } 92 if (u0 >= 0x20000) { /* u3 should be zero */ 93 n = 1; U = u0 >> 1; 94 while (U >= 0x20000) { 95 U >>= 1; 96 n += 1; 97 } 98 m = (1 << n)-1; 99 k = 32-n; 100 (*pu).exponent += n; 101 u3 = ((u2&m)<<k)|(u3>>n); 102 u2 = ((u1&m)<<k)|(u2>>n); 103 u1 = ((u0&m)<<k)|(u1>>n); 104 u0 = U; 105 } else if (u0 < 0x10000) { 106 n = 1; U = u0 << 1; 107 while (U < 0x10000) { 108 U <<= 1; 109 n += 1; 110 } 111 k = 32-n; 112 m = -(1 << k); 113 (*pu).exponent -= n; 114 u0 = (u0<<n)|((u1&m)>>k); 115 u1 = (u1<<n)|((u2&m)>>k); 116 u2 = (u2<<n)|((u3&m)>>k); 117 u3 = (u3<<n); 118 } 119 pu->significand[0] = u0; 120 pu->significand[1] = u1; 121 pu->significand[2] = u2; 122 pu->significand[3] = u3; 123 } 124 } 125 126 /* 127 * Right shift significand sticky by n bits. 128 */ 129 void 130 fpu_rightshift(unpacked *pu, int n) 131 { 132 uint_t m, k, j, u0, u1, u2, u3; 133 if (n > 113) { /* drastic */ 134 if (((*pu).significand[0] | (*pu).significand[1] 135 | (*pu).significand[2] | (*pu).significand[3]) == 0) { 136 /* really zero */ 137 pu->fpclass = fp_zero; 138 return; 139 } else { 140 pu->rounded = 0; 141 pu->sticky = 1; 142 pu->significand[3] = 0; 143 pu->significand[2] = 0; 144 pu->significand[1] = 0; 145 pu->significand[0] = 0; 146 return; 147 } 148 } 149 while (n >= 32) { /* big shift */ 150 pu->sticky |= pu->rounded | (pu->significand[3]&0x7fffffff); 151 pu->rounded = (*pu).significand[3] >> 31; 152 (*pu).significand[3] = (*pu).significand[2]; 153 (*pu).significand[2] = (*pu).significand[1]; 154 (*pu).significand[1] = (*pu).significand[0]; 155 (*pu).significand[0] = 0; 156 n -= 32; 157 } 158 if (n > 0) { /* small shift */ 159 u0 = pu->significand[0]; 160 u1 = pu->significand[1]; 161 u2 = pu->significand[2]; 162 u3 = pu->significand[3]; 163 m = (1<<n)-1; 164 k = 32 - n; 165 j = (1<<(n-1))-1; 166 pu->sticky |= pu->rounded | (u3&j); 167 pu->rounded = (u3&m)>>(n-1); 168 pu->significand[3] = ((u2&m)<<k)|(u3>>n); 169 pu->significand[2] = ((u1&m)<<k)|(u2>>n); 170 pu->significand[1] = ((u0&m)<<k)|(u1>>n); 171 pu->significand[0] = u0>>n; 172 } 173 } 174 175 176 /* 177 * Set the exception bit in the current exception register. 178 */ 179 void 180 fpu_set_exception(pfpsd, ex) 181 fp_simd_type *pfpsd; /* Pointer to simulator data */ 182 enum fp_exception_type ex; 183 { 184 pfpsd->fp_current_exceptions |= 1 << (int)ex; 185 } 186 187 /* 188 * Set invalid exception and error nan in *pu 189 */ 190 void 191 fpu_error_nan(pfpsd, pu) 192 fp_simd_type *pfpsd; /* Pointer to simulator data */ 193 unpacked *pu; 194 { 195 fpu_set_exception(pfpsd, fp_invalid); 196 pu->sign = 0; 197 pu->significand[0] = 0x7fffffff; 198 pu->significand[1] = 0xffffffffUL; 199 pu->significand[2] = 0xffffffffUL; 200 pu->significand[3] = 0xffffffffUL; 201 } 202 203 /* 204 * the following fpu_add3wc should be inlined as 205 * .inline _fpu_add3wc, 3 206 * ld [%o1], %o4 ! sum = x 207 * addcc -1, %o3, %g0 ! restore last carry in cc reg 208 * addxcc %o4, %o2, %o4 ! sum = sum + y + last carry 209 * st %o4, [%o0] ! *z = sum 210 * addx %g0, %g0, %o0 ! return new carry 211 * .end 212 */ 213 uint_t 214 fpu_add3wc(uint_t *z, uint_t x, uint_t y, uint_t carry) 215 { /* *z = x + y + carry, set carry; */ 216 if (carry == 0) { 217 *z = x+y; 218 return (*z < y); 219 } else { 220 *z = x+y+1; 221 return (*z <= y); 222 } 223 } 224 225 /* 226 * The following fpu_sub3wc should be inlined as 227 * .inline _fpu_sub3wc, 3 228 * ld [%o1], %o4 ! sum = *x 229 * addcc -1, %o3, %g0 ! restore last carry in cc reg 230 * subxcc %o4, %o2, %o4 ! sum = sum - y - last carry 231 * st %o4, [%o0] ! *x = sum 232 * addx %g0, %g0, %o0 ! return new carry 233 * .end 234 */ 235 uint_t 236 fpu_sub3wc(uint_t *z, uint_t x, uint_t y, uint_t carry) 237 { /* *z = x - y - carry, set carry; */ 238 if (carry == 0) { 239 *z = x-y; 240 return (*z > x); 241 } else { 242 *z = x-y-1; 243 return (*z >= x); 244 } 245 } 246 247 /* 248 * the following fpu_neg2wc should be inlined as 249 * .inline _fpu_neg2wc, 2 250 * ld [%o1], %o3 ! tmp = *x 251 * addcc -1, %o2, %g0 ! restore last carry in cc reg 252 * subxcc %g0, %o3, %o3 ! sum = 0 - tmp - last carry 253 * st %o3, [%o0] ! *x = sum 254 * addx %g0, %g0, %o0 ! return new carry 255 * .end 256 */ 257 uint_t 258 fpu_neg2wc(uint_t *z, uint_t x, uint_t carry) 259 { /* *x = 0 - *x - carry, set carry; */ 260 if (carry == 0) { 261 *z = -x; 262 return ((*z) != 0); 263 } else { 264 *z = -x-1; 265 return (1); 266 } 267 } 268 269 int 270 fpu_cmpli(uint_t *x, uint_t *y, int n) 271 { /* compare two uint_t array */ 272 int i; 273 i = 0; 274 275 while (i < n) { 276 if (x[i] > y[i]) 277 return (1); 278 else if (x[i] < y[i]) 279 return (-1); 280 i++; 281 } 282 return (0); 283 } 284 285 #ifdef DEBUG 286 287 #include <sys/cmn_err.h> 288 289 /* 290 * Print out unpacked record. 291 */ 292 void 293 display_unpacked(pu) 294 unpacked *pu; 295 { 296 (void) printf(" unpacked "); 297 if (pu->sign) 298 (void) printf("-"); 299 else 300 (void) printf("+"); 301 302 switch (pu->fpclass) { 303 case fp_zero: 304 (void) printf("0 "); 305 break; 306 case fp_normal: 307 (void) printf("normal"); 308 break; 309 case fp_infinity: 310 (void) printf("Inf "); 311 break; 312 case fp_quiet: 313 case fp_signaling: 314 (void) printf("nan "); 315 break; 316 } 317 (void) printf(" %X %X %X %X (%X, %X) exponent %X \n", 318 pu->significand[0], pu->significand[1], pu->significand[2], 319 pu->significand[3], (pu->rounded != 0), 320 (pu->sticky != 0), pu->exponent); 321 } 322 #endif 323