1e72ca652SBlue Swirl /* 2e72ca652SBlue Swirl * S/390 FPU helper routines 3e72ca652SBlue Swirl * 4e72ca652SBlue Swirl * Copyright (c) 2009 Ulrich Hecht 5e72ca652SBlue Swirl * Copyright (c) 2009 Alexander Graf 6e72ca652SBlue Swirl * 7e72ca652SBlue Swirl * This library is free software; you can redistribute it and/or 8e72ca652SBlue Swirl * modify it under the terms of the GNU Lesser General Public 9e72ca652SBlue Swirl * License as published by the Free Software Foundation; either 1041c6a6ddSThomas Huth * version 2.1 of the License, or (at your option) any later version. 11e72ca652SBlue Swirl * 12e72ca652SBlue Swirl * This library is distributed in the hope that it will be useful, 13e72ca652SBlue Swirl * but WITHOUT ANY WARRANTY; without even the implied warranty of 14e72ca652SBlue Swirl * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15e72ca652SBlue Swirl * Lesser General Public License for more details. 16e72ca652SBlue Swirl * 17e72ca652SBlue Swirl * You should have received a copy of the GNU Lesser General Public 18e72ca652SBlue Swirl * License along with this library; if not, see <http://www.gnu.org/licenses/>. 19e72ca652SBlue Swirl */ 20e72ca652SBlue Swirl 219615495aSPeter Maydell #include "qemu/osdep.h" 22e72ca652SBlue Swirl #include "cpu.h" 23b6b47223SCho, Yu-Chen #include "s390x-internal.h" 24bbf6ea3bSDavid Hildenbrand #include "tcg_s390x.h" 2563c91552SPaolo Bonzini #include "exec/exec-all.h" 26f08b6170SPaolo Bonzini #include "exec/cpu_ldst.h" 272ef6175aSRichard Henderson #include "exec/helper-proto.h" 2824f91e81SAlex Bennée #include "fpu/softfloat.h" 29e72ca652SBlue Swirl 30e72ca652SBlue Swirl /* #define DEBUG_HELPER */ 31e72ca652SBlue Swirl #ifdef DEBUG_HELPER 32e72ca652SBlue Swirl #define HELPER_LOG(x...) qemu_log(x) 33e72ca652SBlue Swirl #else 34e72ca652SBlue Swirl #define HELPER_LOG(x...) 35e72ca652SBlue Swirl #endif 36e72ca652SBlue Swirl 37587626f8SRichard Henderson #define RET128(F) (env->retxl = F.low, F.high) 38587626f8SRichard Henderson 394b70fc54SDavid Hildenbrand uint8_t s390_softfloat_exc_to_ieee(unsigned int exc) 404b70fc54SDavid Hildenbrand { 414b70fc54SDavid Hildenbrand uint8_t s390_exc = 0; 424b70fc54SDavid Hildenbrand 434b70fc54SDavid Hildenbrand s390_exc |= (exc & float_flag_invalid) ? S390_IEEE_MASK_INVALID : 0; 444b70fc54SDavid Hildenbrand s390_exc |= (exc & float_flag_divbyzero) ? S390_IEEE_MASK_DIVBYZERO : 0; 454b70fc54SDavid Hildenbrand s390_exc |= (exc & float_flag_overflow) ? S390_IEEE_MASK_OVERFLOW : 0; 464b70fc54SDavid Hildenbrand s390_exc |= (exc & float_flag_underflow) ? S390_IEEE_MASK_UNDERFLOW : 0; 474b70fc54SDavid Hildenbrand s390_exc |= (exc & float_flag_inexact) ? S390_IEEE_MASK_INEXACT : 0; 484b70fc54SDavid Hildenbrand 494b70fc54SDavid Hildenbrand return s390_exc; 504b70fc54SDavid Hildenbrand } 51587626f8SRichard Henderson 52587626f8SRichard Henderson /* Should be called after any operation that may raise IEEE exceptions. */ 53cf97f9ffSDavid Hildenbrand static void handle_exceptions(CPUS390XState *env, bool XxC, uintptr_t retaddr) 54587626f8SRichard Henderson { 55587626f8SRichard Henderson unsigned s390_exc, qemu_exc; 56587626f8SRichard Henderson 57587626f8SRichard Henderson /* Get the exceptions raised by the current operation. Reset the 58587626f8SRichard Henderson fpu_status contents so that the next operation has a clean slate. */ 59587626f8SRichard Henderson qemu_exc = env->fpu_status.float_exception_flags; 60587626f8SRichard Henderson if (qemu_exc == 0) { 61587626f8SRichard Henderson return; 62587626f8SRichard Henderson } 63587626f8SRichard Henderson env->fpu_status.float_exception_flags = 0; 644b70fc54SDavid Hildenbrand s390_exc = s390_softfloat_exc_to_ieee(qemu_exc); 65587626f8SRichard Henderson 66fcb9e9f2SDavid Hildenbrand /* 676d6ad1d1SDavid Hildenbrand * IEEE-Underflow exception recognition exists if a tininess condition 686d6ad1d1SDavid Hildenbrand * (underflow) exists and 696d6ad1d1SDavid Hildenbrand * - The mask bit in the FPC is zero and the result is inexact 706d6ad1d1SDavid Hildenbrand * - The mask bit in the FPC is one 716d6ad1d1SDavid Hildenbrand * So tininess conditions that are not inexact don't trigger any 726d6ad1d1SDavid Hildenbrand * underflow action in case the mask bit is not one. 736d6ad1d1SDavid Hildenbrand */ 746d6ad1d1SDavid Hildenbrand if (!(s390_exc & S390_IEEE_MASK_INEXACT) && 756d6ad1d1SDavid Hildenbrand !((env->fpc >> 24) & S390_IEEE_MASK_UNDERFLOW)) { 766d6ad1d1SDavid Hildenbrand s390_exc &= ~S390_IEEE_MASK_UNDERFLOW; 776d6ad1d1SDavid Hildenbrand } 786d6ad1d1SDavid Hildenbrand 796d6ad1d1SDavid Hildenbrand /* 80fcb9e9f2SDavid Hildenbrand * FIXME: 81fcb9e9f2SDavid Hildenbrand * 1. Right now, all inexact conditions are inidicated as 82fcb9e9f2SDavid Hildenbrand * "truncated" (0) and never as "incremented" (1) in the DXC. 83fcb9e9f2SDavid Hildenbrand * 2. Only traps due to invalid/divbyzero are suppressing. Other traps 84fcb9e9f2SDavid Hildenbrand * are completing, meaning the target register has to be written! 85fcb9e9f2SDavid Hildenbrand * This, however will mean that we have to write the register before 86fcb9e9f2SDavid Hildenbrand * triggering the trap - impossible right now. 87fcb9e9f2SDavid Hildenbrand */ 88587626f8SRichard Henderson 89fcb9e9f2SDavid Hildenbrand /* 90fcb9e9f2SDavid Hildenbrand * invalid/divbyzero cannot coexist with other conditions. 91fcb9e9f2SDavid Hildenbrand * overflow/underflow however can coexist with inexact, we have to 92*44ee69eaSThomas Huth * handle it separately. 93fcb9e9f2SDavid Hildenbrand */ 94fcb9e9f2SDavid Hildenbrand if (s390_exc & ~S390_IEEE_MASK_INEXACT) { 95fcb9e9f2SDavid Hildenbrand if (s390_exc & ~S390_IEEE_MASK_INEXACT & env->fpc >> 24) { 96fcb9e9f2SDavid Hildenbrand /* trap condition - inexact reported along */ 97bbf6ea3bSDavid Hildenbrand tcg_s390_data_exception(env, s390_exc, retaddr); 98587626f8SRichard Henderson } 99fcb9e9f2SDavid Hildenbrand /* nontrap condition - inexact handled differently */ 100fcb9e9f2SDavid Hildenbrand env->fpc |= (s390_exc & ~S390_IEEE_MASK_INEXACT) << 16; 101fcb9e9f2SDavid Hildenbrand } 102fcb9e9f2SDavid Hildenbrand 103fcb9e9f2SDavid Hildenbrand /* inexact handling */ 104cf97f9ffSDavid Hildenbrand if (s390_exc & S390_IEEE_MASK_INEXACT && !XxC) { 105fcb9e9f2SDavid Hildenbrand /* trap condition - overflow/underflow _not_ reported along */ 106fcb9e9f2SDavid Hildenbrand if (s390_exc & S390_IEEE_MASK_INEXACT & env->fpc >> 24) { 107fcb9e9f2SDavid Hildenbrand tcg_s390_data_exception(env, s390_exc & S390_IEEE_MASK_INEXACT, 108fcb9e9f2SDavid Hildenbrand retaddr); 109fcb9e9f2SDavid Hildenbrand } 110fcb9e9f2SDavid Hildenbrand /* nontrap condition */ 111fcb9e9f2SDavid Hildenbrand env->fpc |= (s390_exc & S390_IEEE_MASK_INEXACT) << 16; 112fcb9e9f2SDavid Hildenbrand } 113587626f8SRichard Henderson } 114587626f8SRichard Henderson 11571bfd65cSRichard Henderson int float_comp_to_cc(CPUS390XState *env, FloatRelation float_compare) 116e72ca652SBlue Swirl { 117e72ca652SBlue Swirl switch (float_compare) { 118e72ca652SBlue Swirl case float_relation_equal: 119e72ca652SBlue Swirl return 0; 120e72ca652SBlue Swirl case float_relation_less: 121e72ca652SBlue Swirl return 1; 122e72ca652SBlue Swirl case float_relation_greater: 123e72ca652SBlue Swirl return 2; 124e72ca652SBlue Swirl case float_relation_unordered: 125e72ca652SBlue Swirl return 3; 126e72ca652SBlue Swirl default: 127dc79e928SRichard Henderson cpu_abort(env_cpu(env), "unknown return value for float compare\n"); 128e72ca652SBlue Swirl } 129e72ca652SBlue Swirl } 130e72ca652SBlue Swirl 131e72ca652SBlue Swirl /* condition codes for unary FP ops */ 132e72ca652SBlue Swirl uint32_t set_cc_nz_f32(float32 v) 133e72ca652SBlue Swirl { 134e72ca652SBlue Swirl if (float32_is_any_nan(v)) { 135e72ca652SBlue Swirl return 3; 136e72ca652SBlue Swirl } else if (float32_is_zero(v)) { 137e72ca652SBlue Swirl return 0; 138e72ca652SBlue Swirl } else if (float32_is_neg(v)) { 139e72ca652SBlue Swirl return 1; 140e72ca652SBlue Swirl } else { 141e72ca652SBlue Swirl return 2; 142e72ca652SBlue Swirl } 143e72ca652SBlue Swirl } 144e72ca652SBlue Swirl 145e72ca652SBlue Swirl uint32_t set_cc_nz_f64(float64 v) 146e72ca652SBlue Swirl { 147e72ca652SBlue Swirl if (float64_is_any_nan(v)) { 148e72ca652SBlue Swirl return 3; 149e72ca652SBlue Swirl } else if (float64_is_zero(v)) { 150e72ca652SBlue Swirl return 0; 151e72ca652SBlue Swirl } else if (float64_is_neg(v)) { 152e72ca652SBlue Swirl return 1; 153e72ca652SBlue Swirl } else { 154e72ca652SBlue Swirl return 2; 155e72ca652SBlue Swirl } 156e72ca652SBlue Swirl } 157e72ca652SBlue Swirl 158587626f8SRichard Henderson uint32_t set_cc_nz_f128(float128 v) 159e72ca652SBlue Swirl { 160e72ca652SBlue Swirl if (float128_is_any_nan(v)) { 161e72ca652SBlue Swirl return 3; 162e72ca652SBlue Swirl } else if (float128_is_zero(v)) { 163e72ca652SBlue Swirl return 0; 164e72ca652SBlue Swirl } else if (float128_is_neg(v)) { 165e72ca652SBlue Swirl return 1; 166e72ca652SBlue Swirl } else { 167e72ca652SBlue Swirl return 2; 168e72ca652SBlue Swirl } 169e72ca652SBlue Swirl } 170e72ca652SBlue Swirl 17128761057SUlrich Weigand /* condition codes for FP to integer conversion ops */ 17228761057SUlrich Weigand static uint32_t set_cc_conv_f32(float32 v, float_status *stat) 17328761057SUlrich Weigand { 17428761057SUlrich Weigand if (stat->float_exception_flags & float_flag_invalid) { 17528761057SUlrich Weigand return 3; 17628761057SUlrich Weigand } else { 17728761057SUlrich Weigand return set_cc_nz_f32(v); 17828761057SUlrich Weigand } 17928761057SUlrich Weigand } 18028761057SUlrich Weigand 18128761057SUlrich Weigand static uint32_t set_cc_conv_f64(float64 v, float_status *stat) 18228761057SUlrich Weigand { 18328761057SUlrich Weigand if (stat->float_exception_flags & float_flag_invalid) { 18428761057SUlrich Weigand return 3; 18528761057SUlrich Weigand } else { 18628761057SUlrich Weigand return set_cc_nz_f64(v); 18728761057SUlrich Weigand } 18828761057SUlrich Weigand } 18928761057SUlrich Weigand 19028761057SUlrich Weigand static uint32_t set_cc_conv_f128(float128 v, float_status *stat) 19128761057SUlrich Weigand { 19228761057SUlrich Weigand if (stat->float_exception_flags & float_flag_invalid) { 19328761057SUlrich Weigand return 3; 19428761057SUlrich Weigand } else { 19528761057SUlrich Weigand return set_cc_nz_f128(v); 19628761057SUlrich Weigand } 19728761057SUlrich Weigand } 19828761057SUlrich Weigand 199dce0a58fSDavid Hildenbrand static inline uint8_t round_from_m34(uint32_t m34) 200dce0a58fSDavid Hildenbrand { 201dce0a58fSDavid Hildenbrand return extract32(m34, 0, 4); 202dce0a58fSDavid Hildenbrand } 203dce0a58fSDavid Hildenbrand 204dce0a58fSDavid Hildenbrand static inline bool xxc_from_m34(uint32_t m34) 205dce0a58fSDavid Hildenbrand { 206dce0a58fSDavid Hildenbrand /* XxC is bit 1 of m4 */ 207dce0a58fSDavid Hildenbrand return extract32(m34, 4 + 3 - 1, 1); 208dce0a58fSDavid Hildenbrand } 209dce0a58fSDavid Hildenbrand 210587626f8SRichard Henderson /* 32-bit FP addition */ 211587626f8SRichard Henderson uint64_t HELPER(aeb)(CPUS390XState *env, uint64_t f1, uint64_t f2) 212e72ca652SBlue Swirl { 213587626f8SRichard Henderson float32 ret = float32_add(f1, f2, &env->fpu_status); 214cf97f9ffSDavid Hildenbrand handle_exceptions(env, false, GETPC()); 215587626f8SRichard Henderson return ret; 216e72ca652SBlue Swirl } 217e72ca652SBlue Swirl 218587626f8SRichard Henderson /* 64-bit FP addition */ 219587626f8SRichard Henderson uint64_t HELPER(adb)(CPUS390XState *env, uint64_t f1, uint64_t f2) 220e72ca652SBlue Swirl { 221587626f8SRichard Henderson float64 ret = float64_add(f1, f2, &env->fpu_status); 222cf97f9ffSDavid Hildenbrand handle_exceptions(env, false, GETPC()); 223587626f8SRichard Henderson return ret; 224587626f8SRichard Henderson } 225e72ca652SBlue Swirl 226587626f8SRichard Henderson /* 128-bit FP addition */ 227587626f8SRichard Henderson uint64_t HELPER(axb)(CPUS390XState *env, uint64_t ah, uint64_t al, 228587626f8SRichard Henderson uint64_t bh, uint64_t bl) 229587626f8SRichard Henderson { 230587626f8SRichard Henderson float128 ret = float128_add(make_float128(ah, al), 231587626f8SRichard Henderson make_float128(bh, bl), 232587626f8SRichard Henderson &env->fpu_status); 233cf97f9ffSDavid Hildenbrand handle_exceptions(env, false, GETPC()); 234587626f8SRichard Henderson return RET128(ret); 235e72ca652SBlue Swirl } 236e72ca652SBlue Swirl 2371a800a2dSRichard Henderson /* 32-bit FP subtraction */ 2381a800a2dSRichard Henderson uint64_t HELPER(seb)(CPUS390XState *env, uint64_t f1, uint64_t f2) 239e72ca652SBlue Swirl { 2401a800a2dSRichard Henderson float32 ret = float32_sub(f1, f2, &env->fpu_status); 241cf97f9ffSDavid Hildenbrand handle_exceptions(env, false, GETPC()); 2421a800a2dSRichard Henderson return ret; 243e72ca652SBlue Swirl } 244e72ca652SBlue Swirl 2451a800a2dSRichard Henderson /* 64-bit FP subtraction */ 2461a800a2dSRichard Henderson uint64_t HELPER(sdb)(CPUS390XState *env, uint64_t f1, uint64_t f2) 247e72ca652SBlue Swirl { 2481a800a2dSRichard Henderson float64 ret = float64_sub(f1, f2, &env->fpu_status); 249cf97f9ffSDavid Hildenbrand handle_exceptions(env, false, GETPC()); 2501a800a2dSRichard Henderson return ret; 2511a800a2dSRichard Henderson } 252e72ca652SBlue Swirl 2531a800a2dSRichard Henderson /* 128-bit FP subtraction */ 2541a800a2dSRichard Henderson uint64_t HELPER(sxb)(CPUS390XState *env, uint64_t ah, uint64_t al, 2551a800a2dSRichard Henderson uint64_t bh, uint64_t bl) 2561a800a2dSRichard Henderson { 2571a800a2dSRichard Henderson float128 ret = float128_sub(make_float128(ah, al), 2581a800a2dSRichard Henderson make_float128(bh, bl), 2591a800a2dSRichard Henderson &env->fpu_status); 260cf97f9ffSDavid Hildenbrand handle_exceptions(env, false, GETPC()); 2611a800a2dSRichard Henderson return RET128(ret); 262e72ca652SBlue Swirl } 263e72ca652SBlue Swirl 264f08a5c31SRichard Henderson /* 32-bit FP division */ 265f08a5c31SRichard Henderson uint64_t HELPER(deb)(CPUS390XState *env, uint64_t f1, uint64_t f2) 266e72ca652SBlue Swirl { 267f08a5c31SRichard Henderson float32 ret = float32_div(f1, f2, &env->fpu_status); 268cf97f9ffSDavid Hildenbrand handle_exceptions(env, false, GETPC()); 269f08a5c31SRichard Henderson return ret; 270e72ca652SBlue Swirl } 271e72ca652SBlue Swirl 272f08a5c31SRichard Henderson /* 64-bit FP division */ 273f08a5c31SRichard Henderson uint64_t HELPER(ddb)(CPUS390XState *env, uint64_t f1, uint64_t f2) 274e72ca652SBlue Swirl { 275f08a5c31SRichard Henderson float64 ret = float64_div(f1, f2, &env->fpu_status); 276cf97f9ffSDavid Hildenbrand handle_exceptions(env, false, GETPC()); 277f08a5c31SRichard Henderson return ret; 278f08a5c31SRichard Henderson } 279e72ca652SBlue Swirl 280f08a5c31SRichard Henderson /* 128-bit FP division */ 281f08a5c31SRichard Henderson uint64_t HELPER(dxb)(CPUS390XState *env, uint64_t ah, uint64_t al, 282f08a5c31SRichard Henderson uint64_t bh, uint64_t bl) 283f08a5c31SRichard Henderson { 284f08a5c31SRichard Henderson float128 ret = float128_div(make_float128(ah, al), 285f08a5c31SRichard Henderson make_float128(bh, bl), 286f08a5c31SRichard Henderson &env->fpu_status); 287cf97f9ffSDavid Hildenbrand handle_exceptions(env, false, GETPC()); 288f08a5c31SRichard Henderson return RET128(ret); 289e72ca652SBlue Swirl } 290e72ca652SBlue Swirl 29183b00736SRichard Henderson /* 32-bit FP multiplication */ 29283b00736SRichard Henderson uint64_t HELPER(meeb)(CPUS390XState *env, uint64_t f1, uint64_t f2) 293e72ca652SBlue Swirl { 29483b00736SRichard Henderson float32 ret = float32_mul(f1, f2, &env->fpu_status); 295cf97f9ffSDavid Hildenbrand handle_exceptions(env, false, GETPC()); 29683b00736SRichard Henderson return ret; 297e72ca652SBlue Swirl } 298e72ca652SBlue Swirl 29983b00736SRichard Henderson /* 64-bit FP multiplication */ 30083b00736SRichard Henderson uint64_t HELPER(mdb)(CPUS390XState *env, uint64_t f1, uint64_t f2) 301e72ca652SBlue Swirl { 30283b00736SRichard Henderson float64 ret = float64_mul(f1, f2, &env->fpu_status); 303cf97f9ffSDavid Hildenbrand handle_exceptions(env, false, GETPC()); 30483b00736SRichard Henderson return ret; 30583b00736SRichard Henderson } 306e72ca652SBlue Swirl 30783b00736SRichard Henderson /* 64/32-bit FP multiplication */ 30883b00736SRichard Henderson uint64_t HELPER(mdeb)(CPUS390XState *env, uint64_t f1, uint64_t f2) 30983b00736SRichard Henderson { 31083b00736SRichard Henderson float64 ret = float32_to_float64(f2, &env->fpu_status); 31183b00736SRichard Henderson ret = float64_mul(f1, ret, &env->fpu_status); 312cf97f9ffSDavid Hildenbrand handle_exceptions(env, false, GETPC()); 31383b00736SRichard Henderson return ret; 31483b00736SRichard Henderson } 31583b00736SRichard Henderson 31683b00736SRichard Henderson /* 128-bit FP multiplication */ 31783b00736SRichard Henderson uint64_t HELPER(mxb)(CPUS390XState *env, uint64_t ah, uint64_t al, 31883b00736SRichard Henderson uint64_t bh, uint64_t bl) 31983b00736SRichard Henderson { 32083b00736SRichard Henderson float128 ret = float128_mul(make_float128(ah, al), 32183b00736SRichard Henderson make_float128(bh, bl), 32283b00736SRichard Henderson &env->fpu_status); 323cf97f9ffSDavid Hildenbrand handle_exceptions(env, false, GETPC()); 32483b00736SRichard Henderson return RET128(ret); 32583b00736SRichard Henderson } 32683b00736SRichard Henderson 32783b00736SRichard Henderson /* 128/64-bit FP multiplication */ 32883b00736SRichard Henderson uint64_t HELPER(mxdb)(CPUS390XState *env, uint64_t ah, uint64_t al, 32983b00736SRichard Henderson uint64_t f2) 33083b00736SRichard Henderson { 33183b00736SRichard Henderson float128 ret = float64_to_float128(f2, &env->fpu_status); 33283b00736SRichard Henderson ret = float128_mul(make_float128(ah, al), ret, &env->fpu_status); 333cf97f9ffSDavid Hildenbrand handle_exceptions(env, false, GETPC()); 33483b00736SRichard Henderson return RET128(ret); 335e72ca652SBlue Swirl } 336e72ca652SBlue Swirl 337e72ca652SBlue Swirl /* convert 32-bit float to 64-bit float */ 338587626f8SRichard Henderson uint64_t HELPER(ldeb)(CPUS390XState *env, uint64_t f2) 339e72ca652SBlue Swirl { 340587626f8SRichard Henderson float64 ret = float32_to_float64(f2, &env->fpu_status); 341cf97f9ffSDavid Hildenbrand handle_exceptions(env, false, GETPC()); 342d0cfecb5SRichard Henderson return ret; 343e72ca652SBlue Swirl } 344e72ca652SBlue Swirl 345e72ca652SBlue Swirl /* convert 128-bit float to 64-bit float */ 346bdcfcd44SDavid Hildenbrand uint64_t HELPER(ldxb)(CPUS390XState *env, uint64_t ah, uint64_t al, 347bdcfcd44SDavid Hildenbrand uint32_t m34) 348e72ca652SBlue Swirl { 349bdcfcd44SDavid Hildenbrand int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); 350587626f8SRichard Henderson float64 ret = float128_to_float64(make_float128(ah, al), &env->fpu_status); 351bdcfcd44SDavid Hildenbrand 352bdcfcd44SDavid Hildenbrand s390_restore_bfp_rounding_mode(env, old_mode); 353bdcfcd44SDavid Hildenbrand handle_exceptions(env, xxc_from_m34(m34), GETPC()); 354d0cfecb5SRichard Henderson return ret; 355e72ca652SBlue Swirl } 356e72ca652SBlue Swirl 357e72ca652SBlue Swirl /* convert 64-bit float to 128-bit float */ 358587626f8SRichard Henderson uint64_t HELPER(lxdb)(CPUS390XState *env, uint64_t f2) 359e72ca652SBlue Swirl { 360587626f8SRichard Henderson float128 ret = float64_to_float128(f2, &env->fpu_status); 361cf97f9ffSDavid Hildenbrand handle_exceptions(env, false, GETPC()); 362d0cfecb5SRichard Henderson return RET128(ret); 363587626f8SRichard Henderson } 364e72ca652SBlue Swirl 365587626f8SRichard Henderson /* convert 32-bit float to 128-bit float */ 366587626f8SRichard Henderson uint64_t HELPER(lxeb)(CPUS390XState *env, uint64_t f2) 367587626f8SRichard Henderson { 368587626f8SRichard Henderson float128 ret = float32_to_float128(f2, &env->fpu_status); 369cf97f9ffSDavid Hildenbrand handle_exceptions(env, false, GETPC()); 370d0cfecb5SRichard Henderson return RET128(ret); 371e72ca652SBlue Swirl } 372e72ca652SBlue Swirl 373e72ca652SBlue Swirl /* convert 64-bit float to 32-bit float */ 374bdcfcd44SDavid Hildenbrand uint64_t HELPER(ledb)(CPUS390XState *env, uint64_t f2, uint32_t m34) 375e72ca652SBlue Swirl { 376bdcfcd44SDavid Hildenbrand int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); 377587626f8SRichard Henderson float32 ret = float64_to_float32(f2, &env->fpu_status); 378bdcfcd44SDavid Hildenbrand 379bdcfcd44SDavid Hildenbrand s390_restore_bfp_rounding_mode(env, old_mode); 380bdcfcd44SDavid Hildenbrand handle_exceptions(env, xxc_from_m34(m34), GETPC()); 381d0cfecb5SRichard Henderson return ret; 382e72ca652SBlue Swirl } 383e72ca652SBlue Swirl 384e72ca652SBlue Swirl /* convert 128-bit float to 32-bit float */ 385bdcfcd44SDavid Hildenbrand uint64_t HELPER(lexb)(CPUS390XState *env, uint64_t ah, uint64_t al, 386bdcfcd44SDavid Hildenbrand uint32_t m34) 387e72ca652SBlue Swirl { 388bdcfcd44SDavid Hildenbrand int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); 389587626f8SRichard Henderson float32 ret = float128_to_float32(make_float128(ah, al), &env->fpu_status); 390bdcfcd44SDavid Hildenbrand 391bdcfcd44SDavid Hildenbrand s390_restore_bfp_rounding_mode(env, old_mode); 392bdcfcd44SDavid Hildenbrand handle_exceptions(env, xxc_from_m34(m34), GETPC()); 393d0cfecb5SRichard Henderson return ret; 394e72ca652SBlue Swirl } 395e72ca652SBlue Swirl 396587626f8SRichard Henderson /* 32-bit FP compare */ 397587626f8SRichard Henderson uint32_t HELPER(ceb)(CPUS390XState *env, uint64_t f1, uint64_t f2) 398e72ca652SBlue Swirl { 39971bfd65cSRichard Henderson FloatRelation cmp = float32_compare_quiet(f1, f2, &env->fpu_status); 400cf97f9ffSDavid Hildenbrand handle_exceptions(env, false, GETPC()); 401587626f8SRichard Henderson return float_comp_to_cc(env, cmp); 402e72ca652SBlue Swirl } 403e72ca652SBlue Swirl 404587626f8SRichard Henderson /* 64-bit FP compare */ 405587626f8SRichard Henderson uint32_t HELPER(cdb)(CPUS390XState *env, uint64_t f1, uint64_t f2) 406e72ca652SBlue Swirl { 40771bfd65cSRichard Henderson FloatRelation cmp = float64_compare_quiet(f1, f2, &env->fpu_status); 408cf97f9ffSDavid Hildenbrand handle_exceptions(env, false, GETPC()); 409587626f8SRichard Henderson return float_comp_to_cc(env, cmp); 410e72ca652SBlue Swirl } 411e72ca652SBlue Swirl 412587626f8SRichard Henderson /* 128-bit FP compare */ 413587626f8SRichard Henderson uint32_t HELPER(cxb)(CPUS390XState *env, uint64_t ah, uint64_t al, 414587626f8SRichard Henderson uint64_t bh, uint64_t bl) 415e72ca652SBlue Swirl { 41671bfd65cSRichard Henderson FloatRelation cmp = float128_compare_quiet(make_float128(ah, al), 417587626f8SRichard Henderson make_float128(bh, bl), 418587626f8SRichard Henderson &env->fpu_status); 419cf97f9ffSDavid Hildenbrand handle_exceptions(env, false, GETPC()); 420587626f8SRichard Henderson return float_comp_to_cc(env, cmp); 421e72ca652SBlue Swirl } 422e72ca652SBlue Swirl 423c0ee7015SDavid Hildenbrand int s390_swap_bfp_rounding_mode(CPUS390XState *env, int m3) 424e72ca652SBlue Swirl { 42568c8bd93SRichard Henderson int ret = env->fpu_status.float_rounding_mode; 426b12b103eSDavid Hildenbrand 427e72ca652SBlue Swirl switch (m3) { 428e72ca652SBlue Swirl case 0: 429e72ca652SBlue Swirl /* current mode */ 430e72ca652SBlue Swirl break; 431e72ca652SBlue Swirl case 1: 432b12b103eSDavid Hildenbrand /* round to nearest with ties away from 0 */ 433b12b103eSDavid Hildenbrand set_float_rounding_mode(float_round_ties_away, &env->fpu_status); 434b12b103eSDavid Hildenbrand break; 435b12b103eSDavid Hildenbrand case 3: 436b12b103eSDavid Hildenbrand /* round to prepare for shorter precision */ 437b12b103eSDavid Hildenbrand set_float_rounding_mode(float_round_to_odd, &env->fpu_status); 438b12b103eSDavid Hildenbrand break; 439e72ca652SBlue Swirl case 4: 440b12b103eSDavid Hildenbrand /* round to nearest with ties to even */ 441e72ca652SBlue Swirl set_float_rounding_mode(float_round_nearest_even, &env->fpu_status); 442e72ca652SBlue Swirl break; 443e72ca652SBlue Swirl case 5: 444e72ca652SBlue Swirl /* round to zero */ 445e72ca652SBlue Swirl set_float_rounding_mode(float_round_to_zero, &env->fpu_status); 446e72ca652SBlue Swirl break; 447e72ca652SBlue Swirl case 6: 448e72ca652SBlue Swirl /* round to +inf */ 449e72ca652SBlue Swirl set_float_rounding_mode(float_round_up, &env->fpu_status); 450e72ca652SBlue Swirl break; 451e72ca652SBlue Swirl case 7: 452e72ca652SBlue Swirl /* round to -inf */ 453e72ca652SBlue Swirl set_float_rounding_mode(float_round_down, &env->fpu_status); 454e72ca652SBlue Swirl break; 455b12b103eSDavid Hildenbrand default: 456b12b103eSDavid Hildenbrand g_assert_not_reached(); 457e72ca652SBlue Swirl } 45868c8bd93SRichard Henderson return ret; 459e72ca652SBlue Swirl } 460e72ca652SBlue Swirl 461c0ee7015SDavid Hildenbrand void s390_restore_bfp_rounding_mode(CPUS390XState *env, int old_mode) 462c0ee7015SDavid Hildenbrand { 463c0ee7015SDavid Hildenbrand set_float_rounding_mode(old_mode, &env->fpu_status); 464c0ee7015SDavid Hildenbrand } 465c0ee7015SDavid Hildenbrand 466683bb9a8SRichard Henderson /* convert 64-bit int to 32-bit float */ 467dce0a58fSDavid Hildenbrand uint64_t HELPER(cegb)(CPUS390XState *env, int64_t v2, uint32_t m34) 468683bb9a8SRichard Henderson { 469dce0a58fSDavid Hildenbrand int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); 470683bb9a8SRichard Henderson float32 ret = int64_to_float32(v2, &env->fpu_status); 471c0ee7015SDavid Hildenbrand 472c0ee7015SDavid Hildenbrand s390_restore_bfp_rounding_mode(env, old_mode); 473dce0a58fSDavid Hildenbrand handle_exceptions(env, xxc_from_m34(m34), GETPC()); 474683bb9a8SRichard Henderson return ret; 475683bb9a8SRichard Henderson } 476683bb9a8SRichard Henderson 477683bb9a8SRichard Henderson /* convert 64-bit int to 64-bit float */ 478dce0a58fSDavid Hildenbrand uint64_t HELPER(cdgb)(CPUS390XState *env, int64_t v2, uint32_t m34) 479683bb9a8SRichard Henderson { 480dce0a58fSDavid Hildenbrand int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); 481683bb9a8SRichard Henderson float64 ret = int64_to_float64(v2, &env->fpu_status); 482c0ee7015SDavid Hildenbrand 483c0ee7015SDavid Hildenbrand s390_restore_bfp_rounding_mode(env, old_mode); 484dce0a58fSDavid Hildenbrand handle_exceptions(env, xxc_from_m34(m34), GETPC()); 485683bb9a8SRichard Henderson return ret; 486683bb9a8SRichard Henderson } 487683bb9a8SRichard Henderson 488683bb9a8SRichard Henderson /* convert 64-bit int to 128-bit float */ 489dce0a58fSDavid Hildenbrand uint64_t HELPER(cxgb)(CPUS390XState *env, int64_t v2, uint32_t m34) 490683bb9a8SRichard Henderson { 491dce0a58fSDavid Hildenbrand int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); 492683bb9a8SRichard Henderson float128 ret = int64_to_float128(v2, &env->fpu_status); 493c0ee7015SDavid Hildenbrand 494c0ee7015SDavid Hildenbrand s390_restore_bfp_rounding_mode(env, old_mode); 495dce0a58fSDavid Hildenbrand handle_exceptions(env, xxc_from_m34(m34), GETPC()); 496683bb9a8SRichard Henderson return RET128(ret); 497683bb9a8SRichard Henderson } 498683bb9a8SRichard Henderson 4992112bf1bSRichard Henderson /* convert 64-bit uint to 32-bit float */ 500dce0a58fSDavid Hildenbrand uint64_t HELPER(celgb)(CPUS390XState *env, uint64_t v2, uint32_t m34) 5012112bf1bSRichard Henderson { 502dce0a58fSDavid Hildenbrand int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); 5032112bf1bSRichard Henderson float32 ret = uint64_to_float32(v2, &env->fpu_status); 504c0ee7015SDavid Hildenbrand 505c0ee7015SDavid Hildenbrand s390_restore_bfp_rounding_mode(env, old_mode); 506dce0a58fSDavid Hildenbrand handle_exceptions(env, xxc_from_m34(m34), GETPC()); 5072112bf1bSRichard Henderson return ret; 5082112bf1bSRichard Henderson } 5092112bf1bSRichard Henderson 5102112bf1bSRichard Henderson /* convert 64-bit uint to 64-bit float */ 511dce0a58fSDavid Hildenbrand uint64_t HELPER(cdlgb)(CPUS390XState *env, uint64_t v2, uint32_t m34) 5122112bf1bSRichard Henderson { 513dce0a58fSDavid Hildenbrand int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); 5142112bf1bSRichard Henderson float64 ret = uint64_to_float64(v2, &env->fpu_status); 515c0ee7015SDavid Hildenbrand 516c0ee7015SDavid Hildenbrand s390_restore_bfp_rounding_mode(env, old_mode); 517dce0a58fSDavid Hildenbrand handle_exceptions(env, xxc_from_m34(m34), GETPC()); 5182112bf1bSRichard Henderson return ret; 5192112bf1bSRichard Henderson } 5202112bf1bSRichard Henderson 5212112bf1bSRichard Henderson /* convert 64-bit uint to 128-bit float */ 522dce0a58fSDavid Hildenbrand uint64_t HELPER(cxlgb)(CPUS390XState *env, uint64_t v2, uint32_t m34) 5232112bf1bSRichard Henderson { 524dce0a58fSDavid Hildenbrand int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); 525d2d9feacSRichard Henderson float128 ret = uint64_to_float128(v2, &env->fpu_status); 526c0ee7015SDavid Hildenbrand 527c0ee7015SDavid Hildenbrand s390_restore_bfp_rounding_mode(env, old_mode); 528dce0a58fSDavid Hildenbrand handle_exceptions(env, xxc_from_m34(m34), GETPC()); 5292112bf1bSRichard Henderson return RET128(ret); 5302112bf1bSRichard Henderson } 5312112bf1bSRichard Henderson 532e72ca652SBlue Swirl /* convert 32-bit float to 64-bit int */ 533dce0a58fSDavid Hildenbrand uint64_t HELPER(cgeb)(CPUS390XState *env, uint64_t v2, uint32_t m34) 534e72ca652SBlue Swirl { 535dce0a58fSDavid Hildenbrand int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); 53668c8bd93SRichard Henderson int64_t ret = float32_to_int64(v2, &env->fpu_status); 53728761057SUlrich Weigand uint32_t cc = set_cc_conv_f32(v2, &env->fpu_status); 538c0ee7015SDavid Hildenbrand 539c0ee7015SDavid Hildenbrand s390_restore_bfp_rounding_mode(env, old_mode); 540dce0a58fSDavid Hildenbrand handle_exceptions(env, xxc_from_m34(m34), GETPC()); 54128761057SUlrich Weigand env->cc_op = cc; 5420a3be7beSDavid Hildenbrand if (float32_is_any_nan(v2)) { 5430a3be7beSDavid Hildenbrand return INT64_MIN; 5440a3be7beSDavid Hildenbrand } 54568c8bd93SRichard Henderson return ret; 546e72ca652SBlue Swirl } 547e72ca652SBlue Swirl 548e72ca652SBlue Swirl /* convert 64-bit float to 64-bit int */ 549dce0a58fSDavid Hildenbrand uint64_t HELPER(cgdb)(CPUS390XState *env, uint64_t v2, uint32_t m34) 550e72ca652SBlue Swirl { 551dce0a58fSDavid Hildenbrand int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); 55268c8bd93SRichard Henderson int64_t ret = float64_to_int64(v2, &env->fpu_status); 55328761057SUlrich Weigand uint32_t cc = set_cc_conv_f64(v2, &env->fpu_status); 554c0ee7015SDavid Hildenbrand 555c0ee7015SDavid Hildenbrand s390_restore_bfp_rounding_mode(env, old_mode); 556dce0a58fSDavid Hildenbrand handle_exceptions(env, xxc_from_m34(m34), GETPC()); 55728761057SUlrich Weigand env->cc_op = cc; 5580a3be7beSDavid Hildenbrand if (float64_is_any_nan(v2)) { 5590a3be7beSDavid Hildenbrand return INT64_MIN; 5600a3be7beSDavid Hildenbrand } 56168c8bd93SRichard Henderson return ret; 562e72ca652SBlue Swirl } 563e72ca652SBlue Swirl 564e72ca652SBlue Swirl /* convert 128-bit float to 64-bit int */ 565dce0a58fSDavid Hildenbrand uint64_t HELPER(cgxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m34) 566e72ca652SBlue Swirl { 567dce0a58fSDavid Hildenbrand int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); 56868c8bd93SRichard Henderson float128 v2 = make_float128(h, l); 56968c8bd93SRichard Henderson int64_t ret = float128_to_int64(v2, &env->fpu_status); 57028761057SUlrich Weigand uint32_t cc = set_cc_conv_f128(v2, &env->fpu_status); 571c0ee7015SDavid Hildenbrand 572c0ee7015SDavid Hildenbrand s390_restore_bfp_rounding_mode(env, old_mode); 573dce0a58fSDavid Hildenbrand handle_exceptions(env, xxc_from_m34(m34), GETPC()); 57428761057SUlrich Weigand env->cc_op = cc; 5750a3be7beSDavid Hildenbrand if (float128_is_any_nan(v2)) { 5760a3be7beSDavid Hildenbrand return INT64_MIN; 5770a3be7beSDavid Hildenbrand } 57868c8bd93SRichard Henderson return ret; 579e72ca652SBlue Swirl } 580e72ca652SBlue Swirl 581e72ca652SBlue Swirl /* convert 32-bit float to 32-bit int */ 582dce0a58fSDavid Hildenbrand uint64_t HELPER(cfeb)(CPUS390XState *env, uint64_t v2, uint32_t m34) 583e72ca652SBlue Swirl { 584dce0a58fSDavid Hildenbrand int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); 58568c8bd93SRichard Henderson int32_t ret = float32_to_int32(v2, &env->fpu_status); 58628761057SUlrich Weigand uint32_t cc = set_cc_conv_f32(v2, &env->fpu_status); 587c0ee7015SDavid Hildenbrand 588c0ee7015SDavid Hildenbrand s390_restore_bfp_rounding_mode(env, old_mode); 589dce0a58fSDavid Hildenbrand handle_exceptions(env, xxc_from_m34(m34), GETPC()); 59028761057SUlrich Weigand env->cc_op = cc; 5910a3be7beSDavid Hildenbrand if (float32_is_any_nan(v2)) { 5920a3be7beSDavid Hildenbrand return INT32_MIN; 5930a3be7beSDavid Hildenbrand } 59468c8bd93SRichard Henderson return ret; 595e72ca652SBlue Swirl } 596e72ca652SBlue Swirl 597e72ca652SBlue Swirl /* convert 64-bit float to 32-bit int */ 598dce0a58fSDavid Hildenbrand uint64_t HELPER(cfdb)(CPUS390XState *env, uint64_t v2, uint32_t m34) 599e72ca652SBlue Swirl { 600dce0a58fSDavid Hildenbrand int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); 60168c8bd93SRichard Henderson int32_t ret = float64_to_int32(v2, &env->fpu_status); 60228761057SUlrich Weigand uint32_t cc = set_cc_conv_f64(v2, &env->fpu_status); 603c0ee7015SDavid Hildenbrand 604c0ee7015SDavid Hildenbrand s390_restore_bfp_rounding_mode(env, old_mode); 605dce0a58fSDavid Hildenbrand handle_exceptions(env, xxc_from_m34(m34), GETPC()); 60628761057SUlrich Weigand env->cc_op = cc; 6070a3be7beSDavid Hildenbrand if (float64_is_any_nan(v2)) { 6080a3be7beSDavid Hildenbrand return INT32_MIN; 6090a3be7beSDavid Hildenbrand } 61068c8bd93SRichard Henderson return ret; 611e72ca652SBlue Swirl } 612e72ca652SBlue Swirl 613e72ca652SBlue Swirl /* convert 128-bit float to 32-bit int */ 614dce0a58fSDavid Hildenbrand uint64_t HELPER(cfxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m34) 615e72ca652SBlue Swirl { 616dce0a58fSDavid Hildenbrand int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); 61768c8bd93SRichard Henderson float128 v2 = make_float128(h, l); 61868c8bd93SRichard Henderson int32_t ret = float128_to_int32(v2, &env->fpu_status); 61928761057SUlrich Weigand uint32_t cc = set_cc_conv_f128(v2, &env->fpu_status); 620c0ee7015SDavid Hildenbrand 621c0ee7015SDavid Hildenbrand s390_restore_bfp_rounding_mode(env, old_mode); 622dce0a58fSDavid Hildenbrand handle_exceptions(env, xxc_from_m34(m34), GETPC()); 62328761057SUlrich Weigand env->cc_op = cc; 6240a3be7beSDavid Hildenbrand if (float128_is_any_nan(v2)) { 6250a3be7beSDavid Hildenbrand return INT32_MIN; 6260a3be7beSDavid Hildenbrand } 62768c8bd93SRichard Henderson return ret; 628e72ca652SBlue Swirl } 629e72ca652SBlue Swirl 6306ac1b45fSRichard Henderson /* convert 32-bit float to 64-bit uint */ 631dce0a58fSDavid Hildenbrand uint64_t HELPER(clgeb)(CPUS390XState *env, uint64_t v2, uint32_t m34) 6326ac1b45fSRichard Henderson { 633dce0a58fSDavid Hildenbrand int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); 6340a3be7beSDavid Hildenbrand uint64_t ret = float32_to_uint64(v2, &env->fpu_status); 63528761057SUlrich Weigand uint32_t cc = set_cc_conv_f32(v2, &env->fpu_status); 63628761057SUlrich Weigand 637c0ee7015SDavid Hildenbrand s390_restore_bfp_rounding_mode(env, old_mode); 638dce0a58fSDavid Hildenbrand handle_exceptions(env, xxc_from_m34(m34), GETPC()); 63928761057SUlrich Weigand env->cc_op = cc; 6400a3be7beSDavid Hildenbrand if (float32_is_any_nan(v2)) { 6410a3be7beSDavid Hildenbrand return 0; 6420a3be7beSDavid Hildenbrand } 6436ac1b45fSRichard Henderson return ret; 6446ac1b45fSRichard Henderson } 6456ac1b45fSRichard Henderson 6466ac1b45fSRichard Henderson /* convert 64-bit float to 64-bit uint */ 647dce0a58fSDavid Hildenbrand uint64_t HELPER(clgdb)(CPUS390XState *env, uint64_t v2, uint32_t m34) 6486ac1b45fSRichard Henderson { 649dce0a58fSDavid Hildenbrand int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); 6506ac1b45fSRichard Henderson uint64_t ret = float64_to_uint64(v2, &env->fpu_status); 65128761057SUlrich Weigand uint32_t cc = set_cc_conv_f64(v2, &env->fpu_status); 652c0ee7015SDavid Hildenbrand 653c0ee7015SDavid Hildenbrand s390_restore_bfp_rounding_mode(env, old_mode); 654dce0a58fSDavid Hildenbrand handle_exceptions(env, xxc_from_m34(m34), GETPC()); 65528761057SUlrich Weigand env->cc_op = cc; 6560a3be7beSDavid Hildenbrand if (float64_is_any_nan(v2)) { 6570a3be7beSDavid Hildenbrand return 0; 6580a3be7beSDavid Hildenbrand } 6596ac1b45fSRichard Henderson return ret; 6606ac1b45fSRichard Henderson } 6616ac1b45fSRichard Henderson 6626ac1b45fSRichard Henderson /* convert 128-bit float to 64-bit uint */ 663dce0a58fSDavid Hildenbrand uint64_t HELPER(clgxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m34) 6646ac1b45fSRichard Henderson { 665dce0a58fSDavid Hildenbrand int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); 66628761057SUlrich Weigand float128 v2 = make_float128(h, l); 66728761057SUlrich Weigand uint64_t ret = float128_to_uint64(v2, &env->fpu_status); 66828761057SUlrich Weigand uint32_t cc = set_cc_conv_f128(v2, &env->fpu_status); 669c0ee7015SDavid Hildenbrand 670c0ee7015SDavid Hildenbrand s390_restore_bfp_rounding_mode(env, old_mode); 671dce0a58fSDavid Hildenbrand handle_exceptions(env, xxc_from_m34(m34), GETPC()); 67228761057SUlrich Weigand env->cc_op = cc; 67328761057SUlrich Weigand if (float128_is_any_nan(v2)) { 6740a3be7beSDavid Hildenbrand return 0; 6750a3be7beSDavid Hildenbrand } 6766ac1b45fSRichard Henderson return ret; 6776ac1b45fSRichard Henderson } 6786ac1b45fSRichard Henderson 6796ac1b45fSRichard Henderson /* convert 32-bit float to 32-bit uint */ 680dce0a58fSDavid Hildenbrand uint64_t HELPER(clfeb)(CPUS390XState *env, uint64_t v2, uint32_t m34) 6816ac1b45fSRichard Henderson { 682dce0a58fSDavid Hildenbrand int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); 6836ac1b45fSRichard Henderson uint32_t ret = float32_to_uint32(v2, &env->fpu_status); 68428761057SUlrich Weigand uint32_t cc = set_cc_conv_f32(v2, &env->fpu_status); 685c0ee7015SDavid Hildenbrand 686c0ee7015SDavid Hildenbrand s390_restore_bfp_rounding_mode(env, old_mode); 687dce0a58fSDavid Hildenbrand handle_exceptions(env, xxc_from_m34(m34), GETPC()); 68828761057SUlrich Weigand env->cc_op = cc; 6890a3be7beSDavid Hildenbrand if (float32_is_any_nan(v2)) { 6900a3be7beSDavid Hildenbrand return 0; 6910a3be7beSDavid Hildenbrand } 6926ac1b45fSRichard Henderson return ret; 6936ac1b45fSRichard Henderson } 6946ac1b45fSRichard Henderson 6956ac1b45fSRichard Henderson /* convert 64-bit float to 32-bit uint */ 696dce0a58fSDavid Hildenbrand uint64_t HELPER(clfdb)(CPUS390XState *env, uint64_t v2, uint32_t m34) 6976ac1b45fSRichard Henderson { 698dce0a58fSDavid Hildenbrand int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); 6996ac1b45fSRichard Henderson uint32_t ret = float64_to_uint32(v2, &env->fpu_status); 70028761057SUlrich Weigand uint32_t cc = set_cc_conv_f64(v2, &env->fpu_status); 701c0ee7015SDavid Hildenbrand 702c0ee7015SDavid Hildenbrand s390_restore_bfp_rounding_mode(env, old_mode); 703dce0a58fSDavid Hildenbrand handle_exceptions(env, xxc_from_m34(m34), GETPC()); 70428761057SUlrich Weigand env->cc_op = cc; 7050a3be7beSDavid Hildenbrand if (float64_is_any_nan(v2)) { 7060a3be7beSDavid Hildenbrand return 0; 7070a3be7beSDavid Hildenbrand } 7086ac1b45fSRichard Henderson return ret; 7096ac1b45fSRichard Henderson } 7106ac1b45fSRichard Henderson 7116ac1b45fSRichard Henderson /* convert 128-bit float to 32-bit uint */ 712dce0a58fSDavid Hildenbrand uint64_t HELPER(clfxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m34) 7136ac1b45fSRichard Henderson { 714dce0a58fSDavid Hildenbrand int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); 71528761057SUlrich Weigand float128 v2 = make_float128(h, l); 71628761057SUlrich Weigand uint32_t ret = float128_to_uint32(v2, &env->fpu_status); 71728761057SUlrich Weigand uint32_t cc = set_cc_conv_f128(v2, &env->fpu_status); 718c0ee7015SDavid Hildenbrand 719c0ee7015SDavid Hildenbrand s390_restore_bfp_rounding_mode(env, old_mode); 720dce0a58fSDavid Hildenbrand handle_exceptions(env, xxc_from_m34(m34), GETPC()); 72128761057SUlrich Weigand env->cc_op = cc; 72228761057SUlrich Weigand if (float128_is_any_nan(v2)) { 7230a3be7beSDavid Hildenbrand return 0; 7240a3be7beSDavid Hildenbrand } 7256ac1b45fSRichard Henderson return ret; 7266ac1b45fSRichard Henderson } 7276ac1b45fSRichard Henderson 728ed0bceceSAurelien Jarno /* round to integer 32-bit */ 729dce0a58fSDavid Hildenbrand uint64_t HELPER(fieb)(CPUS390XState *env, uint64_t f2, uint32_t m34) 730ed0bceceSAurelien Jarno { 731dce0a58fSDavid Hildenbrand int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); 732ed0bceceSAurelien Jarno float32 ret = float32_round_to_int(f2, &env->fpu_status); 733c0ee7015SDavid Hildenbrand 734c0ee7015SDavid Hildenbrand s390_restore_bfp_rounding_mode(env, old_mode); 735dce0a58fSDavid Hildenbrand handle_exceptions(env, xxc_from_m34(m34), GETPC()); 736ed0bceceSAurelien Jarno return ret; 737ed0bceceSAurelien Jarno } 738ed0bceceSAurelien Jarno 739ed0bceceSAurelien Jarno /* round to integer 64-bit */ 740dce0a58fSDavid Hildenbrand uint64_t HELPER(fidb)(CPUS390XState *env, uint64_t f2, uint32_t m34) 741ed0bceceSAurelien Jarno { 742dce0a58fSDavid Hildenbrand int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); 743ed0bceceSAurelien Jarno float64 ret = float64_round_to_int(f2, &env->fpu_status); 744c0ee7015SDavid Hildenbrand 745c0ee7015SDavid Hildenbrand s390_restore_bfp_rounding_mode(env, old_mode); 746dce0a58fSDavid Hildenbrand handle_exceptions(env, xxc_from_m34(m34), GETPC()); 747ed0bceceSAurelien Jarno return ret; 748ed0bceceSAurelien Jarno } 749ed0bceceSAurelien Jarno 750ed0bceceSAurelien Jarno /* round to integer 128-bit */ 751dce0a58fSDavid Hildenbrand uint64_t HELPER(fixb)(CPUS390XState *env, uint64_t ah, uint64_t al, 752dce0a58fSDavid Hildenbrand uint32_t m34) 753ed0bceceSAurelien Jarno { 754dce0a58fSDavid Hildenbrand int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); 755ed0bceceSAurelien Jarno float128 ret = float128_round_to_int(make_float128(ah, al), 756ed0bceceSAurelien Jarno &env->fpu_status); 757cf97f9ffSDavid Hildenbrand 758c0ee7015SDavid Hildenbrand s390_restore_bfp_rounding_mode(env, old_mode); 759dce0a58fSDavid Hildenbrand handle_exceptions(env, xxc_from_m34(m34), GETPC()); 760ed0bceceSAurelien Jarno return RET128(ret); 761ed0bceceSAurelien Jarno } 762ed0bceceSAurelien Jarno 7639c8be598SAurelien Jarno /* 32-bit FP compare and signal */ 7649c8be598SAurelien Jarno uint32_t HELPER(keb)(CPUS390XState *env, uint64_t f1, uint64_t f2) 7659c8be598SAurelien Jarno { 76671bfd65cSRichard Henderson FloatRelation cmp = float32_compare(f1, f2, &env->fpu_status); 767cf97f9ffSDavid Hildenbrand handle_exceptions(env, false, GETPC()); 7689c8be598SAurelien Jarno return float_comp_to_cc(env, cmp); 7699c8be598SAurelien Jarno } 7709c8be598SAurelien Jarno 7719c8be598SAurelien Jarno /* 64-bit FP compare and signal */ 7729c8be598SAurelien Jarno uint32_t HELPER(kdb)(CPUS390XState *env, uint64_t f1, uint64_t f2) 7739c8be598SAurelien Jarno { 77471bfd65cSRichard Henderson FloatRelation cmp = float64_compare(f1, f2, &env->fpu_status); 775cf97f9ffSDavid Hildenbrand handle_exceptions(env, false, GETPC()); 7769c8be598SAurelien Jarno return float_comp_to_cc(env, cmp); 7779c8be598SAurelien Jarno } 7789c8be598SAurelien Jarno 7799c8be598SAurelien Jarno /* 128-bit FP compare and signal */ 7809c8be598SAurelien Jarno uint32_t HELPER(kxb)(CPUS390XState *env, uint64_t ah, uint64_t al, 7819c8be598SAurelien Jarno uint64_t bh, uint64_t bl) 7829c8be598SAurelien Jarno { 78371bfd65cSRichard Henderson FloatRelation cmp = float128_compare(make_float128(ah, al), 7849c8be598SAurelien Jarno make_float128(bh, bl), 7859c8be598SAurelien Jarno &env->fpu_status); 786cf97f9ffSDavid Hildenbrand handle_exceptions(env, false, GETPC()); 7879c8be598SAurelien Jarno return float_comp_to_cc(env, cmp); 7889c8be598SAurelien Jarno } 7899c8be598SAurelien Jarno 790722bfec3SRichard Henderson /* 32-bit FP multiply and add */ 791722bfec3SRichard Henderson uint64_t HELPER(maeb)(CPUS390XState *env, uint64_t f1, 792722bfec3SRichard Henderson uint64_t f2, uint64_t f3) 793e72ca652SBlue Swirl { 794722bfec3SRichard Henderson float32 ret = float32_muladd(f2, f3, f1, 0, &env->fpu_status); 795cf97f9ffSDavid Hildenbrand handle_exceptions(env, false, GETPC()); 796722bfec3SRichard Henderson return ret; 797722bfec3SRichard Henderson } 798e72ca652SBlue Swirl 799722bfec3SRichard Henderson /* 64-bit FP multiply and add */ 800722bfec3SRichard Henderson uint64_t HELPER(madb)(CPUS390XState *env, uint64_t f1, 801722bfec3SRichard Henderson uint64_t f2, uint64_t f3) 802722bfec3SRichard Henderson { 803722bfec3SRichard Henderson float64 ret = float64_muladd(f2, f3, f1, 0, &env->fpu_status); 804cf97f9ffSDavid Hildenbrand handle_exceptions(env, false, GETPC()); 805722bfec3SRichard Henderson return ret; 806722bfec3SRichard Henderson } 807722bfec3SRichard Henderson 808722bfec3SRichard Henderson /* 32-bit FP multiply and subtract */ 809722bfec3SRichard Henderson uint64_t HELPER(mseb)(CPUS390XState *env, uint64_t f1, 810722bfec3SRichard Henderson uint64_t f2, uint64_t f3) 811722bfec3SRichard Henderson { 812722bfec3SRichard Henderson float32 ret = float32_muladd(f2, f3, f1, float_muladd_negate_c, 813e72ca652SBlue Swirl &env->fpu_status); 814cf97f9ffSDavid Hildenbrand handle_exceptions(env, false, GETPC()); 815722bfec3SRichard Henderson return ret; 816e72ca652SBlue Swirl } 817e72ca652SBlue Swirl 818722bfec3SRichard Henderson /* 64-bit FP multiply and subtract */ 819722bfec3SRichard Henderson uint64_t HELPER(msdb)(CPUS390XState *env, uint64_t f1, 820722bfec3SRichard Henderson uint64_t f2, uint64_t f3) 821e72ca652SBlue Swirl { 822722bfec3SRichard Henderson float64 ret = float64_muladd(f2, f3, f1, float_muladd_negate_c, 823e72ca652SBlue Swirl &env->fpu_status); 824cf97f9ffSDavid Hildenbrand handle_exceptions(env, false, GETPC()); 825722bfec3SRichard Henderson return ret; 826e72ca652SBlue Swirl } 827e72ca652SBlue Swirl 828fc7cc951SDavid Hildenbrand /* The rightmost bit has the number 11. */ 829fc7cc951SDavid Hildenbrand static inline uint16_t dcmask(int bit, bool neg) 830fc7cc951SDavid Hildenbrand { 831fc7cc951SDavid Hildenbrand return 1 << (11 - bit - neg); 832fc7cc951SDavid Hildenbrand } 833fc7cc951SDavid Hildenbrand 834fc7cc951SDavid Hildenbrand #define DEF_FLOAT_DCMASK(_TYPE) \ 835aae65009SDavid Hildenbrand uint16_t _TYPE##_dcmask(CPUS390XState *env, _TYPE f1) \ 836fc7cc951SDavid Hildenbrand { \ 837fc7cc951SDavid Hildenbrand const bool neg = _TYPE##_is_neg(f1); \ 838fc7cc951SDavid Hildenbrand \ 839fc7cc951SDavid Hildenbrand /* Sorted by most common cases - only one class is possible */ \ 840fc7cc951SDavid Hildenbrand if (_TYPE##_is_normal(f1)) { \ 841fc7cc951SDavid Hildenbrand return dcmask(2, neg); \ 842fc7cc951SDavid Hildenbrand } else if (_TYPE##_is_zero(f1)) { \ 843fc7cc951SDavid Hildenbrand return dcmask(0, neg); \ 844fc7cc951SDavid Hildenbrand } else if (_TYPE##_is_denormal(f1)) { \ 845fc7cc951SDavid Hildenbrand return dcmask(4, neg); \ 846fc7cc951SDavid Hildenbrand } else if (_TYPE##_is_infinity(f1)) { \ 847fc7cc951SDavid Hildenbrand return dcmask(6, neg); \ 848fc7cc951SDavid Hildenbrand } else if (_TYPE##_is_quiet_nan(f1, &env->fpu_status)) { \ 849fc7cc951SDavid Hildenbrand return dcmask(8, neg); \ 850fc7cc951SDavid Hildenbrand } \ 851fc7cc951SDavid Hildenbrand /* signaling nan, as last remaining case */ \ 852fc7cc951SDavid Hildenbrand return dcmask(10, neg); \ 853fc7cc951SDavid Hildenbrand } 854fc7cc951SDavid Hildenbrand DEF_FLOAT_DCMASK(float32) 855fc7cc951SDavid Hildenbrand DEF_FLOAT_DCMASK(float64) 856fc7cc951SDavid Hildenbrand DEF_FLOAT_DCMASK(float128) 857fc7cc951SDavid Hildenbrand 858e72ca652SBlue Swirl /* test data class 32-bit */ 859af39bc8cSAleksandar Markovic uint32_t HELPER(tceb)(CPUS390XState *env, uint64_t f1, uint64_t m2) 860e72ca652SBlue Swirl { 861fc7cc951SDavid Hildenbrand return (m2 & float32_dcmask(env, f1)) != 0; 862e72ca652SBlue Swirl } 863e72ca652SBlue Swirl 864e72ca652SBlue Swirl /* test data class 64-bit */ 865af39bc8cSAleksandar Markovic uint32_t HELPER(tcdb)(CPUS390XState *env, uint64_t v1, uint64_t m2) 866e72ca652SBlue Swirl { 867fc7cc951SDavid Hildenbrand return (m2 & float64_dcmask(env, v1)) != 0; 868e72ca652SBlue Swirl } 869e72ca652SBlue Swirl 870e72ca652SBlue Swirl /* test data class 128-bit */ 871fc7cc951SDavid Hildenbrand uint32_t HELPER(tcxb)(CPUS390XState *env, uint64_t ah, uint64_t al, uint64_t m2) 872e72ca652SBlue Swirl { 873fc7cc951SDavid Hildenbrand return (m2 & float128_dcmask(env, make_float128(ah, al))) != 0; 874e72ca652SBlue Swirl } 875e72ca652SBlue Swirl 87616d7b2a4SRichard Henderson /* square root 32-bit */ 87716d7b2a4SRichard Henderson uint64_t HELPER(sqeb)(CPUS390XState *env, uint64_t f2) 878e72ca652SBlue Swirl { 87916d7b2a4SRichard Henderson float32 ret = float32_sqrt(f2, &env->fpu_status); 880cf97f9ffSDavid Hildenbrand handle_exceptions(env, false, GETPC()); 88116d7b2a4SRichard Henderson return ret; 88216d7b2a4SRichard Henderson } 88316d7b2a4SRichard Henderson 88416d7b2a4SRichard Henderson /* square root 64-bit */ 88516d7b2a4SRichard Henderson uint64_t HELPER(sqdb)(CPUS390XState *env, uint64_t f2) 88616d7b2a4SRichard Henderson { 88716d7b2a4SRichard Henderson float64 ret = float64_sqrt(f2, &env->fpu_status); 888cf97f9ffSDavid Hildenbrand handle_exceptions(env, false, GETPC()); 88916d7b2a4SRichard Henderson return ret; 89016d7b2a4SRichard Henderson } 89116d7b2a4SRichard Henderson 89216d7b2a4SRichard Henderson /* square root 128-bit */ 89316d7b2a4SRichard Henderson uint64_t HELPER(sqxb)(CPUS390XState *env, uint64_t ah, uint64_t al) 89416d7b2a4SRichard Henderson { 89516d7b2a4SRichard Henderson float128 ret = float128_sqrt(make_float128(ah, al), &env->fpu_status); 896cf97f9ffSDavid Hildenbrand handle_exceptions(env, false, GETPC()); 89716d7b2a4SRichard Henderson return RET128(ret); 898e72ca652SBlue Swirl } 8998379bfdbSRichard Henderson 9002aea83c6SDavid Hildenbrand static const int fpc_to_rnd[8] = { 9018379bfdbSRichard Henderson float_round_nearest_even, 9028379bfdbSRichard Henderson float_round_to_zero, 9038379bfdbSRichard Henderson float_round_up, 9042aea83c6SDavid Hildenbrand float_round_down, 9052aea83c6SDavid Hildenbrand -1, 9062aea83c6SDavid Hildenbrand -1, 9072aea83c6SDavid Hildenbrand -1, 9082aea83c6SDavid Hildenbrand float_round_to_odd, 9098379bfdbSRichard Henderson }; 9108379bfdbSRichard Henderson 911411edc22SRichard Henderson /* set fpc */ 912411edc22SRichard Henderson void HELPER(sfpc)(CPUS390XState *env, uint64_t fpc) 913411edc22SRichard Henderson { 9142aea83c6SDavid Hildenbrand if (fpc_to_rnd[fpc & 0x7] == -1 || fpc & 0x03030088u || 9152aea83c6SDavid Hildenbrand (!s390_has_feat(S390_FEAT_FLOATING_POINT_EXT) && fpc & 0x4)) { 9161e36aee6SRichard Henderson tcg_s390_program_interrupt(env, PGM_SPECIFICATION, GETPC()); 9172aea83c6SDavid Hildenbrand } 9182aea83c6SDavid Hildenbrand 9198379bfdbSRichard Henderson /* Install everything in the main FPC. */ 9208379bfdbSRichard Henderson env->fpc = fpc; 9218379bfdbSRichard Henderson 9228379bfdbSRichard Henderson /* Install the rounding mode in the shadow fpu_status. */ 9232aea83c6SDavid Hildenbrand set_float_rounding_mode(fpc_to_rnd[fpc & 0x7], &env->fpu_status); 924411edc22SRichard Henderson } 925411edc22SRichard Henderson 926411edc22SRichard Henderson /* set fpc and signal */ 927f66a0ecfSDavid Hildenbrand void HELPER(sfas)(CPUS390XState *env, uint64_t fpc) 928411edc22SRichard Henderson { 929411edc22SRichard Henderson uint32_t signalling = env->fpc; 930411edc22SRichard Henderson uint32_t s390_exc; 931411edc22SRichard Henderson 9322aea83c6SDavid Hildenbrand if (fpc_to_rnd[fpc & 0x7] == -1 || fpc & 0x03030088u || 9332aea83c6SDavid Hildenbrand (!s390_has_feat(S390_FEAT_FLOATING_POINT_EXT) && fpc & 0x4)) { 9341e36aee6SRichard Henderson tcg_s390_program_interrupt(env, PGM_SPECIFICATION, GETPC()); 9352aea83c6SDavid Hildenbrand } 9362aea83c6SDavid Hildenbrand 937f66a0ecfSDavid Hildenbrand /* 938f66a0ecfSDavid Hildenbrand * FPC is set to the FPC operand with a bitwise OR of the signalling 939f66a0ecfSDavid Hildenbrand * flags. 940f66a0ecfSDavid Hildenbrand */ 941f66a0ecfSDavid Hildenbrand env->fpc = fpc | (signalling & 0x00ff0000); 9422aea83c6SDavid Hildenbrand set_float_rounding_mode(fpc_to_rnd[fpc & 0x7], &env->fpu_status); 943411edc22SRichard Henderson 944f66a0ecfSDavid Hildenbrand /* 945f66a0ecfSDavid Hildenbrand * If any signaling flag is enabled in the new FPC mask, a 946f66a0ecfSDavid Hildenbrand * simulated-iee-exception exception occurs. 947f66a0ecfSDavid Hildenbrand */ 948f66a0ecfSDavid Hildenbrand s390_exc = (signalling >> 16) & (fpc >> 24); 949411edc22SRichard Henderson if (s390_exc) { 9508772bbe4SDavid Hildenbrand if (s390_exc & S390_IEEE_MASK_INVALID) { 9518772bbe4SDavid Hildenbrand s390_exc = S390_IEEE_MASK_INVALID; 9528772bbe4SDavid Hildenbrand } else if (s390_exc & S390_IEEE_MASK_DIVBYZERO) { 9538772bbe4SDavid Hildenbrand s390_exc = S390_IEEE_MASK_DIVBYZERO; 9548772bbe4SDavid Hildenbrand } else if (s390_exc & S390_IEEE_MASK_OVERFLOW) { 9558772bbe4SDavid Hildenbrand s390_exc &= (S390_IEEE_MASK_OVERFLOW | S390_IEEE_MASK_INEXACT); 9568772bbe4SDavid Hildenbrand } else if (s390_exc & S390_IEEE_MASK_UNDERFLOW) { 9578772bbe4SDavid Hildenbrand s390_exc &= (S390_IEEE_MASK_UNDERFLOW | S390_IEEE_MASK_INEXACT); 9588772bbe4SDavid Hildenbrand } else if (s390_exc & S390_IEEE_MASK_INEXACT) { 9598772bbe4SDavid Hildenbrand s390_exc = S390_IEEE_MASK_INEXACT; 9608772bbe4SDavid Hildenbrand } else if (s390_exc & S390_IEEE_MASK_QUANTUM) { 9618772bbe4SDavid Hildenbrand s390_exc = S390_IEEE_MASK_QUANTUM; 9628772bbe4SDavid Hildenbrand } 963bbf6ea3bSDavid Hildenbrand tcg_s390_data_exception(env, s390_exc | 3, GETPC()); 964411edc22SRichard Henderson } 9658379bfdbSRichard Henderson } 966b9c737f5SDavid Hildenbrand 967b9c737f5SDavid Hildenbrand /* set bfp rounding mode */ 968b9c737f5SDavid Hildenbrand void HELPER(srnm)(CPUS390XState *env, uint64_t rnd) 969b9c737f5SDavid Hildenbrand { 970b9c737f5SDavid Hildenbrand if (rnd > 0x7 || fpc_to_rnd[rnd & 0x7] == -1) { 9711e36aee6SRichard Henderson tcg_s390_program_interrupt(env, PGM_SPECIFICATION, GETPC()); 972b9c737f5SDavid Hildenbrand } 973b9c737f5SDavid Hildenbrand 974b9c737f5SDavid Hildenbrand env->fpc = deposit32(env->fpc, 0, 3, rnd); 975b9c737f5SDavid Hildenbrand set_float_rounding_mode(fpc_to_rnd[rnd & 0x7], &env->fpu_status); 976b9c737f5SDavid Hildenbrand } 977