xref: /qemu/target/alpha/fpu_helper.c (revision aa3bad5b)
1fcf5ef2aSThomas Huth /*
2fcf5ef2aSThomas Huth  *  Helpers for floating point instructions.
3fcf5ef2aSThomas Huth  *
4fcf5ef2aSThomas Huth  *  Copyright (c) 2007 Jocelyn Mayer
5fcf5ef2aSThomas Huth  *
6fcf5ef2aSThomas Huth  * This library is free software; you can redistribute it and/or
7fcf5ef2aSThomas Huth  * modify it under the terms of the GNU Lesser General Public
8fcf5ef2aSThomas Huth  * License as published by the Free Software Foundation; either
9d6ea4236SChetan Pant  * version 2.1 of the License, or (at your option) any later version.
10fcf5ef2aSThomas Huth  *
11fcf5ef2aSThomas Huth  * This library is distributed in the hope that it will be useful,
12fcf5ef2aSThomas Huth  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13fcf5ef2aSThomas Huth  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14fcf5ef2aSThomas Huth  * Lesser General Public License for more details.
15fcf5ef2aSThomas Huth  *
16fcf5ef2aSThomas Huth  * You should have received a copy of the GNU Lesser General Public
17fcf5ef2aSThomas Huth  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18fcf5ef2aSThomas Huth  */
19fcf5ef2aSThomas Huth 
20fcf5ef2aSThomas Huth #include "qemu/osdep.h"
21fcf5ef2aSThomas Huth #include "cpu.h"
22fcf5ef2aSThomas Huth #include "exec/exec-all.h"
23fcf5ef2aSThomas Huth #include "exec/helper-proto.h"
24fcf5ef2aSThomas Huth #include "fpu/softfloat.h"
25fcf5ef2aSThomas Huth 
26fcf5ef2aSThomas Huth #define FP_STATUS (env->fp_status)
27fcf5ef2aSThomas Huth 
28fcf5ef2aSThomas Huth 
helper_setroundmode(CPUAlphaState * env,uint32_t val)29fcf5ef2aSThomas Huth void helper_setroundmode(CPUAlphaState *env, uint32_t val)
30fcf5ef2aSThomas Huth {
31fcf5ef2aSThomas Huth     set_float_rounding_mode(val, &FP_STATUS);
32fcf5ef2aSThomas Huth }
33fcf5ef2aSThomas Huth 
helper_setflushzero(CPUAlphaState * env,uint32_t val)34fcf5ef2aSThomas Huth void helper_setflushzero(CPUAlphaState *env, uint32_t val)
35fcf5ef2aSThomas Huth {
36fcf5ef2aSThomas Huth     set_flush_to_zero(val, &FP_STATUS);
37fcf5ef2aSThomas Huth }
38fcf5ef2aSThomas Huth 
39fcf5ef2aSThomas Huth #define CONVERT_BIT(X, SRC, DST) \
40fcf5ef2aSThomas Huth     (SRC > DST ? (X) / (SRC / DST) & (DST) : ((X) & SRC) * (DST / SRC))
41fcf5ef2aSThomas Huth 
soft_to_fpcr_exc(CPUAlphaState * env)42fcf5ef2aSThomas Huth static uint32_t soft_to_fpcr_exc(CPUAlphaState *env)
43fcf5ef2aSThomas Huth {
44fcf5ef2aSThomas Huth     uint8_t exc = get_float_exception_flags(&FP_STATUS);
45fcf5ef2aSThomas Huth     uint32_t ret = 0;
46fcf5ef2aSThomas Huth 
47fcf5ef2aSThomas Huth     if (unlikely(exc)) {
48fcf5ef2aSThomas Huth         set_float_exception_flags(0, &FP_STATUS);
49fcf5ef2aSThomas Huth         ret |= CONVERT_BIT(exc, float_flag_invalid, FPCR_INV);
50fcf5ef2aSThomas Huth         ret |= CONVERT_BIT(exc, float_flag_divbyzero, FPCR_DZE);
51fcf5ef2aSThomas Huth         ret |= CONVERT_BIT(exc, float_flag_overflow, FPCR_OVF);
52fcf5ef2aSThomas Huth         ret |= CONVERT_BIT(exc, float_flag_underflow, FPCR_UNF);
53fcf5ef2aSThomas Huth         ret |= CONVERT_BIT(exc, float_flag_inexact, FPCR_INE);
54fcf5ef2aSThomas Huth     }
55fcf5ef2aSThomas Huth 
56fcf5ef2aSThomas Huth     return ret;
57fcf5ef2aSThomas Huth }
58fcf5ef2aSThomas Huth 
fp_exc_raise1(CPUAlphaState * env,uintptr_t retaddr,uint32_t exc,uint32_t regno,uint32_t hw_exc)59fcf5ef2aSThomas Huth static void fp_exc_raise1(CPUAlphaState *env, uintptr_t retaddr,
60fcf5ef2aSThomas Huth                           uint32_t exc, uint32_t regno, uint32_t hw_exc)
61fcf5ef2aSThomas Huth {
62fcf5ef2aSThomas Huth     hw_exc |= CONVERT_BIT(exc, FPCR_INV, EXC_M_INV);
63fcf5ef2aSThomas Huth     hw_exc |= CONVERT_BIT(exc, FPCR_DZE, EXC_M_DZE);
64fcf5ef2aSThomas Huth     hw_exc |= CONVERT_BIT(exc, FPCR_OVF, EXC_M_FOV);
65fcf5ef2aSThomas Huth     hw_exc |= CONVERT_BIT(exc, FPCR_UNF, EXC_M_UNF);
66fcf5ef2aSThomas Huth     hw_exc |= CONVERT_BIT(exc, FPCR_INE, EXC_M_INE);
67fcf5ef2aSThomas Huth     hw_exc |= CONVERT_BIT(exc, FPCR_IOV, EXC_M_IOV);
68fcf5ef2aSThomas Huth 
69fcf5ef2aSThomas Huth     arith_excp(env, retaddr, hw_exc, 1ull << regno);
70fcf5ef2aSThomas Huth }
71fcf5ef2aSThomas Huth 
72fcf5ef2aSThomas Huth /* Raise exceptions for ieee fp insns without software completion.
73fcf5ef2aSThomas Huth    In that case there are no exceptions that don't trap; the mask
74fcf5ef2aSThomas Huth    doesn't apply.  */
helper_fp_exc_raise(CPUAlphaState * env,uint32_t ignore,uint32_t regno)75fcf5ef2aSThomas Huth void helper_fp_exc_raise(CPUAlphaState *env, uint32_t ignore, uint32_t regno)
76fcf5ef2aSThomas Huth {
77fcf5ef2aSThomas Huth     uint32_t exc = env->error_code;
78fcf5ef2aSThomas Huth     if (exc) {
79fcf5ef2aSThomas Huth         env->fpcr |= exc;
80fcf5ef2aSThomas Huth         exc &= ~ignore;
81fcf5ef2aSThomas Huth         if (exc) {
82fcf5ef2aSThomas Huth             fp_exc_raise1(env, GETPC(), exc, regno, 0);
83fcf5ef2aSThomas Huth         }
84fcf5ef2aSThomas Huth     }
85fcf5ef2aSThomas Huth }
86fcf5ef2aSThomas Huth 
87fcf5ef2aSThomas Huth /* Raise exceptions for ieee fp insns with software completion.  */
helper_fp_exc_raise_s(CPUAlphaState * env,uint32_t ignore,uint32_t regno)88fcf5ef2aSThomas Huth void helper_fp_exc_raise_s(CPUAlphaState *env, uint32_t ignore, uint32_t regno)
89fcf5ef2aSThomas Huth {
90fcf5ef2aSThomas Huth     uint32_t exc = env->error_code & ~ignore;
91fcf5ef2aSThomas Huth     if (exc) {
92fcf5ef2aSThomas Huth         env->fpcr |= exc;
9311bfdbdfSRichard Henderson         exc &= env->fpcr_exc_enable;
9421ba8564SRichard Henderson         /*
9521ba8564SRichard Henderson          * In system mode, the software handler gets invoked
9621ba8564SRichard Henderson          * for any non-ignored exception.
9711bfdbdfSRichard Henderson          * In user mode, the kernel's software handler only
9811bfdbdfSRichard Henderson          * delivers a signal if the exception is enabled.
9921ba8564SRichard Henderson          */
10011bfdbdfSRichard Henderson #ifdef CONFIG_USER_ONLY
10121ba8564SRichard Henderson         if (!exc) {
10221ba8564SRichard Henderson             return;
10321ba8564SRichard Henderson         }
10421ba8564SRichard Henderson #endif
105fcf5ef2aSThomas Huth         fp_exc_raise1(env, GETPC(), exc, regno, EXC_M_SWC);
106fcf5ef2aSThomas Huth     }
107fcf5ef2aSThomas Huth }
108fcf5ef2aSThomas Huth 
109fcf5ef2aSThomas Huth /* Input handing without software completion.  Trap for all
110fcf5ef2aSThomas Huth    non-finite numbers.  */
helper_ieee_input(CPUAlphaState * env,uint64_t val)111fcf5ef2aSThomas Huth void helper_ieee_input(CPUAlphaState *env, uint64_t val)
112fcf5ef2aSThomas Huth {
113fcf5ef2aSThomas Huth     uint32_t exp = (uint32_t)(val >> 52) & 0x7ff;
114fcf5ef2aSThomas Huth     uint64_t frac = val & 0xfffffffffffffull;
115fcf5ef2aSThomas Huth 
116fcf5ef2aSThomas Huth     if (exp == 0) {
117fcf5ef2aSThomas Huth         /* Denormals without /S raise an exception.  */
118fcf5ef2aSThomas Huth         if (frac != 0) {
119fcf5ef2aSThomas Huth             arith_excp(env, GETPC(), EXC_M_INV, 0);
120fcf5ef2aSThomas Huth         }
121fcf5ef2aSThomas Huth     } else if (exp == 0x7ff) {
122fcf5ef2aSThomas Huth         /* Infinity or NaN.  */
123fcf5ef2aSThomas Huth         env->fpcr |= FPCR_INV;
124fcf5ef2aSThomas Huth         arith_excp(env, GETPC(), EXC_M_INV, 0);
125fcf5ef2aSThomas Huth     }
126fcf5ef2aSThomas Huth }
127fcf5ef2aSThomas Huth 
128fcf5ef2aSThomas Huth /* Similar, but does not trap for infinities.  Used for comparisons.  */
helper_ieee_input_cmp(CPUAlphaState * env,uint64_t val)129fcf5ef2aSThomas Huth void helper_ieee_input_cmp(CPUAlphaState *env, uint64_t val)
130fcf5ef2aSThomas Huth {
131fcf5ef2aSThomas Huth     uint32_t exp = (uint32_t)(val >> 52) & 0x7ff;
132fcf5ef2aSThomas Huth     uint64_t frac = val & 0xfffffffffffffull;
133fcf5ef2aSThomas Huth 
134fcf5ef2aSThomas Huth     if (exp == 0) {
135fcf5ef2aSThomas Huth         /* Denormals without /S raise an exception.  */
136fcf5ef2aSThomas Huth         if (frac != 0) {
137fcf5ef2aSThomas Huth             arith_excp(env, GETPC(), EXC_M_INV, 0);
138fcf5ef2aSThomas Huth         }
139fcf5ef2aSThomas Huth     } else if (exp == 0x7ff && frac) {
140fcf5ef2aSThomas Huth         /* NaN.  */
141fcf5ef2aSThomas Huth         env->fpcr |= FPCR_INV;
142fcf5ef2aSThomas Huth         arith_excp(env, GETPC(), EXC_M_INV, 0);
143fcf5ef2aSThomas Huth     }
144fcf5ef2aSThomas Huth }
145fcf5ef2aSThomas Huth 
146fcf5ef2aSThomas Huth /* Input handing with software completion.  Trap for denorms, unless DNZ
147fcf5ef2aSThomas Huth    is set.  If we try to support DNOD (which none of the produced hardware
148fcf5ef2aSThomas Huth    did, AFAICS), we'll need to suppress the trap when FPCR.DNOD is set;
149fcf5ef2aSThomas Huth    then the code downstream of that will need to cope with denorms sans
150fcf5ef2aSThomas Huth    flush_input_to_zero.  Most of it should work sanely, but there's
151fcf5ef2aSThomas Huth    nothing to compare with.  */
helper_ieee_input_s(CPUAlphaState * env,uint64_t val)152fcf5ef2aSThomas Huth void helper_ieee_input_s(CPUAlphaState *env, uint64_t val)
153fcf5ef2aSThomas Huth {
154fcf5ef2aSThomas Huth     if (unlikely(2 * val - 1 < 0x1fffffffffffffull)
155fcf5ef2aSThomas Huth         && !env->fp_status.flush_inputs_to_zero) {
156fcf5ef2aSThomas Huth         arith_excp(env, GETPC(), EXC_M_INV | EXC_M_SWC, 0);
157fcf5ef2aSThomas Huth     }
158fcf5ef2aSThomas Huth }
159fcf5ef2aSThomas Huth 
160fcf5ef2aSThomas Huth /* S floating (single) */
161fcf5ef2aSThomas Huth 
162fcf5ef2aSThomas Huth /* Taken from linux/arch/alpha/kernel/traps.c, s_mem_to_reg.  */
float32_to_s_int(uint32_t fi)163fcf5ef2aSThomas Huth static inline uint64_t float32_to_s_int(uint32_t fi)
164fcf5ef2aSThomas Huth {
165fcf5ef2aSThomas Huth     uint32_t frac = fi & 0x7fffff;
166fcf5ef2aSThomas Huth     uint32_t sign = fi >> 31;
167fcf5ef2aSThomas Huth     uint32_t exp_msb = (fi >> 30) & 1;
168fcf5ef2aSThomas Huth     uint32_t exp_low = (fi >> 23) & 0x7f;
169fcf5ef2aSThomas Huth     uint32_t exp;
170fcf5ef2aSThomas Huth 
171fcf5ef2aSThomas Huth     exp = (exp_msb << 10) | exp_low;
172fcf5ef2aSThomas Huth     if (exp_msb) {
173fcf5ef2aSThomas Huth         if (exp_low == 0x7f) {
174fcf5ef2aSThomas Huth             exp = 0x7ff;
175fcf5ef2aSThomas Huth         }
176fcf5ef2aSThomas Huth     } else {
177fcf5ef2aSThomas Huth         if (exp_low != 0x00) {
178fcf5ef2aSThomas Huth             exp |= 0x380;
179fcf5ef2aSThomas Huth         }
180fcf5ef2aSThomas Huth     }
181fcf5ef2aSThomas Huth 
182fcf5ef2aSThomas Huth     return (((uint64_t)sign << 63)
183fcf5ef2aSThomas Huth             | ((uint64_t)exp << 52)
184fcf5ef2aSThomas Huth             | ((uint64_t)frac << 29));
185fcf5ef2aSThomas Huth }
186fcf5ef2aSThomas Huth 
float32_to_s(float32 fa)187fcf5ef2aSThomas Huth static inline uint64_t float32_to_s(float32 fa)
188fcf5ef2aSThomas Huth {
189fcf5ef2aSThomas Huth     CPU_FloatU a;
190fcf5ef2aSThomas Huth     a.f = fa;
191fcf5ef2aSThomas Huth     return float32_to_s_int(a.l);
192fcf5ef2aSThomas Huth }
193fcf5ef2aSThomas Huth 
s_to_float32_int(uint64_t a)194fcf5ef2aSThomas Huth static inline uint32_t s_to_float32_int(uint64_t a)
195fcf5ef2aSThomas Huth {
196fcf5ef2aSThomas Huth     return ((a >> 32) & 0xc0000000) | ((a >> 29) & 0x3fffffff);
197fcf5ef2aSThomas Huth }
198fcf5ef2aSThomas Huth 
s_to_float32(uint64_t a)199fcf5ef2aSThomas Huth static inline float32 s_to_float32(uint64_t a)
200fcf5ef2aSThomas Huth {
201fcf5ef2aSThomas Huth     CPU_FloatU r;
202fcf5ef2aSThomas Huth     r.l = s_to_float32_int(a);
203fcf5ef2aSThomas Huth     return r.f;
204fcf5ef2aSThomas Huth }
205fcf5ef2aSThomas Huth 
helper_s_to_memory(uint64_t a)206fcf5ef2aSThomas Huth uint32_t helper_s_to_memory(uint64_t a)
207fcf5ef2aSThomas Huth {
208fcf5ef2aSThomas Huth     return s_to_float32_int(a);
209fcf5ef2aSThomas Huth }
210fcf5ef2aSThomas Huth 
helper_memory_to_s(uint32_t a)211fcf5ef2aSThomas Huth uint64_t helper_memory_to_s(uint32_t a)
212fcf5ef2aSThomas Huth {
213fcf5ef2aSThomas Huth     return float32_to_s_int(a);
214fcf5ef2aSThomas Huth }
215fcf5ef2aSThomas Huth 
helper_adds(CPUAlphaState * env,uint64_t a,uint64_t b)216fcf5ef2aSThomas Huth uint64_t helper_adds(CPUAlphaState *env, uint64_t a, uint64_t b)
217fcf5ef2aSThomas Huth {
218fcf5ef2aSThomas Huth     float32 fa, fb, fr;
219fcf5ef2aSThomas Huth 
220fcf5ef2aSThomas Huth     fa = s_to_float32(a);
221fcf5ef2aSThomas Huth     fb = s_to_float32(b);
222fcf5ef2aSThomas Huth     fr = float32_add(fa, fb, &FP_STATUS);
223fcf5ef2aSThomas Huth     env->error_code = soft_to_fpcr_exc(env);
224fcf5ef2aSThomas Huth 
225fcf5ef2aSThomas Huth     return float32_to_s(fr);
226fcf5ef2aSThomas Huth }
227fcf5ef2aSThomas Huth 
helper_subs(CPUAlphaState * env,uint64_t a,uint64_t b)228fcf5ef2aSThomas Huth uint64_t helper_subs(CPUAlphaState *env, uint64_t a, uint64_t b)
229fcf5ef2aSThomas Huth {
230fcf5ef2aSThomas Huth     float32 fa, fb, fr;
231fcf5ef2aSThomas Huth 
232fcf5ef2aSThomas Huth     fa = s_to_float32(a);
233fcf5ef2aSThomas Huth     fb = s_to_float32(b);
234fcf5ef2aSThomas Huth     fr = float32_sub(fa, fb, &FP_STATUS);
235fcf5ef2aSThomas Huth     env->error_code = soft_to_fpcr_exc(env);
236fcf5ef2aSThomas Huth 
237fcf5ef2aSThomas Huth     return float32_to_s(fr);
238fcf5ef2aSThomas Huth }
239fcf5ef2aSThomas Huth 
helper_muls(CPUAlphaState * env,uint64_t a,uint64_t b)240fcf5ef2aSThomas Huth uint64_t helper_muls(CPUAlphaState *env, uint64_t a, uint64_t b)
241fcf5ef2aSThomas Huth {
242fcf5ef2aSThomas Huth     float32 fa, fb, fr;
243fcf5ef2aSThomas Huth 
244fcf5ef2aSThomas Huth     fa = s_to_float32(a);
245fcf5ef2aSThomas Huth     fb = s_to_float32(b);
246fcf5ef2aSThomas Huth     fr = float32_mul(fa, fb, &FP_STATUS);
247fcf5ef2aSThomas Huth     env->error_code = soft_to_fpcr_exc(env);
248fcf5ef2aSThomas Huth 
249fcf5ef2aSThomas Huth     return float32_to_s(fr);
250fcf5ef2aSThomas Huth }
251fcf5ef2aSThomas Huth 
helper_divs(CPUAlphaState * env,uint64_t a,uint64_t b)252fcf5ef2aSThomas Huth uint64_t helper_divs(CPUAlphaState *env, uint64_t a, uint64_t b)
253fcf5ef2aSThomas Huth {
254fcf5ef2aSThomas Huth     float32 fa, fb, fr;
255fcf5ef2aSThomas Huth 
256fcf5ef2aSThomas Huth     fa = s_to_float32(a);
257fcf5ef2aSThomas Huth     fb = s_to_float32(b);
258fcf5ef2aSThomas Huth     fr = float32_div(fa, fb, &FP_STATUS);
259fcf5ef2aSThomas Huth     env->error_code = soft_to_fpcr_exc(env);
260fcf5ef2aSThomas Huth 
261fcf5ef2aSThomas Huth     return float32_to_s(fr);
262fcf5ef2aSThomas Huth }
263fcf5ef2aSThomas Huth 
helper_sqrts(CPUAlphaState * env,uint64_t a)264fcf5ef2aSThomas Huth uint64_t helper_sqrts(CPUAlphaState *env, uint64_t a)
265fcf5ef2aSThomas Huth {
266fcf5ef2aSThomas Huth     float32 fa, fr;
267fcf5ef2aSThomas Huth 
268fcf5ef2aSThomas Huth     fa = s_to_float32(a);
269fcf5ef2aSThomas Huth     fr = float32_sqrt(fa, &FP_STATUS);
270fcf5ef2aSThomas Huth     env->error_code = soft_to_fpcr_exc(env);
271fcf5ef2aSThomas Huth 
272fcf5ef2aSThomas Huth     return float32_to_s(fr);
273fcf5ef2aSThomas Huth }
274fcf5ef2aSThomas Huth 
275fcf5ef2aSThomas Huth 
276fcf5ef2aSThomas Huth /* T floating (double) */
t_to_float64(uint64_t a)277fcf5ef2aSThomas Huth static inline float64 t_to_float64(uint64_t a)
278fcf5ef2aSThomas Huth {
279fcf5ef2aSThomas Huth     /* Memory format is the same as float64 */
280fcf5ef2aSThomas Huth     CPU_DoubleU r;
281fcf5ef2aSThomas Huth     r.ll = a;
282fcf5ef2aSThomas Huth     return r.d;
283fcf5ef2aSThomas Huth }
284fcf5ef2aSThomas Huth 
float64_to_t(float64 fa)285fcf5ef2aSThomas Huth static inline uint64_t float64_to_t(float64 fa)
286fcf5ef2aSThomas Huth {
287fcf5ef2aSThomas Huth     /* Memory format is the same as float64 */
288fcf5ef2aSThomas Huth     CPU_DoubleU r;
289fcf5ef2aSThomas Huth     r.d = fa;
290fcf5ef2aSThomas Huth     return r.ll;
291fcf5ef2aSThomas Huth }
292fcf5ef2aSThomas Huth 
helper_addt(CPUAlphaState * env,uint64_t a,uint64_t b)293fcf5ef2aSThomas Huth uint64_t helper_addt(CPUAlphaState *env, uint64_t a, uint64_t b)
294fcf5ef2aSThomas Huth {
295fcf5ef2aSThomas Huth     float64 fa, fb, fr;
296fcf5ef2aSThomas Huth 
297fcf5ef2aSThomas Huth     fa = t_to_float64(a);
298fcf5ef2aSThomas Huth     fb = t_to_float64(b);
299fcf5ef2aSThomas Huth     fr = float64_add(fa, fb, &FP_STATUS);
300fcf5ef2aSThomas Huth     env->error_code = soft_to_fpcr_exc(env);
301fcf5ef2aSThomas Huth 
302fcf5ef2aSThomas Huth     return float64_to_t(fr);
303fcf5ef2aSThomas Huth }
304fcf5ef2aSThomas Huth 
helper_subt(CPUAlphaState * env,uint64_t a,uint64_t b)305fcf5ef2aSThomas Huth uint64_t helper_subt(CPUAlphaState *env, uint64_t a, uint64_t b)
306fcf5ef2aSThomas Huth {
307fcf5ef2aSThomas Huth     float64 fa, fb, fr;
308fcf5ef2aSThomas Huth 
309fcf5ef2aSThomas Huth     fa = t_to_float64(a);
310fcf5ef2aSThomas Huth     fb = t_to_float64(b);
311fcf5ef2aSThomas Huth     fr = float64_sub(fa, fb, &FP_STATUS);
312fcf5ef2aSThomas Huth     env->error_code = soft_to_fpcr_exc(env);
313fcf5ef2aSThomas Huth 
314fcf5ef2aSThomas Huth     return float64_to_t(fr);
315fcf5ef2aSThomas Huth }
316fcf5ef2aSThomas Huth 
helper_mult(CPUAlphaState * env,uint64_t a,uint64_t b)317fcf5ef2aSThomas Huth uint64_t helper_mult(CPUAlphaState *env, uint64_t a, uint64_t b)
318fcf5ef2aSThomas Huth {
319fcf5ef2aSThomas Huth     float64 fa, fb, fr;
320fcf5ef2aSThomas Huth 
321fcf5ef2aSThomas Huth     fa = t_to_float64(a);
322fcf5ef2aSThomas Huth     fb = t_to_float64(b);
323fcf5ef2aSThomas Huth     fr = float64_mul(fa, fb, &FP_STATUS);
324fcf5ef2aSThomas Huth     env->error_code = soft_to_fpcr_exc(env);
325fcf5ef2aSThomas Huth 
326fcf5ef2aSThomas Huth     return float64_to_t(fr);
327fcf5ef2aSThomas Huth }
328fcf5ef2aSThomas Huth 
helper_divt(CPUAlphaState * env,uint64_t a,uint64_t b)329fcf5ef2aSThomas Huth uint64_t helper_divt(CPUAlphaState *env, uint64_t a, uint64_t b)
330fcf5ef2aSThomas Huth {
331fcf5ef2aSThomas Huth     float64 fa, fb, fr;
332fcf5ef2aSThomas Huth 
333fcf5ef2aSThomas Huth     fa = t_to_float64(a);
334fcf5ef2aSThomas Huth     fb = t_to_float64(b);
335fcf5ef2aSThomas Huth     fr = float64_div(fa, fb, &FP_STATUS);
336fcf5ef2aSThomas Huth     env->error_code = soft_to_fpcr_exc(env);
337fcf5ef2aSThomas Huth 
338fcf5ef2aSThomas Huth     return float64_to_t(fr);
339fcf5ef2aSThomas Huth }
340fcf5ef2aSThomas Huth 
helper_sqrtt(CPUAlphaState * env,uint64_t a)341fcf5ef2aSThomas Huth uint64_t helper_sqrtt(CPUAlphaState *env, uint64_t a)
342fcf5ef2aSThomas Huth {
343fcf5ef2aSThomas Huth     float64 fa, fr;
344fcf5ef2aSThomas Huth 
345fcf5ef2aSThomas Huth     fa = t_to_float64(a);
346fcf5ef2aSThomas Huth     fr = float64_sqrt(fa, &FP_STATUS);
347fcf5ef2aSThomas Huth     env->error_code = soft_to_fpcr_exc(env);
348fcf5ef2aSThomas Huth 
349fcf5ef2aSThomas Huth     return float64_to_t(fr);
350fcf5ef2aSThomas Huth }
351fcf5ef2aSThomas Huth 
352fcf5ef2aSThomas Huth /* Comparisons */
helper_cmptun(CPUAlphaState * env,uint64_t a,uint64_t b)353fcf5ef2aSThomas Huth uint64_t helper_cmptun(CPUAlphaState *env, uint64_t a, uint64_t b)
354fcf5ef2aSThomas Huth {
355fcf5ef2aSThomas Huth     float64 fa, fb;
356fcf5ef2aSThomas Huth     uint64_t ret = 0;
357fcf5ef2aSThomas Huth 
358fcf5ef2aSThomas Huth     fa = t_to_float64(a);
359fcf5ef2aSThomas Huth     fb = t_to_float64(b);
360fcf5ef2aSThomas Huth 
361fcf5ef2aSThomas Huth     if (float64_unordered_quiet(fa, fb, &FP_STATUS)) {
362fcf5ef2aSThomas Huth         ret = 0x4000000000000000ULL;
363fcf5ef2aSThomas Huth     }
364fcf5ef2aSThomas Huth     env->error_code = soft_to_fpcr_exc(env);
365fcf5ef2aSThomas Huth 
366fcf5ef2aSThomas Huth     return ret;
367fcf5ef2aSThomas Huth }
368fcf5ef2aSThomas Huth 
helper_cmpteq(CPUAlphaState * env,uint64_t a,uint64_t b)369fcf5ef2aSThomas Huth uint64_t helper_cmpteq(CPUAlphaState *env, uint64_t a, uint64_t b)
370fcf5ef2aSThomas Huth {
371fcf5ef2aSThomas Huth     float64 fa, fb;
372fcf5ef2aSThomas Huth     uint64_t ret = 0;
373fcf5ef2aSThomas Huth 
374fcf5ef2aSThomas Huth     fa = t_to_float64(a);
375fcf5ef2aSThomas Huth     fb = t_to_float64(b);
376fcf5ef2aSThomas Huth 
377fcf5ef2aSThomas Huth     if (float64_eq_quiet(fa, fb, &FP_STATUS)) {
378fcf5ef2aSThomas Huth         ret = 0x4000000000000000ULL;
379fcf5ef2aSThomas Huth     }
380fcf5ef2aSThomas Huth     env->error_code = soft_to_fpcr_exc(env);
381fcf5ef2aSThomas Huth 
382fcf5ef2aSThomas Huth     return ret;
383fcf5ef2aSThomas Huth }
384fcf5ef2aSThomas Huth 
helper_cmptle(CPUAlphaState * env,uint64_t a,uint64_t b)385fcf5ef2aSThomas Huth uint64_t helper_cmptle(CPUAlphaState *env, uint64_t a, uint64_t b)
386fcf5ef2aSThomas Huth {
387fcf5ef2aSThomas Huth     float64 fa, fb;
388fcf5ef2aSThomas Huth     uint64_t ret = 0;
389fcf5ef2aSThomas Huth 
390fcf5ef2aSThomas Huth     fa = t_to_float64(a);
391fcf5ef2aSThomas Huth     fb = t_to_float64(b);
392fcf5ef2aSThomas Huth 
393fcf5ef2aSThomas Huth     if (float64_le(fa, fb, &FP_STATUS)) {
394fcf5ef2aSThomas Huth         ret = 0x4000000000000000ULL;
395fcf5ef2aSThomas Huth     }
396fcf5ef2aSThomas Huth     env->error_code = soft_to_fpcr_exc(env);
397fcf5ef2aSThomas Huth 
398fcf5ef2aSThomas Huth     return ret;
399fcf5ef2aSThomas Huth }
400fcf5ef2aSThomas Huth 
helper_cmptlt(CPUAlphaState * env,uint64_t a,uint64_t b)401fcf5ef2aSThomas Huth uint64_t helper_cmptlt(CPUAlphaState *env, uint64_t a, uint64_t b)
402fcf5ef2aSThomas Huth {
403fcf5ef2aSThomas Huth     float64 fa, fb;
404fcf5ef2aSThomas Huth     uint64_t ret = 0;
405fcf5ef2aSThomas Huth 
406fcf5ef2aSThomas Huth     fa = t_to_float64(a);
407fcf5ef2aSThomas Huth     fb = t_to_float64(b);
408fcf5ef2aSThomas Huth 
409fcf5ef2aSThomas Huth     if (float64_lt(fa, fb, &FP_STATUS)) {
410fcf5ef2aSThomas Huth         ret = 0x4000000000000000ULL;
411fcf5ef2aSThomas Huth     }
412fcf5ef2aSThomas Huth     env->error_code = soft_to_fpcr_exc(env);
413fcf5ef2aSThomas Huth 
414fcf5ef2aSThomas Huth     return ret;
415fcf5ef2aSThomas Huth }
416fcf5ef2aSThomas Huth 
417fcf5ef2aSThomas Huth /* Floating point format conversion */
helper_cvtts(CPUAlphaState * env,uint64_t a)418fcf5ef2aSThomas Huth uint64_t helper_cvtts(CPUAlphaState *env, uint64_t a)
419fcf5ef2aSThomas Huth {
420fcf5ef2aSThomas Huth     float64 fa;
421fcf5ef2aSThomas Huth     float32 fr;
422fcf5ef2aSThomas Huth 
423fcf5ef2aSThomas Huth     fa = t_to_float64(a);
424fcf5ef2aSThomas Huth     fr = float64_to_float32(fa, &FP_STATUS);
425fcf5ef2aSThomas Huth     env->error_code = soft_to_fpcr_exc(env);
426fcf5ef2aSThomas Huth 
427fcf5ef2aSThomas Huth     return float32_to_s(fr);
428fcf5ef2aSThomas Huth }
429fcf5ef2aSThomas Huth 
helper_cvtst(CPUAlphaState * env,uint64_t a)430fcf5ef2aSThomas Huth uint64_t helper_cvtst(CPUAlphaState *env, uint64_t a)
431fcf5ef2aSThomas Huth {
432fcf5ef2aSThomas Huth     float32 fa;
433fcf5ef2aSThomas Huth     float64 fr;
434fcf5ef2aSThomas Huth 
435fcf5ef2aSThomas Huth     fa = s_to_float32(a);
436fcf5ef2aSThomas Huth     fr = float32_to_float64(fa, &FP_STATUS);
437fcf5ef2aSThomas Huth     env->error_code = soft_to_fpcr_exc(env);
438fcf5ef2aSThomas Huth 
439fcf5ef2aSThomas Huth     return float64_to_t(fr);
440fcf5ef2aSThomas Huth }
441fcf5ef2aSThomas Huth 
helper_cvtqs(CPUAlphaState * env,uint64_t a)442fcf5ef2aSThomas Huth uint64_t helper_cvtqs(CPUAlphaState *env, uint64_t a)
443fcf5ef2aSThomas Huth {
444fcf5ef2aSThomas Huth     float32 fr = int64_to_float32(a, &FP_STATUS);
445fcf5ef2aSThomas Huth     env->error_code = soft_to_fpcr_exc(env);
446fcf5ef2aSThomas Huth 
447fcf5ef2aSThomas Huth     return float32_to_s(fr);
448fcf5ef2aSThomas Huth }
449fcf5ef2aSThomas Huth 
450fcf5ef2aSThomas Huth /* Implement float64 to uint64_t conversion without saturation -- we must
451fcf5ef2aSThomas Huth    supply the truncated result.  This behaviour is used by the compiler
452fcf5ef2aSThomas Huth    to get unsigned conversion for free with the same instruction.  */
453fcf5ef2aSThomas Huth 
do_cvttq(CPUAlphaState * env,uint64_t a,int roundmode)454fcf5ef2aSThomas Huth static uint64_t do_cvttq(CPUAlphaState *env, uint64_t a, int roundmode)
455fcf5ef2aSThomas Huth {
456*aa3bad5bSRichard Henderson     float64 fa;
457*aa3bad5bSRichard Henderson     int64_t ret;
458*aa3bad5bSRichard Henderson     uint32_t exc;
459fcf5ef2aSThomas Huth 
460*aa3bad5bSRichard Henderson     fa = t_to_float64(a);
461*aa3bad5bSRichard Henderson     ret = float64_to_int64_modulo(fa, roundmode, &FP_STATUS);
462fcf5ef2aSThomas Huth 
463*aa3bad5bSRichard Henderson     exc = get_float_exception_flags(&FP_STATUS);
464*aa3bad5bSRichard Henderson     if (unlikely(exc)) {
465*aa3bad5bSRichard Henderson         set_float_exception_flags(0, &FP_STATUS);
466*aa3bad5bSRichard Henderson 
467*aa3bad5bSRichard Henderson         /* We need to massage the resulting exceptions. */
468*aa3bad5bSRichard Henderson         if (exc & float_flag_invalid_cvti) {
469*aa3bad5bSRichard Henderson             /* Overflow, either normal or infinity. */
470*aa3bad5bSRichard Henderson             if (float64_is_infinity(fa)) {
471fcf5ef2aSThomas Huth                 exc = FPCR_INV;
472fcf5ef2aSThomas Huth             } else {
473fcf5ef2aSThomas Huth                 exc = FPCR_IOV | FPCR_INE;
474fcf5ef2aSThomas Huth             }
475*aa3bad5bSRichard Henderson         } else if (exc & float_flag_invalid) {
476*aa3bad5bSRichard Henderson             exc = FPCR_INV;
477*aa3bad5bSRichard Henderson         } else if (exc & float_flag_inexact) {
478fcf5ef2aSThomas Huth             exc = FPCR_INE;
479fcf5ef2aSThomas Huth         }
480fcf5ef2aSThomas Huth     }
481fcf5ef2aSThomas Huth     env->error_code = exc;
482fcf5ef2aSThomas Huth 
483fcf5ef2aSThomas Huth     return ret;
484fcf5ef2aSThomas Huth }
485fcf5ef2aSThomas Huth 
helper_cvttq(CPUAlphaState * env,uint64_t a)486fcf5ef2aSThomas Huth uint64_t helper_cvttq(CPUAlphaState *env, uint64_t a)
487fcf5ef2aSThomas Huth {
488fcf5ef2aSThomas Huth     return do_cvttq(env, a, FP_STATUS.float_rounding_mode);
489fcf5ef2aSThomas Huth }
490fcf5ef2aSThomas Huth 
helper_cvttq_c(CPUAlphaState * env,uint64_t a)491fcf5ef2aSThomas Huth uint64_t helper_cvttq_c(CPUAlphaState *env, uint64_t a)
492fcf5ef2aSThomas Huth {
493fcf5ef2aSThomas Huth     return do_cvttq(env, a, float_round_to_zero);
494fcf5ef2aSThomas Huth }
495fcf5ef2aSThomas Huth 
helper_cvtqt(CPUAlphaState * env,uint64_t a)496fcf5ef2aSThomas Huth uint64_t helper_cvtqt(CPUAlphaState *env, uint64_t a)
497fcf5ef2aSThomas Huth {
498fcf5ef2aSThomas Huth     float64 fr = int64_to_float64(a, &FP_STATUS);
499fcf5ef2aSThomas Huth     env->error_code = soft_to_fpcr_exc(env);
500fcf5ef2aSThomas Huth     return float64_to_t(fr);
501fcf5ef2aSThomas Huth }
502fcf5ef2aSThomas Huth 
helper_cvtql(CPUAlphaState * env,uint64_t val)503fcf5ef2aSThomas Huth uint64_t helper_cvtql(CPUAlphaState *env, uint64_t val)
504fcf5ef2aSThomas Huth {
505fcf5ef2aSThomas Huth     uint32_t exc = 0;
506fcf5ef2aSThomas Huth     if (val != (int32_t)val) {
507fcf5ef2aSThomas Huth         exc = FPCR_IOV | FPCR_INE;
508fcf5ef2aSThomas Huth     }
509fcf5ef2aSThomas Huth     env->error_code = exc;
510fcf5ef2aSThomas Huth 
511fcf5ef2aSThomas Huth     return ((val & 0xc0000000) << 32) | ((val & 0x3fffffff) << 29);
512fcf5ef2aSThomas Huth }
513