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 #pragma ident "%Z%%M% %I% %E% SMI" 23 24 /* 25 * Copyright (c) 1988 by Sun Microsystems, Inc. 26 */ 27 28 /* Pack procedures for Sparc FPU simulator. */ 29 30 #include "_Qquad.h" 31 #include "_Qglobals.h" 32 33 PRIVATE int 34 overflow_to_infinity(sign) 35 int sign; 36 37 /* Returns 1 if overflow should go to infinity, 0 if to max finite. */ 38 39 { 40 int inf; 41 42 switch (fp_direction) { 43 case fp_nearest: 44 inf = 1; 45 break; 46 case fp_tozero: 47 inf = 0; 48 break; 49 case fp_positive: 50 inf = !sign; 51 break; 52 case fp_negative: 53 inf = sign; 54 break; 55 } 56 return (inf); 57 } 58 59 PRIVATE void 60 round(pu) 61 unpacked *pu; 62 63 /* Round according to current rounding mode. */ 64 65 { 66 int increment; /* boolean to indicate round up */ 67 int sr; 68 sr = pu->sticky|pu->rounded; 69 70 if (sr == 0) 71 return; 72 fpu_set_exception(fp_inexact); 73 switch (fp_direction) { 74 case fp_nearest: 75 increment = pu->rounded; 76 break; 77 case fp_tozero: 78 increment = 0; 79 break; 80 case fp_positive: 81 increment = (pu->sign == 0) & (sr != 0); 82 break; 83 case fp_negative: 84 increment = (pu->sign != 0) & (sr != 0); 85 break; 86 } 87 if (increment) { 88 pu->significand[3]++; 89 if (pu->significand[3] == 0) { 90 pu->significand[2]++; 91 if (pu->significand[2] == 0) { 92 pu->significand[1]++; 93 if (pu->significand[1] == 0) { 94 pu->significand[0]++; /* rounding carried out */ 95 if( pu->significand[0] == 0x20000) { 96 pu->exponent++; 97 pu->significand[0] = 0x10000; 98 } 99 } 100 } 101 } 102 } 103 if ((fp_direction == fp_nearest) && 104 (pu->sticky == 0) && increment!=0) { /* ambiguous case */ 105 pu->significand[3] &= 0xfffffffe; /* force round to even */ 106 } 107 } 108 109 PRIVATE void 110 packinteger(pu, px) 111 unpacked *pu; /* unpacked result */ 112 int *px; /* packed integer */ 113 { 114 switch (pu->fpclass) { 115 case fp_zero: 116 *px = 0; 117 break; 118 case fp_normal: 119 if (pu->exponent >= 32) 120 goto overflow; 121 fpu_rightshift(pu, 112 - pu->exponent); 122 round(pu); 123 if (pu->significand[3] >= 0x80000000) 124 if ((pu->sign == 0)||(pu->significand[3] > 0x80000000)) 125 goto overflow; 126 *px = pu->significand[3]; 127 if (pu->sign) 128 *px = -*px; 129 break; 130 case fp_infinity: 131 case fp_quiet: 132 case fp_signaling: 133 overflow: 134 if (pu->sign) 135 *px = 0x80000000; 136 else 137 *px = 0x7fffffff; 138 _fp_current_exceptions &= ~(1 << (int) fp_inexact); 139 fpu_set_exception(fp_invalid); 140 break; 141 } 142 } 143 144 PRIVATE void 145 packsingle(pu, px) 146 unpacked *pu; /* unpacked result */ 147 single_type *px; /* packed single */ 148 { 149 px->sign = pu->sign; 150 switch (pu->fpclass) { 151 case fp_zero: 152 px->exponent = 0; 153 px->significand = 0; 154 break; 155 case fp_infinity: 156 infinity: 157 px->exponent = 0xff; 158 px->significand = 0; 159 break; 160 case fp_quiet: 161 case fp_signaling: 162 fpu_rightshift(pu, 113-24); 163 px->exponent = 0xff; 164 px->significand = 0x400000|(0x3fffff&pu->significand[3]); 165 break; 166 case fp_normal: 167 fpu_rightshift(pu, 113-24); 168 pu->exponent += SINGLE_BIAS; 169 if (pu->exponent <= 0) { 170 px->exponent = 0; 171 fpu_rightshift(pu, 1 - pu->exponent); 172 round(pu); 173 if (pu->significand[3] == 0x800000) { /* rounded 174 * back up to 175 * normal */ 176 px->exponent = 1; 177 px->significand = 0; 178 return; 179 } 180 if (_fp_current_exceptions & (1 << fp_inexact)) 181 fpu_set_exception(fp_underflow); 182 px->significand = 0x7fffff & pu->significand[3]; 183 return; 184 } 185 round(pu); 186 if (pu->significand[3] == 0x1000000) { /* rounding overflow */ 187 pu->significand[3] = 0x800000; 188 pu->exponent += 1; 189 } 190 if (pu->exponent >= 0xff) { 191 fpu_set_exception(fp_overflow); 192 fpu_set_exception(fp_inexact); 193 if (overflow_to_infinity(pu->sign)) 194 goto infinity; 195 px->exponent = 0xfe; 196 px->significand = 0x7fffff; 197 return; 198 } 199 px->exponent = pu->exponent; 200 px->significand = 0x7fffff & pu->significand[3]; 201 } 202 } 203 204 PRIVATE void 205 packdouble(pu, px, py) 206 unpacked *pu; /* unpacked result */ 207 double_type *px; /* packed double */ 208 unsigned *py; 209 { 210 px->sign = pu->sign; 211 switch (pu->fpclass) { 212 case fp_zero: 213 px->exponent = 0; 214 px->significand = 0; 215 *py = 0; 216 break; 217 case fp_infinity: 218 infinity: 219 px->exponent = 0x7ff; 220 px->significand = 0; 221 *py = 0; 222 break; 223 case fp_quiet: 224 case fp_signaling: 225 fpu_rightshift(pu, 113-53); 226 px->exponent = 0x7ff; 227 px->significand = 0x80000 | (0x7ffff & pu->significand[2]); 228 *py = pu->significand[3]; 229 break; 230 case fp_normal: 231 fpu_rightshift(pu, 113-53); 232 pu->exponent += DOUBLE_BIAS; 233 if (pu->exponent <= 0) { /* underflow */ 234 px->exponent = 0; 235 fpu_rightshift(pu, 1 - pu->exponent); 236 round(pu); 237 if (pu->significand[2] == 0x100000) { /* rounded 238 * back up to 239 * normal */ 240 px->exponent = 1; 241 px->significand = 0; 242 *py = 0; 243 return; 244 } 245 if (_fp_current_exceptions & (1 << fp_inexact)) 246 fpu_set_exception(fp_underflow); 247 px->exponent = 0; 248 px->significand = 0xfffff & pu->significand[2]; 249 *py = pu->significand[3]; 250 return; 251 } 252 round(pu); 253 if (pu->significand[2] == 0x200000) { /* rounding overflow */ 254 pu->significand[2] = 0x100000; 255 pu->exponent += 1; 256 } 257 if (pu->exponent >= 0x7ff) { /* overflow */ 258 fpu_set_exception(fp_overflow); 259 fpu_set_exception(fp_inexact); 260 if (overflow_to_infinity(pu->sign)) 261 goto infinity; 262 px->exponent = 0x7fe; 263 px->significand = 0xfffff; 264 *py = 0xffffffff; 265 return; 266 } 267 px->exponent = pu->exponent; 268 px->significand = 0xfffff & pu->significand[2]; 269 *py = pu->significand[3]; 270 break; 271 } 272 } 273 274 PRIVATE void 275 packextended(pu, px, py, pz, pw) 276 unpacked *pu; /* unpacked result */ 277 extended_type *px; /* packed extended */ 278 unsigned *py, *pz, *pw; 279 { 280 px->sign = pu->sign; 281 switch (pu->fpclass) { 282 case fp_zero: 283 px->exponent = 0; 284 px->significand = 0; 285 *pz = 0; 286 *py = 0; 287 *pw = 0; 288 break; 289 case fp_infinity: 290 infinity: 291 px->exponent = 0x7fff; 292 px->significand = 0; 293 *pz = 0; 294 *py = 0; 295 *pw = 0; 296 break; 297 case fp_quiet: 298 case fp_signaling: 299 px->exponent = 0x7fff; 300 px->significand = 0x8000 | pu->significand[0]; /* Insure quiet 301 * nan. */ 302 *py = pu->significand[1]; 303 *pz = pu->significand[2]; 304 *pw = pu->significand[3]; 305 break; 306 case fp_normal: 307 pu->exponent += EXTENDED_BIAS; 308 if (pu->exponent <= 0) { /* underflow */ 309 fpu_rightshift(pu, 1-pu->exponent); 310 round(pu); 311 if (pu->significand[0] < 0x00010000) { /* not rounded 312 * back up 313 * to normal */ 314 if (_fp_current_exceptions & (1 << fp_inexact)) 315 fpu_set_exception(fp_underflow); 316 px->exponent = 0; 317 } else 318 px->exponent = 1; 319 px->significand = pu->significand[0]; 320 *py = pu->significand[1]; 321 *pz = pu->significand[2]; 322 *pw = pu->significand[3]; 323 return; 324 } 325 round(pu); /* rounding overflow handled in round() */ 326 if (pu->exponent >= 0x7fff) { /* overflow */ 327 fpu_set_exception(fp_overflow); 328 fpu_set_exception(fp_inexact); 329 if (overflow_to_infinity(pu->sign)) 330 goto infinity; 331 px->exponent = 0x7ffe; /* overflow to max norm */ 332 px->significand = 0xffff; 333 *py = 0xffffffff; 334 *pz = 0xffffffff; 335 *pw = 0xffffffff; 336 return; 337 } 338 px->exponent = pu->exponent; 339 px->significand = pu->significand[0]; 340 *py = pu->significand[1]; 341 *pz = pu->significand[2]; 342 *pw = pu->significand[3]; 343 break; 344 } 345 } 346 347 void 348 _fp_pack(pu, n, type) 349 unpacked *pu; /* unpacked operand */ 350 int *n; /* output result's address */ 351 enum fp_op_type type; /* type of datum */ 352 353 { 354 switch (type) { 355 case fp_op_integer: 356 { 357 packinteger(pu, n); 358 break; 359 } 360 case fp_op_single: 361 { 362 single_type x; 363 packsingle(pu, &x); 364 n[0] = *(int*)&x; 365 break; 366 } 367 case fp_op_double: 368 { 369 double_type x; 370 double t=1.0; 371 int i0,i1; 372 if((*(int*)&t)!=0) {i0=0;i1=1;} else {i0=1;i1=0;} 373 packdouble(pu, &x,&n[i1]); 374 n[i0] = *(int*)&x; 375 break; 376 } 377 case fp_op_extended: 378 { 379 extended_type x; 380 unsigned y, z, w; 381 unpacked u; 382 int k; 383 switch (fp_precision) { /* Implement extended 384 * rounding precision mode. */ 385 case fp_single: 386 { 387 single_type tx; 388 packsingle(pu, &tx); 389 pu = &u; 390 unpacksingle(pu, tx); 391 break; 392 } 393 case fp_double: 394 { 395 double_type tx; 396 unsigned ty; 397 packdouble(pu, &tx, &ty); 398 pu = &u; 399 unpackdouble(pu, tx, ty); 400 break; 401 } 402 case fp_precision_3: /* rounded to 64 bits */ 403 { 404 k = pu->exponent+ EXTENDED_BIAS; 405 if(k>=0) k = 113-64; 406 else k = 113-64-k; 407 fpu_rightshift(pu,113-64); 408 round(pu); 409 pu->sticky=pu->rounded=0; 410 pu->exponent += k; 411 fpu_normalize(pu); 412 break; 413 } 414 } 415 { 416 int i0,i1,i2,i3; 417 double t = 1.0; 418 if((*(int*)&t)!=0) {i0=0;i1=1;i2=2;i3=3;} 419 else {i0=3;i1=2;i2=1;i3=0;} 420 packextended(pu, &x, &n[i1], &n[i2], &n[i3]); 421 n[i0] = *(int*)&x; 422 } 423 424 break; 425 } 426 } 427 } 428 429