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/>.
21 #include "exec/helper-proto.h"
22 #include "fpu/softfloat.h"
24 #define FP_STATUS (env->fp_status)
27 void helper_setroundmode(CPUAlphaState
*env
, uint32_t val
)
29 set_float_rounding_mode(val
, &FP_STATUS
);
32 void helper_setflushzero(CPUAlphaState
*env
, uint32_t val
)
34 set_flush_to_zero(val
, &FP_STATUS
);
37 void helper_fp_exc_clear(CPUAlphaState
*env
)
39 set_float_exception_flags(0, &FP_STATUS
);
42 uint32_t helper_fp_exc_get(CPUAlphaState
*env
)
44 return get_float_exception_flags(&FP_STATUS
);
47 static inline void inline_fp_exc_raise(CPUAlphaState
*env
, uintptr_t retaddr
,
48 uint32_t exc
, uint32_t regno
)
53 if (exc
& float_flag_invalid
) {
56 if (exc
& float_flag_divbyzero
) {
59 if (exc
& float_flag_overflow
) {
62 if (exc
& float_flag_underflow
) {
65 if (exc
& float_flag_inexact
) {
69 arith_excp(env
, retaddr
, hw_exc
, 1ull << regno
);
73 /* Raise exceptions for ieee fp insns without software completion.
74 In that case there are no exceptions that don't trap; the mask
76 void helper_fp_exc_raise(CPUAlphaState
*env
, uint32_t exc
, uint32_t regno
)
78 inline_fp_exc_raise(env
, GETPC(), exc
, regno
);
81 /* Raise exceptions for ieee fp insns with software completion. */
82 void helper_fp_exc_raise_s(CPUAlphaState
*env
, uint32_t exc
, uint32_t regno
)
85 env
->fpcr_exc_status
|= exc
;
86 exc
&= ~env
->fpcr_exc_mask
;
87 inline_fp_exc_raise(env
, GETPC(), exc
, regno
);
91 /* Input handing without software completion. Trap for all
92 non-finite numbers. */
93 void helper_ieee_input(CPUAlphaState
*env
, uint64_t val
)
95 uint32_t exp
= (uint32_t)(val
>> 52) & 0x7ff;
96 uint64_t frac
= val
& 0xfffffffffffffull
;
99 /* Denormals without DNZ set raise an exception. */
100 if (frac
!= 0 && !env
->fp_status
.flush_inputs_to_zero
) {
101 arith_excp(env
, GETPC(), EXC_M_UNF
, 0);
103 } else if (exp
== 0x7ff) {
104 /* Infinity or NaN. */
105 /* ??? I'm not sure these exception bit flags are correct. I do
106 know that the Linux kernel, at least, doesn't rely on them and
107 just emulates the insn to figure out what exception to use. */
108 arith_excp(env
, GETPC(), frac
? EXC_M_INV
: EXC_M_FOV
, 0);
112 /* Similar, but does not trap for infinities. Used for comparisons. */
113 void helper_ieee_input_cmp(CPUAlphaState
*env
, uint64_t val
)
115 uint32_t exp
= (uint32_t)(val
>> 52) & 0x7ff;
116 uint64_t frac
= val
& 0xfffffffffffffull
;
119 /* Denormals without DNZ set raise an exception. */
120 if (frac
!= 0 && !env
->fp_status
.flush_inputs_to_zero
) {
121 arith_excp(env
, GETPC(), EXC_M_UNF
, 0);
123 } else if (exp
== 0x7ff && frac
) {
125 arith_excp(env
, GETPC(), EXC_M_INV
, 0);
129 /* F floating (VAX) */
130 static uint64_t float32_to_f(float32 fa
)
132 uint64_t r
, exp
, mant
, sig
;
136 sig
= ((uint64_t)a
.l
& 0x80000000) << 32;
137 exp
= (a
.l
>> 23) & 0xff;
138 mant
= ((uint64_t)a
.l
& 0x007fffff) << 29;
141 /* NaN or infinity */
142 r
= 1; /* VAX dirty zero */
143 } else if (exp
== 0) {
149 r
= sig
| ((exp
+ 1) << 52) | mant
;
154 r
= 1; /* VAX dirty zero */
156 r
= sig
| ((exp
+ 2) << 52);
163 static float32
f_to_float32(CPUAlphaState
*env
, uintptr_t retaddr
, uint64_t a
)
165 uint32_t exp
, mant_sig
;
168 exp
= ((a
>> 55) & 0x80) | ((a
>> 52) & 0x7f);
169 mant_sig
= ((a
>> 32) & 0x80000000) | ((a
>> 29) & 0x007fffff);
171 if (unlikely(!exp
&& mant_sig
)) {
172 /* Reserved operands / Dirty zero */
173 dynamic_excp(env
, retaddr
, EXCP_OPCDEC
, 0);
180 r
.l
= ((exp
- 2) << 23) | mant_sig
;
186 uint32_t helper_f_to_memory(uint64_t a
)
189 r
= (a
& 0x00001fffe0000000ull
) >> 13;
190 r
|= (a
& 0x07ffe00000000000ull
) >> 45;
191 r
|= (a
& 0xc000000000000000ull
) >> 48;
195 uint64_t helper_memory_to_f(uint32_t a
)
198 r
= ((uint64_t)(a
& 0x0000c000)) << 48;
199 r
|= ((uint64_t)(a
& 0x003fffff)) << 45;
200 r
|= ((uint64_t)(a
& 0xffff0000)) << 13;
201 if (!(a
& 0x00004000)) {
207 /* ??? Emulating VAX arithmetic with IEEE arithmetic is wrong. We should
208 either implement VAX arithmetic properly or just signal invalid opcode. */
210 uint64_t helper_addf(CPUAlphaState
*env
, uint64_t a
, uint64_t b
)
214 fa
= f_to_float32(env
, GETPC(), a
);
215 fb
= f_to_float32(env
, GETPC(), b
);
216 fr
= float32_add(fa
, fb
, &FP_STATUS
);
217 return float32_to_f(fr
);
220 uint64_t helper_subf(CPUAlphaState
*env
, uint64_t a
, uint64_t b
)
224 fa
= f_to_float32(env
, GETPC(), a
);
225 fb
= f_to_float32(env
, GETPC(), b
);
226 fr
= float32_sub(fa
, fb
, &FP_STATUS
);
227 return float32_to_f(fr
);
230 uint64_t helper_mulf(CPUAlphaState
*env
, uint64_t a
, uint64_t b
)
234 fa
= f_to_float32(env
, GETPC(), a
);
235 fb
= f_to_float32(env
, GETPC(), b
);
236 fr
= float32_mul(fa
, fb
, &FP_STATUS
);
237 return float32_to_f(fr
);
240 uint64_t helper_divf(CPUAlphaState
*env
, uint64_t a
, uint64_t b
)
244 fa
= f_to_float32(env
, GETPC(), a
);
245 fb
= f_to_float32(env
, GETPC(), b
);
246 fr
= float32_div(fa
, fb
, &FP_STATUS
);
247 return float32_to_f(fr
);
250 uint64_t helper_sqrtf(CPUAlphaState
*env
, uint64_t t
)
254 ft
= f_to_float32(env
, GETPC(), t
);
255 fr
= float32_sqrt(ft
, &FP_STATUS
);
256 return float32_to_f(fr
);
260 /* G floating (VAX) */
261 static uint64_t float64_to_g(float64 fa
)
263 uint64_t r
, exp
, mant
, sig
;
267 sig
= a
.ll
& 0x8000000000000000ull
;
268 exp
= (a
.ll
>> 52) & 0x7ff;
269 mant
= a
.ll
& 0x000fffffffffffffull
;
272 /* NaN or infinity */
273 r
= 1; /* VAX dirty zero */
274 } else if (exp
== 0) {
280 r
= sig
| ((exp
+ 1) << 52) | mant
;
285 r
= 1; /* VAX dirty zero */
287 r
= sig
| ((exp
+ 2) << 52);
294 static float64
g_to_float64(CPUAlphaState
*env
, uintptr_t retaddr
, uint64_t a
)
296 uint64_t exp
, mant_sig
;
299 exp
= (a
>> 52) & 0x7ff;
300 mant_sig
= a
& 0x800fffffffffffffull
;
302 if (!exp
&& mant_sig
) {
303 /* Reserved operands / Dirty zero */
304 dynamic_excp(env
, retaddr
, EXCP_OPCDEC
, 0);
311 r
.ll
= ((exp
- 2) << 52) | mant_sig
;
317 uint64_t helper_g_to_memory(uint64_t a
)
320 r
= (a
& 0x000000000000ffffull
) << 48;
321 r
|= (a
& 0x00000000ffff0000ull
) << 16;
322 r
|= (a
& 0x0000ffff00000000ull
) >> 16;
323 r
|= (a
& 0xffff000000000000ull
) >> 48;
327 uint64_t helper_memory_to_g(uint64_t a
)
330 r
= (a
& 0x000000000000ffffull
) << 48;
331 r
|= (a
& 0x00000000ffff0000ull
) << 16;
332 r
|= (a
& 0x0000ffff00000000ull
) >> 16;
333 r
|= (a
& 0xffff000000000000ull
) >> 48;
337 uint64_t helper_addg(CPUAlphaState
*env
, uint64_t a
, uint64_t b
)
341 fa
= g_to_float64(env
, GETPC(), a
);
342 fb
= g_to_float64(env
, GETPC(), b
);
343 fr
= float64_add(fa
, fb
, &FP_STATUS
);
344 return float64_to_g(fr
);
347 uint64_t helper_subg(CPUAlphaState
*env
, uint64_t a
, uint64_t b
)
351 fa
= g_to_float64(env
, GETPC(), a
);
352 fb
= g_to_float64(env
, GETPC(), b
);
353 fr
= float64_sub(fa
, fb
, &FP_STATUS
);
354 return float64_to_g(fr
);
357 uint64_t helper_mulg(CPUAlphaState
*env
, uint64_t a
, uint64_t b
)
361 fa
= g_to_float64(env
, GETPC(), a
);
362 fb
= g_to_float64(env
, GETPC(), b
);
363 fr
= float64_mul(fa
, fb
, &FP_STATUS
);
364 return float64_to_g(fr
);
367 uint64_t helper_divg(CPUAlphaState
*env
, uint64_t a
, uint64_t b
)
371 fa
= g_to_float64(env
, GETPC(), a
);
372 fb
= g_to_float64(env
, GETPC(), b
);
373 fr
= float64_div(fa
, fb
, &FP_STATUS
);
374 return float64_to_g(fr
);
377 uint64_t helper_sqrtg(CPUAlphaState
*env
, uint64_t a
)
381 fa
= g_to_float64(env
, GETPC(), a
);
382 fr
= float64_sqrt(fa
, &FP_STATUS
);
383 return float64_to_g(fr
);
387 /* S floating (single) */
389 /* Taken from linux/arch/alpha/kernel/traps.c, s_mem_to_reg. */
390 static inline uint64_t float32_to_s_int(uint32_t fi
)
392 uint32_t frac
= fi
& 0x7fffff;
393 uint32_t sign
= fi
>> 31;
394 uint32_t exp_msb
= (fi
>> 30) & 1;
395 uint32_t exp_low
= (fi
>> 23) & 0x7f;
398 exp
= (exp_msb
<< 10) | exp_low
;
400 if (exp_low
== 0x7f) {
404 if (exp_low
!= 0x00) {
409 return (((uint64_t)sign
<< 63)
410 | ((uint64_t)exp
<< 52)
411 | ((uint64_t)frac
<< 29));
414 static inline uint64_t float32_to_s(float32 fa
)
418 return float32_to_s_int(a
.l
);
421 static inline uint32_t s_to_float32_int(uint64_t a
)
423 return ((a
>> 32) & 0xc0000000) | ((a
>> 29) & 0x3fffffff);
426 static inline float32
s_to_float32(uint64_t a
)
429 r
.l
= s_to_float32_int(a
);
433 uint32_t helper_s_to_memory(uint64_t a
)
435 return s_to_float32_int(a
);
438 uint64_t helper_memory_to_s(uint32_t a
)
440 return float32_to_s_int(a
);
443 uint64_t helper_adds(CPUAlphaState
*env
, uint64_t a
, uint64_t b
)
447 fa
= s_to_float32(a
);
448 fb
= s_to_float32(b
);
449 fr
= float32_add(fa
, fb
, &FP_STATUS
);
450 return float32_to_s(fr
);
453 uint64_t helper_subs(CPUAlphaState
*env
, uint64_t a
, uint64_t b
)
457 fa
= s_to_float32(a
);
458 fb
= s_to_float32(b
);
459 fr
= float32_sub(fa
, fb
, &FP_STATUS
);
460 return float32_to_s(fr
);
463 uint64_t helper_muls(CPUAlphaState
*env
, uint64_t a
, uint64_t b
)
467 fa
= s_to_float32(a
);
468 fb
= s_to_float32(b
);
469 fr
= float32_mul(fa
, fb
, &FP_STATUS
);
470 return float32_to_s(fr
);
473 uint64_t helper_divs(CPUAlphaState
*env
, uint64_t a
, uint64_t b
)
477 fa
= s_to_float32(a
);
478 fb
= s_to_float32(b
);
479 fr
= float32_div(fa
, fb
, &FP_STATUS
);
480 return float32_to_s(fr
);
483 uint64_t helper_sqrts(CPUAlphaState
*env
, uint64_t a
)
487 fa
= s_to_float32(a
);
488 fr
= float32_sqrt(fa
, &FP_STATUS
);
489 return float32_to_s(fr
);
493 /* T floating (double) */
494 static inline float64
t_to_float64(uint64_t a
)
496 /* Memory format is the same as float64 */
502 static inline uint64_t float64_to_t(float64 fa
)
504 /* Memory format is the same as float64 */
510 uint64_t helper_addt(CPUAlphaState
*env
, uint64_t a
, uint64_t b
)
514 fa
= t_to_float64(a
);
515 fb
= t_to_float64(b
);
516 fr
= float64_add(fa
, fb
, &FP_STATUS
);
517 return float64_to_t(fr
);
520 uint64_t helper_subt(CPUAlphaState
*env
, uint64_t a
, uint64_t b
)
524 fa
= t_to_float64(a
);
525 fb
= t_to_float64(b
);
526 fr
= float64_sub(fa
, fb
, &FP_STATUS
);
527 return float64_to_t(fr
);
530 uint64_t helper_mult(CPUAlphaState
*env
, uint64_t a
, uint64_t b
)
534 fa
= t_to_float64(a
);
535 fb
= t_to_float64(b
);
536 fr
= float64_mul(fa
, fb
, &FP_STATUS
);
537 return float64_to_t(fr
);
540 uint64_t helper_divt(CPUAlphaState
*env
, uint64_t a
, uint64_t b
)
544 fa
= t_to_float64(a
);
545 fb
= t_to_float64(b
);
546 fr
= float64_div(fa
, fb
, &FP_STATUS
);
547 return float64_to_t(fr
);
550 uint64_t helper_sqrtt(CPUAlphaState
*env
, uint64_t a
)
554 fa
= t_to_float64(a
);
555 fr
= float64_sqrt(fa
, &FP_STATUS
);
556 return float64_to_t(fr
);
560 uint64_t helper_cmptun(CPUAlphaState
*env
, uint64_t a
, uint64_t b
)
564 fa
= t_to_float64(a
);
565 fb
= t_to_float64(b
);
567 if (float64_unordered_quiet(fa
, fb
, &FP_STATUS
)) {
568 return 0x4000000000000000ULL
;
574 uint64_t helper_cmpteq(CPUAlphaState
*env
, uint64_t a
, uint64_t b
)
578 fa
= t_to_float64(a
);
579 fb
= t_to_float64(b
);
581 if (float64_eq_quiet(fa
, fb
, &FP_STATUS
)) {
582 return 0x4000000000000000ULL
;
588 uint64_t helper_cmptle(CPUAlphaState
*env
, uint64_t a
, uint64_t b
)
592 fa
= t_to_float64(a
);
593 fb
= t_to_float64(b
);
595 if (float64_le(fa
, fb
, &FP_STATUS
)) {
596 return 0x4000000000000000ULL
;
602 uint64_t helper_cmptlt(CPUAlphaState
*env
, uint64_t a
, uint64_t b
)
606 fa
= t_to_float64(a
);
607 fb
= t_to_float64(b
);
609 if (float64_lt(fa
, fb
, &FP_STATUS
)) {
610 return 0x4000000000000000ULL
;
616 uint64_t helper_cmpgeq(CPUAlphaState
*env
, uint64_t a
, uint64_t b
)
620 fa
= g_to_float64(env
, GETPC(), a
);
621 fb
= g_to_float64(env
, GETPC(), b
);
623 if (float64_eq_quiet(fa
, fb
, &FP_STATUS
)) {
624 return 0x4000000000000000ULL
;
630 uint64_t helper_cmpgle(CPUAlphaState
*env
, uint64_t a
, uint64_t b
)
634 fa
= g_to_float64(env
, GETPC(), a
);
635 fb
= g_to_float64(env
, GETPC(), b
);
637 if (float64_le(fa
, fb
, &FP_STATUS
)) {
638 return 0x4000000000000000ULL
;
644 uint64_t helper_cmpglt(CPUAlphaState
*env
, uint64_t a
, uint64_t b
)
648 fa
= g_to_float64(env
, GETPC(), a
);
649 fb
= g_to_float64(env
, GETPC(), b
);
651 if (float64_lt(fa
, fb
, &FP_STATUS
)) {
652 return 0x4000000000000000ULL
;
658 /* Floating point format conversion */
659 uint64_t helper_cvtts(CPUAlphaState
*env
, uint64_t a
)
664 fa
= t_to_float64(a
);
665 fr
= float64_to_float32(fa
, &FP_STATUS
);
666 return float32_to_s(fr
);
669 uint64_t helper_cvtst(CPUAlphaState
*env
, uint64_t a
)
674 fa
= s_to_float32(a
);
675 fr
= float32_to_float64(fa
, &FP_STATUS
);
676 return float64_to_t(fr
);
679 uint64_t helper_cvtqs(CPUAlphaState
*env
, uint64_t a
)
681 float32 fr
= int64_to_float32(a
, &FP_STATUS
);
682 return float32_to_s(fr
);
685 /* Implement float64 to uint64 conversion without saturation -- we must
686 supply the truncated result. This behaviour is used by the compiler
687 to get unsigned conversion for free with the same instruction.
689 The VI flag is set when overflow or inexact exceptions should be raised. */
691 static inline uint64_t inline_cvttq(CPUAlphaState
*env
, uint64_t a
,
692 int roundmode
, int VI
)
694 uint64_t frac
, ret
= 0;
695 uint32_t exp
, sign
, exc
= 0;
699 exp
= (uint32_t)(a
>> 52) & 0x7ff;
700 frac
= a
& 0xfffffffffffffull
;
703 if (unlikely(frac
!= 0)) {
706 } else if (exp
== 0x7ff) {
707 exc
= (frac
? float_flag_invalid
: VI
? float_flag_overflow
: 0);
709 /* Restore implicit bit. */
710 frac
|= 0x10000000000000ull
;
712 shift
= exp
- 1023 - 52;
714 /* In this case the number is so large that we must shift
715 the fraction left. There is no rounding to do. */
718 if (VI
&& (ret
>> shift
) != frac
) {
719 exc
= float_flag_overflow
;
725 /* In this case the number is smaller than the fraction as
726 represented by the 52 bit number. Here we must think
727 about rounding the result. Handle this by shifting the
728 fractional part of the number into the high bits of ROUND.
729 This will let us efficiently handle round-to-nearest. */
733 round
= frac
<< (64 - shift
);
735 /* The exponent is so small we shift out everything.
736 Leave a sticky bit for proper rounding below. */
742 exc
= (VI
? float_flag_inexact
: 0);
744 case float_round_nearest_even
:
745 if (round
== (1ull << 63)) {
746 /* Fraction is exactly 0.5; round to even. */
748 } else if (round
> (1ull << 63)) {
752 case float_round_to_zero
:
757 case float_round_down
:
768 float_raise(exc
, &FP_STATUS
);
774 uint64_t helper_cvttq(CPUAlphaState
*env
, uint64_t a
)
776 return inline_cvttq(env
, a
, FP_STATUS
.float_rounding_mode
, 1);
779 uint64_t helper_cvttq_c(CPUAlphaState
*env
, uint64_t a
)
781 return inline_cvttq(env
, a
, float_round_to_zero
, 0);
784 uint64_t helper_cvttq_svic(CPUAlphaState
*env
, uint64_t a
)
786 return inline_cvttq(env
, a
, float_round_to_zero
, 1);
789 uint64_t helper_cvtqt(CPUAlphaState
*env
, uint64_t a
)
791 float64 fr
= int64_to_float64(a
, &FP_STATUS
);
792 return float64_to_t(fr
);
795 uint64_t helper_cvtqf(CPUAlphaState
*env
, uint64_t a
)
797 float32 fr
= int64_to_float32(a
, &FP_STATUS
);
798 return float32_to_f(fr
);
801 uint64_t helper_cvtgf(CPUAlphaState
*env
, uint64_t a
)
806 fa
= g_to_float64(env
, GETPC(), a
);
807 fr
= float64_to_float32(fa
, &FP_STATUS
);
808 return float32_to_f(fr
);
811 uint64_t helper_cvtgq(CPUAlphaState
*env
, uint64_t a
)
813 float64 fa
= g_to_float64(env
, GETPC(), a
);
814 return float64_to_int64_round_to_zero(fa
, &FP_STATUS
);
817 uint64_t helper_cvtqg(CPUAlphaState
*env
, uint64_t a
)
820 fr
= int64_to_float64(a
, &FP_STATUS
);
821 return float64_to_g(fr
);
824 void helper_fcvtql_v_input(CPUAlphaState
*env
, uint64_t val
)
826 if (val
!= (int32_t)val
) {
827 arith_excp(env
, GETPC(), EXC_M_IOV
, 0);