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,1995-1996,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 /* Pack procedures for Sparc FPU simulator. */ 30 31 #include <sys/fpu/fpu_simulator.h> 32 #include <sys/fpu/globals.h> 33 34 /* 35 * Returns 1 if overflow should go to infinity, 0 if to max finite. 36 */ 37 static int 38 overflow_to_infinity( 39 fp_simd_type *pfpsd, /* Pointer to simulator data */ 40 int sign) /* negative or positive */ 41 { 42 int inf; 43 44 switch (pfpsd->fp_direction) { 45 case fp_nearest: 46 inf = 1; 47 break; 48 case fp_tozero: 49 inf = 0; 50 break; 51 case fp_positive: 52 inf = !sign; 53 break; 54 case fp_negative: 55 inf = sign; 56 break; 57 } 58 return (inf); 59 } 60 61 /* 62 * Round according to current rounding mode. 63 */ 64 static void 65 round( 66 fp_simd_type *pfpsd, /* Pointer to simulator data */ 67 unpacked *pu) /* unpacked result */ 68 { 69 int increment; /* boolean to indicate round up */ 70 int sr; 71 72 sr = pu->sticky|pu->rounded; 73 74 if (sr == 0) 75 return; 76 fpu_set_exception(pfpsd, fp_inexact); 77 switch (pfpsd->fp_direction) { 78 case fp_nearest: 79 increment = pu->rounded; 80 break; 81 case fp_tozero: 82 increment = 0; 83 break; 84 case fp_positive: 85 increment = (pu->sign == 0) & (sr != 0); 86 break; 87 case fp_negative: 88 increment = (pu->sign != 0) & (sr != 0); 89 break; 90 } 91 if (increment) { 92 pu->significand[3]++; 93 if (pu->significand[3] == 0) { 94 pu->significand[2]++; 95 if (pu->significand[2] == 0) { 96 pu->significand[1]++; 97 if (pu->significand[1] == 0) { 98 pu->significand[0]++; /* rounding carried out */ 99 if (pu->significand[0] == 0x20000) { 100 pu->exponent++; 101 pu->significand[0] = 0x10000; 102 } 103 } 104 } 105 } 106 } 107 if ((pfpsd->fp_direction == fp_nearest) && 108 (pu->sticky == 0) && increment != 0) { /* ambiguous case */ 109 pu->significand[3] &= 0xfffffffe; /* force round to even */ 110 } 111 } 112 113 static void 114 packint32( 115 fp_simd_type *pfpsd, /* Pointer to simulator data */ 116 unpacked *pu, /* unpacked result */ 117 int32_t *px) /* packed int32_t */ 118 { 119 switch (pu->fpclass) { 120 case fp_zero: 121 *px = 0; 122 break; 123 case fp_normal: 124 if (pu->exponent >= 32) 125 goto overflow; 126 fpu_rightshift(pu, 112 - pu->exponent); 127 round(pfpsd, pu); 128 if (pu->significand[3] >= 0x80000000) 129 if ((pu->sign == 0)||(pu->significand[3] > 0x80000000)) 130 goto overflow; 131 *px = pu->significand[3]; 132 if (pu->sign) 133 *px = -*px; 134 break; 135 case fp_infinity: 136 case fp_quiet: 137 case fp_signaling: 138 overflow: 139 if (pu->sign) 140 *px = 0x80000000; 141 else 142 *px = 0x7fffffff; 143 pfpsd->fp_current_exceptions &= ~(1 << (int)fp_inexact); 144 fpu_set_exception(pfpsd, fp_invalid); 145 break; 146 } 147 } 148 149 static void 150 packint64( 151 fp_simd_type *pfpsd, /* Pointer to simulator data */ 152 unpacked *pu, /* unpacked result */ 153 int64_t *px) /* packed int64_t */ 154 { 155 union { 156 uint64_t ll; 157 uint32_t i[2]; 158 } x; 159 160 switch (pu->fpclass) { 161 case fp_zero: 162 *px = 0; 163 break; 164 case fp_normal: 165 if (pu->exponent >= 64) 166 goto overflow; 167 fpu_rightshift(pu, 112 - pu->exponent); 168 round(pfpsd, pu); 169 if (pu->significand[2] >= 0x80000000) 170 if ((pu->sign == 0) || 171 (pu->significand[2] > 0x80000000) || 172 (((pu->significand[2] == 0x80000000) && 173 (pu->significand[3] > 0)))) 174 goto overflow; 175 x.i[0] = pu->significand[2]; 176 x.i[1] = pu->significand[3]; 177 *px = x.ll; 178 if (pu->sign) 179 *px = -*px; 180 break; 181 case fp_infinity: 182 case fp_quiet: 183 case fp_signaling: 184 overflow: 185 if (pu->sign) 186 *px = (int64_t)0x8000000000000000; 187 else 188 *px = (int64_t)0x7fffffffffffffff; 189 pfpsd->fp_current_exceptions &= ~(1 << (int)fp_inexact); 190 fpu_set_exception(pfpsd, fp_invalid); 191 break; 192 } 193 } 194 195 static void 196 packsingle( 197 fp_simd_type *pfpsd, /* Pointer to simulator data */ 198 unpacked *pu, /* unpacked result */ 199 single_type *px) /* packed single */ 200 { 201 px->sign = pu->sign; 202 switch (pu->fpclass) { 203 case fp_zero: 204 px->exponent = 0; 205 px->significand = 0; 206 break; 207 case fp_infinity: 208 infinity: 209 px->exponent = 0xff; 210 px->significand = 0; 211 break; 212 case fp_quiet: 213 case fp_signaling: 214 fpu_rightshift(pu, 113-24); 215 px->exponent = 0xff; 216 px->significand = 0x400000|(0x3fffff&pu->significand[3]); 217 break; 218 case fp_normal: 219 fpu_rightshift(pu, 113-24); 220 pu->exponent += SINGLE_BIAS; 221 if (pu->exponent <= 0) { 222 px->exponent = 0; 223 fpu_rightshift(pu, 1 - pu->exponent); 224 round(pfpsd, pu); 225 if (pu->significand[3] == 0x800000) { 226 /* 227 * rounded 228 * back up to 229 * normal 230 */ 231 px->exponent = 1; 232 px->significand = 0; 233 fpu_set_exception(pfpsd, fp_inexact); 234 } else 235 px->significand = 0x7fffff & pu->significand[3]; 236 237 if (pfpsd->fp_current_exceptions & (1 << fp_inexact)) 238 fpu_set_exception(pfpsd, fp_underflow); 239 if (pfpsd->fp_fsrtem & (1<<fp_underflow)) { 240 fpu_set_exception(pfpsd, fp_underflow); 241 pfpsd->fp_current_exceptions &= 242 ~(1 << (int)fp_inexact); 243 } 244 return; 245 } 246 round(pfpsd, pu); 247 if (pu->significand[3] == 0x1000000) { /* rounding overflow */ 248 pu->significand[3] = 0x800000; 249 pu->exponent += 1; 250 } 251 if (pu->exponent >= 0xff) { 252 fpu_set_exception(pfpsd, fp_overflow); 253 fpu_set_exception(pfpsd, fp_inexact); 254 if (pfpsd->fp_fsrtem & (1<<fp_overflow)) { 255 pfpsd->fp_current_exceptions &= 256 ~(1 << (int)fp_inexact); 257 } 258 if (overflow_to_infinity(pfpsd, pu->sign)) 259 goto infinity; 260 px->exponent = 0xfe; 261 px->significand = 0x7fffff; 262 return; 263 } 264 px->exponent = pu->exponent; 265 px->significand = 0x7fffff & pu->significand[3]; 266 } 267 } 268 269 static void 270 packdouble( 271 fp_simd_type *pfpsd, /* Pointer to simulator data */ 272 unpacked *pu, /* unpacked result */ 273 double_type *px, /* packed double, sign/exponent/upper 20 bits */ 274 uint_t *py) /* and the lower 32 bits of the significand */ 275 { 276 px->sign = pu->sign; 277 switch (pu->fpclass) { 278 case fp_zero: 279 px->exponent = 0; 280 px->significand = 0; 281 *py = 0; 282 break; 283 case fp_infinity: 284 infinity: 285 px->exponent = 0x7ff; 286 px->significand = 0; 287 *py = 0; 288 break; 289 case fp_quiet: 290 case fp_signaling: 291 fpu_rightshift(pu, 113-53); 292 px->exponent = 0x7ff; 293 px->significand = 0x80000 | (0x7ffff & pu->significand[2]); 294 *py = pu->significand[3]; 295 break; 296 case fp_normal: 297 fpu_rightshift(pu, 113-53); 298 pu->exponent += DOUBLE_BIAS; 299 if (pu->exponent <= 0) { /* underflow */ 300 px->exponent = 0; 301 fpu_rightshift(pu, 1 - pu->exponent); 302 round(pfpsd, pu); 303 if (pu->significand[2] == 0x100000) { 304 /* 305 * rounded 306 * back up to 307 * normal 308 */ 309 px->exponent = 1; 310 px->significand = 0; 311 *py = 0; 312 fpu_set_exception(pfpsd, fp_inexact); 313 } else { 314 px->exponent = 0; 315 px->significand = 0xfffff & pu->significand[2]; 316 *py = pu->significand[3]; 317 } 318 if (pfpsd->fp_current_exceptions & (1 << fp_inexact)) 319 fpu_set_exception(pfpsd, fp_underflow); 320 if (pfpsd->fp_fsrtem & (1<<fp_underflow)) { 321 fpu_set_exception(pfpsd, fp_underflow); 322 pfpsd->fp_current_exceptions &= 323 ~(1 << (int)fp_inexact); 324 } 325 return; 326 } 327 round(pfpsd, pu); 328 if (pu->significand[2] == 0x200000) { /* rounding overflow */ 329 pu->significand[2] = 0x100000; 330 pu->exponent += 1; 331 } 332 if (pu->exponent >= 0x7ff) { /* overflow */ 333 fpu_set_exception(pfpsd, fp_overflow); 334 fpu_set_exception(pfpsd, fp_inexact); 335 if (pfpsd->fp_fsrtem & (1<<fp_overflow)) { 336 pfpsd->fp_current_exceptions &= 337 ~(1 << (int)fp_inexact); 338 } 339 if (overflow_to_infinity(pfpsd, pu->sign)) 340 goto infinity; 341 px->exponent = 0x7fe; 342 px->significand = 0xfffff; 343 *py = 0xffffffffU; 344 return; 345 } 346 px->exponent = pu->exponent; 347 px->significand = 0xfffff & pu->significand[2]; 348 *py = pu->significand[3]; 349 break; 350 } 351 } 352 353 static void 354 packextended( 355 fp_simd_type *pfpsd, /* Pointer to simulator data */ 356 unpacked *pu, /* unpacked result */ 357 extended_type *px, /* packed extended, sign/exponent/16 bits */ 358 uint_t *py, /* 2nd word of extended significand */ 359 uint_t *pz, /* 3rd word of extended significand */ 360 uint_t *pw) /* 4th word of extended significand */ 361 { 362 px->sign = pu->sign; 363 switch (pu->fpclass) { 364 case fp_zero: 365 px->exponent = 0; 366 px->significand = 0; 367 *pz = 0; 368 *py = 0; 369 *pw = 0; 370 break; 371 case fp_infinity: 372 infinity: 373 px->exponent = 0x7fff; 374 px->significand = 0; 375 *pz = 0; 376 *py = 0; 377 *pw = 0; 378 break; 379 case fp_quiet: 380 case fp_signaling: 381 px->exponent = 0x7fff; 382 px->significand = 0x8000 | pu->significand[0]; 383 /* 384 * Insure quiet 385 * nan. 386 */ 387 *py = pu->significand[1]; 388 *pz = pu->significand[2]; 389 *pw = pu->significand[3]; 390 break; 391 case fp_normal: 392 pu->exponent += EXTENDED_BIAS; 393 if (pu->exponent <= 0) { /* underflow */ 394 fpu_rightshift(pu, 1-pu->exponent); 395 round(pfpsd, pu); 396 if (pu->significand[0] < 0x00010000) { 397 /* 398 * not rounded 399 * back up 400 * to normal 401 */ 402 px->exponent = 0; 403 } else { 404 px->exponent = 1; 405 fpu_set_exception(pfpsd, fp_inexact); 406 } 407 if (pfpsd->fp_current_exceptions & (1 << fp_inexact)) 408 fpu_set_exception(pfpsd, fp_underflow); 409 if (pfpsd->fp_fsrtem & (1<<fp_underflow)) { 410 fpu_set_exception(pfpsd, fp_underflow); 411 pfpsd->fp_current_exceptions &= 412 ~(1 << (int)fp_inexact); 413 } 414 px->significand = pu->significand[0]; 415 *py = pu->significand[1]; 416 *pz = pu->significand[2]; 417 *pw = pu->significand[3]; 418 return; 419 } 420 round(pfpsd, pu); /* rounding overflow handled in round() */ 421 if (pu->exponent >= 0x7fff) { /* overflow */ 422 fpu_set_exception(pfpsd, fp_overflow); 423 fpu_set_exception(pfpsd, fp_inexact); 424 if (pfpsd->fp_fsrtem & (1<<fp_overflow)) { 425 pfpsd->fp_current_exceptions &= 426 ~(1 << (int)fp_inexact); 427 } 428 if (overflow_to_infinity(pfpsd, pu->sign)) 429 goto infinity; 430 px->exponent = 0x7ffe; /* overflow to max norm */ 431 px->significand = 0xffff; 432 *py = 0xffffffffU; 433 *pz = 0xffffffffU; 434 *pw = 0xffffffffU; 435 return; 436 } 437 px->exponent = pu->exponent; 438 px->significand = pu->significand[0]; 439 *py = pu->significand[1]; 440 *pz = pu->significand[2]; 441 *pw = pu->significand[3]; 442 break; 443 } 444 } 445 446 void 447 _fp_pack( 448 fp_simd_type *pfpsd, /* Pointer to simulator data */ 449 unpacked *pu, /* unpacked operand */ 450 uint_t n, /* register where datum starts */ 451 enum fp_op_type type) /* type of datum */ 452 453 { 454 switch (type) { 455 case fp_op_int32: 456 { 457 int32_t x; 458 459 packint32(pfpsd, pu, &x); 460 if (!(pfpsd->fp_current_exceptions & pfpsd->fp_fsrtem)) 461 pfpsd->fp_current_write_freg(&x, n, pfpsd); 462 break; 463 } 464 case fp_op_int64: 465 { 466 int64_t x; 467 468 packint64(pfpsd, pu, &x); 469 if ((n & 0x1) == 1) /* fix register encoding */ 470 n = (n & 0x1e) | 0x20; 471 if (!(pfpsd->fp_current_exceptions & pfpsd->fp_fsrtem)) 472 pfpsd->fp_current_write_dreg(&x, DOUBLE(n), pfpsd); 473 break; 474 } 475 case fp_op_single: 476 { 477 single_type x; 478 479 packsingle(pfpsd, pu, &x); 480 if (!(pfpsd->fp_current_exceptions & pfpsd->fp_fsrtem)) 481 pfpsd->fp_current_write_freg(&x, n, pfpsd); 482 break; 483 } 484 case fp_op_double: 485 { 486 union { 487 double_type x[2]; 488 uint32_t y[2]; 489 uint64_t ll; 490 } db; 491 492 packdouble(pfpsd, pu, &db.x[0], &db.y[1]); 493 if (!(pfpsd->fp_current_exceptions & 494 pfpsd->fp_fsrtem)) { 495 if ((n & 0x1) == 1) /* fix register encoding */ 496 n = (n & 0x1e) | 0x20; 497 pfpsd->fp_current_write_dreg(&db.ll, DOUBLE(n), 498 pfpsd); 499 } 500 break; 501 } 502 case fp_op_extended: 503 { 504 union { 505 extended_type x; 506 uint32_t y[4]; 507 uint64_t ll[2]; 508 } ex; 509 unpacked U; 510 int k; 511 switch (pfpsd->fp_precision) { 512 /* 513 * Implement extended 514 * rounding precision 515 * mode. 516 */ 517 case fp_single: 518 { 519 single_type tx; 520 521 packsingle(pfpsd, pu, &tx); 522 pu = &U; 523 unpacksingle(pfpsd, pu, tx); 524 break; 525 } 526 case fp_double: 527 { 528 double_type tx; 529 uint_t ty; 530 531 packdouble(pfpsd, pu, &tx, &ty); 532 pu = &U; 533 unpackdouble(pfpsd, pu, tx, ty); 534 break; 535 } 536 case fp_precision_3: /* rounded to 64 bits */ 537 { 538 k = pu->exponent + EXTENDED_BIAS; 539 if (k >= 0) k = 113-64; 540 else k = 113-64-k; 541 fpu_rightshift(pu, 113-64); 542 round(pfpsd, pu); 543 pu->sticky = pu->rounded = 0; 544 pu->exponent += k; 545 fpu_normalize(pu); 546 break; 547 } 548 } 549 packextended(pfpsd, pu, &ex.x, &ex.y[1], 550 &ex.y[2], &ex.y[3]); 551 if (!(pfpsd->fp_current_exceptions & 552 pfpsd->fp_fsrtem)) { 553 if ((n & 0x1) == 1) /* fix register encoding */ 554 n = (n & 0x1e) | 0x20; 555 pfpsd->fp_current_write_dreg(&ex.ll[0], 556 QUAD_E(n), pfpsd); 557 pfpsd->fp_current_write_dreg(&ex.ll[1], 558 QUAD_F(n), pfpsd); 559 } 560 561 break; 562 } 563 } 564 } 565 566 void 567 _fp_pack_word( 568 fp_simd_type *pfpsd, /* Pointer to simulator data */ 569 uint32_t *pu, /* unpacked operand */ 570 uint_t n) /* register where datum starts */ 571 { 572 pfpsd->fp_current_write_freg(pu, n, pfpsd); 573 } 574 575 void 576 _fp_pack_extword( 577 fp_simd_type *pfpsd, /* Pointer to simulator data */ 578 uint64_t *pu, /* unpacked operand */ 579 uint_t n) /* register where datum starts */ 580 { 581 if ((n & 1) == 1) /* fix register encoding */ 582 n = (n & 0x1e) | 0x20; 583 pfpsd->fp_current_write_dreg(pu, DOUBLE(n), pfpsd); 584 } 585