1 /* 2 * FPU op helpers 3 * 4 * Copyright (c) 2003-2005 Fabrice Bellard 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, see <http://www.gnu.org/licenses/>. 18 */ 19 20 #include "qemu/osdep.h" 21 #include "cpu.h" 22 #include "exec/helper-proto.h" 23 #include "fpu/softfloat.h" 24 25 static inline float128 f128_in(Int128 i) 26 { 27 union { 28 Int128 i; 29 float128 f; 30 } u; 31 32 u.i = i; 33 return u.f; 34 } 35 36 static inline Int128 f128_ret(float128 f) 37 { 38 union { 39 Int128 i; 40 float128 f; 41 } u; 42 43 u.f = f; 44 return u.i; 45 } 46 47 static void check_ieee_exceptions(CPUSPARCState *env, uintptr_t ra) 48 { 49 target_ulong status = get_float_exception_flags(&env->fp_status); 50 uint32_t cexc = 0; 51 52 if (unlikely(status)) { 53 /* Keep exception flags clear for next time. */ 54 set_float_exception_flags(0, &env->fp_status); 55 56 /* Copy IEEE 754 flags into FSR */ 57 if (status & float_flag_invalid) { 58 cexc |= FSR_NVC; 59 } 60 if (status & float_flag_overflow) { 61 cexc |= FSR_OFC; 62 } 63 if (status & float_flag_underflow) { 64 cexc |= FSR_UFC; 65 } 66 if (status & float_flag_divbyzero) { 67 cexc |= FSR_DZC; 68 } 69 if (status & float_flag_inexact) { 70 cexc |= FSR_NXC; 71 } 72 73 if (cexc & (env->fsr >> FSR_TEM_SHIFT)) { 74 /* Unmasked exception, generate an IEEE trap. */ 75 env->fsr_cexc_ftt = cexc | FSR_FTT_IEEE_EXCP; 76 cpu_raise_exception_ra(env, TT_FP_EXCP, ra); 77 } 78 79 /* Accumulate exceptions */ 80 env->fsr |= cexc << FSR_AEXC_SHIFT; 81 } 82 83 /* No trap, so FTT is cleared. */ 84 env->fsr_cexc_ftt = cexc; 85 } 86 87 float32 helper_fadds(CPUSPARCState *env, float32 src1, float32 src2) 88 { 89 float32 ret = float32_add(src1, src2, &env->fp_status); 90 check_ieee_exceptions(env, GETPC()); 91 return ret; 92 } 93 94 float32 helper_fsubs(CPUSPARCState *env, float32 src1, float32 src2) 95 { 96 float32 ret = float32_sub(src1, src2, &env->fp_status); 97 check_ieee_exceptions(env, GETPC()); 98 return ret; 99 } 100 101 float32 helper_fmuls(CPUSPARCState *env, float32 src1, float32 src2) 102 { 103 float32 ret = float32_mul(src1, src2, &env->fp_status); 104 check_ieee_exceptions(env, GETPC()); 105 return ret; 106 } 107 108 float32 helper_fdivs(CPUSPARCState *env, float32 src1, float32 src2) 109 { 110 float32 ret = float32_div(src1, src2, &env->fp_status); 111 check_ieee_exceptions(env, GETPC()); 112 return ret; 113 } 114 115 float64 helper_faddd(CPUSPARCState *env, float64 src1, float64 src2) 116 { 117 float64 ret = float64_add(src1, src2, &env->fp_status); 118 check_ieee_exceptions(env, GETPC()); 119 return ret; 120 } 121 122 float64 helper_fsubd(CPUSPARCState *env, float64 src1, float64 src2) 123 { 124 float64 ret = float64_sub(src1, src2, &env->fp_status); 125 check_ieee_exceptions(env, GETPC()); 126 return ret; 127 } 128 129 float64 helper_fmuld(CPUSPARCState *env, float64 src1, float64 src2) 130 { 131 float64 ret = float64_mul(src1, src2, &env->fp_status); 132 check_ieee_exceptions(env, GETPC()); 133 return ret; 134 } 135 136 float64 helper_fdivd(CPUSPARCState *env, float64 src1, float64 src2) 137 { 138 float64 ret = float64_div(src1, src2, &env->fp_status); 139 check_ieee_exceptions(env, GETPC()); 140 return ret; 141 } 142 143 Int128 helper_faddq(CPUSPARCState *env, Int128 src1, Int128 src2) 144 { 145 float128 ret = float128_add(f128_in(src1), f128_in(src2), &env->fp_status); 146 check_ieee_exceptions(env, GETPC()); 147 return f128_ret(ret); 148 } 149 150 Int128 helper_fsubq(CPUSPARCState *env, Int128 src1, Int128 src2) 151 { 152 float128 ret = float128_sub(f128_in(src1), f128_in(src2), &env->fp_status); 153 check_ieee_exceptions(env, GETPC()); 154 return f128_ret(ret); 155 } 156 157 Int128 helper_fmulq(CPUSPARCState *env, Int128 src1, Int128 src2) 158 { 159 float128 ret = float128_mul(f128_in(src1), f128_in(src2), &env->fp_status); 160 check_ieee_exceptions(env, GETPC()); 161 return f128_ret(ret); 162 } 163 164 Int128 helper_fdivq(CPUSPARCState *env, Int128 src1, Int128 src2) 165 { 166 float128 ret = float128_div(f128_in(src1), f128_in(src2), &env->fp_status); 167 check_ieee_exceptions(env, GETPC()); 168 return f128_ret(ret); 169 } 170 171 float64 helper_fsmuld(CPUSPARCState *env, float32 src1, float32 src2) 172 { 173 float64 ret = float64_mul(float32_to_float64(src1, &env->fp_status), 174 float32_to_float64(src2, &env->fp_status), 175 &env->fp_status); 176 check_ieee_exceptions(env, GETPC()); 177 return ret; 178 } 179 180 Int128 helper_fdmulq(CPUSPARCState *env, float64 src1, float64 src2) 181 { 182 float128 ret = float128_mul(float64_to_float128(src1, &env->fp_status), 183 float64_to_float128(src2, &env->fp_status), 184 &env->fp_status); 185 check_ieee_exceptions(env, GETPC()); 186 return f128_ret(ret); 187 } 188 189 /* Integer to float conversion. */ 190 float32 helper_fitos(CPUSPARCState *env, int32_t src) 191 { 192 float32 ret = int32_to_float32(src, &env->fp_status); 193 check_ieee_exceptions(env, GETPC()); 194 return ret; 195 } 196 197 float64 helper_fitod(CPUSPARCState *env, int32_t src) 198 { 199 float64 ret = int32_to_float64(src, &env->fp_status); 200 check_ieee_exceptions(env, GETPC()); 201 return ret; 202 } 203 204 Int128 helper_fitoq(CPUSPARCState *env, int32_t src) 205 { 206 float128 ret = int32_to_float128(src, &env->fp_status); 207 check_ieee_exceptions(env, GETPC()); 208 return f128_ret(ret); 209 } 210 211 #ifdef TARGET_SPARC64 212 float32 helper_fxtos(CPUSPARCState *env, int64_t src) 213 { 214 float32 ret = int64_to_float32(src, &env->fp_status); 215 check_ieee_exceptions(env, GETPC()); 216 return ret; 217 } 218 219 float64 helper_fxtod(CPUSPARCState *env, int64_t src) 220 { 221 float64 ret = int64_to_float64(src, &env->fp_status); 222 check_ieee_exceptions(env, GETPC()); 223 return ret; 224 } 225 226 Int128 helper_fxtoq(CPUSPARCState *env, int64_t src) 227 { 228 float128 ret = int64_to_float128(src, &env->fp_status); 229 check_ieee_exceptions(env, GETPC()); 230 return f128_ret(ret); 231 } 232 #endif 233 234 /* floating point conversion */ 235 float32 helper_fdtos(CPUSPARCState *env, float64 src) 236 { 237 float32 ret = float64_to_float32(src, &env->fp_status); 238 check_ieee_exceptions(env, GETPC()); 239 return ret; 240 } 241 242 float64 helper_fstod(CPUSPARCState *env, float32 src) 243 { 244 float64 ret = float32_to_float64(src, &env->fp_status); 245 check_ieee_exceptions(env, GETPC()); 246 return ret; 247 } 248 249 float32 helper_fqtos(CPUSPARCState *env, Int128 src) 250 { 251 float32 ret = float128_to_float32(f128_in(src), &env->fp_status); 252 check_ieee_exceptions(env, GETPC()); 253 return ret; 254 } 255 256 Int128 helper_fstoq(CPUSPARCState *env, float32 src) 257 { 258 float128 ret = float32_to_float128(src, &env->fp_status); 259 check_ieee_exceptions(env, GETPC()); 260 return f128_ret(ret); 261 } 262 263 float64 helper_fqtod(CPUSPARCState *env, Int128 src) 264 { 265 float64 ret = float128_to_float64(f128_in(src), &env->fp_status); 266 check_ieee_exceptions(env, GETPC()); 267 return ret; 268 } 269 270 Int128 helper_fdtoq(CPUSPARCState *env, float64 src) 271 { 272 float128 ret = float64_to_float128(src, &env->fp_status); 273 check_ieee_exceptions(env, GETPC()); 274 return f128_ret(ret); 275 } 276 277 /* Float to integer conversion. */ 278 int32_t helper_fstoi(CPUSPARCState *env, float32 src) 279 { 280 int32_t ret = float32_to_int32_round_to_zero(src, &env->fp_status); 281 check_ieee_exceptions(env, GETPC()); 282 return ret; 283 } 284 285 int32_t helper_fdtoi(CPUSPARCState *env, float64 src) 286 { 287 int32_t ret = float64_to_int32_round_to_zero(src, &env->fp_status); 288 check_ieee_exceptions(env, GETPC()); 289 return ret; 290 } 291 292 int32_t helper_fqtoi(CPUSPARCState *env, Int128 src) 293 { 294 int32_t ret = float128_to_int32_round_to_zero(f128_in(src), 295 &env->fp_status); 296 check_ieee_exceptions(env, GETPC()); 297 return ret; 298 } 299 300 #ifdef TARGET_SPARC64 301 int64_t helper_fstox(CPUSPARCState *env, float32 src) 302 { 303 int64_t ret = float32_to_int64_round_to_zero(src, &env->fp_status); 304 check_ieee_exceptions(env, GETPC()); 305 return ret; 306 } 307 308 int64_t helper_fdtox(CPUSPARCState *env, float64 src) 309 { 310 int64_t ret = float64_to_int64_round_to_zero(src, &env->fp_status); 311 check_ieee_exceptions(env, GETPC()); 312 return ret; 313 } 314 315 int64_t helper_fqtox(CPUSPARCState *env, Int128 src) 316 { 317 int64_t ret = float128_to_int64_round_to_zero(f128_in(src), 318 &env->fp_status); 319 check_ieee_exceptions(env, GETPC()); 320 return ret; 321 } 322 #endif 323 324 float32 helper_fsqrts(CPUSPARCState *env, float32 src) 325 { 326 float32 ret = float32_sqrt(src, &env->fp_status); 327 check_ieee_exceptions(env, GETPC()); 328 return ret; 329 } 330 331 float64 helper_fsqrtd(CPUSPARCState *env, float64 src) 332 { 333 float64 ret = float64_sqrt(src, &env->fp_status); 334 check_ieee_exceptions(env, GETPC()); 335 return ret; 336 } 337 338 Int128 helper_fsqrtq(CPUSPARCState *env, Int128 src) 339 { 340 float128 ret = float128_sqrt(f128_in(src), &env->fp_status); 341 check_ieee_exceptions(env, GETPC()); 342 return f128_ret(ret); 343 } 344 345 float32 helper_fmadds(CPUSPARCState *env, float32 s1, 346 float32 s2, float32 s3, int32_t sc, uint32_t op) 347 { 348 float32 ret = float32_muladd_scalbn(s1, s2, s3, sc, op, &env->fp_status); 349 check_ieee_exceptions(env, GETPC()); 350 return ret; 351 } 352 353 float64 helper_fmaddd(CPUSPARCState *env, float64 s1, 354 float64 s2, float64 s3, int32_t sc, uint32_t op) 355 { 356 float64 ret = float64_muladd_scalbn(s1, s2, s3, sc, op, &env->fp_status); 357 check_ieee_exceptions(env, GETPC()); 358 return ret; 359 } 360 361 float32 helper_fnadds(CPUSPARCState *env, float32 src1, float32 src2) 362 { 363 float32 ret = float32_add(src1, src2, &env->fp_status); 364 365 /* 366 * NaN inputs or result do not get a sign change. 367 * Nor, apparently, does zero: on hardware, -(x + -x) yields +0. 368 */ 369 if (!float32_is_any_nan(ret) && !float32_is_zero(ret)) { 370 ret = float32_chs(ret); 371 } 372 check_ieee_exceptions(env, GETPC()); 373 return ret; 374 } 375 376 float32 helper_fnmuls(CPUSPARCState *env, float32 src1, float32 src2) 377 { 378 float32 ret = float32_mul(src1, src2, &env->fp_status); 379 380 /* NaN inputs or result do not get a sign change. */ 381 if (!float32_is_any_nan(ret)) { 382 ret = float32_chs(ret); 383 } 384 check_ieee_exceptions(env, GETPC()); 385 return ret; 386 } 387 388 float64 helper_fnaddd(CPUSPARCState *env, float64 src1, float64 src2) 389 { 390 float64 ret = float64_add(src1, src2, &env->fp_status); 391 392 /* 393 * NaN inputs or result do not get a sign change. 394 * Nor, apparently, does zero: on hardware, -(x + -x) yields +0. 395 */ 396 if (!float64_is_any_nan(ret) && !float64_is_zero(ret)) { 397 ret = float64_chs(ret); 398 } 399 check_ieee_exceptions(env, GETPC()); 400 return ret; 401 } 402 403 float64 helper_fnmuld(CPUSPARCState *env, float64 src1, float64 src2) 404 { 405 float64 ret = float64_mul(src1, src2, &env->fp_status); 406 407 /* NaN inputs or result do not get a sign change. */ 408 if (!float64_is_any_nan(ret)) { 409 ret = float64_chs(ret); 410 } 411 check_ieee_exceptions(env, GETPC()); 412 return ret; 413 } 414 415 float64 helper_fnsmuld(CPUSPARCState *env, float32 src1, float32 src2) 416 { 417 float64 ret = float64_mul(float32_to_float64(src1, &env->fp_status), 418 float32_to_float64(src2, &env->fp_status), 419 &env->fp_status); 420 421 /* NaN inputs or result do not get a sign change. */ 422 if (!float64_is_any_nan(ret)) { 423 ret = float64_chs(ret); 424 } 425 check_ieee_exceptions(env, GETPC()); 426 return ret; 427 } 428 429 static uint32_t finish_fcmp(CPUSPARCState *env, FloatRelation r, uintptr_t ra) 430 { 431 check_ieee_exceptions(env, ra); 432 433 /* 434 * FCC values: 435 * 0 = 436 * 1 < 437 * 2 > 438 * 3 unordered 439 */ 440 switch (r) { 441 case float_relation_equal: 442 return 0; 443 case float_relation_less: 444 return 1; 445 case float_relation_greater: 446 return 2; 447 case float_relation_unordered: 448 return 3; 449 } 450 g_assert_not_reached(); 451 } 452 453 uint32_t helper_fcmps(CPUSPARCState *env, float32 src1, float32 src2) 454 { 455 FloatRelation r = float32_compare_quiet(src1, src2, &env->fp_status); 456 return finish_fcmp(env, r, GETPC()); 457 } 458 459 uint32_t helper_fcmpes(CPUSPARCState *env, float32 src1, float32 src2) 460 { 461 FloatRelation r = float32_compare(src1, src2, &env->fp_status); 462 return finish_fcmp(env, r, GETPC()); 463 } 464 465 uint32_t helper_fcmpd(CPUSPARCState *env, float64 src1, float64 src2) 466 { 467 FloatRelation r = float64_compare_quiet(src1, src2, &env->fp_status); 468 return finish_fcmp(env, r, GETPC()); 469 } 470 471 uint32_t helper_fcmped(CPUSPARCState *env, float64 src1, float64 src2) 472 { 473 FloatRelation r = float64_compare(src1, src2, &env->fp_status); 474 return finish_fcmp(env, r, GETPC()); 475 } 476 477 uint32_t helper_fcmpq(CPUSPARCState *env, Int128 src1, Int128 src2) 478 { 479 FloatRelation r = float128_compare_quiet(f128_in(src1), f128_in(src2), 480 &env->fp_status); 481 return finish_fcmp(env, r, GETPC()); 482 } 483 484 uint32_t helper_fcmpeq(CPUSPARCState *env, Int128 src1, Int128 src2) 485 { 486 FloatRelation r = float128_compare(f128_in(src1), f128_in(src2), 487 &env->fp_status); 488 return finish_fcmp(env, r, GETPC()); 489 } 490 491 uint32_t helper_flcmps(CPUSPARCState *env, float32 src1, float32 src2) 492 { 493 /* 494 * FLCMP never raises an exception nor modifies any FSR fields. 495 * Perform the comparison with a dummy fp environment. 496 */ 497 float_status discard = env->fp_status; 498 FloatRelation r; 499 500 set_float_2nan_prop_rule(float_2nan_prop_s_ba, &discard); 501 r = float32_compare_quiet(src1, src2, &discard); 502 503 switch (r) { 504 case float_relation_equal: 505 if (src2 == float32_zero && src1 != float32_zero) { 506 return 1; /* -0.0 < +0.0 */ 507 } 508 return 0; 509 case float_relation_less: 510 return 1; 511 case float_relation_greater: 512 return 0; 513 case float_relation_unordered: 514 return float32_is_any_nan(src2) ? 3 : 2; 515 } 516 g_assert_not_reached(); 517 } 518 519 uint32_t helper_flcmpd(CPUSPARCState *env, float64 src1, float64 src2) 520 { 521 float_status discard = env->fp_status; 522 FloatRelation r; 523 524 set_float_2nan_prop_rule(float_2nan_prop_s_ba, &discard); 525 r = float64_compare_quiet(src1, src2, &discard); 526 527 switch (r) { 528 case float_relation_equal: 529 if (src2 == float64_zero && src1 != float64_zero) { 530 return 1; /* -0.0 < +0.0 */ 531 } 532 return 0; 533 case float_relation_less: 534 return 1; 535 case float_relation_greater: 536 return 0; 537 case float_relation_unordered: 538 return float64_is_any_nan(src2) ? 3 : 2; 539 } 540 g_assert_not_reached(); 541 } 542 543 target_ulong cpu_get_fsr(CPUSPARCState *env) 544 { 545 target_ulong fsr = env->fsr | env->fsr_cexc_ftt; 546 547 fsr |= env->fcc[0] << FSR_FCC0_SHIFT; 548 #ifdef TARGET_SPARC64 549 fsr |= (uint64_t)env->fcc[1] << FSR_FCC1_SHIFT; 550 fsr |= (uint64_t)env->fcc[2] << FSR_FCC2_SHIFT; 551 fsr |= (uint64_t)env->fcc[3] << FSR_FCC3_SHIFT; 552 #elif !defined(CONFIG_USER_ONLY) 553 fsr |= env->fsr_qne; 554 #endif 555 556 /* VER is kept completely separate until re-assembly. */ 557 fsr |= env->def.fpu_version; 558 559 return fsr; 560 } 561 562 target_ulong helper_get_fsr(CPUSPARCState *env) 563 { 564 return cpu_get_fsr(env); 565 } 566 567 static void set_fsr_nonsplit(CPUSPARCState *env, target_ulong fsr) 568 { 569 int rnd_mode; 570 571 env->fsr = fsr & (FSR_RD_MASK | FSR_TEM_MASK | FSR_AEXC_MASK); 572 573 switch (fsr & FSR_RD_MASK) { 574 case FSR_RD_NEAREST: 575 rnd_mode = float_round_nearest_even; 576 break; 577 default: 578 case FSR_RD_ZERO: 579 rnd_mode = float_round_to_zero; 580 break; 581 case FSR_RD_POS: 582 rnd_mode = float_round_up; 583 break; 584 case FSR_RD_NEG: 585 rnd_mode = float_round_down; 586 break; 587 } 588 set_float_rounding_mode(rnd_mode, &env->fp_status); 589 } 590 591 void cpu_put_fsr(CPUSPARCState *env, target_ulong fsr) 592 { 593 env->fsr_cexc_ftt = fsr & (FSR_CEXC_MASK | FSR_FTT_MASK); 594 595 env->fcc[0] = extract32(fsr, FSR_FCC0_SHIFT, 2); 596 #ifdef TARGET_SPARC64 597 env->fcc[1] = extract64(fsr, FSR_FCC1_SHIFT, 2); 598 env->fcc[2] = extract64(fsr, FSR_FCC2_SHIFT, 2); 599 env->fcc[3] = extract64(fsr, FSR_FCC3_SHIFT, 2); 600 #elif !defined(CONFIG_USER_ONLY) 601 env->fsr_qne = fsr & FSR_QNE; 602 #endif 603 604 set_fsr_nonsplit(env, fsr); 605 } 606 607 void helper_set_fsr_nofcc_noftt(CPUSPARCState *env, uint32_t fsr) 608 { 609 env->fsr_cexc_ftt &= FSR_FTT_MASK; 610 env->fsr_cexc_ftt |= fsr & FSR_CEXC_MASK; 611 set_fsr_nonsplit(env, fsr); 612 } 613 614 void helper_set_fsr_nofcc(CPUSPARCState *env, uint32_t fsr) 615 { 616 env->fsr_cexc_ftt = fsr & (FSR_CEXC_MASK | FSR_FTT_MASK); 617 set_fsr_nonsplit(env, fsr); 618 } 619