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