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, uint64_t f1, uint64_t f2) 325 { 326 float128 f1_128 = float64_to_float128(f1, &env->fpu_status); 327 float128 ret = float64_to_float128(f2, &env->fpu_status); 328 ret = float128_mul(f1_128, ret, &env->fpu_status); 329 handle_exceptions(env, false, GETPC()); 330 return RET128(ret); 331 } 332 333 /* convert 32-bit float to 64-bit float */ 334 uint64_t HELPER(ldeb)(CPUS390XState *env, uint64_t f2) 335 { 336 float64 ret = float32_to_float64(f2, &env->fpu_status); 337 handle_exceptions(env, false, GETPC()); 338 return ret; 339 } 340 341 /* convert 128-bit float to 64-bit float */ 342 uint64_t HELPER(ldxb)(CPUS390XState *env, Int128 a, uint32_t m34) 343 { 344 int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); 345 float64 ret = float128_to_float64(ARG128(a), &env->fpu_status); 346 347 s390_restore_bfp_rounding_mode(env, old_mode); 348 handle_exceptions(env, xxc_from_m34(m34), GETPC()); 349 return ret; 350 } 351 352 /* convert 64-bit float to 128-bit float */ 353 Int128 HELPER(lxdb)(CPUS390XState *env, uint64_t f2) 354 { 355 float128 ret = float64_to_float128(f2, &env->fpu_status); 356 handle_exceptions(env, false, GETPC()); 357 return RET128(ret); 358 } 359 360 /* convert 32-bit float to 128-bit float */ 361 Int128 HELPER(lxeb)(CPUS390XState *env, uint64_t f2) 362 { 363 float128 ret = float32_to_float128(f2, &env->fpu_status); 364 handle_exceptions(env, false, GETPC()); 365 return RET128(ret); 366 } 367 368 /* convert 64-bit float to 32-bit float */ 369 uint64_t HELPER(ledb)(CPUS390XState *env, uint64_t f2, uint32_t m34) 370 { 371 int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); 372 float32 ret = float64_to_float32(f2, &env->fpu_status); 373 374 s390_restore_bfp_rounding_mode(env, old_mode); 375 handle_exceptions(env, xxc_from_m34(m34), GETPC()); 376 return ret; 377 } 378 379 /* convert 128-bit float to 32-bit float */ 380 uint64_t HELPER(lexb)(CPUS390XState *env, Int128 a, uint32_t m34) 381 { 382 int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); 383 float32 ret = float128_to_float32(ARG128(a), &env->fpu_status); 384 385 s390_restore_bfp_rounding_mode(env, old_mode); 386 handle_exceptions(env, xxc_from_m34(m34), GETPC()); 387 return ret; 388 } 389 390 /* 32-bit FP compare */ 391 uint32_t HELPER(ceb)(CPUS390XState *env, uint64_t f1, uint64_t f2) 392 { 393 FloatRelation cmp = float32_compare_quiet(f1, f2, &env->fpu_status); 394 handle_exceptions(env, false, GETPC()); 395 return float_comp_to_cc(env, cmp); 396 } 397 398 /* 64-bit FP compare */ 399 uint32_t HELPER(cdb)(CPUS390XState *env, uint64_t f1, uint64_t f2) 400 { 401 FloatRelation cmp = float64_compare_quiet(f1, f2, &env->fpu_status); 402 handle_exceptions(env, false, GETPC()); 403 return float_comp_to_cc(env, cmp); 404 } 405 406 /* 128-bit FP compare */ 407 uint32_t HELPER(cxb)(CPUS390XState *env, Int128 a, Int128 b) 408 { 409 FloatRelation cmp = float128_compare_quiet(ARG128(a), ARG128(b), 410 &env->fpu_status); 411 handle_exceptions(env, false, GETPC()); 412 return float_comp_to_cc(env, cmp); 413 } 414 415 int s390_swap_bfp_rounding_mode(CPUS390XState *env, int m3) 416 { 417 int ret = env->fpu_status.float_rounding_mode; 418 419 switch (m3) { 420 case 0: 421 /* current mode */ 422 break; 423 case 1: 424 /* round to nearest with ties away from 0 */ 425 set_float_rounding_mode(float_round_ties_away, &env->fpu_status); 426 break; 427 case 3: 428 /* round to prepare for shorter precision */ 429 set_float_rounding_mode(float_round_to_odd, &env->fpu_status); 430 break; 431 case 4: 432 /* round to nearest with ties to even */ 433 set_float_rounding_mode(float_round_nearest_even, &env->fpu_status); 434 break; 435 case 5: 436 /* round to zero */ 437 set_float_rounding_mode(float_round_to_zero, &env->fpu_status); 438 break; 439 case 6: 440 /* round to +inf */ 441 set_float_rounding_mode(float_round_up, &env->fpu_status); 442 break; 443 case 7: 444 /* round to -inf */ 445 set_float_rounding_mode(float_round_down, &env->fpu_status); 446 break; 447 default: 448 g_assert_not_reached(); 449 } 450 return ret; 451 } 452 453 void s390_restore_bfp_rounding_mode(CPUS390XState *env, int old_mode) 454 { 455 set_float_rounding_mode(old_mode, &env->fpu_status); 456 } 457 458 /* convert 64-bit int to 32-bit float */ 459 uint64_t HELPER(cegb)(CPUS390XState *env, int64_t v2, uint32_t m34) 460 { 461 int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); 462 float32 ret = int64_to_float32(v2, &env->fpu_status); 463 464 s390_restore_bfp_rounding_mode(env, old_mode); 465 handle_exceptions(env, xxc_from_m34(m34), GETPC()); 466 return ret; 467 } 468 469 /* convert 64-bit int to 64-bit float */ 470 uint64_t HELPER(cdgb)(CPUS390XState *env, int64_t v2, uint32_t m34) 471 { 472 int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); 473 float64 ret = int64_to_float64(v2, &env->fpu_status); 474 475 s390_restore_bfp_rounding_mode(env, old_mode); 476 handle_exceptions(env, xxc_from_m34(m34), GETPC()); 477 return ret; 478 } 479 480 /* convert 64-bit int to 128-bit float */ 481 Int128 HELPER(cxgb)(CPUS390XState *env, int64_t v2, uint32_t m34) 482 { 483 int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); 484 float128 ret = int64_to_float128(v2, &env->fpu_status); 485 486 s390_restore_bfp_rounding_mode(env, old_mode); 487 handle_exceptions(env, xxc_from_m34(m34), GETPC()); 488 return RET128(ret); 489 } 490 491 /* convert 64-bit uint to 32-bit float */ 492 uint64_t HELPER(celgb)(CPUS390XState *env, uint64_t v2, uint32_t m34) 493 { 494 int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); 495 float32 ret = uint64_to_float32(v2, &env->fpu_status); 496 497 s390_restore_bfp_rounding_mode(env, old_mode); 498 handle_exceptions(env, xxc_from_m34(m34), GETPC()); 499 return ret; 500 } 501 502 /* convert 64-bit uint to 64-bit float */ 503 uint64_t HELPER(cdlgb)(CPUS390XState *env, uint64_t v2, uint32_t m34) 504 { 505 int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); 506 float64 ret = uint64_to_float64(v2, &env->fpu_status); 507 508 s390_restore_bfp_rounding_mode(env, old_mode); 509 handle_exceptions(env, xxc_from_m34(m34), GETPC()); 510 return ret; 511 } 512 513 /* convert 64-bit uint to 128-bit float */ 514 Int128 HELPER(cxlgb)(CPUS390XState *env, uint64_t v2, uint32_t m34) 515 { 516 int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); 517 float128 ret = uint64_to_float128(v2, &env->fpu_status); 518 519 s390_restore_bfp_rounding_mode(env, old_mode); 520 handle_exceptions(env, xxc_from_m34(m34), GETPC()); 521 return RET128(ret); 522 } 523 524 /* convert 32-bit float to 64-bit int */ 525 uint64_t HELPER(cgeb)(CPUS390XState *env, uint64_t v2, uint32_t m34) 526 { 527 int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); 528 int64_t ret = float32_to_int64(v2, &env->fpu_status); 529 uint32_t cc = set_cc_conv_f32(v2, &env->fpu_status); 530 531 s390_restore_bfp_rounding_mode(env, old_mode); 532 handle_exceptions(env, xxc_from_m34(m34), GETPC()); 533 env->cc_op = cc; 534 if (float32_is_any_nan(v2)) { 535 return INT64_MIN; 536 } 537 return ret; 538 } 539 540 /* convert 64-bit float to 64-bit int */ 541 uint64_t HELPER(cgdb)(CPUS390XState *env, uint64_t v2, uint32_t m34) 542 { 543 int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); 544 int64_t ret = float64_to_int64(v2, &env->fpu_status); 545 uint32_t cc = set_cc_conv_f64(v2, &env->fpu_status); 546 547 s390_restore_bfp_rounding_mode(env, old_mode); 548 handle_exceptions(env, xxc_from_m34(m34), GETPC()); 549 env->cc_op = cc; 550 if (float64_is_any_nan(v2)) { 551 return INT64_MIN; 552 } 553 return ret; 554 } 555 556 /* convert 128-bit float to 64-bit int */ 557 uint64_t HELPER(cgxb)(CPUS390XState *env, Int128 i2, uint32_t m34) 558 { 559 int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); 560 float128 v2 = ARG128(i2); 561 int64_t ret = float128_to_int64(v2, &env->fpu_status); 562 uint32_t cc = set_cc_conv_f128(v2, &env->fpu_status); 563 564 s390_restore_bfp_rounding_mode(env, old_mode); 565 handle_exceptions(env, xxc_from_m34(m34), GETPC()); 566 env->cc_op = cc; 567 if (float128_is_any_nan(v2)) { 568 return INT64_MIN; 569 } 570 return ret; 571 } 572 573 /* convert 32-bit float to 32-bit int */ 574 uint64_t HELPER(cfeb)(CPUS390XState *env, uint64_t v2, uint32_t m34) 575 { 576 int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); 577 int32_t ret = float32_to_int32(v2, &env->fpu_status); 578 uint32_t cc = set_cc_conv_f32(v2, &env->fpu_status); 579 580 s390_restore_bfp_rounding_mode(env, old_mode); 581 handle_exceptions(env, xxc_from_m34(m34), GETPC()); 582 env->cc_op = cc; 583 if (float32_is_any_nan(v2)) { 584 return INT32_MIN; 585 } 586 return ret; 587 } 588 589 /* convert 64-bit float to 32-bit int */ 590 uint64_t HELPER(cfdb)(CPUS390XState *env, uint64_t v2, uint32_t m34) 591 { 592 int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); 593 int32_t ret = float64_to_int32(v2, &env->fpu_status); 594 uint32_t cc = set_cc_conv_f64(v2, &env->fpu_status); 595 596 s390_restore_bfp_rounding_mode(env, old_mode); 597 handle_exceptions(env, xxc_from_m34(m34), GETPC()); 598 env->cc_op = cc; 599 if (float64_is_any_nan(v2)) { 600 return INT32_MIN; 601 } 602 return ret; 603 } 604 605 /* convert 128-bit float to 32-bit int */ 606 uint64_t HELPER(cfxb)(CPUS390XState *env, Int128 i2, uint32_t m34) 607 { 608 int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); 609 float128 v2 = ARG128(i2); 610 int32_t ret = float128_to_int32(v2, &env->fpu_status); 611 uint32_t cc = set_cc_conv_f128(v2, &env->fpu_status); 612 613 s390_restore_bfp_rounding_mode(env, old_mode); 614 handle_exceptions(env, xxc_from_m34(m34), GETPC()); 615 env->cc_op = cc; 616 if (float128_is_any_nan(v2)) { 617 return INT32_MIN; 618 } 619 return ret; 620 } 621 622 /* convert 32-bit float to 64-bit uint */ 623 uint64_t HELPER(clgeb)(CPUS390XState *env, uint64_t v2, uint32_t m34) 624 { 625 int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); 626 uint64_t ret = float32_to_uint64(v2, &env->fpu_status); 627 uint32_t cc = set_cc_conv_f32(v2, &env->fpu_status); 628 629 s390_restore_bfp_rounding_mode(env, old_mode); 630 handle_exceptions(env, xxc_from_m34(m34), GETPC()); 631 env->cc_op = cc; 632 if (float32_is_any_nan(v2)) { 633 return 0; 634 } 635 return ret; 636 } 637 638 /* convert 64-bit float to 64-bit uint */ 639 uint64_t HELPER(clgdb)(CPUS390XState *env, uint64_t v2, uint32_t m34) 640 { 641 int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); 642 uint64_t ret = float64_to_uint64(v2, &env->fpu_status); 643 uint32_t cc = set_cc_conv_f64(v2, &env->fpu_status); 644 645 s390_restore_bfp_rounding_mode(env, old_mode); 646 handle_exceptions(env, xxc_from_m34(m34), GETPC()); 647 env->cc_op = cc; 648 if (float64_is_any_nan(v2)) { 649 return 0; 650 } 651 return ret; 652 } 653 654 /* convert 128-bit float to 64-bit uint */ 655 uint64_t HELPER(clgxb)(CPUS390XState *env, Int128 i2, uint32_t m34) 656 { 657 int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); 658 float128 v2 = ARG128(i2); 659 uint64_t ret = float128_to_uint64(v2, &env->fpu_status); 660 uint32_t cc = set_cc_conv_f128(v2, &env->fpu_status); 661 662 s390_restore_bfp_rounding_mode(env, old_mode); 663 handle_exceptions(env, xxc_from_m34(m34), GETPC()); 664 env->cc_op = cc; 665 if (float128_is_any_nan(v2)) { 666 return 0; 667 } 668 return ret; 669 } 670 671 /* convert 32-bit float to 32-bit uint */ 672 uint64_t HELPER(clfeb)(CPUS390XState *env, uint64_t v2, uint32_t m34) 673 { 674 int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); 675 uint32_t ret = float32_to_uint32(v2, &env->fpu_status); 676 uint32_t cc = set_cc_conv_f32(v2, &env->fpu_status); 677 678 s390_restore_bfp_rounding_mode(env, old_mode); 679 handle_exceptions(env, xxc_from_m34(m34), GETPC()); 680 env->cc_op = cc; 681 if (float32_is_any_nan(v2)) { 682 return 0; 683 } 684 return ret; 685 } 686 687 /* convert 64-bit float to 32-bit uint */ 688 uint64_t HELPER(clfdb)(CPUS390XState *env, uint64_t v2, uint32_t m34) 689 { 690 int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); 691 uint32_t ret = float64_to_uint32(v2, &env->fpu_status); 692 uint32_t cc = set_cc_conv_f64(v2, &env->fpu_status); 693 694 s390_restore_bfp_rounding_mode(env, old_mode); 695 handle_exceptions(env, xxc_from_m34(m34), GETPC()); 696 env->cc_op = cc; 697 if (float64_is_any_nan(v2)) { 698 return 0; 699 } 700 return ret; 701 } 702 703 /* convert 128-bit float to 32-bit uint */ 704 uint64_t HELPER(clfxb)(CPUS390XState *env, Int128 i2, uint32_t m34) 705 { 706 int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); 707 float128 v2 = ARG128(i2); 708 uint32_t ret = float128_to_uint32(v2, &env->fpu_status); 709 uint32_t cc = set_cc_conv_f128(v2, &env->fpu_status); 710 711 s390_restore_bfp_rounding_mode(env, old_mode); 712 handle_exceptions(env, xxc_from_m34(m34), GETPC()); 713 env->cc_op = cc; 714 if (float128_is_any_nan(v2)) { 715 return 0; 716 } 717 return ret; 718 } 719 720 /* round to integer 32-bit */ 721 uint64_t HELPER(fieb)(CPUS390XState *env, uint64_t f2, uint32_t m34) 722 { 723 int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); 724 float32 ret = float32_round_to_int(f2, &env->fpu_status); 725 726 s390_restore_bfp_rounding_mode(env, old_mode); 727 handle_exceptions(env, xxc_from_m34(m34), GETPC()); 728 return ret; 729 } 730 731 /* round to integer 64-bit */ 732 uint64_t HELPER(fidb)(CPUS390XState *env, uint64_t f2, uint32_t m34) 733 { 734 int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); 735 float64 ret = float64_round_to_int(f2, &env->fpu_status); 736 737 s390_restore_bfp_rounding_mode(env, old_mode); 738 handle_exceptions(env, xxc_from_m34(m34), GETPC()); 739 return ret; 740 } 741 742 /* round to integer 128-bit */ 743 Int128 HELPER(fixb)(CPUS390XState *env, Int128 a, uint32_t m34) 744 { 745 int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); 746 float128 ret = float128_round_to_int(ARG128(a), &env->fpu_status); 747 748 s390_restore_bfp_rounding_mode(env, old_mode); 749 handle_exceptions(env, xxc_from_m34(m34), GETPC()); 750 return RET128(ret); 751 } 752 753 /* 32-bit FP compare and signal */ 754 uint32_t HELPER(keb)(CPUS390XState *env, uint64_t f1, uint64_t f2) 755 { 756 FloatRelation cmp = float32_compare(f1, f2, &env->fpu_status); 757 handle_exceptions(env, false, GETPC()); 758 return float_comp_to_cc(env, cmp); 759 } 760 761 /* 64-bit FP compare and signal */ 762 uint32_t HELPER(kdb)(CPUS390XState *env, uint64_t f1, uint64_t f2) 763 { 764 FloatRelation cmp = float64_compare(f1, f2, &env->fpu_status); 765 handle_exceptions(env, false, GETPC()); 766 return float_comp_to_cc(env, cmp); 767 } 768 769 /* 128-bit FP compare and signal */ 770 uint32_t HELPER(kxb)(CPUS390XState *env, Int128 a, Int128 b) 771 { 772 FloatRelation cmp = float128_compare(ARG128(a), ARG128(b), 773 &env->fpu_status); 774 handle_exceptions(env, false, GETPC()); 775 return float_comp_to_cc(env, cmp); 776 } 777 778 /* 32-bit FP multiply and add */ 779 uint64_t HELPER(maeb)(CPUS390XState *env, uint64_t f1, 780 uint64_t f2, uint64_t f3) 781 { 782 float32 ret = float32_muladd(f2, f3, f1, 0, &env->fpu_status); 783 handle_exceptions(env, false, GETPC()); 784 return ret; 785 } 786 787 /* 64-bit FP multiply and add */ 788 uint64_t HELPER(madb)(CPUS390XState *env, uint64_t f1, 789 uint64_t f2, uint64_t f3) 790 { 791 float64 ret = float64_muladd(f2, f3, f1, 0, &env->fpu_status); 792 handle_exceptions(env, false, GETPC()); 793 return ret; 794 } 795 796 /* 32-bit FP multiply and subtract */ 797 uint64_t HELPER(mseb)(CPUS390XState *env, uint64_t f1, 798 uint64_t f2, uint64_t f3) 799 { 800 float32 ret = float32_muladd(f2, f3, f1, float_muladd_negate_c, 801 &env->fpu_status); 802 handle_exceptions(env, false, GETPC()); 803 return ret; 804 } 805 806 /* 64-bit FP multiply and subtract */ 807 uint64_t HELPER(msdb)(CPUS390XState *env, uint64_t f1, 808 uint64_t f2, uint64_t f3) 809 { 810 float64 ret = float64_muladd(f2, f3, f1, float_muladd_negate_c, 811 &env->fpu_status); 812 handle_exceptions(env, false, GETPC()); 813 return ret; 814 } 815 816 /* The rightmost bit has the number 11. */ 817 static inline uint16_t dcmask(int bit, bool neg) 818 { 819 return 1 << (11 - bit - neg); 820 } 821 822 #define DEF_FLOAT_DCMASK(_TYPE) \ 823 uint16_t _TYPE##_dcmask(CPUS390XState *env, _TYPE f1) \ 824 { \ 825 const bool neg = _TYPE##_is_neg(f1); \ 826 \ 827 /* Sorted by most common cases - only one class is possible */ \ 828 if (_TYPE##_is_normal(f1)) { \ 829 return dcmask(2, neg); \ 830 } else if (_TYPE##_is_zero(f1)) { \ 831 return dcmask(0, neg); \ 832 } else if (_TYPE##_is_denormal(f1)) { \ 833 return dcmask(4, neg); \ 834 } else if (_TYPE##_is_infinity(f1)) { \ 835 return dcmask(6, neg); \ 836 } else if (_TYPE##_is_quiet_nan(f1, &env->fpu_status)) { \ 837 return dcmask(8, neg); \ 838 } \ 839 /* signaling nan, as last remaining case */ \ 840 return dcmask(10, neg); \ 841 } 842 DEF_FLOAT_DCMASK(float32) 843 DEF_FLOAT_DCMASK(float64) 844 DEF_FLOAT_DCMASK(float128) 845 846 /* test data class 32-bit */ 847 uint32_t HELPER(tceb)(CPUS390XState *env, uint64_t f1, uint64_t m2) 848 { 849 return (m2 & float32_dcmask(env, f1)) != 0; 850 } 851 852 /* test data class 64-bit */ 853 uint32_t HELPER(tcdb)(CPUS390XState *env, uint64_t v1, uint64_t m2) 854 { 855 return (m2 & float64_dcmask(env, v1)) != 0; 856 } 857 858 /* test data class 128-bit */ 859 uint32_t HELPER(tcxb)(CPUS390XState *env, Int128 a, uint64_t m2) 860 { 861 return (m2 & float128_dcmask(env, ARG128(a))) != 0; 862 } 863 864 /* square root 32-bit */ 865 uint64_t HELPER(sqeb)(CPUS390XState *env, uint64_t f2) 866 { 867 float32 ret = float32_sqrt(f2, &env->fpu_status); 868 handle_exceptions(env, false, GETPC()); 869 return ret; 870 } 871 872 /* square root 64-bit */ 873 uint64_t HELPER(sqdb)(CPUS390XState *env, uint64_t f2) 874 { 875 float64 ret = float64_sqrt(f2, &env->fpu_status); 876 handle_exceptions(env, false, GETPC()); 877 return ret; 878 } 879 880 /* square root 128-bit */ 881 Int128 HELPER(sqxb)(CPUS390XState *env, Int128 a) 882 { 883 float128 ret = float128_sqrt(ARG128(a), &env->fpu_status); 884 handle_exceptions(env, false, GETPC()); 885 return RET128(ret); 886 } 887 888 static const int fpc_to_rnd[8] = { 889 float_round_nearest_even, 890 float_round_to_zero, 891 float_round_up, 892 float_round_down, 893 -1, 894 -1, 895 -1, 896 float_round_to_odd, 897 }; 898 899 /* set fpc */ 900 void HELPER(sfpc)(CPUS390XState *env, uint64_t fpc) 901 { 902 if (fpc_to_rnd[fpc & 0x7] == -1 || fpc & 0x03030088u || 903 (!s390_has_feat(S390_FEAT_FLOATING_POINT_EXT) && fpc & 0x4)) { 904 tcg_s390_program_interrupt(env, PGM_SPECIFICATION, GETPC()); 905 } 906 907 /* Install everything in the main FPC. */ 908 env->fpc = fpc; 909 910 /* Install the rounding mode in the shadow fpu_status. */ 911 set_float_rounding_mode(fpc_to_rnd[fpc & 0x7], &env->fpu_status); 912 } 913 914 /* set fpc and signal */ 915 void HELPER(sfas)(CPUS390XState *env, uint64_t fpc) 916 { 917 uint32_t signalling = env->fpc; 918 uint32_t s390_exc; 919 920 if (fpc_to_rnd[fpc & 0x7] == -1 || fpc & 0x03030088u || 921 (!s390_has_feat(S390_FEAT_FLOATING_POINT_EXT) && fpc & 0x4)) { 922 tcg_s390_program_interrupt(env, PGM_SPECIFICATION, GETPC()); 923 } 924 925 /* 926 * FPC is set to the FPC operand with a bitwise OR of the signalling 927 * flags. 928 */ 929 env->fpc = fpc | (signalling & 0x00ff0000); 930 set_float_rounding_mode(fpc_to_rnd[fpc & 0x7], &env->fpu_status); 931 932 /* 933 * If any signaling flag is enabled in the new FPC mask, a 934 * simulated-iee-exception exception occurs. 935 */ 936 s390_exc = (signalling >> 16) & (fpc >> 24); 937 if (s390_exc) { 938 if (s390_exc & S390_IEEE_MASK_INVALID) { 939 s390_exc = S390_IEEE_MASK_INVALID; 940 } else if (s390_exc & S390_IEEE_MASK_DIVBYZERO) { 941 s390_exc = S390_IEEE_MASK_DIVBYZERO; 942 } else if (s390_exc & S390_IEEE_MASK_OVERFLOW) { 943 s390_exc &= (S390_IEEE_MASK_OVERFLOW | S390_IEEE_MASK_INEXACT); 944 } else if (s390_exc & S390_IEEE_MASK_UNDERFLOW) { 945 s390_exc &= (S390_IEEE_MASK_UNDERFLOW | S390_IEEE_MASK_INEXACT); 946 } else if (s390_exc & S390_IEEE_MASK_INEXACT) { 947 s390_exc = S390_IEEE_MASK_INEXACT; 948 } else if (s390_exc & S390_IEEE_MASK_QUANTUM) { 949 s390_exc = S390_IEEE_MASK_QUANTUM; 950 } 951 tcg_s390_data_exception(env, s390_exc | 3, GETPC()); 952 } 953 } 954 955 /* set bfp rounding mode */ 956 void HELPER(srnm)(CPUS390XState *env, uint64_t rnd) 957 { 958 if (rnd > 0x7 || fpc_to_rnd[rnd & 0x7] == -1) { 959 tcg_s390_program_interrupt(env, PGM_SPECIFICATION, GETPC()); 960 } 961 962 env->fpc = deposit32(env->fpc, 0, 3, rnd); 963 set_float_rounding_mode(fpc_to_rnd[rnd & 0x7], &env->fpu_status); 964 } 965