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