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