2 * Helpers for floating point instructions.
4 * Copyright (c) 2007 Jocelyn Mayer
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
20 #include "qemu/osdep.h"
22 #include "exec/exec-all.h"
23 #include "exec/helper-proto.h"
24 #include "fpu/softfloat.h"
26 #define FP_STATUS (env->fp_status)
29 void helper_setroundmode(CPUAlphaState
*env
, uint32_t val
)
31 set_float_rounding_mode(val
, &FP_STATUS
);
34 void helper_setflushzero(CPUAlphaState
*env
, uint32_t val
)
36 set_flush_to_zero(val
, &FP_STATUS
);
39 #define CONVERT_BIT(X, SRC, DST) \
40 (SRC > DST ? (X) / (SRC / DST) & (DST) : ((X) & SRC) * (DST / SRC))
42 static uint32_t soft_to_fpcr_exc(CPUAlphaState
*env
)
44 uint8_t exc
= get_float_exception_flags(&FP_STATUS
);
48 set_float_exception_flags(0, &FP_STATUS
);
49 ret
|= CONVERT_BIT(exc
, float_flag_invalid
, FPCR_INV
);
50 ret
|= CONVERT_BIT(exc
, float_flag_divbyzero
, FPCR_DZE
);
51 ret
|= CONVERT_BIT(exc
, float_flag_overflow
, FPCR_OVF
);
52 ret
|= CONVERT_BIT(exc
, float_flag_underflow
, FPCR_UNF
);
53 ret
|= CONVERT_BIT(exc
, float_flag_inexact
, FPCR_INE
);
59 static void fp_exc_raise1(CPUAlphaState
*env
, uintptr_t retaddr
,
60 uint32_t exc
, uint32_t regno
, uint32_t hw_exc
)
62 hw_exc
|= CONVERT_BIT(exc
, FPCR_INV
, EXC_M_INV
);
63 hw_exc
|= CONVERT_BIT(exc
, FPCR_DZE
, EXC_M_DZE
);
64 hw_exc
|= CONVERT_BIT(exc
, FPCR_OVF
, EXC_M_FOV
);
65 hw_exc
|= CONVERT_BIT(exc
, FPCR_UNF
, EXC_M_UNF
);
66 hw_exc
|= CONVERT_BIT(exc
, FPCR_INE
, EXC_M_INE
);
67 hw_exc
|= CONVERT_BIT(exc
, FPCR_IOV
, EXC_M_IOV
);
69 arith_excp(env
, retaddr
, hw_exc
, 1ull << regno
);
72 /* Raise exceptions for ieee fp insns without software completion.
73 In that case there are no exceptions that don't trap; the mask
75 void helper_fp_exc_raise(CPUAlphaState
*env
, uint32_t ignore
, uint32_t regno
)
77 uint32_t exc
= env
->error_code
;
82 fp_exc_raise1(env
, GETPC(), exc
, regno
, 0);
87 /* Raise exceptions for ieee fp insns with software completion. */
88 void helper_fp_exc_raise_s(CPUAlphaState
*env
, uint32_t ignore
, uint32_t regno
)
90 uint32_t exc
= env
->error_code
& ~ignore
;
95 exc
&= env
->fpcr_exc_enable
;
96 fp_exc_raise1(env
, GETPC(), exc
, regno
, EXC_M_SWC
);
101 /* Input handing without software completion. Trap for all
102 non-finite numbers. */
103 void helper_ieee_input(CPUAlphaState
*env
, uint64_t val
)
105 uint32_t exp
= (uint32_t)(val
>> 52) & 0x7ff;
106 uint64_t frac
= val
& 0xfffffffffffffull
;
109 /* Denormals without /S raise an exception. */
111 arith_excp(env
, GETPC(), EXC_M_INV
, 0);
113 } else if (exp
== 0x7ff) {
114 /* Infinity or NaN. */
115 env
->fpcr
|= FPCR_INV
;
116 arith_excp(env
, GETPC(), EXC_M_INV
, 0);
120 /* Similar, but does not trap for infinities. Used for comparisons. */
121 void helper_ieee_input_cmp(CPUAlphaState
*env
, uint64_t val
)
123 uint32_t exp
= (uint32_t)(val
>> 52) & 0x7ff;
124 uint64_t frac
= val
& 0xfffffffffffffull
;
127 /* Denormals without /S raise an exception. */
129 arith_excp(env
, GETPC(), EXC_M_INV
, 0);
131 } else if (exp
== 0x7ff && frac
) {
133 env
->fpcr
|= FPCR_INV
;
134 arith_excp(env
, GETPC(), EXC_M_INV
, 0);
138 /* Input handing with software completion. Trap for denorms, unless DNZ
139 is set. If we try to support DNOD (which none of the produced hardware
140 did, AFAICS), we'll need to suppress the trap when FPCR.DNOD is set;
141 then the code downstream of that will need to cope with denorms sans
142 flush_input_to_zero. Most of it should work sanely, but there's
143 nothing to compare with. */
144 void helper_ieee_input_s(CPUAlphaState
*env
, uint64_t val
)
146 if (unlikely(2 * val
- 1 < 0x1fffffffffffffull
)
147 && !env
->fp_status
.flush_inputs_to_zero
) {
148 arith_excp(env
, GETPC(), EXC_M_INV
| EXC_M_SWC
, 0);
152 /* S floating (single) */
154 /* Taken from linux/arch/alpha/kernel/traps.c, s_mem_to_reg. */
155 static inline uint64_t float32_to_s_int(uint32_t fi
)
157 uint32_t frac
= fi
& 0x7fffff;
158 uint32_t sign
= fi
>> 31;
159 uint32_t exp_msb
= (fi
>> 30) & 1;
160 uint32_t exp_low
= (fi
>> 23) & 0x7f;
163 exp
= (exp_msb
<< 10) | exp_low
;
165 if (exp_low
== 0x7f) {
169 if (exp_low
!= 0x00) {
174 return (((uint64_t)sign
<< 63)
175 | ((uint64_t)exp
<< 52)
176 | ((uint64_t)frac
<< 29));
179 static inline uint64_t float32_to_s(float32 fa
)
183 return float32_to_s_int(a
.l
);
186 static inline uint32_t s_to_float32_int(uint64_t a
)
188 return ((a
>> 32) & 0xc0000000) | ((a
>> 29) & 0x3fffffff);
191 static inline float32
s_to_float32(uint64_t a
)
194 r
.l
= s_to_float32_int(a
);
198 uint32_t helper_s_to_memory(uint64_t a
)
200 return s_to_float32_int(a
);
203 uint64_t helper_memory_to_s(uint32_t a
)
205 return float32_to_s_int(a
);
208 uint64_t helper_adds(CPUAlphaState
*env
, uint64_t a
, uint64_t b
)
212 fa
= s_to_float32(a
);
213 fb
= s_to_float32(b
);
214 fr
= float32_add(fa
, fb
, &FP_STATUS
);
215 env
->error_code
= soft_to_fpcr_exc(env
);
217 return float32_to_s(fr
);
220 uint64_t helper_subs(CPUAlphaState
*env
, uint64_t a
, uint64_t b
)
224 fa
= s_to_float32(a
);
225 fb
= s_to_float32(b
);
226 fr
= float32_sub(fa
, fb
, &FP_STATUS
);
227 env
->error_code
= soft_to_fpcr_exc(env
);
229 return float32_to_s(fr
);
232 uint64_t helper_muls(CPUAlphaState
*env
, uint64_t a
, uint64_t b
)
236 fa
= s_to_float32(a
);
237 fb
= s_to_float32(b
);
238 fr
= float32_mul(fa
, fb
, &FP_STATUS
);
239 env
->error_code
= soft_to_fpcr_exc(env
);
241 return float32_to_s(fr
);
244 uint64_t helper_divs(CPUAlphaState
*env
, uint64_t a
, uint64_t b
)
248 fa
= s_to_float32(a
);
249 fb
= s_to_float32(b
);
250 fr
= float32_div(fa
, fb
, &FP_STATUS
);
251 env
->error_code
= soft_to_fpcr_exc(env
);
253 return float32_to_s(fr
);
256 uint64_t helper_sqrts(CPUAlphaState
*env
, uint64_t a
)
260 fa
= s_to_float32(a
);
261 fr
= float32_sqrt(fa
, &FP_STATUS
);
262 env
->error_code
= soft_to_fpcr_exc(env
);
264 return float32_to_s(fr
);
268 /* T floating (double) */
269 static inline float64
t_to_float64(uint64_t a
)
271 /* Memory format is the same as float64 */
277 static inline uint64_t float64_to_t(float64 fa
)
279 /* Memory format is the same as float64 */
285 uint64_t helper_addt(CPUAlphaState
*env
, uint64_t a
, uint64_t b
)
289 fa
= t_to_float64(a
);
290 fb
= t_to_float64(b
);
291 fr
= float64_add(fa
, fb
, &FP_STATUS
);
292 env
->error_code
= soft_to_fpcr_exc(env
);
294 return float64_to_t(fr
);
297 uint64_t helper_subt(CPUAlphaState
*env
, uint64_t a
, uint64_t b
)
301 fa
= t_to_float64(a
);
302 fb
= t_to_float64(b
);
303 fr
= float64_sub(fa
, fb
, &FP_STATUS
);
304 env
->error_code
= soft_to_fpcr_exc(env
);
306 return float64_to_t(fr
);
309 uint64_t helper_mult(CPUAlphaState
*env
, uint64_t a
, uint64_t b
)
313 fa
= t_to_float64(a
);
314 fb
= t_to_float64(b
);
315 fr
= float64_mul(fa
, fb
, &FP_STATUS
);
316 env
->error_code
= soft_to_fpcr_exc(env
);
318 return float64_to_t(fr
);
321 uint64_t helper_divt(CPUAlphaState
*env
, uint64_t a
, uint64_t b
)
325 fa
= t_to_float64(a
);
326 fb
= t_to_float64(b
);
327 fr
= float64_div(fa
, fb
, &FP_STATUS
);
328 env
->error_code
= soft_to_fpcr_exc(env
);
330 return float64_to_t(fr
);
333 uint64_t helper_sqrtt(CPUAlphaState
*env
, uint64_t a
)
337 fa
= t_to_float64(a
);
338 fr
= float64_sqrt(fa
, &FP_STATUS
);
339 env
->error_code
= soft_to_fpcr_exc(env
);
341 return float64_to_t(fr
);
345 uint64_t helper_cmptun(CPUAlphaState
*env
, uint64_t a
, uint64_t b
)
350 fa
= t_to_float64(a
);
351 fb
= t_to_float64(b
);
353 if (float64_unordered_quiet(fa
, fb
, &FP_STATUS
)) {
354 ret
= 0x4000000000000000ULL
;
356 env
->error_code
= soft_to_fpcr_exc(env
);
361 uint64_t helper_cmpteq(CPUAlphaState
*env
, uint64_t a
, uint64_t b
)
366 fa
= t_to_float64(a
);
367 fb
= t_to_float64(b
);
369 if (float64_eq_quiet(fa
, fb
, &FP_STATUS
)) {
370 ret
= 0x4000000000000000ULL
;
372 env
->error_code
= soft_to_fpcr_exc(env
);
377 uint64_t helper_cmptle(CPUAlphaState
*env
, uint64_t a
, uint64_t b
)
382 fa
= t_to_float64(a
);
383 fb
= t_to_float64(b
);
385 if (float64_le(fa
, fb
, &FP_STATUS
)) {
386 ret
= 0x4000000000000000ULL
;
388 env
->error_code
= soft_to_fpcr_exc(env
);
393 uint64_t helper_cmptlt(CPUAlphaState
*env
, uint64_t a
, uint64_t b
)
398 fa
= t_to_float64(a
);
399 fb
= t_to_float64(b
);
401 if (float64_lt(fa
, fb
, &FP_STATUS
)) {
402 ret
= 0x4000000000000000ULL
;
404 env
->error_code
= soft_to_fpcr_exc(env
);
409 /* Floating point format conversion */
410 uint64_t helper_cvtts(CPUAlphaState
*env
, uint64_t a
)
415 fa
= t_to_float64(a
);
416 fr
= float64_to_float32(fa
, &FP_STATUS
);
417 env
->error_code
= soft_to_fpcr_exc(env
);
419 return float32_to_s(fr
);
422 uint64_t helper_cvtst(CPUAlphaState
*env
, uint64_t a
)
427 fa
= s_to_float32(a
);
428 fr
= float32_to_float64(fa
, &FP_STATUS
);
429 env
->error_code
= soft_to_fpcr_exc(env
);
431 return float64_to_t(fr
);
434 uint64_t helper_cvtqs(CPUAlphaState
*env
, uint64_t a
)
436 float32 fr
= int64_to_float32(a
, &FP_STATUS
);
437 env
->error_code
= soft_to_fpcr_exc(env
);
439 return float32_to_s(fr
);
442 /* Implement float64 to uint64_t conversion without saturation -- we must
443 supply the truncated result. This behaviour is used by the compiler
444 to get unsigned conversion for free with the same instruction. */
446 static uint64_t do_cvttq(CPUAlphaState
*env
, uint64_t a
, int roundmode
)
448 uint64_t frac
, ret
= 0;
449 uint32_t exp
, sign
, exc
= 0;
453 exp
= (uint32_t)(a
>> 52) & 0x7ff;
454 frac
= a
& 0xfffffffffffffull
;
457 if (unlikely(frac
!= 0) && !env
->fp_status
.flush_inputs_to_zero
) {
460 } else if (exp
== 0x7ff) {
463 /* Restore implicit bit. */
464 frac
|= 0x10000000000000ull
;
466 shift
= exp
- 1023 - 52;
468 /* In this case the number is so large that we must shift
469 the fraction left. There is no rounding to do. */
473 /* Check for overflow. Note the special case of -0x1p63. */
474 if (shift
>= 11 && a
!= 0xC3E0000000000000ull
) {
475 exc
= FPCR_IOV
| FPCR_INE
;
480 /* In this case the number is smaller than the fraction as
481 represented by the 52 bit number. Here we must think
482 about rounding the result. Handle this by shifting the
483 fractional part of the number into the high bits of ROUND.
484 This will let us efficiently handle round-to-nearest. */
488 round
= frac
<< (64 - shift
);
490 /* The exponent is so small we shift out everything.
491 Leave a sticky bit for proper rounding below. */
499 case float_round_nearest_even
:
500 if (round
== (1ull << 63)) {
501 /* Fraction is exactly 0.5; round to even. */
503 } else if (round
> (1ull << 63)) {
507 case float_round_to_zero
:
512 case float_round_down
:
522 env
->error_code
= exc
;
527 uint64_t helper_cvttq(CPUAlphaState
*env
, uint64_t a
)
529 return do_cvttq(env
, a
, FP_STATUS
.float_rounding_mode
);
532 uint64_t helper_cvttq_c(CPUAlphaState
*env
, uint64_t a
)
534 return do_cvttq(env
, a
, float_round_to_zero
);
537 uint64_t helper_cvtqt(CPUAlphaState
*env
, uint64_t a
)
539 float64 fr
= int64_to_float64(a
, &FP_STATUS
);
540 env
->error_code
= soft_to_fpcr_exc(env
);
541 return float64_to_t(fr
);
544 uint64_t helper_cvtql(CPUAlphaState
*env
, uint64_t val
)
547 if (val
!= (int32_t)val
) {
548 exc
= FPCR_IOV
| FPCR_INE
;
550 env
->error_code
= exc
;
552 return ((val
& 0xc0000000) << 32) | ((val
& 0x3fffffff) << 29);