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