14a58aedfSRichard Henderson /* 24a58aedfSRichard Henderson * Helpers for floating point instructions. 34a58aedfSRichard Henderson * 44a58aedfSRichard Henderson * Copyright (c) 2007 Jocelyn Mayer 54a58aedfSRichard Henderson * 64a58aedfSRichard Henderson * This library is free software; you can redistribute it and/or 74a58aedfSRichard Henderson * modify it under the terms of the GNU Lesser General Public 84a58aedfSRichard Henderson * License as published by the Free Software Foundation; either 94a58aedfSRichard Henderson * version 2 of the License, or (at your option) any later version. 104a58aedfSRichard Henderson * 114a58aedfSRichard Henderson * This library is distributed in the hope that it will be useful, 124a58aedfSRichard Henderson * but WITHOUT ANY WARRANTY; without even the implied warranty of 134a58aedfSRichard Henderson * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 144a58aedfSRichard Henderson * Lesser General Public License for more details. 154a58aedfSRichard Henderson * 164a58aedfSRichard Henderson * You should have received a copy of the GNU Lesser General Public 174a58aedfSRichard Henderson * License along with this library; if not, see <http://www.gnu.org/licenses/>. 184a58aedfSRichard Henderson */ 194a58aedfSRichard Henderson 204a58aedfSRichard Henderson #include "cpu.h" 212ef6175aSRichard Henderson #include "exec/helper-proto.h" 226b4c305cSPaolo Bonzini #include "fpu/softfloat.h" 234a58aedfSRichard Henderson 244a58aedfSRichard Henderson #define FP_STATUS (env->fp_status) 254a58aedfSRichard Henderson 264a58aedfSRichard Henderson 274a58aedfSRichard Henderson void helper_setroundmode(CPUAlphaState *env, uint32_t val) 284a58aedfSRichard Henderson { 294a58aedfSRichard Henderson set_float_rounding_mode(val, &FP_STATUS); 304a58aedfSRichard Henderson } 314a58aedfSRichard Henderson 324a58aedfSRichard Henderson void helper_setflushzero(CPUAlphaState *env, uint32_t val) 334a58aedfSRichard Henderson { 344a58aedfSRichard Henderson set_flush_to_zero(val, &FP_STATUS); 354a58aedfSRichard Henderson } 364a58aedfSRichard Henderson 37f3d3aad4SRichard Henderson #define CONVERT_BIT(X, SRC, DST) \ 38f3d3aad4SRichard Henderson (SRC > DST ? (X) / (SRC / DST) & (DST) : ((X) & SRC) * (DST / SRC)) 39f3d3aad4SRichard Henderson 40f3d3aad4SRichard Henderson static uint32_t soft_to_fpcr_exc(CPUAlphaState *env) 414a58aedfSRichard Henderson { 42f3d3aad4SRichard Henderson uint8_t exc = get_float_exception_flags(&FP_STATUS); 43f3d3aad4SRichard Henderson uint32_t ret = 0; 44f3d3aad4SRichard Henderson 45f3d3aad4SRichard Henderson if (unlikely(exc)) { 464a58aedfSRichard Henderson set_float_exception_flags(0, &FP_STATUS); 47f3d3aad4SRichard Henderson ret |= CONVERT_BIT(exc, float_flag_invalid, FPCR_INV); 48f3d3aad4SRichard Henderson ret |= CONVERT_BIT(exc, float_flag_divbyzero, FPCR_DZE); 49f3d3aad4SRichard Henderson ret |= CONVERT_BIT(exc, float_flag_overflow, FPCR_OVF); 50f3d3aad4SRichard Henderson ret |= CONVERT_BIT(exc, float_flag_underflow, FPCR_UNF); 51f3d3aad4SRichard Henderson ret |= CONVERT_BIT(exc, float_flag_inexact, FPCR_INE); 524a58aedfSRichard Henderson } 534a58aedfSRichard Henderson 54f3d3aad4SRichard Henderson return ret; 554a58aedfSRichard Henderson } 564a58aedfSRichard Henderson 57f3d3aad4SRichard Henderson static void fp_exc_raise1(CPUAlphaState *env, uintptr_t retaddr, 584a58aedfSRichard Henderson uint32_t exc, uint32_t regno) 594a58aedfSRichard Henderson { 604a58aedfSRichard Henderson if (exc) { 614a58aedfSRichard Henderson uint32_t hw_exc = 0; 624a58aedfSRichard Henderson 63f3d3aad4SRichard Henderson hw_exc |= CONVERT_BIT(exc, FPCR_INV, EXC_M_INV); 64f3d3aad4SRichard Henderson hw_exc |= CONVERT_BIT(exc, FPCR_DZE, EXC_M_DZE); 65f3d3aad4SRichard Henderson hw_exc |= CONVERT_BIT(exc, FPCR_OVF, EXC_M_FOV); 66f3d3aad4SRichard Henderson hw_exc |= CONVERT_BIT(exc, FPCR_UNF, EXC_M_UNF); 67f3d3aad4SRichard Henderson hw_exc |= CONVERT_BIT(exc, FPCR_INE, EXC_M_INE); 68f3d3aad4SRichard Henderson hw_exc |= CONVERT_BIT(exc, FPCR_IOV, EXC_M_IOV); 694a58aedfSRichard Henderson 704a58aedfSRichard Henderson arith_excp(env, retaddr, hw_exc, 1ull << regno); 714a58aedfSRichard Henderson } 724a58aedfSRichard Henderson } 734a58aedfSRichard Henderson 744a58aedfSRichard Henderson /* Raise exceptions for ieee fp insns without software completion. 754a58aedfSRichard Henderson In that case there are no exceptions that don't trap; the mask 764a58aedfSRichard Henderson doesn't apply. */ 77f3d3aad4SRichard Henderson void helper_fp_exc_raise(CPUAlphaState *env, uint32_t ignore, uint32_t regno) 784a58aedfSRichard Henderson { 79f3d3aad4SRichard Henderson uint32_t exc = env->error_code & ~ignore; 80f3d3aad4SRichard Henderson fp_exc_raise1(env, GETPC(), exc, regno); 814a58aedfSRichard Henderson } 824a58aedfSRichard Henderson 834a58aedfSRichard Henderson /* Raise exceptions for ieee fp insns with software completion. */ 84f3d3aad4SRichard Henderson void helper_fp_exc_raise_s(CPUAlphaState *env, uint32_t ignore, uint32_t regno) 854a58aedfSRichard Henderson { 86f3d3aad4SRichard Henderson uint32_t exc = env->error_code & ~ignore; 874a58aedfSRichard Henderson if (exc) { 88f3d3aad4SRichard Henderson env->fpcr |= exc; 89f3d3aad4SRichard Henderson exc &= env->fpcr_exc_enable; 90f3d3aad4SRichard Henderson fp_exc_raise1(env, GETPC(), exc, regno); 914a58aedfSRichard Henderson } 924a58aedfSRichard Henderson } 934a58aedfSRichard Henderson 9474343409SRichard Henderson /* Input handing without software completion. Trap for all 9574343409SRichard Henderson non-finite numbers. */ 9674343409SRichard Henderson void helper_ieee_input(CPUAlphaState *env, uint64_t val) 974a58aedfSRichard Henderson { 984a58aedfSRichard Henderson uint32_t exp = (uint32_t)(val >> 52) & 0x7ff; 994a58aedfSRichard Henderson uint64_t frac = val & 0xfffffffffffffull; 1004a58aedfSRichard Henderson 1014a58aedfSRichard Henderson if (exp == 0) { 10274343409SRichard Henderson /* Denormals without DNZ set raise an exception. */ 10374343409SRichard Henderson if (frac != 0 && !env->fp_status.flush_inputs_to_zero) { 1044a58aedfSRichard Henderson arith_excp(env, GETPC(), EXC_M_UNF, 0); 1054a58aedfSRichard Henderson } 1064a58aedfSRichard Henderson } else if (exp == 0x7ff) { 1074a58aedfSRichard Henderson /* Infinity or NaN. */ 1084a58aedfSRichard Henderson /* ??? I'm not sure these exception bit flags are correct. I do 1094a58aedfSRichard Henderson know that the Linux kernel, at least, doesn't rely on them and 1104a58aedfSRichard Henderson just emulates the insn to figure out what exception to use. */ 1114a58aedfSRichard Henderson arith_excp(env, GETPC(), frac ? EXC_M_INV : EXC_M_FOV, 0); 1124a58aedfSRichard Henderson } 1134a58aedfSRichard Henderson } 1144a58aedfSRichard Henderson 1154a58aedfSRichard Henderson /* Similar, but does not trap for infinities. Used for comparisons. */ 11674343409SRichard Henderson void helper_ieee_input_cmp(CPUAlphaState *env, uint64_t val) 1174a58aedfSRichard Henderson { 1184a58aedfSRichard Henderson uint32_t exp = (uint32_t)(val >> 52) & 0x7ff; 1194a58aedfSRichard Henderson uint64_t frac = val & 0xfffffffffffffull; 1204a58aedfSRichard Henderson 1214a58aedfSRichard Henderson if (exp == 0) { 12274343409SRichard Henderson /* Denormals without DNZ set raise an exception. */ 12374343409SRichard Henderson if (frac != 0 && !env->fp_status.flush_inputs_to_zero) { 1244a58aedfSRichard Henderson arith_excp(env, GETPC(), EXC_M_UNF, 0); 1254a58aedfSRichard Henderson } 1264a58aedfSRichard Henderson } else if (exp == 0x7ff && frac) { 1274a58aedfSRichard Henderson /* NaN. */ 1284a58aedfSRichard Henderson arith_excp(env, GETPC(), EXC_M_INV, 0); 1294a58aedfSRichard Henderson } 1304a58aedfSRichard Henderson } 1314a58aedfSRichard Henderson 1324a58aedfSRichard Henderson 1334a58aedfSRichard Henderson /* S floating (single) */ 1344a58aedfSRichard Henderson 1354a58aedfSRichard Henderson /* Taken from linux/arch/alpha/kernel/traps.c, s_mem_to_reg. */ 1364a58aedfSRichard Henderson static inline uint64_t float32_to_s_int(uint32_t fi) 1374a58aedfSRichard Henderson { 1384a58aedfSRichard Henderson uint32_t frac = fi & 0x7fffff; 1394a58aedfSRichard Henderson uint32_t sign = fi >> 31; 1404a58aedfSRichard Henderson uint32_t exp_msb = (fi >> 30) & 1; 1414a58aedfSRichard Henderson uint32_t exp_low = (fi >> 23) & 0x7f; 1424a58aedfSRichard Henderson uint32_t exp; 1434a58aedfSRichard Henderson 1444a58aedfSRichard Henderson exp = (exp_msb << 10) | exp_low; 1454a58aedfSRichard Henderson if (exp_msb) { 1464a58aedfSRichard Henderson if (exp_low == 0x7f) { 1474a58aedfSRichard Henderson exp = 0x7ff; 1484a58aedfSRichard Henderson } 1494a58aedfSRichard Henderson } else { 1504a58aedfSRichard Henderson if (exp_low != 0x00) { 1514a58aedfSRichard Henderson exp |= 0x380; 1524a58aedfSRichard Henderson } 1534a58aedfSRichard Henderson } 1544a58aedfSRichard Henderson 1554a58aedfSRichard Henderson return (((uint64_t)sign << 63) 1564a58aedfSRichard Henderson | ((uint64_t)exp << 52) 1574a58aedfSRichard Henderson | ((uint64_t)frac << 29)); 1584a58aedfSRichard Henderson } 1594a58aedfSRichard Henderson 1604a58aedfSRichard Henderson static inline uint64_t float32_to_s(float32 fa) 1614a58aedfSRichard Henderson { 1624a58aedfSRichard Henderson CPU_FloatU a; 1634a58aedfSRichard Henderson a.f = fa; 1644a58aedfSRichard Henderson return float32_to_s_int(a.l); 1654a58aedfSRichard Henderson } 1664a58aedfSRichard Henderson 1674a58aedfSRichard Henderson static inline uint32_t s_to_float32_int(uint64_t a) 1684a58aedfSRichard Henderson { 1694a58aedfSRichard Henderson return ((a >> 32) & 0xc0000000) | ((a >> 29) & 0x3fffffff); 1704a58aedfSRichard Henderson } 1714a58aedfSRichard Henderson 1724a58aedfSRichard Henderson static inline float32 s_to_float32(uint64_t a) 1734a58aedfSRichard Henderson { 1744a58aedfSRichard Henderson CPU_FloatU r; 1754a58aedfSRichard Henderson r.l = s_to_float32_int(a); 1764a58aedfSRichard Henderson return r.f; 1774a58aedfSRichard Henderson } 1784a58aedfSRichard Henderson 1794a58aedfSRichard Henderson uint32_t helper_s_to_memory(uint64_t a) 1804a58aedfSRichard Henderson { 1814a58aedfSRichard Henderson return s_to_float32_int(a); 1824a58aedfSRichard Henderson } 1834a58aedfSRichard Henderson 1844a58aedfSRichard Henderson uint64_t helper_memory_to_s(uint32_t a) 1854a58aedfSRichard Henderson { 1864a58aedfSRichard Henderson return float32_to_s_int(a); 1874a58aedfSRichard Henderson } 1884a58aedfSRichard Henderson 1894a58aedfSRichard Henderson uint64_t helper_adds(CPUAlphaState *env, uint64_t a, uint64_t b) 1904a58aedfSRichard Henderson { 1914a58aedfSRichard Henderson float32 fa, fb, fr; 1924a58aedfSRichard Henderson 1934a58aedfSRichard Henderson fa = s_to_float32(a); 1944a58aedfSRichard Henderson fb = s_to_float32(b); 1954a58aedfSRichard Henderson fr = float32_add(fa, fb, &FP_STATUS); 196f3d3aad4SRichard Henderson env->error_code = soft_to_fpcr_exc(env); 197f3d3aad4SRichard Henderson 1984a58aedfSRichard Henderson return float32_to_s(fr); 1994a58aedfSRichard Henderson } 2004a58aedfSRichard Henderson 2014a58aedfSRichard Henderson uint64_t helper_subs(CPUAlphaState *env, uint64_t a, uint64_t b) 2024a58aedfSRichard Henderson { 2034a58aedfSRichard Henderson float32 fa, fb, fr; 2044a58aedfSRichard Henderson 2054a58aedfSRichard Henderson fa = s_to_float32(a); 2064a58aedfSRichard Henderson fb = s_to_float32(b); 2074a58aedfSRichard Henderson fr = float32_sub(fa, fb, &FP_STATUS); 208f3d3aad4SRichard Henderson env->error_code = soft_to_fpcr_exc(env); 209f3d3aad4SRichard Henderson 2104a58aedfSRichard Henderson return float32_to_s(fr); 2114a58aedfSRichard Henderson } 2124a58aedfSRichard Henderson 2134a58aedfSRichard Henderson uint64_t helper_muls(CPUAlphaState *env, uint64_t a, uint64_t b) 2144a58aedfSRichard Henderson { 2154a58aedfSRichard Henderson float32 fa, fb, fr; 2164a58aedfSRichard Henderson 2174a58aedfSRichard Henderson fa = s_to_float32(a); 2184a58aedfSRichard Henderson fb = s_to_float32(b); 2194a58aedfSRichard Henderson fr = float32_mul(fa, fb, &FP_STATUS); 220f3d3aad4SRichard Henderson env->error_code = soft_to_fpcr_exc(env); 221f3d3aad4SRichard Henderson 2224a58aedfSRichard Henderson return float32_to_s(fr); 2234a58aedfSRichard Henderson } 2244a58aedfSRichard Henderson 2254a58aedfSRichard Henderson uint64_t helper_divs(CPUAlphaState *env, uint64_t a, uint64_t b) 2264a58aedfSRichard Henderson { 2274a58aedfSRichard Henderson float32 fa, fb, fr; 2284a58aedfSRichard Henderson 2294a58aedfSRichard Henderson fa = s_to_float32(a); 2304a58aedfSRichard Henderson fb = s_to_float32(b); 2314a58aedfSRichard Henderson fr = float32_div(fa, fb, &FP_STATUS); 232f3d3aad4SRichard Henderson env->error_code = soft_to_fpcr_exc(env); 233f3d3aad4SRichard Henderson 2344a58aedfSRichard Henderson return float32_to_s(fr); 2354a58aedfSRichard Henderson } 2364a58aedfSRichard Henderson 2374a58aedfSRichard Henderson uint64_t helper_sqrts(CPUAlphaState *env, uint64_t a) 2384a58aedfSRichard Henderson { 2394a58aedfSRichard Henderson float32 fa, fr; 2404a58aedfSRichard Henderson 2414a58aedfSRichard Henderson fa = s_to_float32(a); 2424a58aedfSRichard Henderson fr = float32_sqrt(fa, &FP_STATUS); 243f3d3aad4SRichard Henderson env->error_code = soft_to_fpcr_exc(env); 244f3d3aad4SRichard Henderson 2454a58aedfSRichard Henderson return float32_to_s(fr); 2464a58aedfSRichard Henderson } 2474a58aedfSRichard Henderson 2484a58aedfSRichard Henderson 2494a58aedfSRichard Henderson /* T floating (double) */ 2504a58aedfSRichard Henderson static inline float64 t_to_float64(uint64_t a) 2514a58aedfSRichard Henderson { 2524a58aedfSRichard Henderson /* Memory format is the same as float64 */ 2534a58aedfSRichard Henderson CPU_DoubleU r; 2544a58aedfSRichard Henderson r.ll = a; 2554a58aedfSRichard Henderson return r.d; 2564a58aedfSRichard Henderson } 2574a58aedfSRichard Henderson 2584a58aedfSRichard Henderson static inline uint64_t float64_to_t(float64 fa) 2594a58aedfSRichard Henderson { 2604a58aedfSRichard Henderson /* Memory format is the same as float64 */ 2614a58aedfSRichard Henderson CPU_DoubleU r; 2624a58aedfSRichard Henderson r.d = fa; 2634a58aedfSRichard Henderson return r.ll; 2644a58aedfSRichard Henderson } 2654a58aedfSRichard Henderson 2664a58aedfSRichard Henderson uint64_t helper_addt(CPUAlphaState *env, uint64_t a, uint64_t b) 2674a58aedfSRichard Henderson { 2684a58aedfSRichard Henderson float64 fa, fb, fr; 2694a58aedfSRichard Henderson 2704a58aedfSRichard Henderson fa = t_to_float64(a); 2714a58aedfSRichard Henderson fb = t_to_float64(b); 2724a58aedfSRichard Henderson fr = float64_add(fa, fb, &FP_STATUS); 273f3d3aad4SRichard Henderson env->error_code = soft_to_fpcr_exc(env); 274f3d3aad4SRichard Henderson 2754a58aedfSRichard Henderson return float64_to_t(fr); 2764a58aedfSRichard Henderson } 2774a58aedfSRichard Henderson 2784a58aedfSRichard Henderson uint64_t helper_subt(CPUAlphaState *env, uint64_t a, uint64_t b) 2794a58aedfSRichard Henderson { 2804a58aedfSRichard Henderson float64 fa, fb, fr; 2814a58aedfSRichard Henderson 2824a58aedfSRichard Henderson fa = t_to_float64(a); 2834a58aedfSRichard Henderson fb = t_to_float64(b); 2844a58aedfSRichard Henderson fr = float64_sub(fa, fb, &FP_STATUS); 285f3d3aad4SRichard Henderson env->error_code = soft_to_fpcr_exc(env); 286f3d3aad4SRichard Henderson 2874a58aedfSRichard Henderson return float64_to_t(fr); 2884a58aedfSRichard Henderson } 2894a58aedfSRichard Henderson 2904a58aedfSRichard Henderson uint64_t helper_mult(CPUAlphaState *env, uint64_t a, uint64_t b) 2914a58aedfSRichard Henderson { 2924a58aedfSRichard Henderson float64 fa, fb, fr; 2934a58aedfSRichard Henderson 2944a58aedfSRichard Henderson fa = t_to_float64(a); 2954a58aedfSRichard Henderson fb = t_to_float64(b); 2964a58aedfSRichard Henderson fr = float64_mul(fa, fb, &FP_STATUS); 297f3d3aad4SRichard Henderson env->error_code = soft_to_fpcr_exc(env); 298f3d3aad4SRichard Henderson 2994a58aedfSRichard Henderson return float64_to_t(fr); 3004a58aedfSRichard Henderson } 3014a58aedfSRichard Henderson 3024a58aedfSRichard Henderson uint64_t helper_divt(CPUAlphaState *env, uint64_t a, uint64_t b) 3034a58aedfSRichard Henderson { 3044a58aedfSRichard Henderson float64 fa, fb, fr; 3054a58aedfSRichard Henderson 3064a58aedfSRichard Henderson fa = t_to_float64(a); 3074a58aedfSRichard Henderson fb = t_to_float64(b); 3084a58aedfSRichard Henderson fr = float64_div(fa, fb, &FP_STATUS); 309f3d3aad4SRichard Henderson env->error_code = soft_to_fpcr_exc(env); 310f3d3aad4SRichard Henderson 3114a58aedfSRichard Henderson return float64_to_t(fr); 3124a58aedfSRichard Henderson } 3134a58aedfSRichard Henderson 3144a58aedfSRichard Henderson uint64_t helper_sqrtt(CPUAlphaState *env, uint64_t a) 3154a58aedfSRichard Henderson { 3164a58aedfSRichard Henderson float64 fa, fr; 3174a58aedfSRichard Henderson 3184a58aedfSRichard Henderson fa = t_to_float64(a); 3194a58aedfSRichard Henderson fr = float64_sqrt(fa, &FP_STATUS); 320f3d3aad4SRichard Henderson env->error_code = soft_to_fpcr_exc(env); 321f3d3aad4SRichard Henderson 3224a58aedfSRichard Henderson return float64_to_t(fr); 3234a58aedfSRichard Henderson } 3244a58aedfSRichard Henderson 3254a58aedfSRichard Henderson /* Comparisons */ 3264a58aedfSRichard Henderson uint64_t helper_cmptun(CPUAlphaState *env, uint64_t a, uint64_t b) 3274a58aedfSRichard Henderson { 3284a58aedfSRichard Henderson float64 fa, fb; 329f3d3aad4SRichard Henderson uint64_t ret = 0; 3304a58aedfSRichard Henderson 3314a58aedfSRichard Henderson fa = t_to_float64(a); 3324a58aedfSRichard Henderson fb = t_to_float64(b); 3334a58aedfSRichard Henderson 3344a58aedfSRichard Henderson if (float64_unordered_quiet(fa, fb, &FP_STATUS)) { 335f3d3aad4SRichard Henderson ret = 0x4000000000000000ULL; 3364a58aedfSRichard Henderson } 337f3d3aad4SRichard Henderson env->error_code = soft_to_fpcr_exc(env); 338f3d3aad4SRichard Henderson 339f3d3aad4SRichard Henderson return ret; 3404a58aedfSRichard Henderson } 3414a58aedfSRichard Henderson 3424a58aedfSRichard Henderson uint64_t helper_cmpteq(CPUAlphaState *env, uint64_t a, uint64_t b) 3434a58aedfSRichard Henderson { 3444a58aedfSRichard Henderson float64 fa, fb; 345f3d3aad4SRichard Henderson uint64_t ret = 0; 3464a58aedfSRichard Henderson 3474a58aedfSRichard Henderson fa = t_to_float64(a); 3484a58aedfSRichard Henderson fb = t_to_float64(b); 3494a58aedfSRichard Henderson 3504a58aedfSRichard Henderson if (float64_eq_quiet(fa, fb, &FP_STATUS)) { 351f3d3aad4SRichard Henderson ret = 0x4000000000000000ULL; 3524a58aedfSRichard Henderson } 353f3d3aad4SRichard Henderson env->error_code = soft_to_fpcr_exc(env); 354f3d3aad4SRichard Henderson 355f3d3aad4SRichard Henderson return ret; 3564a58aedfSRichard Henderson } 3574a58aedfSRichard Henderson 3584a58aedfSRichard Henderson uint64_t helper_cmptle(CPUAlphaState *env, uint64_t a, uint64_t b) 3594a58aedfSRichard Henderson { 3604a58aedfSRichard Henderson float64 fa, fb; 361f3d3aad4SRichard Henderson uint64_t ret = 0; 3624a58aedfSRichard Henderson 3634a58aedfSRichard Henderson fa = t_to_float64(a); 3644a58aedfSRichard Henderson fb = t_to_float64(b); 3654a58aedfSRichard Henderson 3664a58aedfSRichard Henderson if (float64_le(fa, fb, &FP_STATUS)) { 367f3d3aad4SRichard Henderson ret = 0x4000000000000000ULL; 3684a58aedfSRichard Henderson } 369f3d3aad4SRichard Henderson env->error_code = soft_to_fpcr_exc(env); 370f3d3aad4SRichard Henderson 371f3d3aad4SRichard Henderson return ret; 3724a58aedfSRichard Henderson } 3734a58aedfSRichard Henderson 3744a58aedfSRichard Henderson uint64_t helper_cmptlt(CPUAlphaState *env, uint64_t a, uint64_t b) 3754a58aedfSRichard Henderson { 3764a58aedfSRichard Henderson float64 fa, fb; 377f3d3aad4SRichard Henderson uint64_t ret = 0; 3784a58aedfSRichard Henderson 3794a58aedfSRichard Henderson fa = t_to_float64(a); 3804a58aedfSRichard Henderson fb = t_to_float64(b); 3814a58aedfSRichard Henderson 3824a58aedfSRichard Henderson if (float64_lt(fa, fb, &FP_STATUS)) { 383f3d3aad4SRichard Henderson ret = 0x4000000000000000ULL; 3844a58aedfSRichard Henderson } 385f3d3aad4SRichard Henderson env->error_code = soft_to_fpcr_exc(env); 386f3d3aad4SRichard Henderson 387f3d3aad4SRichard Henderson return ret; 3884a58aedfSRichard Henderson } 3894a58aedfSRichard Henderson 3904a58aedfSRichard Henderson /* Floating point format conversion */ 3914a58aedfSRichard Henderson uint64_t helper_cvtts(CPUAlphaState *env, uint64_t a) 3924a58aedfSRichard Henderson { 3934a58aedfSRichard Henderson float64 fa; 3944a58aedfSRichard Henderson float32 fr; 3954a58aedfSRichard Henderson 3964a58aedfSRichard Henderson fa = t_to_float64(a); 3974a58aedfSRichard Henderson fr = float64_to_float32(fa, &FP_STATUS); 398f3d3aad4SRichard Henderson env->error_code = soft_to_fpcr_exc(env); 399f3d3aad4SRichard Henderson 4004a58aedfSRichard Henderson return float32_to_s(fr); 4014a58aedfSRichard Henderson } 4024a58aedfSRichard Henderson 4034a58aedfSRichard Henderson uint64_t helper_cvtst(CPUAlphaState *env, uint64_t a) 4044a58aedfSRichard Henderson { 4054a58aedfSRichard Henderson float32 fa; 4064a58aedfSRichard Henderson float64 fr; 4074a58aedfSRichard Henderson 4084a58aedfSRichard Henderson fa = s_to_float32(a); 4094a58aedfSRichard Henderson fr = float32_to_float64(fa, &FP_STATUS); 410f3d3aad4SRichard Henderson env->error_code = soft_to_fpcr_exc(env); 411f3d3aad4SRichard Henderson 4124a58aedfSRichard Henderson return float64_to_t(fr); 4134a58aedfSRichard Henderson } 4144a58aedfSRichard Henderson 4154a58aedfSRichard Henderson uint64_t helper_cvtqs(CPUAlphaState *env, uint64_t a) 4164a58aedfSRichard Henderson { 4174a58aedfSRichard Henderson float32 fr = int64_to_float32(a, &FP_STATUS); 418f3d3aad4SRichard Henderson env->error_code = soft_to_fpcr_exc(env); 419f3d3aad4SRichard Henderson 4204a58aedfSRichard Henderson return float32_to_s(fr); 4214a58aedfSRichard Henderson } 4224a58aedfSRichard Henderson 4234a58aedfSRichard Henderson /* Implement float64 to uint64 conversion without saturation -- we must 4244a58aedfSRichard Henderson supply the truncated result. This behaviour is used by the compiler 4254a58aedfSRichard Henderson to get unsigned conversion for free with the same instruction. 4264a58aedfSRichard Henderson 4274a58aedfSRichard Henderson The VI flag is set when overflow or inexact exceptions should be raised. */ 4284a58aedfSRichard Henderson 4294a58aedfSRichard Henderson static inline uint64_t inline_cvttq(CPUAlphaState *env, uint64_t a, 4304a58aedfSRichard Henderson int roundmode, int VI) 4314a58aedfSRichard Henderson { 4324a58aedfSRichard Henderson uint64_t frac, ret = 0; 4334a58aedfSRichard Henderson uint32_t exp, sign, exc = 0; 4344a58aedfSRichard Henderson int shift; 4354a58aedfSRichard Henderson 4364a58aedfSRichard Henderson sign = (a >> 63); 4374a58aedfSRichard Henderson exp = (uint32_t)(a >> 52) & 0x7ff; 4384a58aedfSRichard Henderson frac = a & 0xfffffffffffffull; 4394a58aedfSRichard Henderson 4404a58aedfSRichard Henderson if (exp == 0) { 4414a58aedfSRichard Henderson if (unlikely(frac != 0)) { 4424a58aedfSRichard Henderson goto do_underflow; 4434a58aedfSRichard Henderson } 4444a58aedfSRichard Henderson } else if (exp == 0x7ff) { 445f3d3aad4SRichard Henderson exc = (frac ? FPCR_INV : VI ? FPCR_OVF : 0); 4464a58aedfSRichard Henderson } else { 4474a58aedfSRichard Henderson /* Restore implicit bit. */ 4484a58aedfSRichard Henderson frac |= 0x10000000000000ull; 4494a58aedfSRichard Henderson 4504a58aedfSRichard Henderson shift = exp - 1023 - 52; 4514a58aedfSRichard Henderson if (shift >= 0) { 4524a58aedfSRichard Henderson /* In this case the number is so large that we must shift 4534a58aedfSRichard Henderson the fraction left. There is no rounding to do. */ 4544a58aedfSRichard Henderson if (shift < 63) { 4554a58aedfSRichard Henderson ret = frac << shift; 4564a58aedfSRichard Henderson if (VI && (ret >> shift) != frac) { 457f3d3aad4SRichard Henderson exc = FPCR_OVF; 4584a58aedfSRichard Henderson } 4594a58aedfSRichard Henderson } 4604a58aedfSRichard Henderson } else { 4614a58aedfSRichard Henderson uint64_t round; 4624a58aedfSRichard Henderson 4634a58aedfSRichard Henderson /* In this case the number is smaller than the fraction as 4644a58aedfSRichard Henderson represented by the 52 bit number. Here we must think 4654a58aedfSRichard Henderson about rounding the result. Handle this by shifting the 4664a58aedfSRichard Henderson fractional part of the number into the high bits of ROUND. 4674a58aedfSRichard Henderson This will let us efficiently handle round-to-nearest. */ 4684a58aedfSRichard Henderson shift = -shift; 4694a58aedfSRichard Henderson if (shift < 63) { 4704a58aedfSRichard Henderson ret = frac >> shift; 4714a58aedfSRichard Henderson round = frac << (64 - shift); 4724a58aedfSRichard Henderson } else { 4734a58aedfSRichard Henderson /* The exponent is so small we shift out everything. 4744a58aedfSRichard Henderson Leave a sticky bit for proper rounding below. */ 4754a58aedfSRichard Henderson do_underflow: 4764a58aedfSRichard Henderson round = 1; 4774a58aedfSRichard Henderson } 4784a58aedfSRichard Henderson 4794a58aedfSRichard Henderson if (round) { 480f3d3aad4SRichard Henderson exc = (VI ? FPCR_INE : 0); 4814a58aedfSRichard Henderson switch (roundmode) { 4824a58aedfSRichard Henderson case float_round_nearest_even: 4834a58aedfSRichard Henderson if (round == (1ull << 63)) { 4844a58aedfSRichard Henderson /* Fraction is exactly 0.5; round to even. */ 4854a58aedfSRichard Henderson ret += (ret & 1); 4864a58aedfSRichard Henderson } else if (round > (1ull << 63)) { 4874a58aedfSRichard Henderson ret += 1; 4884a58aedfSRichard Henderson } 4894a58aedfSRichard Henderson break; 4904a58aedfSRichard Henderson case float_round_to_zero: 4914a58aedfSRichard Henderson break; 4924a58aedfSRichard Henderson case float_round_up: 4934a58aedfSRichard Henderson ret += 1 - sign; 4944a58aedfSRichard Henderson break; 4954a58aedfSRichard Henderson case float_round_down: 4964a58aedfSRichard Henderson ret += sign; 4974a58aedfSRichard Henderson break; 4984a58aedfSRichard Henderson } 4994a58aedfSRichard Henderson } 5004a58aedfSRichard Henderson } 5014a58aedfSRichard Henderson if (sign) { 5024a58aedfSRichard Henderson ret = -ret; 5034a58aedfSRichard Henderson } 5044a58aedfSRichard Henderson } 505f3d3aad4SRichard Henderson env->error_code = exc; 5064a58aedfSRichard Henderson 5074a58aedfSRichard Henderson return ret; 5084a58aedfSRichard Henderson } 5094a58aedfSRichard Henderson 5104a58aedfSRichard Henderson uint64_t helper_cvttq(CPUAlphaState *env, uint64_t a) 5114a58aedfSRichard Henderson { 5124a58aedfSRichard Henderson return inline_cvttq(env, a, FP_STATUS.float_rounding_mode, 1); 5134a58aedfSRichard Henderson } 5144a58aedfSRichard Henderson 5154a58aedfSRichard Henderson uint64_t helper_cvttq_c(CPUAlphaState *env, uint64_t a) 5164a58aedfSRichard Henderson { 5174a58aedfSRichard Henderson return inline_cvttq(env, a, float_round_to_zero, 0); 5184a58aedfSRichard Henderson } 5194a58aedfSRichard Henderson 5204a58aedfSRichard Henderson uint64_t helper_cvttq_svic(CPUAlphaState *env, uint64_t a) 5214a58aedfSRichard Henderson { 5224a58aedfSRichard Henderson return inline_cvttq(env, a, float_round_to_zero, 1); 5234a58aedfSRichard Henderson } 5244a58aedfSRichard Henderson 5254a58aedfSRichard Henderson uint64_t helper_cvtqt(CPUAlphaState *env, uint64_t a) 5264a58aedfSRichard Henderson { 5274a58aedfSRichard Henderson float64 fr = int64_to_float64(a, &FP_STATUS); 528f3d3aad4SRichard Henderson env->error_code = soft_to_fpcr_exc(env); 5294a58aedfSRichard Henderson return float64_to_t(fr); 5304a58aedfSRichard Henderson } 5314a58aedfSRichard Henderson 5323da653faSRichard Henderson void helper_cvtql_v_input(CPUAlphaState *env, uint64_t val) 533e8d8fef4SRichard Henderson { 534e8d8fef4SRichard Henderson if (val != (int32_t)val) { 535e8d8fef4SRichard Henderson arith_excp(env, GETPC(), EXC_M_IOV, 0); 536e8d8fef4SRichard Henderson } 537e8d8fef4SRichard Henderson } 538