fp_arith.c (14665B)
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 4 fp_arith.c: floating-point math routines for the Linux-m68k 5 floating point emulator. 6 7 Copyright (c) 1998-1999 David Huggins-Daines. 8 9 Somewhat based on the AlphaLinux floating point emulator, by David 10 Mosberger-Tang. 11 12 */ 13 14#include "fp_emu.h" 15#include "multi_arith.h" 16#include "fp_arith.h" 17 18const struct fp_ext fp_QNaN = 19{ 20 .exp = 0x7fff, 21 .mant = { .m64 = ~0 } 22}; 23 24const struct fp_ext fp_Inf = 25{ 26 .exp = 0x7fff, 27}; 28 29/* let's start with the easy ones */ 30 31struct fp_ext * 32fp_fabs(struct fp_ext *dest, struct fp_ext *src) 33{ 34 dprint(PINSTR, "fabs\n"); 35 36 fp_monadic_check(dest, src); 37 38 dest->sign = 0; 39 40 return dest; 41} 42 43struct fp_ext * 44fp_fneg(struct fp_ext *dest, struct fp_ext *src) 45{ 46 dprint(PINSTR, "fneg\n"); 47 48 fp_monadic_check(dest, src); 49 50 dest->sign = !dest->sign; 51 52 return dest; 53} 54 55/* Now, the slightly harder ones */ 56 57/* fp_fadd: Implements the kernel of the FADD, FSADD, FDADD, FSUB, 58 FDSUB, and FCMP instructions. */ 59 60struct fp_ext * 61fp_fadd(struct fp_ext *dest, struct fp_ext *src) 62{ 63 int diff; 64 65 dprint(PINSTR, "fadd\n"); 66 67 fp_dyadic_check(dest, src); 68 69 if (IS_INF(dest)) { 70 /* infinity - infinity == NaN */ 71 if (IS_INF(src) && (src->sign != dest->sign)) 72 fp_set_nan(dest); 73 return dest; 74 } 75 if (IS_INF(src)) { 76 fp_copy_ext(dest, src); 77 return dest; 78 } 79 80 if (IS_ZERO(dest)) { 81 if (IS_ZERO(src)) { 82 if (src->sign != dest->sign) { 83 if (FPDATA->rnd == FPCR_ROUND_RM) 84 dest->sign = 1; 85 else 86 dest->sign = 0; 87 } 88 } else 89 fp_copy_ext(dest, src); 90 return dest; 91 } 92 93 dest->lowmant = src->lowmant = 0; 94 95 if ((diff = dest->exp - src->exp) > 0) 96 fp_denormalize(src, diff); 97 else if ((diff = -diff) > 0) 98 fp_denormalize(dest, diff); 99 100 if (dest->sign == src->sign) { 101 if (fp_addmant(dest, src)) 102 if (!fp_addcarry(dest)) 103 return dest; 104 } else { 105 if (dest->mant.m64 < src->mant.m64) { 106 fp_submant(dest, src, dest); 107 dest->sign = !dest->sign; 108 } else 109 fp_submant(dest, dest, src); 110 } 111 112 return dest; 113} 114 115/* fp_fsub: Implements the kernel of the FSUB, FSSUB, and FDSUB 116 instructions. 117 118 Remember that the arguments are in assembler-syntax order! */ 119 120struct fp_ext * 121fp_fsub(struct fp_ext *dest, struct fp_ext *src) 122{ 123 dprint(PINSTR, "fsub "); 124 125 src->sign = !src->sign; 126 return fp_fadd(dest, src); 127} 128 129 130struct fp_ext * 131fp_fcmp(struct fp_ext *dest, struct fp_ext *src) 132{ 133 dprint(PINSTR, "fcmp "); 134 135 FPDATA->temp[1] = *dest; 136 src->sign = !src->sign; 137 return fp_fadd(&FPDATA->temp[1], src); 138} 139 140struct fp_ext * 141fp_ftst(struct fp_ext *dest, struct fp_ext *src) 142{ 143 dprint(PINSTR, "ftst\n"); 144 145 (void)dest; 146 147 return src; 148} 149 150struct fp_ext * 151fp_fmul(struct fp_ext *dest, struct fp_ext *src) 152{ 153 union fp_mant128 temp; 154 int exp; 155 156 dprint(PINSTR, "fmul\n"); 157 158 fp_dyadic_check(dest, src); 159 160 /* calculate the correct sign now, as it's necessary for infinities */ 161 dest->sign = src->sign ^ dest->sign; 162 163 /* Handle infinities */ 164 if (IS_INF(dest)) { 165 if (IS_ZERO(src)) 166 fp_set_nan(dest); 167 return dest; 168 } 169 if (IS_INF(src)) { 170 if (IS_ZERO(dest)) 171 fp_set_nan(dest); 172 else 173 fp_copy_ext(dest, src); 174 return dest; 175 } 176 177 /* Of course, as we all know, zero * anything = zero. You may 178 not have known that it might be a positive or negative 179 zero... */ 180 if (IS_ZERO(dest) || IS_ZERO(src)) { 181 dest->exp = 0; 182 dest->mant.m64 = 0; 183 dest->lowmant = 0; 184 185 return dest; 186 } 187 188 exp = dest->exp + src->exp - 0x3ffe; 189 190 /* shift up the mantissa for denormalized numbers, 191 so that the highest bit is set, this makes the 192 shift of the result below easier */ 193 if ((long)dest->mant.m32[0] >= 0) 194 exp -= fp_overnormalize(dest); 195 if ((long)src->mant.m32[0] >= 0) 196 exp -= fp_overnormalize(src); 197 198 /* now, do a 64-bit multiply with expansion */ 199 fp_multiplymant(&temp, dest, src); 200 201 /* normalize it back to 64 bits and stuff it back into the 202 destination struct */ 203 if ((long)temp.m32[0] > 0) { 204 exp--; 205 fp_putmant128(dest, &temp, 1); 206 } else 207 fp_putmant128(dest, &temp, 0); 208 209 if (exp >= 0x7fff) { 210 fp_set_ovrflw(dest); 211 return dest; 212 } 213 dest->exp = exp; 214 if (exp < 0) { 215 fp_set_sr(FPSR_EXC_UNFL); 216 fp_denormalize(dest, -exp); 217 } 218 219 return dest; 220} 221 222/* fp_fdiv: Implements the "kernel" of the FDIV, FSDIV, FDDIV and 223 FSGLDIV instructions. 224 225 Note that the order of the operands is counter-intuitive: instead 226 of src / dest, the result is actually dest / src. */ 227 228struct fp_ext * 229fp_fdiv(struct fp_ext *dest, struct fp_ext *src) 230{ 231 union fp_mant128 temp; 232 int exp; 233 234 dprint(PINSTR, "fdiv\n"); 235 236 fp_dyadic_check(dest, src); 237 238 /* calculate the correct sign now, as it's necessary for infinities */ 239 dest->sign = src->sign ^ dest->sign; 240 241 /* Handle infinities */ 242 if (IS_INF(dest)) { 243 /* infinity / infinity = NaN (quiet, as always) */ 244 if (IS_INF(src)) 245 fp_set_nan(dest); 246 /* infinity / anything else = infinity (with appropriate sign) */ 247 return dest; 248 } 249 if (IS_INF(src)) { 250 /* anything / infinity = zero (with appropriate sign) */ 251 dest->exp = 0; 252 dest->mant.m64 = 0; 253 dest->lowmant = 0; 254 255 return dest; 256 } 257 258 /* zeroes */ 259 if (IS_ZERO(dest)) { 260 /* zero / zero = NaN */ 261 if (IS_ZERO(src)) 262 fp_set_nan(dest); 263 /* zero / anything else = zero */ 264 return dest; 265 } 266 if (IS_ZERO(src)) { 267 /* anything / zero = infinity (with appropriate sign) */ 268 fp_set_sr(FPSR_EXC_DZ); 269 dest->exp = 0x7fff; 270 dest->mant.m64 = 0; 271 272 return dest; 273 } 274 275 exp = dest->exp - src->exp + 0x3fff; 276 277 /* shift up the mantissa for denormalized numbers, 278 so that the highest bit is set, this makes lots 279 of things below easier */ 280 if ((long)dest->mant.m32[0] >= 0) 281 exp -= fp_overnormalize(dest); 282 if ((long)src->mant.m32[0] >= 0) 283 exp -= fp_overnormalize(src); 284 285 /* now, do the 64-bit divide */ 286 fp_dividemant(&temp, dest, src); 287 288 /* normalize it back to 64 bits and stuff it back into the 289 destination struct */ 290 if (!temp.m32[0]) { 291 exp--; 292 fp_putmant128(dest, &temp, 32); 293 } else 294 fp_putmant128(dest, &temp, 31); 295 296 if (exp >= 0x7fff) { 297 fp_set_ovrflw(dest); 298 return dest; 299 } 300 dest->exp = exp; 301 if (exp < 0) { 302 fp_set_sr(FPSR_EXC_UNFL); 303 fp_denormalize(dest, -exp); 304 } 305 306 return dest; 307} 308 309struct fp_ext * 310fp_fsglmul(struct fp_ext *dest, struct fp_ext *src) 311{ 312 int exp; 313 314 dprint(PINSTR, "fsglmul\n"); 315 316 fp_dyadic_check(dest, src); 317 318 /* calculate the correct sign now, as it's necessary for infinities */ 319 dest->sign = src->sign ^ dest->sign; 320 321 /* Handle infinities */ 322 if (IS_INF(dest)) { 323 if (IS_ZERO(src)) 324 fp_set_nan(dest); 325 return dest; 326 } 327 if (IS_INF(src)) { 328 if (IS_ZERO(dest)) 329 fp_set_nan(dest); 330 else 331 fp_copy_ext(dest, src); 332 return dest; 333 } 334 335 /* Of course, as we all know, zero * anything = zero. You may 336 not have known that it might be a positive or negative 337 zero... */ 338 if (IS_ZERO(dest) || IS_ZERO(src)) { 339 dest->exp = 0; 340 dest->mant.m64 = 0; 341 dest->lowmant = 0; 342 343 return dest; 344 } 345 346 exp = dest->exp + src->exp - 0x3ffe; 347 348 /* do a 32-bit multiply */ 349 fp_mul64(dest->mant.m32[0], dest->mant.m32[1], 350 dest->mant.m32[0] & 0xffffff00, 351 src->mant.m32[0] & 0xffffff00); 352 353 if (exp >= 0x7fff) { 354 fp_set_ovrflw(dest); 355 return dest; 356 } 357 dest->exp = exp; 358 if (exp < 0) { 359 fp_set_sr(FPSR_EXC_UNFL); 360 fp_denormalize(dest, -exp); 361 } 362 363 return dest; 364} 365 366struct fp_ext * 367fp_fsgldiv(struct fp_ext *dest, struct fp_ext *src) 368{ 369 int exp; 370 unsigned long quot, rem; 371 372 dprint(PINSTR, "fsgldiv\n"); 373 374 fp_dyadic_check(dest, src); 375 376 /* calculate the correct sign now, as it's necessary for infinities */ 377 dest->sign = src->sign ^ dest->sign; 378 379 /* Handle infinities */ 380 if (IS_INF(dest)) { 381 /* infinity / infinity = NaN (quiet, as always) */ 382 if (IS_INF(src)) 383 fp_set_nan(dest); 384 /* infinity / anything else = infinity (with approprate sign) */ 385 return dest; 386 } 387 if (IS_INF(src)) { 388 /* anything / infinity = zero (with appropriate sign) */ 389 dest->exp = 0; 390 dest->mant.m64 = 0; 391 dest->lowmant = 0; 392 393 return dest; 394 } 395 396 /* zeroes */ 397 if (IS_ZERO(dest)) { 398 /* zero / zero = NaN */ 399 if (IS_ZERO(src)) 400 fp_set_nan(dest); 401 /* zero / anything else = zero */ 402 return dest; 403 } 404 if (IS_ZERO(src)) { 405 /* anything / zero = infinity (with appropriate sign) */ 406 fp_set_sr(FPSR_EXC_DZ); 407 dest->exp = 0x7fff; 408 dest->mant.m64 = 0; 409 410 return dest; 411 } 412 413 exp = dest->exp - src->exp + 0x3fff; 414 415 dest->mant.m32[0] &= 0xffffff00; 416 src->mant.m32[0] &= 0xffffff00; 417 418 /* do the 32-bit divide */ 419 if (dest->mant.m32[0] >= src->mant.m32[0]) { 420 fp_sub64(dest->mant, src->mant); 421 fp_div64(quot, rem, dest->mant.m32[0], 0, src->mant.m32[0]); 422 dest->mant.m32[0] = 0x80000000 | (quot >> 1); 423 dest->mant.m32[1] = (quot & 1) | rem; /* only for rounding */ 424 } else { 425 fp_div64(quot, rem, dest->mant.m32[0], 0, src->mant.m32[0]); 426 dest->mant.m32[0] = quot; 427 dest->mant.m32[1] = rem; /* only for rounding */ 428 exp--; 429 } 430 431 if (exp >= 0x7fff) { 432 fp_set_ovrflw(dest); 433 return dest; 434 } 435 dest->exp = exp; 436 if (exp < 0) { 437 fp_set_sr(FPSR_EXC_UNFL); 438 fp_denormalize(dest, -exp); 439 } 440 441 return dest; 442} 443 444/* fp_roundint: Internal rounding function for use by several of these 445 emulated instructions. 446 447 This one rounds off the fractional part using the rounding mode 448 specified. */ 449 450static void fp_roundint(struct fp_ext *dest, int mode) 451{ 452 union fp_mant64 oldmant; 453 unsigned long mask; 454 455 if (!fp_normalize_ext(dest)) 456 return; 457 458 /* infinities and zeroes */ 459 if (IS_INF(dest) || IS_ZERO(dest)) 460 return; 461 462 /* first truncate the lower bits */ 463 oldmant = dest->mant; 464 switch (dest->exp) { 465 case 0 ... 0x3ffe: 466 dest->mant.m64 = 0; 467 break; 468 case 0x3fff ... 0x401e: 469 dest->mant.m32[0] &= 0xffffffffU << (0x401e - dest->exp); 470 dest->mant.m32[1] = 0; 471 if (oldmant.m64 == dest->mant.m64) 472 return; 473 break; 474 case 0x401f ... 0x403e: 475 dest->mant.m32[1] &= 0xffffffffU << (0x403e - dest->exp); 476 if (oldmant.m32[1] == dest->mant.m32[1]) 477 return; 478 break; 479 default: 480 return; 481 } 482 fp_set_sr(FPSR_EXC_INEX2); 483 484 /* We might want to normalize upwards here... however, since 485 we know that this is only called on the output of fp_fdiv, 486 or with the input to fp_fint or fp_fintrz, and the inputs 487 to all these functions are either normal or denormalized 488 (no subnormals allowed!), there's really no need. 489 490 In the case of fp_fdiv, observe that 0x80000000 / 0xffff = 491 0xffff8000, and the same holds for 128-bit / 64-bit. (i.e. the 492 smallest possible normal dividend and the largest possible normal 493 divisor will still produce a normal quotient, therefore, (normal 494 << 64) / normal is normal in all cases) */ 495 496 switch (mode) { 497 case FPCR_ROUND_RN: 498 switch (dest->exp) { 499 case 0 ... 0x3ffd: 500 return; 501 case 0x3ffe: 502 /* As noted above, the input is always normal, so the 503 guard bit (bit 63) is always set. therefore, the 504 only case in which we will NOT round to 1.0 is when 505 the input is exactly 0.5. */ 506 if (oldmant.m64 == (1ULL << 63)) 507 return; 508 break; 509 case 0x3fff ... 0x401d: 510 mask = 1 << (0x401d - dest->exp); 511 if (!(oldmant.m32[0] & mask)) 512 return; 513 if (oldmant.m32[0] & (mask << 1)) 514 break; 515 if (!(oldmant.m32[0] << (dest->exp - 0x3ffd)) && 516 !oldmant.m32[1]) 517 return; 518 break; 519 case 0x401e: 520 if (oldmant.m32[1] & 0x80000000) 521 return; 522 if (oldmant.m32[0] & 1) 523 break; 524 if (!(oldmant.m32[1] << 1)) 525 return; 526 break; 527 case 0x401f ... 0x403d: 528 mask = 1 << (0x403d - dest->exp); 529 if (!(oldmant.m32[1] & mask)) 530 return; 531 if (oldmant.m32[1] & (mask << 1)) 532 break; 533 if (!(oldmant.m32[1] << (dest->exp - 0x401d))) 534 return; 535 break; 536 default: 537 return; 538 } 539 break; 540 case FPCR_ROUND_RZ: 541 return; 542 default: 543 if (dest->sign ^ (mode - FPCR_ROUND_RM)) 544 break; 545 return; 546 } 547 548 switch (dest->exp) { 549 case 0 ... 0x3ffe: 550 dest->exp = 0x3fff; 551 dest->mant.m64 = 1ULL << 63; 552 break; 553 case 0x3fff ... 0x401e: 554 mask = 1 << (0x401e - dest->exp); 555 if (dest->mant.m32[0] += mask) 556 break; 557 dest->mant.m32[0] = 0x80000000; 558 dest->exp++; 559 break; 560 case 0x401f ... 0x403e: 561 mask = 1 << (0x403e - dest->exp); 562 if (dest->mant.m32[1] += mask) 563 break; 564 if (dest->mant.m32[0] += 1) 565 break; 566 dest->mant.m32[0] = 0x80000000; 567 dest->exp++; 568 break; 569 } 570} 571 572/* modrem_kernel: Implementation of the FREM and FMOD instructions 573 (which are exactly the same, except for the rounding used on the 574 intermediate value) */ 575 576static struct fp_ext * 577modrem_kernel(struct fp_ext *dest, struct fp_ext *src, int mode) 578{ 579 struct fp_ext tmp; 580 581 fp_dyadic_check(dest, src); 582 583 /* Infinities and zeros */ 584 if (IS_INF(dest) || IS_ZERO(src)) { 585 fp_set_nan(dest); 586 return dest; 587 } 588 if (IS_ZERO(dest) || IS_INF(src)) 589 return dest; 590 591 /* FIXME: there is almost certainly a smarter way to do this */ 592 fp_copy_ext(&tmp, dest); 593 fp_fdiv(&tmp, src); /* NOTE: src might be modified */ 594 fp_roundint(&tmp, mode); 595 fp_fmul(&tmp, src); 596 fp_fsub(dest, &tmp); 597 598 /* set the quotient byte */ 599 fp_set_quotient((dest->mant.m64 & 0x7f) | (dest->sign << 7)); 600 return dest; 601} 602 603/* fp_fmod: Implements the kernel of the FMOD instruction. 604 605 Again, the argument order is backwards. The result, as defined in 606 the Motorola manuals, is: 607 608 fmod(src,dest) = (dest - (src * floor(dest / src))) */ 609 610struct fp_ext * 611fp_fmod(struct fp_ext *dest, struct fp_ext *src) 612{ 613 dprint(PINSTR, "fmod\n"); 614 return modrem_kernel(dest, src, FPCR_ROUND_RZ); 615} 616 617/* fp_frem: Implements the kernel of the FREM instruction. 618 619 frem(src,dest) = (dest - (src * round(dest / src))) 620 */ 621 622struct fp_ext * 623fp_frem(struct fp_ext *dest, struct fp_ext *src) 624{ 625 dprint(PINSTR, "frem\n"); 626 return modrem_kernel(dest, src, FPCR_ROUND_RN); 627} 628 629struct fp_ext * 630fp_fint(struct fp_ext *dest, struct fp_ext *src) 631{ 632 dprint(PINSTR, "fint\n"); 633 634 fp_copy_ext(dest, src); 635 636 fp_roundint(dest, FPDATA->rnd); 637 638 return dest; 639} 640 641struct fp_ext * 642fp_fintrz(struct fp_ext *dest, struct fp_ext *src) 643{ 644 dprint(PINSTR, "fintrz\n"); 645 646 fp_copy_ext(dest, src); 647 648 fp_roundint(dest, FPCR_ROUND_RZ); 649 650 return dest; 651} 652 653struct fp_ext * 654fp_fscale(struct fp_ext *dest, struct fp_ext *src) 655{ 656 int scale, oldround; 657 658 dprint(PINSTR, "fscale\n"); 659 660 fp_dyadic_check(dest, src); 661 662 /* Infinities */ 663 if (IS_INF(src)) { 664 fp_set_nan(dest); 665 return dest; 666 } 667 if (IS_INF(dest)) 668 return dest; 669 670 /* zeroes */ 671 if (IS_ZERO(src) || IS_ZERO(dest)) 672 return dest; 673 674 /* Source exponent out of range */ 675 if (src->exp >= 0x400c) { 676 fp_set_ovrflw(dest); 677 return dest; 678 } 679 680 /* src must be rounded with round to zero. */ 681 oldround = FPDATA->rnd; 682 FPDATA->rnd = FPCR_ROUND_RZ; 683 scale = fp_conv_ext2long(src); 684 FPDATA->rnd = oldround; 685 686 /* new exponent */ 687 scale += dest->exp; 688 689 if (scale >= 0x7fff) { 690 fp_set_ovrflw(dest); 691 } else if (scale <= 0) { 692 fp_set_sr(FPSR_EXC_UNFL); 693 fp_denormalize(dest, -scale); 694 } else 695 dest->exp = scale; 696 697 return dest; 698} 699