1 /* 2 * S/390 FPU helper routines 3 * 4 * Copyright (c) 2009 Ulrich Hecht 5 * Copyright (c) 2009 Alexander Graf 6 * 7 * This library is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public 9 * License as published by the Free Software Foundation; either 10 * version 2.1 of the License, or (at your option) any later version. 11 * 12 * This library is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with this library; if not, see <http://www.gnu.org/licenses/>. 19 */ 20 21 #include "qemu/osdep.h" 22 #include "cpu.h" 23 #include "s390x-internal.h" 24 #include "tcg_s390x.h" 25 #include "exec/exec-all.h" 26 #include "exec/cpu_ldst.h" 27 #include "exec/helper-proto.h" 28 #include "fpu/softfloat.h" 29 30 /* #define DEBUG_HELPER */ 31 #ifdef DEBUG_HELPER 32 #define HELPER_LOG(x...) qemu_log(x) 33 #else 34 #define HELPER_LOG(x...) 35 #endif 36 37 static inline Int128 RET128(float128 f) 38 { 39 return int128_make128(f.low, f.high); 40 } 41 42 static inline float128 ARG128(Int128 i) 43 { 44 return make_float128(int128_gethi(i), int128_getlo(i)); 45 } 46 47 uint8_t s390_softfloat_exc_to_ieee(unsigned int exc) 48 { 49 uint8_t s390_exc = 0; 50 51 s390_exc |= (exc & float_flag_invalid) ? S390_IEEE_MASK_INVALID : 0; 52 s390_exc |= (exc & float_flag_divbyzero) ? S390_IEEE_MASK_DIVBYZERO : 0; 53 s390_exc |= (exc & float_flag_overflow) ? S390_IEEE_MASK_OVERFLOW : 0; 54 s390_exc |= (exc & float_flag_underflow) ? S390_IEEE_MASK_UNDERFLOW : 0; 55 s390_exc |= (exc & float_flag_inexact) ? S390_IEEE_MASK_INEXACT : 0; 56 57 return s390_exc; 58 } 59 60 /* Should be called after any operation that may raise IEEE exceptions. */ 61 static void handle_exceptions(CPUS390XState *env, bool XxC, uintptr_t retaddr) 62 { 63 unsigned s390_exc, qemu_exc; 64 65 /* Get the exceptions raised by the current operation. Reset the 66 fpu_status contents so that the next operation has a clean slate. */ 67 qemu_exc = env->fpu_status.float_exception_flags; 68 if (qemu_exc == 0) { 69 return; 70 } 71 env->fpu_status.float_exception_flags = 0; 72 s390_exc = s390_softfloat_exc_to_ieee(qemu_exc); 73 74 /* 75 * IEEE-Underflow exception recognition exists if a tininess condition 76 * (underflow) exists and 77 * - The mask bit in the FPC is zero and the result is inexact 78 * - The mask bit in the FPC is one 79 * So tininess conditions that are not inexact don't trigger any 80 * underflow action in case the mask bit is not one. 81 */ 82 if (!(s390_exc & S390_IEEE_MASK_INEXACT) && 83 !((env->fpc >> 24) & S390_IEEE_MASK_UNDERFLOW)) { 84 s390_exc &= ~S390_IEEE_MASK_UNDERFLOW; 85 } 86 87 /* 88 * FIXME: 89 * 1. Right now, all inexact conditions are inidicated as 90 * "truncated" (0) and never as "incremented" (1) in the DXC. 91 * 2. Only traps due to invalid/divbyzero are suppressing. Other traps 92 * are completing, meaning the target register has to be written! 93 * This, however will mean that we have to write the register before 94 * triggering the trap - impossible right now. 95 */ 96 97 /* 98 * invalid/divbyzero cannot coexist with other conditions. 99 * overflow/underflow however can coexist with inexact, we have to 100 * handle it separately. 101 */ 102 if (s390_exc & ~S390_IEEE_MASK_INEXACT) { 103 if (s390_exc & ~S390_IEEE_MASK_INEXACT & env->fpc >> 24) { 104 /* trap condition - inexact reported along */ 105 tcg_s390_data_exception(env, s390_exc, retaddr); 106 } 107 /* nontrap condition - inexact handled differently */ 108 env->fpc |= (s390_exc & ~S390_IEEE_MASK_INEXACT) << 16; 109 } 110 111 /* inexact handling */ 112 if (s390_exc & S390_IEEE_MASK_INEXACT && !XxC) { 113 /* trap condition - overflow/underflow _not_ reported along */ 114 if (s390_exc & S390_IEEE_MASK_INEXACT & env->fpc >> 24) { 115 tcg_s390_data_exception(env, s390_exc & S390_IEEE_MASK_INEXACT, 116 retaddr); 117 } 118 /* nontrap condition */ 119 env->fpc |= (s390_exc & S390_IEEE_MASK_INEXACT) << 16; 120 } 121 } 122 123 int float_comp_to_cc(CPUS390XState *env, FloatRelation float_compare) 124 { 125 switch (float_compare) { 126 case float_relation_equal: 127 return 0; 128 case float_relation_less: 129 return 1; 130 case float_relation_greater: 131 return 2; 132 case float_relation_unordered: 133 return 3; 134 default: 135 cpu_abort(env_cpu(env), "unknown return value for float compare\n"); 136 } 137 } 138 139 /* condition codes for unary FP ops */ 140 uint32_t set_cc_nz_f32(float32 v) 141 { 142 if (float32_is_any_nan(v)) { 143 return 3; 144 } else if (float32_is_zero(v)) { 145 return 0; 146 } else if (float32_is_neg(v)) { 147 return 1; 148 } else { 149 return 2; 150 } 151 } 152 153 uint32_t set_cc_nz_f64(float64 v) 154 { 155 if (float64_is_any_nan(v)) { 156 return 3; 157 } else if (float64_is_zero(v)) { 158 return 0; 159 } else if (float64_is_neg(v)) { 160 return 1; 161 } else { 162 return 2; 163 } 164 } 165 166 uint32_t set_cc_nz_f128(float128 v) 167 { 168 if (float128_is_any_nan(v)) { 169 return 3; 170 } else if (float128_is_zero(v)) { 171 return 0; 172 } else if (float128_is_neg(v)) { 173 return 1; 174 } else { 175 return 2; 176 } 177 } 178 179 /* condition codes for FP to integer conversion ops */ 180 static uint32_t set_cc_conv_f32(float32 v, float_status *stat) 181 { 182 if (stat->float_exception_flags & float_flag_invalid) { 183 return 3; 184 } else { 185 return set_cc_nz_f32(v); 186 } 187 } 188 189 static uint32_t set_cc_conv_f64(float64 v, float_status *stat) 190 { 191 if (stat->float_exception_flags & float_flag_invalid) { 192 return 3; 193 } else { 194 return set_cc_nz_f64(v); 195 } 196 } 197 198 static uint32_t set_cc_conv_f128(float128 v, float_status *stat) 199 { 200 if (stat->float_exception_flags & float_flag_invalid) { 201 return 3; 202 } else { 203 return set_cc_nz_f128(v); 204 } 205 } 206 207 static inline uint8_t round_from_m34(uint32_t m34) 208 { 209 return extract32(m34, 0, 4); 210 } 211 212 static inline bool xxc_from_m34(uint32_t m34) 213 { 214 /* XxC is bit 1 of m4 */ 215 return extract32(m34, 4 + 3 - 1, 1); 216 } 217 218 /* 32-bit FP addition */ 219 uint64_t HELPER(aeb)(CPUS390XState *env, uint64_t f1, uint64_t f2) 220 { 221 float32 ret = float32_add(f1, f2, &env->fpu_status); 222 handle_exceptions(env, false, GETPC()); 223 return ret; 224 } 225 226 /* 64-bit FP addition */ 227 uint64_t HELPER(adb)(CPUS390XState *env, uint64_t f1, uint64_t f2) 228 { 229 float64 ret = float64_add(f1, f2, &env->fpu_status); 230 handle_exceptions(env, false, GETPC()); 231 return ret; 232 } 233 234 /* 128-bit FP addition */ 235 Int128 HELPER(axb)(CPUS390XState *env, Int128 a, Int128 b) 236 { 237 float128 ret = float128_add(ARG128(a), ARG128(b), &env->fpu_status); 238 handle_exceptions(env, false, GETPC()); 239 return RET128(ret); 240 } 241 242 /* 32-bit FP subtraction */ 243 uint64_t HELPER(seb)(CPUS390XState *env, uint64_t f1, uint64_t f2) 244 { 245 float32 ret = float32_sub(f1, f2, &env->fpu_status); 246 handle_exceptions(env, false, GETPC()); 247 return ret; 248 } 249 250 /* 64-bit FP subtraction */ 251 uint64_t HELPER(sdb)(CPUS390XState *env, uint64_t f1, uint64_t f2) 252 { 253 float64 ret = float64_sub(f1, f2, &env->fpu_status); 254 handle_exceptions(env, false, GETPC()); 255 return ret; 256 } 257 258 /* 128-bit FP subtraction */ 259 Int128 HELPER(sxb)(CPUS390XState *env, Int128 a, Int128 b) 260 { 261 float128 ret = float128_sub(ARG128(a), ARG128(b), &env->fpu_status); 262 handle_exceptions(env, false, GETPC()); 263 return RET128(ret); 264 } 265 266 /* 32-bit FP division */ 267 uint64_t HELPER(deb)(CPUS390XState *env, uint64_t f1, uint64_t f2) 268 { 269 float32 ret = float32_div(f1, f2, &env->fpu_status); 270 handle_exceptions(env, false, GETPC()); 271 return ret; 272 } 273 274 /* 64-bit FP division */ 275 uint64_t HELPER(ddb)(CPUS390XState *env, uint64_t f1, uint64_t f2) 276 { 277 float64 ret = float64_div(f1, f2, &env->fpu_status); 278 handle_exceptions(env, false, GETPC()); 279 return ret; 280 } 281 282 /* 128-bit FP division */ 283 Int128 HELPER(dxb)(CPUS390XState *env, Int128 a, Int128 b) 284 { 285 float128 ret = float128_div(ARG128(a), ARG128(b), &env->fpu_status); 286 handle_exceptions(env, false, GETPC()); 287 return RET128(ret); 288 } 289 290 /* 32-bit FP multiplication */ 291 uint64_t HELPER(meeb)(CPUS390XState *env, uint64_t f1, uint64_t f2) 292 { 293 float32 ret = float32_mul(f1, f2, &env->fpu_status); 294 handle_exceptions(env, false, GETPC()); 295 return ret; 296 } 297 298 /* 64-bit FP multiplication */ 299 uint64_t HELPER(mdb)(CPUS390XState *env, uint64_t f1, uint64_t f2) 300 { 301 float64 ret = float64_mul(f1, f2, &env->fpu_status); 302 handle_exceptions(env, false, GETPC()); 303 return ret; 304 } 305 306 /* 64/32-bit FP multiplication */ 307 uint64_t HELPER(mdeb)(CPUS390XState *env, uint64_t f1, uint64_t f2) 308 { 309 float64 ret = float32_to_float64(f2, &env->fpu_status); 310 ret = float64_mul(f1, ret, &env->fpu_status); 311 handle_exceptions(env, false, GETPC()); 312 return ret; 313 } 314 315 /* 128-bit FP multiplication */ 316 Int128 HELPER(mxb)(CPUS390XState *env, Int128 a, Int128 b) 317 { 318 float128 ret = float128_mul(ARG128(a), ARG128(b), &env->fpu_status); 319 handle_exceptions(env, false, GETPC()); 320 return RET128(ret); 321 } 322 323 /* 128/64-bit FP multiplication */ 324 Int128 HELPER(mxdb)(CPUS390XState *env, Int128 a, uint64_t f2) 325 { 326 float128 ret = float64_to_float128(f2, &env->fpu_status); 327 ret = float128_mul(ARG128(a), ret, &env->fpu_status); 328 handle_exceptions(env, false, GETPC()); 329 return RET128(ret); 330 } 331 332 /* convert 32-bit float to 64-bit float */ 333 uint64_t HELPER(ldeb)(CPUS390XState *env, uint64_t f2) 334 { 335 float64 ret = float32_to_float64(f2, &env->fpu_status); 336 handle_exceptions(env, false, GETPC()); 337 return ret; 338 } 339 340 /* convert 128-bit float to 64-bit float */ 341 uint64_t HELPER(ldxb)(CPUS390XState *env, Int128 a, uint32_t m34) 342 { 343 int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); 344 float64 ret = float128_to_float64(ARG128(a), &env->fpu_status); 345 346 s390_restore_bfp_rounding_mode(env, old_mode); 347 handle_exceptions(env, xxc_from_m34(m34), GETPC()); 348 return ret; 349 } 350 351 /* convert 64-bit float to 128-bit float */ 352 Int128 HELPER(lxdb)(CPUS390XState *env, uint64_t f2) 353 { 354 float128 ret = float64_to_float128(f2, &env->fpu_status); 355 handle_exceptions(env, false, GETPC()); 356 return RET128(ret); 357 } 358 359 /* convert 32-bit float to 128-bit float */ 360 Int128 HELPER(lxeb)(CPUS390XState *env, uint64_t f2) 361 { 362 float128 ret = float32_to_float128(f2, &env->fpu_status); 363 handle_exceptions(env, false, GETPC()); 364 return RET128(ret); 365 } 366 367 /* convert 64-bit float to 32-bit float */ 368 uint64_t HELPER(ledb)(CPUS390XState *env, uint64_t f2, uint32_t m34) 369 { 370 int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); 371 float32 ret = float64_to_float32(f2, &env->fpu_status); 372 373 s390_restore_bfp_rounding_mode(env, old_mode); 374 handle_exceptions(env, xxc_from_m34(m34), GETPC()); 375 return ret; 376 } 377 378 /* convert 128-bit float to 32-bit float */ 379 uint64_t HELPER(lexb)(CPUS390XState *env, Int128 a, uint32_t m34) 380 { 381 int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); 382 float32 ret = float128_to_float32(ARG128(a), &env->fpu_status); 383 384 s390_restore_bfp_rounding_mode(env, old_mode); 385 handle_exceptions(env, xxc_from_m34(m34), GETPC()); 386 return ret; 387 } 388 389 /* 32-bit FP compare */ 390 uint32_t HELPER(ceb)(CPUS390XState *env, uint64_t f1, uint64_t f2) 391 { 392 FloatRelation cmp = float32_compare_quiet(f1, f2, &env->fpu_status); 393 handle_exceptions(env, false, GETPC()); 394 return float_comp_to_cc(env, cmp); 395 } 396 397 /* 64-bit FP compare */ 398 uint32_t HELPER(cdb)(CPUS390XState *env, uint64_t f1, uint64_t f2) 399 { 400 FloatRelation cmp = float64_compare_quiet(f1, f2, &env->fpu_status); 401 handle_exceptions(env, false, GETPC()); 402 return float_comp_to_cc(env, cmp); 403 } 404 405 /* 128-bit FP compare */ 406 uint32_t HELPER(cxb)(CPUS390XState *env, Int128 a, Int128 b) 407 { 408 FloatRelation cmp = float128_compare_quiet(ARG128(a), ARG128(b), 409 &env->fpu_status); 410 handle_exceptions(env, false, GETPC()); 411 return float_comp_to_cc(env, cmp); 412 } 413 414 int s390_swap_bfp_rounding_mode(CPUS390XState *env, int m3) 415 { 416 int ret = env->fpu_status.float_rounding_mode; 417 418 switch (m3) { 419 case 0: 420 /* current mode */ 421 break; 422 case 1: 423 /* round to nearest with ties away from 0 */ 424 set_float_rounding_mode(float_round_ties_away, &env->fpu_status); 425 break; 426 case 3: 427 /* round to prepare for shorter precision */ 428 set_float_rounding_mode(float_round_to_odd, &env->fpu_status); 429 break; 430 case 4: 431 /* round to nearest with ties to even */ 432 set_float_rounding_mode(float_round_nearest_even, &env->fpu_status); 433 break; 434 case 5: 435 /* round to zero */ 436 set_float_rounding_mode(float_round_to_zero, &env->fpu_status); 437 break; 438 case 6: 439 /* round to +inf */ 440 set_float_rounding_mode(float_round_up, &env->fpu_status); 441 break; 442 case 7: 443 /* round to -inf */ 444 set_float_rounding_mode(float_round_down, &env->fpu_status); 445 break; 446 default: 447 g_assert_not_reached(); 448 } 449 return ret; 450 } 451 452 void s390_restore_bfp_rounding_mode(CPUS390XState *env, int old_mode) 453 { 454 set_float_rounding_mode(old_mode, &env->fpu_status); 455 } 456 457 /* convert 64-bit int to 32-bit float */ 458 uint64_t HELPER(cegb)(CPUS390XState *env, int64_t v2, uint32_t m34) 459 { 460 int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); 461 float32 ret = int64_to_float32(v2, &env->fpu_status); 462 463 s390_restore_bfp_rounding_mode(env, old_mode); 464 handle_exceptions(env, xxc_from_m34(m34), GETPC()); 465 return ret; 466 } 467 468 /* convert 64-bit int to 64-bit float */ 469 uint64_t HELPER(cdgb)(CPUS390XState *env, int64_t v2, uint32_t m34) 470 { 471 int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); 472 float64 ret = int64_to_float64(v2, &env->fpu_status); 473 474 s390_restore_bfp_rounding_mode(env, old_mode); 475 handle_exceptions(env, xxc_from_m34(m34), GETPC()); 476 return ret; 477 } 478 479 /* convert 64-bit int to 128-bit float */ 480 Int128 HELPER(cxgb)(CPUS390XState *env, int64_t v2, uint32_t m34) 481 { 482 int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); 483 float128 ret = int64_to_float128(v2, &env->fpu_status); 484 485 s390_restore_bfp_rounding_mode(env, old_mode); 486 handle_exceptions(env, xxc_from_m34(m34), GETPC()); 487 return RET128(ret); 488 } 489 490 /* convert 64-bit uint to 32-bit float */ 491 uint64_t HELPER(celgb)(CPUS390XState *env, uint64_t v2, uint32_t m34) 492 { 493 int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); 494 float32 ret = uint64_to_float32(v2, &env->fpu_status); 495 496 s390_restore_bfp_rounding_mode(env, old_mode); 497 handle_exceptions(env, xxc_from_m34(m34), GETPC()); 498 return ret; 499 } 500 501 /* convert 64-bit uint to 64-bit float */ 502 uint64_t HELPER(cdlgb)(CPUS390XState *env, uint64_t v2, uint32_t m34) 503 { 504 int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); 505 float64 ret = uint64_to_float64(v2, &env->fpu_status); 506 507 s390_restore_bfp_rounding_mode(env, old_mode); 508 handle_exceptions(env, xxc_from_m34(m34), GETPC()); 509 return ret; 510 } 511 512 /* convert 64-bit uint to 128-bit float */ 513 Int128 HELPER(cxlgb)(CPUS390XState *env, uint64_t v2, uint32_t m34) 514 { 515 int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); 516 float128 ret = uint64_to_float128(v2, &env->fpu_status); 517 518 s390_restore_bfp_rounding_mode(env, old_mode); 519 handle_exceptions(env, xxc_from_m34(m34), GETPC()); 520 return RET128(ret); 521 } 522 523 /* convert 32-bit float to 64-bit int */ 524 uint64_t HELPER(cgeb)(CPUS390XState *env, uint64_t v2, uint32_t m34) 525 { 526 int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); 527 int64_t ret = float32_to_int64(v2, &env->fpu_status); 528 uint32_t cc = set_cc_conv_f32(v2, &env->fpu_status); 529 530 s390_restore_bfp_rounding_mode(env, old_mode); 531 handle_exceptions(env, xxc_from_m34(m34), GETPC()); 532 env->cc_op = cc; 533 if (float32_is_any_nan(v2)) { 534 return INT64_MIN; 535 } 536 return ret; 537 } 538 539 /* convert 64-bit float to 64-bit int */ 540 uint64_t HELPER(cgdb)(CPUS390XState *env, uint64_t v2, uint32_t m34) 541 { 542 int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); 543 int64_t ret = float64_to_int64(v2, &env->fpu_status); 544 uint32_t cc = set_cc_conv_f64(v2, &env->fpu_status); 545 546 s390_restore_bfp_rounding_mode(env, old_mode); 547 handle_exceptions(env, xxc_from_m34(m34), GETPC()); 548 env->cc_op = cc; 549 if (float64_is_any_nan(v2)) { 550 return INT64_MIN; 551 } 552 return ret; 553 } 554 555 /* convert 128-bit float to 64-bit int */ 556 uint64_t HELPER(cgxb)(CPUS390XState *env, Int128 i2, uint32_t m34) 557 { 558 int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); 559 float128 v2 = ARG128(i2); 560 int64_t ret = float128_to_int64(v2, &env->fpu_status); 561 uint32_t cc = set_cc_conv_f128(v2, &env->fpu_status); 562 563 s390_restore_bfp_rounding_mode(env, old_mode); 564 handle_exceptions(env, xxc_from_m34(m34), GETPC()); 565 env->cc_op = cc; 566 if (float128_is_any_nan(v2)) { 567 return INT64_MIN; 568 } 569 return ret; 570 } 571 572 /* convert 32-bit float to 32-bit int */ 573 uint64_t HELPER(cfeb)(CPUS390XState *env, uint64_t v2, uint32_t m34) 574 { 575 int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); 576 int32_t ret = float32_to_int32(v2, &env->fpu_status); 577 uint32_t cc = set_cc_conv_f32(v2, &env->fpu_status); 578 579 s390_restore_bfp_rounding_mode(env, old_mode); 580 handle_exceptions(env, xxc_from_m34(m34), GETPC()); 581 env->cc_op = cc; 582 if (float32_is_any_nan(v2)) { 583 return INT32_MIN; 584 } 585 return ret; 586 } 587 588 /* convert 64-bit float to 32-bit int */ 589 uint64_t HELPER(cfdb)(CPUS390XState *env, uint64_t v2, uint32_t m34) 590 { 591 int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); 592 int32_t ret = float64_to_int32(v2, &env->fpu_status); 593 uint32_t cc = set_cc_conv_f64(v2, &env->fpu_status); 594 595 s390_restore_bfp_rounding_mode(env, old_mode); 596 handle_exceptions(env, xxc_from_m34(m34), GETPC()); 597 env->cc_op = cc; 598 if (float64_is_any_nan(v2)) { 599 return INT32_MIN; 600 } 601 return ret; 602 } 603 604 /* convert 128-bit float to 32-bit int */ 605 uint64_t HELPER(cfxb)(CPUS390XState *env, Int128 i2, uint32_t m34) 606 { 607 int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); 608 float128 v2 = ARG128(i2); 609 int32_t ret = float128_to_int32(v2, &env->fpu_status); 610 uint32_t cc = set_cc_conv_f128(v2, &env->fpu_status); 611 612 s390_restore_bfp_rounding_mode(env, old_mode); 613 handle_exceptions(env, xxc_from_m34(m34), GETPC()); 614 env->cc_op = cc; 615 if (float128_is_any_nan(v2)) { 616 return INT32_MIN; 617 } 618 return ret; 619 } 620 621 /* convert 32-bit float to 64-bit uint */ 622 uint64_t HELPER(clgeb)(CPUS390XState *env, uint64_t v2, uint32_t m34) 623 { 624 int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); 625 uint64_t ret = float32_to_uint64(v2, &env->fpu_status); 626 uint32_t cc = set_cc_conv_f32(v2, &env->fpu_status); 627 628 s390_restore_bfp_rounding_mode(env, old_mode); 629 handle_exceptions(env, xxc_from_m34(m34), GETPC()); 630 env->cc_op = cc; 631 if (float32_is_any_nan(v2)) { 632 return 0; 633 } 634 return ret; 635 } 636 637 /* convert 64-bit float to 64-bit uint */ 638 uint64_t HELPER(clgdb)(CPUS390XState *env, uint64_t v2, uint32_t m34) 639 { 640 int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); 641 uint64_t ret = float64_to_uint64(v2, &env->fpu_status); 642 uint32_t cc = set_cc_conv_f64(v2, &env->fpu_status); 643 644 s390_restore_bfp_rounding_mode(env, old_mode); 645 handle_exceptions(env, xxc_from_m34(m34), GETPC()); 646 env->cc_op = cc; 647 if (float64_is_any_nan(v2)) { 648 return 0; 649 } 650 return ret; 651 } 652 653 /* convert 128-bit float to 64-bit uint */ 654 uint64_t HELPER(clgxb)(CPUS390XState *env, Int128 i2, uint32_t m34) 655 { 656 int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); 657 float128 v2 = ARG128(i2); 658 uint64_t ret = float128_to_uint64(v2, &env->fpu_status); 659 uint32_t cc = set_cc_conv_f128(v2, &env->fpu_status); 660 661 s390_restore_bfp_rounding_mode(env, old_mode); 662 handle_exceptions(env, xxc_from_m34(m34), GETPC()); 663 env->cc_op = cc; 664 if (float128_is_any_nan(v2)) { 665 return 0; 666 } 667 return ret; 668 } 669 670 /* convert 32-bit float to 32-bit uint */ 671 uint64_t HELPER(clfeb)(CPUS390XState *env, uint64_t v2, uint32_t m34) 672 { 673 int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); 674 uint32_t ret = float32_to_uint32(v2, &env->fpu_status); 675 uint32_t cc = set_cc_conv_f32(v2, &env->fpu_status); 676 677 s390_restore_bfp_rounding_mode(env, old_mode); 678 handle_exceptions(env, xxc_from_m34(m34), GETPC()); 679 env->cc_op = cc; 680 if (float32_is_any_nan(v2)) { 681 return 0; 682 } 683 return ret; 684 } 685 686 /* convert 64-bit float to 32-bit uint */ 687 uint64_t HELPER(clfdb)(CPUS390XState *env, uint64_t v2, uint32_t m34) 688 { 689 int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); 690 uint32_t ret = float64_to_uint32(v2, &env->fpu_status); 691 uint32_t cc = set_cc_conv_f64(v2, &env->fpu_status); 692 693 s390_restore_bfp_rounding_mode(env, old_mode); 694 handle_exceptions(env, xxc_from_m34(m34), GETPC()); 695 env->cc_op = cc; 696 if (float64_is_any_nan(v2)) { 697 return 0; 698 } 699 return ret; 700 } 701 702 /* convert 128-bit float to 32-bit uint */ 703 uint64_t HELPER(clfxb)(CPUS390XState *env, Int128 i2, uint32_t m34) 704 { 705 int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); 706 float128 v2 = ARG128(i2); 707 uint32_t ret = float128_to_uint32(v2, &env->fpu_status); 708 uint32_t cc = set_cc_conv_f128(v2, &env->fpu_status); 709 710 s390_restore_bfp_rounding_mode(env, old_mode); 711 handle_exceptions(env, xxc_from_m34(m34), GETPC()); 712 env->cc_op = cc; 713 if (float128_is_any_nan(v2)) { 714 return 0; 715 } 716 return ret; 717 } 718 719 /* round to integer 32-bit */ 720 uint64_t HELPER(fieb)(CPUS390XState *env, uint64_t f2, uint32_t m34) 721 { 722 int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); 723 float32 ret = float32_round_to_int(f2, &env->fpu_status); 724 725 s390_restore_bfp_rounding_mode(env, old_mode); 726 handle_exceptions(env, xxc_from_m34(m34), GETPC()); 727 return ret; 728 } 729 730 /* round to integer 64-bit */ 731 uint64_t HELPER(fidb)(CPUS390XState *env, uint64_t f2, uint32_t m34) 732 { 733 int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); 734 float64 ret = float64_round_to_int(f2, &env->fpu_status); 735 736 s390_restore_bfp_rounding_mode(env, old_mode); 737 handle_exceptions(env, xxc_from_m34(m34), GETPC()); 738 return ret; 739 } 740 741 /* round to integer 128-bit */ 742 Int128 HELPER(fixb)(CPUS390XState *env, Int128 a, uint32_t m34) 743 { 744 int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); 745 float128 ret = float128_round_to_int(ARG128(a), &env->fpu_status); 746 747 s390_restore_bfp_rounding_mode(env, old_mode); 748 handle_exceptions(env, xxc_from_m34(m34), GETPC()); 749 return RET128(ret); 750 } 751 752 /* 32-bit FP compare and signal */ 753 uint32_t HELPER(keb)(CPUS390XState *env, uint64_t f1, uint64_t f2) 754 { 755 FloatRelation cmp = float32_compare(f1, f2, &env->fpu_status); 756 handle_exceptions(env, false, GETPC()); 757 return float_comp_to_cc(env, cmp); 758 } 759 760 /* 64-bit FP compare and signal */ 761 uint32_t HELPER(kdb)(CPUS390XState *env, uint64_t f1, uint64_t f2) 762 { 763 FloatRelation cmp = float64_compare(f1, f2, &env->fpu_status); 764 handle_exceptions(env, false, GETPC()); 765 return float_comp_to_cc(env, cmp); 766 } 767 768 /* 128-bit FP compare and signal */ 769 uint32_t HELPER(kxb)(CPUS390XState *env, Int128 a, Int128 b) 770 { 771 FloatRelation cmp = float128_compare(ARG128(a), ARG128(b), 772 &env->fpu_status); 773 handle_exceptions(env, false, GETPC()); 774 return float_comp_to_cc(env, cmp); 775 } 776 777 /* 32-bit FP multiply and add */ 778 uint64_t HELPER(maeb)(CPUS390XState *env, uint64_t f1, 779 uint64_t f2, uint64_t f3) 780 { 781 float32 ret = float32_muladd(f2, f3, f1, 0, &env->fpu_status); 782 handle_exceptions(env, false, GETPC()); 783 return ret; 784 } 785 786 /* 64-bit FP multiply and add */ 787 uint64_t HELPER(madb)(CPUS390XState *env, uint64_t f1, 788 uint64_t f2, uint64_t f3) 789 { 790 float64 ret = float64_muladd(f2, f3, f1, 0, &env->fpu_status); 791 handle_exceptions(env, false, GETPC()); 792 return ret; 793 } 794 795 /* 32-bit FP multiply and subtract */ 796 uint64_t HELPER(mseb)(CPUS390XState *env, uint64_t f1, 797 uint64_t f2, uint64_t f3) 798 { 799 float32 ret = float32_muladd(f2, f3, f1, float_muladd_negate_c, 800 &env->fpu_status); 801 handle_exceptions(env, false, GETPC()); 802 return ret; 803 } 804 805 /* 64-bit FP multiply and subtract */ 806 uint64_t HELPER(msdb)(CPUS390XState *env, uint64_t f1, 807 uint64_t f2, uint64_t f3) 808 { 809 float64 ret = float64_muladd(f2, f3, f1, float_muladd_negate_c, 810 &env->fpu_status); 811 handle_exceptions(env, false, GETPC()); 812 return ret; 813 } 814 815 /* The rightmost bit has the number 11. */ 816 static inline uint16_t dcmask(int bit, bool neg) 817 { 818 return 1 << (11 - bit - neg); 819 } 820 821 #define DEF_FLOAT_DCMASK(_TYPE) \ 822 uint16_t _TYPE##_dcmask(CPUS390XState *env, _TYPE f1) \ 823 { \ 824 const bool neg = _TYPE##_is_neg(f1); \ 825 \ 826 /* Sorted by most common cases - only one class is possible */ \ 827 if (_TYPE##_is_normal(f1)) { \ 828 return dcmask(2, neg); \ 829 } else if (_TYPE##_is_zero(f1)) { \ 830 return dcmask(0, neg); \ 831 } else if (_TYPE##_is_denormal(f1)) { \ 832 return dcmask(4, neg); \ 833 } else if (_TYPE##_is_infinity(f1)) { \ 834 return dcmask(6, neg); \ 835 } else if (_TYPE##_is_quiet_nan(f1, &env->fpu_status)) { \ 836 return dcmask(8, neg); \ 837 } \ 838 /* signaling nan, as last remaining case */ \ 839 return dcmask(10, neg); \ 840 } 841 DEF_FLOAT_DCMASK(float32) 842 DEF_FLOAT_DCMASK(float64) 843 DEF_FLOAT_DCMASK(float128) 844 845 /* test data class 32-bit */ 846 uint32_t HELPER(tceb)(CPUS390XState *env, uint64_t f1, uint64_t m2) 847 { 848 return (m2 & float32_dcmask(env, f1)) != 0; 849 } 850 851 /* test data class 64-bit */ 852 uint32_t HELPER(tcdb)(CPUS390XState *env, uint64_t v1, uint64_t m2) 853 { 854 return (m2 & float64_dcmask(env, v1)) != 0; 855 } 856 857 /* test data class 128-bit */ 858 uint32_t HELPER(tcxb)(CPUS390XState *env, Int128 a, uint64_t m2) 859 { 860 return (m2 & float128_dcmask(env, ARG128(a))) != 0; 861 } 862 863 /* square root 32-bit */ 864 uint64_t HELPER(sqeb)(CPUS390XState *env, uint64_t f2) 865 { 866 float32 ret = float32_sqrt(f2, &env->fpu_status); 867 handle_exceptions(env, false, GETPC()); 868 return ret; 869 } 870 871 /* square root 64-bit */ 872 uint64_t HELPER(sqdb)(CPUS390XState *env, uint64_t f2) 873 { 874 float64 ret = float64_sqrt(f2, &env->fpu_status); 875 handle_exceptions(env, false, GETPC()); 876 return ret; 877 } 878 879 /* square root 128-bit */ 880 Int128 HELPER(sqxb)(CPUS390XState *env, Int128 a) 881 { 882 float128 ret = float128_sqrt(ARG128(a), &env->fpu_status); 883 handle_exceptions(env, false, GETPC()); 884 return RET128(ret); 885 } 886 887 static const int fpc_to_rnd[8] = { 888 float_round_nearest_even, 889 float_round_to_zero, 890 float_round_up, 891 float_round_down, 892 -1, 893 -1, 894 -1, 895 float_round_to_odd, 896 }; 897 898 /* set fpc */ 899 void HELPER(sfpc)(CPUS390XState *env, uint64_t fpc) 900 { 901 if (fpc_to_rnd[fpc & 0x7] == -1 || fpc & 0x03030088u || 902 (!s390_has_feat(S390_FEAT_FLOATING_POINT_EXT) && fpc & 0x4)) { 903 tcg_s390_program_interrupt(env, PGM_SPECIFICATION, GETPC()); 904 } 905 906 /* Install everything in the main FPC. */ 907 env->fpc = fpc; 908 909 /* Install the rounding mode in the shadow fpu_status. */ 910 set_float_rounding_mode(fpc_to_rnd[fpc & 0x7], &env->fpu_status); 911 } 912 913 /* set fpc and signal */ 914 void HELPER(sfas)(CPUS390XState *env, uint64_t fpc) 915 { 916 uint32_t signalling = env->fpc; 917 uint32_t s390_exc; 918 919 if (fpc_to_rnd[fpc & 0x7] == -1 || fpc & 0x03030088u || 920 (!s390_has_feat(S390_FEAT_FLOATING_POINT_EXT) && fpc & 0x4)) { 921 tcg_s390_program_interrupt(env, PGM_SPECIFICATION, GETPC()); 922 } 923 924 /* 925 * FPC is set to the FPC operand with a bitwise OR of the signalling 926 * flags. 927 */ 928 env->fpc = fpc | (signalling & 0x00ff0000); 929 set_float_rounding_mode(fpc_to_rnd[fpc & 0x7], &env->fpu_status); 930 931 /* 932 * If any signaling flag is enabled in the new FPC mask, a 933 * simulated-iee-exception exception occurs. 934 */ 935 s390_exc = (signalling >> 16) & (fpc >> 24); 936 if (s390_exc) { 937 if (s390_exc & S390_IEEE_MASK_INVALID) { 938 s390_exc = S390_IEEE_MASK_INVALID; 939 } else if (s390_exc & S390_IEEE_MASK_DIVBYZERO) { 940 s390_exc = S390_IEEE_MASK_DIVBYZERO; 941 } else if (s390_exc & S390_IEEE_MASK_OVERFLOW) { 942 s390_exc &= (S390_IEEE_MASK_OVERFLOW | S390_IEEE_MASK_INEXACT); 943 } else if (s390_exc & S390_IEEE_MASK_UNDERFLOW) { 944 s390_exc &= (S390_IEEE_MASK_UNDERFLOW | S390_IEEE_MASK_INEXACT); 945 } else if (s390_exc & S390_IEEE_MASK_INEXACT) { 946 s390_exc = S390_IEEE_MASK_INEXACT; 947 } else if (s390_exc & S390_IEEE_MASK_QUANTUM) { 948 s390_exc = S390_IEEE_MASK_QUANTUM; 949 } 950 tcg_s390_data_exception(env, s390_exc | 3, GETPC()); 951 } 952 } 953 954 /* set bfp rounding mode */ 955 void HELPER(srnm)(CPUS390XState *env, uint64_t rnd) 956 { 957 if (rnd > 0x7 || fpc_to_rnd[rnd & 0x7] == -1) { 958 tcg_s390_program_interrupt(env, PGM_SPECIFICATION, GETPC()); 959 } 960 961 env->fpc = deposit32(env->fpc, 0, 3, rnd); 962 set_float_rounding_mode(fpc_to_rnd[rnd & 0x7], &env->fpu_status); 963 } 964