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