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 "helper.h"
  23
  24#if !defined(CONFIG_USER_ONLY)
  25#include "exec/softmmu_exec.h"
  26#endif
  27
  28/* #define DEBUG_HELPER */
  29#ifdef DEBUG_HELPER
  30#define HELPER_LOG(x...) qemu_log(x)
  31#else
  32#define HELPER_LOG(x...)
  33#endif
  34
  35#define RET128(F) (env->retxl = F.low, F.high)
  36
  37#define convert_bit(mask, from, to) \
  38    (to < from                      \
  39     ? (mask / (from / to)) & to    \
  40     : (mask & from) * (to / from))
  41
  42static void ieee_exception(CPUS390XState *env, uint32_t dxc, uintptr_t retaddr)
  43{
  44    /* Install the DXC code.  */
  45    env->fpc = (env->fpc & ~0xff00) | (dxc << 8);
  46    /* Trap.  */
  47    runtime_exception(env, PGM_DATA, retaddr);
  48}
  49
  50/* Should be called after any operation that may raise IEEE exceptions.  */
  51static void handle_exceptions(CPUS390XState *env, uintptr_t retaddr)
  52{
  53    unsigned s390_exc, qemu_exc;
  54
  55    /* Get the exceptions raised by the current operation.  Reset the
  56       fpu_status contents so that the next operation has a clean slate.  */
  57    qemu_exc = env->fpu_status.float_exception_flags;
  58    if (qemu_exc == 0) {
  59        return;
  60    }
  61    env->fpu_status.float_exception_flags = 0;
  62
  63    /* Convert softfloat exception bits to s390 exception bits.  */
  64    s390_exc = 0;
  65    s390_exc |= convert_bit(qemu_exc, float_flag_invalid, 0x80);
  66    s390_exc |= convert_bit(qemu_exc, float_flag_divbyzero, 0x40);
  67    s390_exc |= convert_bit(qemu_exc, float_flag_overflow, 0x20);
  68    s390_exc |= convert_bit(qemu_exc, float_flag_underflow, 0x10);
  69    s390_exc |= convert_bit(qemu_exc, float_flag_inexact, 0x08);
  70
  71    /* Install the exceptions that we raised.  */
  72    env->fpc |= s390_exc << 16;
  73
  74    /* Send signals for enabled exceptions.  */
  75    s390_exc &= env->fpc >> 24;
  76    if (s390_exc) {
  77        ieee_exception(env, s390_exc, retaddr);
  78    }
  79}
  80
  81static inline int float_comp_to_cc(CPUS390XState *env, int float_compare)
  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(env, "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 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 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(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(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 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 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/* 32-bit FP multiply and add */
 557uint64_t HELPER(maeb)(CPUS390XState *env, uint64_t f1,
 558                      uint64_t f2, uint64_t f3)
 559{
 560    float32 ret = float32_muladd(f2, f3, f1, 0, &env->fpu_status);
 561    handle_exceptions(env, GETPC());
 562    return ret;
 563}
 564
 565/* 64-bit FP multiply and add */
 566uint64_t HELPER(madb)(CPUS390XState *env, uint64_t f1,
 567                      uint64_t f2, uint64_t f3)
 568{
 569    float64 ret = float64_muladd(f2, f3, f1, 0, &env->fpu_status);
 570    handle_exceptions(env, GETPC());
 571    return ret;
 572}
 573
 574/* 32-bit FP multiply and subtract */
 575uint64_t HELPER(mseb)(CPUS390XState *env, uint64_t f1,
 576                      uint64_t f2, uint64_t f3)
 577{
 578    float32 ret = float32_muladd(f2, f3, f1, float_muladd_negate_c,
 579                                 &env->fpu_status);
 580    handle_exceptions(env, GETPC());
 581    return ret;
 582}
 583
 584/* 64-bit FP multiply and subtract */
 585uint64_t HELPER(msdb)(CPUS390XState *env, uint64_t f1,
 586                      uint64_t f2, uint64_t f3)
 587{
 588    float64 ret = float64_muladd(f2, f3, f1, float_muladd_negate_c,
 589                                 &env->fpu_status);
 590    handle_exceptions(env, GETPC());
 591    return ret;
 592}
 593
 594/* test data class 32-bit */
 595uint32_t HELPER(tceb)(uint64_t f1, uint64_t m2)
 596{
 597    float32 v1 = f1;
 598    int neg = float32_is_neg(v1);
 599    uint32_t cc = 0;
 600
 601    if ((float32_is_zero(v1) && (m2 & (1 << (11-neg)))) ||
 602        (float32_is_infinity(v1) && (m2 & (1 << (5-neg)))) ||
 603        (float32_is_any_nan(v1) && (m2 & (1 << (3-neg)))) ||
 604        (float32_is_signaling_nan(v1) && (m2 & (1 << (1-neg))))) {
 605        cc = 1;
 606    } else if (m2 & (1 << (9-neg))) {
 607        /* assume normalized number */
 608        cc = 1;
 609    }
 610    /* FIXME: denormalized? */
 611    return cc;
 612}
 613
 614/* test data class 64-bit */
 615uint32_t HELPER(tcdb)(uint64_t v1, uint64_t m2)
 616{
 617    int neg = float64_is_neg(v1);
 618    uint32_t cc = 0;
 619
 620    if ((float64_is_zero(v1) && (m2 & (1 << (11-neg)))) ||
 621        (float64_is_infinity(v1) && (m2 & (1 << (5-neg)))) ||
 622        (float64_is_any_nan(v1) && (m2 & (1 << (3-neg)))) ||
 623        (float64_is_signaling_nan(v1) && (m2 & (1 << (1-neg))))) {
 624        cc = 1;
 625    } else if (m2 & (1 << (9-neg))) {
 626        /* assume normalized number */
 627        cc = 1;
 628    }
 629    /* FIXME: denormalized? */
 630    return cc;
 631}
 632
 633/* test data class 128-bit */
 634uint32_t HELPER(tcxb)(uint64_t ah, uint64_t al, uint64_t m2)
 635{
 636    float128 v1 = make_float128(ah, al);
 637    int neg = float128_is_neg(v1);
 638    uint32_t cc = 0;
 639
 640    if ((float128_is_zero(v1) && (m2 & (1 << (11-neg)))) ||
 641        (float128_is_infinity(v1) && (m2 & (1 << (5-neg)))) ||
 642        (float128_is_any_nan(v1) && (m2 & (1 << (3-neg)))) ||
 643        (float128_is_signaling_nan(v1) && (m2 & (1 << (1-neg))))) {
 644        cc = 1;
 645    } else if (m2 & (1 << (9-neg))) {
 646        /* assume normalized number */
 647        cc = 1;
 648    }
 649    /* FIXME: denormalized? */
 650    return cc;
 651}
 652
 653/* square root 32-bit */
 654uint64_t HELPER(sqeb)(CPUS390XState *env, uint64_t f2)
 655{
 656    float32 ret = float32_sqrt(f2, &env->fpu_status);
 657    handle_exceptions(env, GETPC());
 658    return ret;
 659}
 660
 661/* square root 64-bit */
 662uint64_t HELPER(sqdb)(CPUS390XState *env, uint64_t f2)
 663{
 664    float64 ret = float64_sqrt(f2, &env->fpu_status);
 665    handle_exceptions(env, GETPC());
 666    return ret;
 667}
 668
 669/* square root 128-bit */
 670uint64_t HELPER(sqxb)(CPUS390XState *env, uint64_t ah, uint64_t al)
 671{
 672    float128 ret = float128_sqrt(make_float128(ah, al), &env->fpu_status);
 673    handle_exceptions(env, GETPC());
 674    return RET128(ret);
 675}
 676
 677static const int fpc_to_rnd[4] = {
 678    float_round_nearest_even,
 679    float_round_to_zero,
 680    float_round_up,
 681    float_round_down
 682};
 683
 684/* set fpc */
 685void HELPER(sfpc)(CPUS390XState *env, uint64_t fpc)
 686{
 687    /* Install everything in the main FPC.  */
 688    env->fpc = fpc;
 689
 690    /* Install the rounding mode in the shadow fpu_status.  */
 691    set_float_rounding_mode(fpc_to_rnd[fpc & 3], &env->fpu_status);
 692}
 693
 694/* set fpc and signal */
 695void HELPER(sfas)(CPUS390XState *env, uint64_t val)
 696{
 697    uint32_t signalling = env->fpc;
 698    uint32_t source = val;
 699    uint32_t s390_exc;
 700
 701    /* The contents of the source operand are placed in the FPC register;
 702       then the flags in the FPC register are set to the logical OR of the
 703       signalling flags and the source flags.  */
 704    env->fpc = source | (signalling & 0x00ff0000);
 705    set_float_rounding_mode(fpc_to_rnd[source & 3], &env->fpu_status);
 706
 707    /* If any signalling flag is 1 and the corresponding source mask
 708       is also 1, a simulated-iee-exception trap occurs.  */
 709    s390_exc = (signalling >> 16) & (source >> 24);
 710    if (s390_exc) {
 711        ieee_exception(env, s390_exc | 3, GETPC());
 712    }
 713}
 714