xref: /qemu/target/alpha/fpu_helper.c (revision 471d4930470aee38dffe6fc4890ede3d8eaf23c4)
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     uint32_t hw_exc = 0;
614a58aedfSRichard Henderson 
62f3d3aad4SRichard Henderson     hw_exc |= CONVERT_BIT(exc, FPCR_INV, EXC_M_INV);
63f3d3aad4SRichard Henderson     hw_exc |= CONVERT_BIT(exc, FPCR_DZE, EXC_M_DZE);
64f3d3aad4SRichard Henderson     hw_exc |= CONVERT_BIT(exc, FPCR_OVF, EXC_M_FOV);
65f3d3aad4SRichard Henderson     hw_exc |= CONVERT_BIT(exc, FPCR_UNF, EXC_M_UNF);
66f3d3aad4SRichard Henderson     hw_exc |= CONVERT_BIT(exc, FPCR_INE, EXC_M_INE);
67f3d3aad4SRichard Henderson     hw_exc |= CONVERT_BIT(exc, FPCR_IOV, EXC_M_IOV);
684a58aedfSRichard Henderson 
694a58aedfSRichard Henderson     arith_excp(env, retaddr, hw_exc, 1ull << regno);
704a58aedfSRichard Henderson }
714a58aedfSRichard Henderson 
724a58aedfSRichard Henderson /* Raise exceptions for ieee fp insns without software completion.
734a58aedfSRichard Henderson    In that case there are no exceptions that don't trap; the mask
744a58aedfSRichard Henderson    doesn't apply.  */
75f3d3aad4SRichard Henderson void helper_fp_exc_raise(CPUAlphaState *env, uint32_t ignore, uint32_t regno)
764a58aedfSRichard Henderson {
77471d4930SRichard Henderson     uint32_t exc = env->error_code;
78471d4930SRichard Henderson     if (exc) {
79471d4930SRichard Henderson         env->fpcr |= exc;
80471d4930SRichard Henderson         exc &= ~ignore;
81471d4930SRichard Henderson         if (exc) {
82f3d3aad4SRichard Henderson             fp_exc_raise1(env, GETPC(), exc, regno);
834a58aedfSRichard Henderson         }
84471d4930SRichard Henderson     }
85471d4930SRichard Henderson }
864a58aedfSRichard Henderson 
874a58aedfSRichard Henderson /* Raise exceptions for ieee fp insns with software completion.  */
88f3d3aad4SRichard Henderson void helper_fp_exc_raise_s(CPUAlphaState *env, uint32_t ignore, uint32_t regno)
894a58aedfSRichard Henderson {
90f3d3aad4SRichard Henderson     uint32_t exc = env->error_code & ~ignore;
914a58aedfSRichard Henderson     if (exc) {
92f3d3aad4SRichard Henderson         env->fpcr |= exc;
93471d4930SRichard Henderson         exc &= ~ignore;
94471d4930SRichard Henderson         if (exc) {
95f3d3aad4SRichard Henderson             exc &= env->fpcr_exc_enable;
96f3d3aad4SRichard Henderson             fp_exc_raise1(env, GETPC(), exc, regno);
974a58aedfSRichard Henderson         }
984a58aedfSRichard Henderson     }
99471d4930SRichard Henderson }
1004a58aedfSRichard Henderson 
10174343409SRichard Henderson /* Input handing without software completion.  Trap for all
10274343409SRichard Henderson    non-finite numbers.  */
10374343409SRichard Henderson void helper_ieee_input(CPUAlphaState *env, uint64_t val)
1044a58aedfSRichard Henderson {
1054a58aedfSRichard Henderson     uint32_t exp = (uint32_t)(val >> 52) & 0x7ff;
1064a58aedfSRichard Henderson     uint64_t frac = val & 0xfffffffffffffull;
1074a58aedfSRichard Henderson 
1084a58aedfSRichard Henderson     if (exp == 0) {
10974343409SRichard Henderson         /* Denormals without DNZ set raise an exception.  */
11074343409SRichard Henderson         if (frac != 0 && !env->fp_status.flush_inputs_to_zero) {
1114a58aedfSRichard Henderson             arith_excp(env, GETPC(), EXC_M_UNF, 0);
1124a58aedfSRichard Henderson         }
1134a58aedfSRichard Henderson     } else if (exp == 0x7ff) {
1144a58aedfSRichard Henderson         /* Infinity or NaN.  */
1154a58aedfSRichard Henderson         /* ??? I'm not sure these exception bit flags are correct.  I do
1164a58aedfSRichard Henderson            know that the Linux kernel, at least, doesn't rely on them and
1174a58aedfSRichard Henderson            just emulates the insn to figure out what exception to use.  */
1184a58aedfSRichard Henderson         arith_excp(env, GETPC(), frac ? EXC_M_INV : EXC_M_FOV, 0);
1194a58aedfSRichard Henderson     }
1204a58aedfSRichard Henderson }
1214a58aedfSRichard Henderson 
1224a58aedfSRichard Henderson /* Similar, but does not trap for infinities.  Used for comparisons.  */
12374343409SRichard Henderson void helper_ieee_input_cmp(CPUAlphaState *env, uint64_t val)
1244a58aedfSRichard Henderson {
1254a58aedfSRichard Henderson     uint32_t exp = (uint32_t)(val >> 52) & 0x7ff;
1264a58aedfSRichard Henderson     uint64_t frac = val & 0xfffffffffffffull;
1274a58aedfSRichard Henderson 
1284a58aedfSRichard Henderson     if (exp == 0) {
12974343409SRichard Henderson         /* Denormals without DNZ set raise an exception.  */
13074343409SRichard Henderson         if (frac != 0 && !env->fp_status.flush_inputs_to_zero) {
1314a58aedfSRichard Henderson             arith_excp(env, GETPC(), EXC_M_UNF, 0);
1324a58aedfSRichard Henderson         }
1334a58aedfSRichard Henderson     } else if (exp == 0x7ff && frac) {
1344a58aedfSRichard Henderson         /* NaN.  */
1354a58aedfSRichard Henderson         arith_excp(env, GETPC(), EXC_M_INV, 0);
1364a58aedfSRichard Henderson     }
1374a58aedfSRichard Henderson }
1384a58aedfSRichard Henderson 
1394a58aedfSRichard Henderson 
1404a58aedfSRichard Henderson /* S floating (single) */
1414a58aedfSRichard Henderson 
1424a58aedfSRichard Henderson /* Taken from linux/arch/alpha/kernel/traps.c, s_mem_to_reg.  */
1434a58aedfSRichard Henderson static inline uint64_t float32_to_s_int(uint32_t fi)
1444a58aedfSRichard Henderson {
1454a58aedfSRichard Henderson     uint32_t frac = fi & 0x7fffff;
1464a58aedfSRichard Henderson     uint32_t sign = fi >> 31;
1474a58aedfSRichard Henderson     uint32_t exp_msb = (fi >> 30) & 1;
1484a58aedfSRichard Henderson     uint32_t exp_low = (fi >> 23) & 0x7f;
1494a58aedfSRichard Henderson     uint32_t exp;
1504a58aedfSRichard Henderson 
1514a58aedfSRichard Henderson     exp = (exp_msb << 10) | exp_low;
1524a58aedfSRichard Henderson     if (exp_msb) {
1534a58aedfSRichard Henderson         if (exp_low == 0x7f) {
1544a58aedfSRichard Henderson             exp = 0x7ff;
1554a58aedfSRichard Henderson         }
1564a58aedfSRichard Henderson     } else {
1574a58aedfSRichard Henderson         if (exp_low != 0x00) {
1584a58aedfSRichard Henderson             exp |= 0x380;
1594a58aedfSRichard Henderson         }
1604a58aedfSRichard Henderson     }
1614a58aedfSRichard Henderson 
1624a58aedfSRichard Henderson     return (((uint64_t)sign << 63)
1634a58aedfSRichard Henderson             | ((uint64_t)exp << 52)
1644a58aedfSRichard Henderson             | ((uint64_t)frac << 29));
1654a58aedfSRichard Henderson }
1664a58aedfSRichard Henderson 
1674a58aedfSRichard Henderson static inline uint64_t float32_to_s(float32 fa)
1684a58aedfSRichard Henderson {
1694a58aedfSRichard Henderson     CPU_FloatU a;
1704a58aedfSRichard Henderson     a.f = fa;
1714a58aedfSRichard Henderson     return float32_to_s_int(a.l);
1724a58aedfSRichard Henderson }
1734a58aedfSRichard Henderson 
1744a58aedfSRichard Henderson static inline uint32_t s_to_float32_int(uint64_t a)
1754a58aedfSRichard Henderson {
1764a58aedfSRichard Henderson     return ((a >> 32) & 0xc0000000) | ((a >> 29) & 0x3fffffff);
1774a58aedfSRichard Henderson }
1784a58aedfSRichard Henderson 
1794a58aedfSRichard Henderson static inline float32 s_to_float32(uint64_t a)
1804a58aedfSRichard Henderson {
1814a58aedfSRichard Henderson     CPU_FloatU r;
1824a58aedfSRichard Henderson     r.l = s_to_float32_int(a);
1834a58aedfSRichard Henderson     return r.f;
1844a58aedfSRichard Henderson }
1854a58aedfSRichard Henderson 
1864a58aedfSRichard Henderson uint32_t helper_s_to_memory(uint64_t a)
1874a58aedfSRichard Henderson {
1884a58aedfSRichard Henderson     return s_to_float32_int(a);
1894a58aedfSRichard Henderson }
1904a58aedfSRichard Henderson 
1914a58aedfSRichard Henderson uint64_t helper_memory_to_s(uint32_t a)
1924a58aedfSRichard Henderson {
1934a58aedfSRichard Henderson     return float32_to_s_int(a);
1944a58aedfSRichard Henderson }
1954a58aedfSRichard Henderson 
1964a58aedfSRichard Henderson uint64_t helper_adds(CPUAlphaState *env, uint64_t a, uint64_t b)
1974a58aedfSRichard Henderson {
1984a58aedfSRichard Henderson     float32 fa, fb, fr;
1994a58aedfSRichard Henderson 
2004a58aedfSRichard Henderson     fa = s_to_float32(a);
2014a58aedfSRichard Henderson     fb = s_to_float32(b);
2024a58aedfSRichard Henderson     fr = float32_add(fa, fb, &FP_STATUS);
203f3d3aad4SRichard Henderson     env->error_code = soft_to_fpcr_exc(env);
204f3d3aad4SRichard Henderson 
2054a58aedfSRichard Henderson     return float32_to_s(fr);
2064a58aedfSRichard Henderson }
2074a58aedfSRichard Henderson 
2084a58aedfSRichard Henderson uint64_t helper_subs(CPUAlphaState *env, uint64_t a, uint64_t b)
2094a58aedfSRichard Henderson {
2104a58aedfSRichard Henderson     float32 fa, fb, fr;
2114a58aedfSRichard Henderson 
2124a58aedfSRichard Henderson     fa = s_to_float32(a);
2134a58aedfSRichard Henderson     fb = s_to_float32(b);
2144a58aedfSRichard Henderson     fr = float32_sub(fa, fb, &FP_STATUS);
215f3d3aad4SRichard Henderson     env->error_code = soft_to_fpcr_exc(env);
216f3d3aad4SRichard Henderson 
2174a58aedfSRichard Henderson     return float32_to_s(fr);
2184a58aedfSRichard Henderson }
2194a58aedfSRichard Henderson 
2204a58aedfSRichard Henderson uint64_t helper_muls(CPUAlphaState *env, uint64_t a, uint64_t b)
2214a58aedfSRichard Henderson {
2224a58aedfSRichard Henderson     float32 fa, fb, fr;
2234a58aedfSRichard Henderson 
2244a58aedfSRichard Henderson     fa = s_to_float32(a);
2254a58aedfSRichard Henderson     fb = s_to_float32(b);
2264a58aedfSRichard Henderson     fr = float32_mul(fa, fb, &FP_STATUS);
227f3d3aad4SRichard Henderson     env->error_code = soft_to_fpcr_exc(env);
228f3d3aad4SRichard Henderson 
2294a58aedfSRichard Henderson     return float32_to_s(fr);
2304a58aedfSRichard Henderson }
2314a58aedfSRichard Henderson 
2324a58aedfSRichard Henderson uint64_t helper_divs(CPUAlphaState *env, uint64_t a, uint64_t b)
2334a58aedfSRichard Henderson {
2344a58aedfSRichard Henderson     float32 fa, fb, fr;
2354a58aedfSRichard Henderson 
2364a58aedfSRichard Henderson     fa = s_to_float32(a);
2374a58aedfSRichard Henderson     fb = s_to_float32(b);
2384a58aedfSRichard Henderson     fr = float32_div(fa, fb, &FP_STATUS);
239f3d3aad4SRichard Henderson     env->error_code = soft_to_fpcr_exc(env);
240f3d3aad4SRichard Henderson 
2414a58aedfSRichard Henderson     return float32_to_s(fr);
2424a58aedfSRichard Henderson }
2434a58aedfSRichard Henderson 
2444a58aedfSRichard Henderson uint64_t helper_sqrts(CPUAlphaState *env, uint64_t a)
2454a58aedfSRichard Henderson {
2464a58aedfSRichard Henderson     float32 fa, fr;
2474a58aedfSRichard Henderson 
2484a58aedfSRichard Henderson     fa = s_to_float32(a);
2494a58aedfSRichard Henderson     fr = float32_sqrt(fa, &FP_STATUS);
250f3d3aad4SRichard Henderson     env->error_code = soft_to_fpcr_exc(env);
251f3d3aad4SRichard Henderson 
2524a58aedfSRichard Henderson     return float32_to_s(fr);
2534a58aedfSRichard Henderson }
2544a58aedfSRichard Henderson 
2554a58aedfSRichard Henderson 
2564a58aedfSRichard Henderson /* T floating (double) */
2574a58aedfSRichard Henderson static inline float64 t_to_float64(uint64_t a)
2584a58aedfSRichard Henderson {
2594a58aedfSRichard Henderson     /* Memory format is the same as float64 */
2604a58aedfSRichard Henderson     CPU_DoubleU r;
2614a58aedfSRichard Henderson     r.ll = a;
2624a58aedfSRichard Henderson     return r.d;
2634a58aedfSRichard Henderson }
2644a58aedfSRichard Henderson 
2654a58aedfSRichard Henderson static inline uint64_t float64_to_t(float64 fa)
2664a58aedfSRichard Henderson {
2674a58aedfSRichard Henderson     /* Memory format is the same as float64 */
2684a58aedfSRichard Henderson     CPU_DoubleU r;
2694a58aedfSRichard Henderson     r.d = fa;
2704a58aedfSRichard Henderson     return r.ll;
2714a58aedfSRichard Henderson }
2724a58aedfSRichard Henderson 
2734a58aedfSRichard Henderson uint64_t helper_addt(CPUAlphaState *env, uint64_t a, uint64_t b)
2744a58aedfSRichard Henderson {
2754a58aedfSRichard Henderson     float64 fa, fb, fr;
2764a58aedfSRichard Henderson 
2774a58aedfSRichard Henderson     fa = t_to_float64(a);
2784a58aedfSRichard Henderson     fb = t_to_float64(b);
2794a58aedfSRichard Henderson     fr = float64_add(fa, fb, &FP_STATUS);
280f3d3aad4SRichard Henderson     env->error_code = soft_to_fpcr_exc(env);
281f3d3aad4SRichard Henderson 
2824a58aedfSRichard Henderson     return float64_to_t(fr);
2834a58aedfSRichard Henderson }
2844a58aedfSRichard Henderson 
2854a58aedfSRichard Henderson uint64_t helper_subt(CPUAlphaState *env, uint64_t a, uint64_t b)
2864a58aedfSRichard Henderson {
2874a58aedfSRichard Henderson     float64 fa, fb, fr;
2884a58aedfSRichard Henderson 
2894a58aedfSRichard Henderson     fa = t_to_float64(a);
2904a58aedfSRichard Henderson     fb = t_to_float64(b);
2914a58aedfSRichard Henderson     fr = float64_sub(fa, fb, &FP_STATUS);
292f3d3aad4SRichard Henderson     env->error_code = soft_to_fpcr_exc(env);
293f3d3aad4SRichard Henderson 
2944a58aedfSRichard Henderson     return float64_to_t(fr);
2954a58aedfSRichard Henderson }
2964a58aedfSRichard Henderson 
2974a58aedfSRichard Henderson uint64_t helper_mult(CPUAlphaState *env, uint64_t a, uint64_t b)
2984a58aedfSRichard Henderson {
2994a58aedfSRichard Henderson     float64 fa, fb, fr;
3004a58aedfSRichard Henderson 
3014a58aedfSRichard Henderson     fa = t_to_float64(a);
3024a58aedfSRichard Henderson     fb = t_to_float64(b);
3034a58aedfSRichard Henderson     fr = float64_mul(fa, fb, &FP_STATUS);
304f3d3aad4SRichard Henderson     env->error_code = soft_to_fpcr_exc(env);
305f3d3aad4SRichard Henderson 
3064a58aedfSRichard Henderson     return float64_to_t(fr);
3074a58aedfSRichard Henderson }
3084a58aedfSRichard Henderson 
3094a58aedfSRichard Henderson uint64_t helper_divt(CPUAlphaState *env, uint64_t a, uint64_t b)
3104a58aedfSRichard Henderson {
3114a58aedfSRichard Henderson     float64 fa, fb, fr;
3124a58aedfSRichard Henderson 
3134a58aedfSRichard Henderson     fa = t_to_float64(a);
3144a58aedfSRichard Henderson     fb = t_to_float64(b);
3154a58aedfSRichard Henderson     fr = float64_div(fa, fb, &FP_STATUS);
316f3d3aad4SRichard Henderson     env->error_code = soft_to_fpcr_exc(env);
317f3d3aad4SRichard Henderson 
3184a58aedfSRichard Henderson     return float64_to_t(fr);
3194a58aedfSRichard Henderson }
3204a58aedfSRichard Henderson 
3214a58aedfSRichard Henderson uint64_t helper_sqrtt(CPUAlphaState *env, uint64_t a)
3224a58aedfSRichard Henderson {
3234a58aedfSRichard Henderson     float64 fa, fr;
3244a58aedfSRichard Henderson 
3254a58aedfSRichard Henderson     fa = t_to_float64(a);
3264a58aedfSRichard Henderson     fr = float64_sqrt(fa, &FP_STATUS);
327f3d3aad4SRichard Henderson     env->error_code = soft_to_fpcr_exc(env);
328f3d3aad4SRichard Henderson 
3294a58aedfSRichard Henderson     return float64_to_t(fr);
3304a58aedfSRichard Henderson }
3314a58aedfSRichard Henderson 
3324a58aedfSRichard Henderson /* Comparisons */
3334a58aedfSRichard Henderson uint64_t helper_cmptun(CPUAlphaState *env, uint64_t a, uint64_t b)
3344a58aedfSRichard Henderson {
3354a58aedfSRichard Henderson     float64 fa, fb;
336f3d3aad4SRichard Henderson     uint64_t ret = 0;
3374a58aedfSRichard Henderson 
3384a58aedfSRichard Henderson     fa = t_to_float64(a);
3394a58aedfSRichard Henderson     fb = t_to_float64(b);
3404a58aedfSRichard Henderson 
3414a58aedfSRichard Henderson     if (float64_unordered_quiet(fa, fb, &FP_STATUS)) {
342f3d3aad4SRichard Henderson         ret = 0x4000000000000000ULL;
3434a58aedfSRichard Henderson     }
344f3d3aad4SRichard Henderson     env->error_code = soft_to_fpcr_exc(env);
345f3d3aad4SRichard Henderson 
346f3d3aad4SRichard Henderson     return ret;
3474a58aedfSRichard Henderson }
3484a58aedfSRichard Henderson 
3494a58aedfSRichard Henderson uint64_t helper_cmpteq(CPUAlphaState *env, uint64_t a, uint64_t b)
3504a58aedfSRichard Henderson {
3514a58aedfSRichard Henderson     float64 fa, fb;
352f3d3aad4SRichard Henderson     uint64_t ret = 0;
3534a58aedfSRichard Henderson 
3544a58aedfSRichard Henderson     fa = t_to_float64(a);
3554a58aedfSRichard Henderson     fb = t_to_float64(b);
3564a58aedfSRichard Henderson 
3574a58aedfSRichard Henderson     if (float64_eq_quiet(fa, fb, &FP_STATUS)) {
358f3d3aad4SRichard Henderson         ret = 0x4000000000000000ULL;
3594a58aedfSRichard Henderson     }
360f3d3aad4SRichard Henderson     env->error_code = soft_to_fpcr_exc(env);
361f3d3aad4SRichard Henderson 
362f3d3aad4SRichard Henderson     return ret;
3634a58aedfSRichard Henderson }
3644a58aedfSRichard Henderson 
3654a58aedfSRichard Henderson uint64_t helper_cmptle(CPUAlphaState *env, uint64_t a, uint64_t b)
3664a58aedfSRichard Henderson {
3674a58aedfSRichard Henderson     float64 fa, fb;
368f3d3aad4SRichard Henderson     uint64_t ret = 0;
3694a58aedfSRichard Henderson 
3704a58aedfSRichard Henderson     fa = t_to_float64(a);
3714a58aedfSRichard Henderson     fb = t_to_float64(b);
3724a58aedfSRichard Henderson 
3734a58aedfSRichard Henderson     if (float64_le(fa, fb, &FP_STATUS)) {
374f3d3aad4SRichard Henderson         ret = 0x4000000000000000ULL;
3754a58aedfSRichard Henderson     }
376f3d3aad4SRichard Henderson     env->error_code = soft_to_fpcr_exc(env);
377f3d3aad4SRichard Henderson 
378f3d3aad4SRichard Henderson     return ret;
3794a58aedfSRichard Henderson }
3804a58aedfSRichard Henderson 
3814a58aedfSRichard Henderson uint64_t helper_cmptlt(CPUAlphaState *env, uint64_t a, uint64_t b)
3824a58aedfSRichard Henderson {
3834a58aedfSRichard Henderson     float64 fa, fb;
384f3d3aad4SRichard Henderson     uint64_t ret = 0;
3854a58aedfSRichard Henderson 
3864a58aedfSRichard Henderson     fa = t_to_float64(a);
3874a58aedfSRichard Henderson     fb = t_to_float64(b);
3884a58aedfSRichard Henderson 
3894a58aedfSRichard Henderson     if (float64_lt(fa, fb, &FP_STATUS)) {
390f3d3aad4SRichard Henderson         ret = 0x4000000000000000ULL;
3914a58aedfSRichard Henderson     }
392f3d3aad4SRichard Henderson     env->error_code = soft_to_fpcr_exc(env);
393f3d3aad4SRichard Henderson 
394f3d3aad4SRichard Henderson     return ret;
3954a58aedfSRichard Henderson }
3964a58aedfSRichard Henderson 
3974a58aedfSRichard Henderson /* Floating point format conversion */
3984a58aedfSRichard Henderson uint64_t helper_cvtts(CPUAlphaState *env, uint64_t a)
3994a58aedfSRichard Henderson {
4004a58aedfSRichard Henderson     float64 fa;
4014a58aedfSRichard Henderson     float32 fr;
4024a58aedfSRichard Henderson 
4034a58aedfSRichard Henderson     fa = t_to_float64(a);
4044a58aedfSRichard Henderson     fr = float64_to_float32(fa, &FP_STATUS);
405f3d3aad4SRichard Henderson     env->error_code = soft_to_fpcr_exc(env);
406f3d3aad4SRichard Henderson 
4074a58aedfSRichard Henderson     return float32_to_s(fr);
4084a58aedfSRichard Henderson }
4094a58aedfSRichard Henderson 
4104a58aedfSRichard Henderson uint64_t helper_cvtst(CPUAlphaState *env, uint64_t a)
4114a58aedfSRichard Henderson {
4124a58aedfSRichard Henderson     float32 fa;
4134a58aedfSRichard Henderson     float64 fr;
4144a58aedfSRichard Henderson 
4154a58aedfSRichard Henderson     fa = s_to_float32(a);
4164a58aedfSRichard Henderson     fr = float32_to_float64(fa, &FP_STATUS);
417f3d3aad4SRichard Henderson     env->error_code = soft_to_fpcr_exc(env);
418f3d3aad4SRichard Henderson 
4194a58aedfSRichard Henderson     return float64_to_t(fr);
4204a58aedfSRichard Henderson }
4214a58aedfSRichard Henderson 
4224a58aedfSRichard Henderson uint64_t helper_cvtqs(CPUAlphaState *env, uint64_t a)
4234a58aedfSRichard Henderson {
4244a58aedfSRichard Henderson     float32 fr = int64_to_float32(a, &FP_STATUS);
425f3d3aad4SRichard Henderson     env->error_code = soft_to_fpcr_exc(env);
426f3d3aad4SRichard Henderson 
4274a58aedfSRichard Henderson     return float32_to_s(fr);
4284a58aedfSRichard Henderson }
4294a58aedfSRichard Henderson 
4304a58aedfSRichard Henderson /* Implement float64 to uint64 conversion without saturation -- we must
4314a58aedfSRichard Henderson    supply the truncated result.  This behaviour is used by the compiler
4324a58aedfSRichard Henderson    to get unsigned conversion for free with the same instruction.
4334a58aedfSRichard Henderson 
4344a58aedfSRichard Henderson    The VI flag is set when overflow or inexact exceptions should be raised.  */
4354a58aedfSRichard Henderson 
4364a58aedfSRichard Henderson static inline uint64_t inline_cvttq(CPUAlphaState *env, uint64_t a,
4374a58aedfSRichard Henderson                                     int roundmode, int VI)
4384a58aedfSRichard Henderson {
4394a58aedfSRichard Henderson     uint64_t frac, ret = 0;
4404a58aedfSRichard Henderson     uint32_t exp, sign, exc = 0;
4414a58aedfSRichard Henderson     int shift;
4424a58aedfSRichard Henderson 
4434a58aedfSRichard Henderson     sign = (a >> 63);
4444a58aedfSRichard Henderson     exp = (uint32_t)(a >> 52) & 0x7ff;
4454a58aedfSRichard Henderson     frac = a & 0xfffffffffffffull;
4464a58aedfSRichard Henderson 
4474a58aedfSRichard Henderson     if (exp == 0) {
4484a58aedfSRichard Henderson         if (unlikely(frac != 0)) {
4494a58aedfSRichard Henderson             goto do_underflow;
4504a58aedfSRichard Henderson         }
4514a58aedfSRichard Henderson     } else if (exp == 0x7ff) {
452f3d3aad4SRichard Henderson         exc = (frac ? FPCR_INV : VI ? FPCR_OVF : 0);
4534a58aedfSRichard Henderson     } else {
4544a58aedfSRichard Henderson         /* Restore implicit bit.  */
4554a58aedfSRichard Henderson         frac |= 0x10000000000000ull;
4564a58aedfSRichard Henderson 
4574a58aedfSRichard Henderson         shift = exp - 1023 - 52;
4584a58aedfSRichard Henderson         if (shift >= 0) {
4594a58aedfSRichard Henderson             /* In this case the number is so large that we must shift
4604a58aedfSRichard Henderson                the fraction left.  There is no rounding to do.  */
4614a58aedfSRichard Henderson             if (shift < 63) {
4624a58aedfSRichard Henderson                 ret = frac << shift;
4634a58aedfSRichard Henderson                 if (VI && (ret >> shift) != frac) {
464f3d3aad4SRichard Henderson                     exc = FPCR_OVF;
4654a58aedfSRichard Henderson                 }
4664a58aedfSRichard Henderson             }
4674a58aedfSRichard Henderson         } else {
4684a58aedfSRichard Henderson             uint64_t round;
4694a58aedfSRichard Henderson 
4704a58aedfSRichard Henderson             /* In this case the number is smaller than the fraction as
4714a58aedfSRichard Henderson                represented by the 52 bit number.  Here we must think
4724a58aedfSRichard Henderson                about rounding the result.  Handle this by shifting the
4734a58aedfSRichard Henderson                fractional part of the number into the high bits of ROUND.
4744a58aedfSRichard Henderson                This will let us efficiently handle round-to-nearest.  */
4754a58aedfSRichard Henderson             shift = -shift;
4764a58aedfSRichard Henderson             if (shift < 63) {
4774a58aedfSRichard Henderson                 ret = frac >> shift;
4784a58aedfSRichard Henderson                 round = frac << (64 - shift);
4794a58aedfSRichard Henderson             } else {
4804a58aedfSRichard Henderson                 /* The exponent is so small we shift out everything.
4814a58aedfSRichard Henderson                    Leave a sticky bit for proper rounding below.  */
4824a58aedfSRichard Henderson             do_underflow:
4834a58aedfSRichard Henderson                 round = 1;
4844a58aedfSRichard Henderson             }
4854a58aedfSRichard Henderson 
4864a58aedfSRichard Henderson             if (round) {
487f3d3aad4SRichard Henderson                 exc = (VI ? FPCR_INE : 0);
4884a58aedfSRichard Henderson                 switch (roundmode) {
4894a58aedfSRichard Henderson                 case float_round_nearest_even:
4904a58aedfSRichard Henderson                     if (round == (1ull << 63)) {
4914a58aedfSRichard Henderson                         /* Fraction is exactly 0.5; round to even.  */
4924a58aedfSRichard Henderson                         ret += (ret & 1);
4934a58aedfSRichard Henderson                     } else if (round > (1ull << 63)) {
4944a58aedfSRichard Henderson                         ret += 1;
4954a58aedfSRichard Henderson                     }
4964a58aedfSRichard Henderson                     break;
4974a58aedfSRichard Henderson                 case float_round_to_zero:
4984a58aedfSRichard Henderson                     break;
4994a58aedfSRichard Henderson                 case float_round_up:
5004a58aedfSRichard Henderson                     ret += 1 - sign;
5014a58aedfSRichard Henderson                     break;
5024a58aedfSRichard Henderson                 case float_round_down:
5034a58aedfSRichard Henderson                     ret += sign;
5044a58aedfSRichard Henderson                     break;
5054a58aedfSRichard Henderson                 }
5064a58aedfSRichard Henderson             }
5074a58aedfSRichard Henderson         }
5084a58aedfSRichard Henderson         if (sign) {
5094a58aedfSRichard Henderson             ret = -ret;
5104a58aedfSRichard Henderson         }
5114a58aedfSRichard Henderson     }
512f3d3aad4SRichard Henderson     env->error_code = exc;
5134a58aedfSRichard Henderson 
5144a58aedfSRichard Henderson     return ret;
5154a58aedfSRichard Henderson }
5164a58aedfSRichard Henderson 
5174a58aedfSRichard Henderson uint64_t helper_cvttq(CPUAlphaState *env, uint64_t a)
5184a58aedfSRichard Henderson {
5194a58aedfSRichard Henderson     return inline_cvttq(env, a, FP_STATUS.float_rounding_mode, 1);
5204a58aedfSRichard Henderson }
5214a58aedfSRichard Henderson 
5224a58aedfSRichard Henderson uint64_t helper_cvttq_c(CPUAlphaState *env, uint64_t a)
5234a58aedfSRichard Henderson {
5244a58aedfSRichard Henderson     return inline_cvttq(env, a, float_round_to_zero, 0);
5254a58aedfSRichard Henderson }
5264a58aedfSRichard Henderson 
5274a58aedfSRichard Henderson uint64_t helper_cvttq_svic(CPUAlphaState *env, uint64_t a)
5284a58aedfSRichard Henderson {
5294a58aedfSRichard Henderson     return inline_cvttq(env, a, float_round_to_zero, 1);
5304a58aedfSRichard Henderson }
5314a58aedfSRichard Henderson 
5324a58aedfSRichard Henderson uint64_t helper_cvtqt(CPUAlphaState *env, uint64_t a)
5334a58aedfSRichard Henderson {
5344a58aedfSRichard Henderson     float64 fr = int64_to_float64(a, &FP_STATUS);
535f3d3aad4SRichard Henderson     env->error_code = soft_to_fpcr_exc(env);
5364a58aedfSRichard Henderson     return float64_to_t(fr);
5374a58aedfSRichard Henderson }
5384a58aedfSRichard Henderson 
5393da653faSRichard Henderson void helper_cvtql_v_input(CPUAlphaState *env, uint64_t val)
540e8d8fef4SRichard Henderson {
541e8d8fef4SRichard Henderson     if (val != (int32_t)val) {
542e8d8fef4SRichard Henderson         arith_excp(env, GETPC(), EXC_M_IOV, 0);
543e8d8fef4SRichard Henderson     }
544e8d8fef4SRichard Henderson }
545