qemu/target-s390x/fpu_helper.c
<<
>>
Prefs
   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 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 "cpu.h"
  22#include "exec/cpu_ldst.h"
  23#include "exec/helper-proto.h"
  24
  25/* #define DEBUG_HELPER */
  26#ifdef DEBUG_HELPER
  27#define HELPER_LOG(x...) qemu_log(x)
  28#else
  29#define HELPER_LOG(x...)
  30#endif
  31
  32#define RET128(F) (env->retxl = F.low, F.high)
  33
  34#define convert_bit(mask, from, to) \
  35    (to < from                      \
  36     ? (mask / (from / to)) & to    \
  37     : (mask & from) * (to / from))
  38
  39static void ieee_exception(CPUS390XState *env, uint32_t dxc, uintptr_t retaddr)
  40{
  41    /* Install the DXC code.  */
  42    env->fpc = (env->fpc & ~0xff00) | (dxc << 8);
  43    /* Trap.  */
  44    runtime_exception(env, PGM_DATA, retaddr);
  45}
  46
  47/* Should be called after any operation that may raise IEEE exceptions.  */
  48static void handle_exceptions(CPUS390XState *env, uintptr_t retaddr)
  49{
  50    unsigned s390_exc, qemu_exc;
  51
  52    /* Get the exceptions raised by the current operation.  Reset the
  53       fpu_status contents so that the next operation has a clean slate.  */
  54    qemu_exc = env->fpu_status.float_exception_flags;
  55    if (qemu_exc == 0) {
  56        return;
  57    }
  58    env->fpu_status.float_exception_flags = 0;
  59
  60    /* Convert softfloat exception bits to s390 exception bits.  */
  61    s390_exc = 0;
  62    s390_exc |= convert_bit(qemu_exc, float_flag_invalid, 0x80);
  63    s390_exc |= convert_bit(qemu_exc, float_flag_divbyzero, 0x40);
  64    s390_exc |= convert_bit(qemu_exc, float_flag_overflow, 0x20);
  65    s390_exc |= convert_bit(qemu_exc, float_flag_underflow, 0x10);
  66    s390_exc |= convert_bit(qemu_exc, float_flag_inexact, 0x08);
  67
  68    /* Install the exceptions that we raised.  */
  69    env->fpc |= s390_exc << 16;
  70
  71    /* Send signals for enabled exceptions.  */
  72    s390_exc &= env->fpc >> 24;
  73    if (s390_exc) {
  74        ieee_exception(env, s390_exc, retaddr);
  75    }
  76}
  77
  78static inline int float_comp_to_cc(CPUS390XState *env, int float_compare)
  79{
  80    S390CPU *cpu = s390_env_get_cpu(env);
  81
  82    switch (float_compare) {
  83    case float_relation_equal:
  84        return 0;
  85    case float_relation_less:
  86        return 1;
  87    case float_relation_greater:
  88        return 2;
  89    case float_relation_unordered:
  90        return 3;
  91    default:
  92        cpu_abort(CPU(cpu), "unknown return value for float compare\n");
  93    }
  94}
  95
  96/* condition codes for unary FP ops */
  97uint32_t set_cc_nz_f32(float32 v)
  98{
  99    if (float32_is_any_nan(v)) {
 100        return 3;
 101    } else if (float32_is_zero(v)) {
 102        return 0;
 103    } else if (float32_is_neg(v)) {
 104        return 1;
 105    } else {
 106        return 2;
 107    }
 108}
 109
 110uint32_t set_cc_nz_f64(float64 v)
 111{
 112    if (float64_is_any_nan(v)) {
 113        return 3;
 114    } else if (float64_is_zero(v)) {
 115        return 0;
 116    } else if (float64_is_neg(v)) {
 117        return 1;
 118    } else {
 119        return 2;
 120    }
 121}
 122
 123uint32_t set_cc_nz_f128(float128 v)
 124{
 125    if (float128_is_any_nan(v)) {
 126        return 3;
 127    } else if (float128_is_zero(v)) {
 128        return 0;
 129    } else if (float128_is_neg(v)) {
 130        return 1;
 131    } else {
 132        return 2;
 133    }
 134}
 135
 136/* 32-bit FP addition */
 137uint64_t HELPER(aeb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
 138{
 139    float32 ret = float32_add(f1, f2, &env->fpu_status);
 140    handle_exceptions(env, GETPC());
 141    return ret;
 142}
 143
 144/* 64-bit FP addition */
 145uint64_t HELPER(adb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
 146{
 147    float64 ret = float64_add(f1, f2, &env->fpu_status);
 148    handle_exceptions(env, GETPC());
 149    return ret;
 150}
 151
 152/* 128-bit FP addition */
 153uint64_t HELPER(axb)(CPUS390XState *env, uint64_t ah, uint64_t al,
 154                     uint64_t bh, uint64_t bl)
 155{
 156    float128 ret = float128_add(make_float128(ah, al),
 157                                make_float128(bh, bl),
 158                                &env->fpu_status);
 159    handle_exceptions(env, GETPC());
 160    return RET128(ret);
 161}
 162
 163/* 32-bit FP subtraction */
 164uint64_t HELPER(seb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
 165{
 166    float32 ret = float32_sub(f1, f2, &env->fpu_status);
 167    handle_exceptions(env, GETPC());
 168    return ret;
 169}
 170
 171/* 64-bit FP subtraction */
 172uint64_t HELPER(sdb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
 173{
 174    float64 ret = float64_sub(f1, f2, &env->fpu_status);
 175    handle_exceptions(env, GETPC());
 176    return ret;
 177}
 178
 179/* 128-bit FP subtraction */
 180uint64_t HELPER(sxb)(CPUS390XState *env, uint64_t ah, uint64_t al,
 181                     uint64_t bh, uint64_t bl)
 182{
 183    float128 ret = float128_sub(make_float128(ah, al),
 184                                make_float128(bh, bl),
 185                                &env->fpu_status);
 186    handle_exceptions(env, GETPC());
 187    return RET128(ret);
 188}
 189
 190/* 32-bit FP division */
 191uint64_t HELPER(deb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
 192{
 193    float32 ret = float32_div(f1, f2, &env->fpu_status);
 194    handle_exceptions(env, GETPC());
 195    return ret;
 196}
 197
 198/* 64-bit FP division */
 199uint64_t HELPER(ddb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
 200{
 201    float64 ret = float64_div(f1, f2, &env->fpu_status);
 202    handle_exceptions(env, GETPC());
 203    return ret;
 204}
 205
 206/* 128-bit FP division */
 207uint64_t HELPER(dxb)(CPUS390XState *env, uint64_t ah, uint64_t al,
 208                     uint64_t bh, uint64_t bl)
 209{
 210    float128 ret = float128_div(make_float128(ah, al),
 211                                make_float128(bh, bl),
 212                                &env->fpu_status);
 213    handle_exceptions(env, GETPC());
 214    return RET128(ret);
 215}
 216
 217/* 32-bit FP multiplication */
 218uint64_t HELPER(meeb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
 219{
 220    float32 ret = float32_mul(f1, f2, &env->fpu_status);
 221    handle_exceptions(env, GETPC());
 222    return ret;
 223}
 224
 225/* 64-bit FP multiplication */
 226uint64_t HELPER(mdb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
 227{
 228    float64 ret = float64_mul(f1, f2, &env->fpu_status);
 229    handle_exceptions(env, GETPC());
 230    return ret;
 231}
 232
 233/* 64/32-bit FP multiplication */
 234uint64_t HELPER(mdeb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
 235{
 236    float64 ret = float32_to_float64(f2, &env->fpu_status);
 237    ret = float64_mul(f1, ret, &env->fpu_status);
 238    handle_exceptions(env, GETPC());
 239    return ret;
 240}
 241
 242/* 128-bit FP multiplication */
 243uint64_t HELPER(mxb)(CPUS390XState *env, uint64_t ah, uint64_t al,
 244                     uint64_t bh, uint64_t bl)
 245{
 246    float128 ret = float128_mul(make_float128(ah, al),
 247                                make_float128(bh, bl),
 248                                &env->fpu_status);
 249    handle_exceptions(env, GETPC());
 250    return RET128(ret);
 251}
 252
 253/* 128/64-bit FP multiplication */
 254uint64_t HELPER(mxdb)(CPUS390XState *env, uint64_t ah, uint64_t al,
 255                      uint64_t f2)
 256{
 257    float128 ret = float64_to_float128(f2, &env->fpu_status);
 258    ret = float128_mul(make_float128(ah, al), ret, &env->fpu_status);
 259    handle_exceptions(env, GETPC());
 260    return RET128(ret);
 261}
 262
 263/* convert 32-bit float to 64-bit float */
 264uint64_t HELPER(ldeb)(CPUS390XState *env, uint64_t f2)
 265{
 266    float64 ret = float32_to_float64(f2, &env->fpu_status);
 267    handle_exceptions(env, GETPC());
 268    return float64_maybe_silence_nan(ret);
 269}
 270
 271/* convert 128-bit float to 64-bit float */
 272uint64_t HELPER(ldxb)(CPUS390XState *env, uint64_t ah, uint64_t al)
 273{
 274    float64 ret = float128_to_float64(make_float128(ah, al), &env->fpu_status);
 275    handle_exceptions(env, GETPC());
 276    return float64_maybe_silence_nan(ret);
 277}
 278
 279/* convert 64-bit float to 128-bit float */
 280uint64_t HELPER(lxdb)(CPUS390XState *env, uint64_t f2)
 281{
 282    float128 ret = float64_to_float128(f2, &env->fpu_status);
 283    handle_exceptions(env, GETPC());
 284    return RET128(float128_maybe_silence_nan(ret));
 285}
 286
 287/* convert 32-bit float to 128-bit float */
 288uint64_t HELPER(lxeb)(CPUS390XState *env, uint64_t f2)
 289{
 290    float128 ret = float32_to_float128(f2, &env->fpu_status);
 291    handle_exceptions(env, GETPC());
 292    return RET128(float128_maybe_silence_nan(ret));
 293}
 294
 295/* convert 64-bit float to 32-bit float */
 296uint64_t HELPER(ledb)(CPUS390XState *env, uint64_t f2)
 297{
 298    float32 ret = float64_to_float32(f2, &env->fpu_status);
 299    handle_exceptions(env, GETPC());
 300    return float32_maybe_silence_nan(ret);
 301}
 302
 303/* convert 128-bit float to 32-bit float */
 304uint64_t HELPER(lexb)(CPUS390XState *env, uint64_t ah, uint64_t al)
 305{
 306    float32 ret = float128_to_float32(make_float128(ah, al), &env->fpu_status);
 307    handle_exceptions(env, GETPC());
 308    return float32_maybe_silence_nan(ret);
 309}
 310
 311/* 32-bit FP compare */
 312uint32_t HELPER(ceb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
 313{
 314    int cmp = float32_compare_quiet(f1, f2, &env->fpu_status);
 315    handle_exceptions(env, GETPC());
 316    return float_comp_to_cc(env, cmp);
 317}
 318
 319/* 64-bit FP compare */
 320uint32_t HELPER(cdb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
 321{
 322    int cmp = float64_compare_quiet(f1, f2, &env->fpu_status);
 323    handle_exceptions(env, GETPC());
 324    return float_comp_to_cc(env, cmp);
 325}
 326
 327/* 128-bit FP compare */
 328uint32_t HELPER(cxb)(CPUS390XState *env, uint64_t ah, uint64_t al,
 329                     uint64_t bh, uint64_t bl)
 330{
 331    int cmp = float128_compare_quiet(make_float128(ah, al),
 332                                     make_float128(bh, bl),
 333                                     &env->fpu_status);
 334    handle_exceptions(env, GETPC());
 335    return float_comp_to_cc(env, cmp);
 336}
 337
 338static int swap_round_mode(CPUS390XState *env, int m3)
 339{
 340    int ret = env->fpu_status.float_rounding_mode;
 341    switch (m3) {
 342    case 0:
 343        /* current mode */
 344        break;
 345    case 1:
 346        /* biased round no nearest */
 347    case 4:
 348        /* round to nearest */
 349        set_float_rounding_mode(float_round_nearest_even, &env->fpu_status);
 350        break;
 351    case 5:
 352        /* round to zero */
 353        set_float_rounding_mode(float_round_to_zero, &env->fpu_status);
 354        break;
 355    case 6:
 356        /* round to +inf */
 357        set_float_rounding_mode(float_round_up, &env->fpu_status);
 358        break;
 359    case 7:
 360        /* round to -inf */
 361        set_float_rounding_mode(float_round_down, &env->fpu_status);
 362        break;
 363    }
 364    return ret;
 365}
 366
 367/* convert 64-bit int to 32-bit float */
 368uint64_t HELPER(cegb)(CPUS390XState *env, int64_t v2, uint32_t m3)
 369{
 370    int hold = swap_round_mode(env, m3);
 371    float32 ret = int64_to_float32(v2, &env->fpu_status);
 372    set_float_rounding_mode(hold, &env->fpu_status);
 373    handle_exceptions(env, GETPC());
 374    return ret;
 375}
 376
 377/* convert 64-bit int to 64-bit float */
 378uint64_t HELPER(cdgb)(CPUS390XState *env, int64_t v2, uint32_t m3)
 379{
 380    int hold = swap_round_mode(env, m3);
 381    float64 ret = int64_to_float64(v2, &env->fpu_status);
 382    set_float_rounding_mode(hold, &env->fpu_status);
 383    handle_exceptions(env, GETPC());
 384    return ret;
 385}
 386
 387/* convert 64-bit int to 128-bit float */
 388uint64_t HELPER(cxgb)(CPUS390XState *env, int64_t v2, uint32_t m3)
 389{
 390    int hold = swap_round_mode(env, m3);
 391    float128 ret = int64_to_float128(v2, &env->fpu_status);
 392    set_float_rounding_mode(hold, &env->fpu_status);
 393    handle_exceptions(env, GETPC());
 394    return RET128(ret);
 395}
 396
 397/* convert 64-bit uint to 32-bit float */
 398uint64_t HELPER(celgb)(CPUS390XState *env, uint64_t v2, uint32_t m3)
 399{
 400    int hold = swap_round_mode(env, m3);
 401    float32 ret = uint64_to_float32(v2, &env->fpu_status);
 402    set_float_rounding_mode(hold, &env->fpu_status);
 403    handle_exceptions(env, GETPC());
 404    return ret;
 405}
 406
 407/* convert 64-bit uint to 64-bit float */
 408uint64_t HELPER(cdlgb)(CPUS390XState *env, uint64_t v2, uint32_t m3)
 409{
 410    int hold = swap_round_mode(env, m3);
 411    float64 ret = uint64_to_float64(v2, &env->fpu_status);
 412    set_float_rounding_mode(hold, &env->fpu_status);
 413    handle_exceptions(env, GETPC());
 414    return ret;
 415}
 416
 417/* convert 64-bit uint to 128-bit float */
 418uint64_t HELPER(cxlgb)(CPUS390XState *env, uint64_t v2, uint32_t m3)
 419{
 420    int hold = swap_round_mode(env, m3);
 421    float128 ret = uint64_to_float128(v2, &env->fpu_status);
 422    set_float_rounding_mode(hold, &env->fpu_status);
 423    handle_exceptions(env, GETPC());
 424    return RET128(ret);
 425}
 426
 427/* convert 32-bit float to 64-bit int */
 428uint64_t HELPER(cgeb)(CPUS390XState *env, uint64_t v2, uint32_t m3)
 429{
 430    int hold = swap_round_mode(env, m3);
 431    int64_t ret = float32_to_int64(v2, &env->fpu_status);
 432    set_float_rounding_mode(hold, &env->fpu_status);
 433    handle_exceptions(env, GETPC());
 434    return ret;
 435}
 436
 437/* convert 64-bit float to 64-bit int */
 438uint64_t HELPER(cgdb)(CPUS390XState *env, uint64_t v2, uint32_t m3)
 439{
 440    int hold = swap_round_mode(env, m3);
 441    int64_t ret = float64_to_int64(v2, &env->fpu_status);
 442    set_float_rounding_mode(hold, &env->fpu_status);
 443    handle_exceptions(env, GETPC());
 444    return ret;
 445}
 446
 447/* convert 128-bit float to 64-bit int */
 448uint64_t HELPER(cgxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m3)
 449{
 450    int hold = swap_round_mode(env, m3);
 451    float128 v2 = make_float128(h, l);
 452    int64_t ret = float128_to_int64(v2, &env->fpu_status);
 453    set_float_rounding_mode(hold, &env->fpu_status);
 454    handle_exceptions(env, GETPC());
 455    return ret;
 456}
 457
 458/* convert 32-bit float to 32-bit int */
 459uint64_t HELPER(cfeb)(CPUS390XState *env, uint64_t v2, uint32_t m3)
 460{
 461    int hold = swap_round_mode(env, m3);
 462    int32_t ret = float32_to_int32(v2, &env->fpu_status);
 463    set_float_rounding_mode(hold, &env->fpu_status);
 464    handle_exceptions(env, GETPC());
 465    return ret;
 466}
 467
 468/* convert 64-bit float to 32-bit int */
 469uint64_t HELPER(cfdb)(CPUS390XState *env, uint64_t v2, uint32_t m3)
 470{
 471    int hold = swap_round_mode(env, m3);
 472    int32_t ret = float64_to_int32(v2, &env->fpu_status);
 473    set_float_rounding_mode(hold, &env->fpu_status);
 474    handle_exceptions(env, GETPC());
 475    return ret;
 476}
 477
 478/* convert 128-bit float to 32-bit int */
 479uint64_t HELPER(cfxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m3)
 480{
 481    int hold = swap_round_mode(env, m3);
 482    float128 v2 = make_float128(h, l);
 483    int32_t ret = float128_to_int32(v2, &env->fpu_status);
 484    set_float_rounding_mode(hold, &env->fpu_status);
 485    handle_exceptions(env, GETPC());
 486    return ret;
 487}
 488
 489/* convert 32-bit float to 64-bit uint */
 490uint64_t HELPER(clgeb)(CPUS390XState *env, uint64_t v2, uint32_t m3)
 491{
 492    int hold = swap_round_mode(env, m3);
 493    uint64_t ret;
 494    v2 = float32_to_float64(v2, &env->fpu_status);
 495    ret = float64_to_uint64(v2, &env->fpu_status);
 496    set_float_rounding_mode(hold, &env->fpu_status);
 497    handle_exceptions(env, GETPC());
 498    return ret;
 499}
 500
 501/* convert 64-bit float to 64-bit uint */
 502uint64_t HELPER(clgdb)(CPUS390XState *env, uint64_t v2, uint32_t m3)
 503{
 504    int hold = swap_round_mode(env, m3);
 505    uint64_t ret = float64_to_uint64(v2, &env->fpu_status);
 506    set_float_rounding_mode(hold, &env->fpu_status);
 507    handle_exceptions(env, GETPC());
 508    return ret;
 509}
 510
 511/* convert 128-bit float to 64-bit uint */
 512uint64_t HELPER(clgxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m3)
 513{
 514    int hold = swap_round_mode(env, m3);
 515    float128 v2 = make_float128(h, l);
 516    /* ??? Not 100% correct.  */
 517    uint64_t ret = float128_to_int64(v2, &env->fpu_status);
 518    set_float_rounding_mode(hold, &env->fpu_status);
 519    handle_exceptions(env, GETPC());
 520    return ret;
 521}
 522
 523/* convert 32-bit float to 32-bit uint */
 524uint64_t HELPER(clfeb)(CPUS390XState *env, uint64_t v2, uint32_t m3)
 525{
 526    int hold = swap_round_mode(env, m3);
 527    uint32_t ret = float32_to_uint32(v2, &env->fpu_status);
 528    set_float_rounding_mode(hold, &env->fpu_status);
 529    handle_exceptions(env, GETPC());
 530    return ret;
 531}
 532
 533/* convert 64-bit float to 32-bit uint */
 534uint64_t HELPER(clfdb)(CPUS390XState *env, uint64_t v2, uint32_t m3)
 535{
 536    int hold = swap_round_mode(env, m3);
 537    uint32_t ret = float64_to_uint32(v2, &env->fpu_status);
 538    set_float_rounding_mode(hold, &env->fpu_status);
 539    handle_exceptions(env, GETPC());
 540    return ret;
 541}
 542
 543/* convert 128-bit float to 32-bit uint */
 544uint64_t HELPER(clfxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m3)
 545{
 546    int hold = swap_round_mode(env, m3);
 547    float128 v2 = make_float128(h, l);
 548    /* Not 100% correct.  */
 549    uint32_t ret = float128_to_int64(v2, &env->fpu_status);
 550    set_float_rounding_mode(hold, &env->fpu_status);
 551    handle_exceptions(env, GETPC());
 552    return ret;
 553}
 554
 555/* round to integer 32-bit */
 556uint64_t HELPER(fieb)(CPUS390XState *env, uint64_t f2, uint32_t m3)
 557{
 558    int hold = swap_round_mode(env, m3);
 559    float32 ret = float32_round_to_int(f2, &env->fpu_status);
 560    set_float_rounding_mode(hold, &env->fpu_status);
 561    handle_exceptions(env, GETPC());
 562    return ret;
 563}
 564
 565/* round to integer 64-bit */
 566uint64_t HELPER(fidb)(CPUS390XState *env, uint64_t f2, uint32_t m3)
 567{
 568    int hold = swap_round_mode(env, m3);
 569    float64 ret = float64_round_to_int(f2, &env->fpu_status);
 570    set_float_rounding_mode(hold, &env->fpu_status);
 571    handle_exceptions(env, GETPC());
 572    return ret;
 573}
 574
 575/* round to integer 128-bit */
 576uint64_t HELPER(fixb)(CPUS390XState *env, uint64_t ah, uint64_t al, uint32_t m3)
 577{
 578    int hold = swap_round_mode(env, m3);
 579    float128 ret = float128_round_to_int(make_float128(ah, al),
 580                                         &env->fpu_status);
 581    set_float_rounding_mode(hold, &env->fpu_status);
 582    handle_exceptions(env, GETPC());
 583    return RET128(ret);
 584}
 585
 586/* 32-bit FP multiply and add */
 587uint64_t HELPER(maeb)(CPUS390XState *env, uint64_t f1,
 588                      uint64_t f2, uint64_t f3)
 589{
 590    float32 ret = float32_muladd(f2, f3, f1, 0, &env->fpu_status);
 591    handle_exceptions(env, GETPC());
 592    return ret;
 593}
 594
 595/* 64-bit FP multiply and add */
 596uint64_t HELPER(madb)(CPUS390XState *env, uint64_t f1,
 597                      uint64_t f2, uint64_t f3)
 598{
 599    float64 ret = float64_muladd(f2, f3, f1, 0, &env->fpu_status);
 600    handle_exceptions(env, GETPC());
 601    return ret;
 602}
 603
 604/* 32-bit FP multiply and subtract */
 605uint64_t HELPER(mseb)(CPUS390XState *env, uint64_t f1,
 606                      uint64_t f2, uint64_t f3)
 607{
 608    float32 ret = float32_muladd(f2, f3, f1, float_muladd_negate_c,
 609                                 &env->fpu_status);
 610    handle_exceptions(env, GETPC());
 611    return ret;
 612}
 613
 614/* 64-bit FP multiply and subtract */
 615uint64_t HELPER(msdb)(CPUS390XState *env, uint64_t f1,
 616                      uint64_t f2, uint64_t f3)
 617{
 618    float64 ret = float64_muladd(f2, f3, f1, float_muladd_negate_c,
 619                                 &env->fpu_status);
 620    handle_exceptions(env, GETPC());
 621    return ret;
 622}
 623
 624/* test data class 32-bit */
 625uint32_t HELPER(tceb)(uint64_t f1, uint64_t m2)
 626{
 627    float32 v1 = f1;
 628    int neg = float32_is_neg(v1);
 629    uint32_t cc = 0;
 630
 631    if ((float32_is_zero(v1) && (m2 & (1 << (11-neg)))) ||
 632        (float32_is_infinity(v1) && (m2 & (1 << (5-neg)))) ||
 633        (float32_is_any_nan(v1) && (m2 & (1 << (3-neg)))) ||
 634        (float32_is_signaling_nan(v1) && (m2 & (1 << (1-neg))))) {
 635        cc = 1;
 636    } else if (m2 & (1 << (9-neg))) {
 637        /* assume normalized number */
 638        cc = 1;
 639    }
 640    /* FIXME: denormalized? */
 641    return cc;
 642}
 643
 644/* test data class 64-bit */
 645uint32_t HELPER(tcdb)(uint64_t v1, uint64_t m2)
 646{
 647    int neg = float64_is_neg(v1);
 648    uint32_t cc = 0;
 649
 650    if ((float64_is_zero(v1) && (m2 & (1 << (11-neg)))) ||
 651        (float64_is_infinity(v1) && (m2 & (1 << (5-neg)))) ||
 652        (float64_is_any_nan(v1) && (m2 & (1 << (3-neg)))) ||
 653        (float64_is_signaling_nan(v1) && (m2 & (1 << (1-neg))))) {
 654        cc = 1;
 655    } else if (m2 & (1 << (9-neg))) {
 656        /* assume normalized number */
 657        cc = 1;
 658    }
 659    /* FIXME: denormalized? */
 660    return cc;
 661}
 662
 663/* test data class 128-bit */
 664uint32_t HELPER(tcxb)(uint64_t ah, uint64_t al, uint64_t m2)
 665{
 666    float128 v1 = make_float128(ah, al);
 667    int neg = float128_is_neg(v1);
 668    uint32_t cc = 0;
 669
 670    if ((float128_is_zero(v1) && (m2 & (1 << (11-neg)))) ||
 671        (float128_is_infinity(v1) && (m2 & (1 << (5-neg)))) ||
 672        (float128_is_any_nan(v1) && (m2 & (1 << (3-neg)))) ||
 673        (float128_is_signaling_nan(v1) && (m2 & (1 << (1-neg))))) {
 674        cc = 1;
 675    } else if (m2 & (1 << (9-neg))) {
 676        /* assume normalized number */
 677        cc = 1;
 678    }
 679    /* FIXME: denormalized? */
 680    return cc;
 681}
 682
 683/* square root 32-bit */
 684uint64_t HELPER(sqeb)(CPUS390XState *env, uint64_t f2)
 685{
 686    float32 ret = float32_sqrt(f2, &env->fpu_status);
 687    handle_exceptions(env, GETPC());
 688    return ret;
 689}
 690
 691/* square root 64-bit */
 692uint64_t HELPER(sqdb)(CPUS390XState *env, uint64_t f2)
 693{
 694    float64 ret = float64_sqrt(f2, &env->fpu_status);
 695    handle_exceptions(env, GETPC());
 696    return ret;
 697}
 698
 699/* square root 128-bit */
 700uint64_t HELPER(sqxb)(CPUS390XState *env, uint64_t ah, uint64_t al)
 701{
 702    float128 ret = float128_sqrt(make_float128(ah, al), &env->fpu_status);
 703    handle_exceptions(env, GETPC());
 704    return RET128(ret);
 705}
 706
 707static const int fpc_to_rnd[4] = {
 708    float_round_nearest_even,
 709    float_round_to_zero,
 710    float_round_up,
 711    float_round_down
 712};
 713
 714/* set fpc */
 715void HELPER(sfpc)(CPUS390XState *env, uint64_t fpc)
 716{
 717    /* Install everything in the main FPC.  */
 718    env->fpc = fpc;
 719
 720    /* Install the rounding mode in the shadow fpu_status.  */
 721    set_float_rounding_mode(fpc_to_rnd[fpc & 3], &env->fpu_status);
 722}
 723
 724/* set fpc and signal */
 725void HELPER(sfas)(CPUS390XState *env, uint64_t val)
 726{
 727    uint32_t signalling = env->fpc;
 728    uint32_t source = val;
 729    uint32_t s390_exc;
 730
 731    /* The contents of the source operand are placed in the FPC register;
 732       then the flags in the FPC register are set to the logical OR of the
 733       signalling flags and the source flags.  */
 734    env->fpc = source | (signalling & 0x00ff0000);
 735    set_float_rounding_mode(fpc_to_rnd[source & 3], &env->fpu_status);
 736
 737    /* If any signalling flag is 1 and the corresponding source mask
 738       is also 1, a simulated-iee-exception trap occurs.  */
 739    s390_exc = (signalling >> 16) & (source >> 24);
 740    if (s390_exc) {
 741        ieee_exception(env, s390_exc | 3, GETPC());
 742    }
 743}
 744