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