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
;
93 exc
&= env
->fpcr_exc_enable
;
95 * In system mode, the software handler gets invoked
96 * for any non-ignored exception.
97 * In user mode, the kernel's software handler only
98 * delivers a signal if the exception is enabled.
100 #ifdef CONFIG_USER_ONLY
105 fp_exc_raise1(env
, GETPC(), exc
, regno
, EXC_M_SWC
);
109 /* Input handing without software completion. Trap for all
110 non-finite numbers. */
111 void helper_ieee_input(CPUAlphaState
*env
, uint64_t val
)
113 uint32_t exp
= (uint32_t)(val
>> 52) & 0x7ff;
114 uint64_t frac
= val
& 0xfffffffffffffull
;
117 /* Denormals without /S raise an exception. */
119 arith_excp(env
, GETPC(), EXC_M_INV
, 0);
121 } else if (exp
== 0x7ff) {
122 /* Infinity or NaN. */
123 env
->fpcr
|= FPCR_INV
;
124 arith_excp(env
, GETPC(), EXC_M_INV
, 0);
128 /* Similar, but does not trap for infinities. Used for comparisons. */
129 void helper_ieee_input_cmp(CPUAlphaState
*env
, uint64_t val
)
131 uint32_t exp
= (uint32_t)(val
>> 52) & 0x7ff;
132 uint64_t frac
= val
& 0xfffffffffffffull
;
135 /* Denormals without /S raise an exception. */
137 arith_excp(env
, GETPC(), EXC_M_INV
, 0);
139 } else if (exp
== 0x7ff && frac
) {
141 env
->fpcr
|= FPCR_INV
;
142 arith_excp(env
, GETPC(), EXC_M_INV
, 0);
146 /* Input handing with software completion. Trap for denorms, unless DNZ
147 is set. If we try to support DNOD (which none of the produced hardware
148 did, AFAICS), we'll need to suppress the trap when FPCR.DNOD is set;
149 then the code downstream of that will need to cope with denorms sans
150 flush_input_to_zero. Most of it should work sanely, but there's
151 nothing to compare with. */
152 void helper_ieee_input_s(CPUAlphaState
*env
, uint64_t val
)
154 if (unlikely(2 * val
- 1 < 0x1fffffffffffffull
)
155 && !env
->fp_status
.flush_inputs_to_zero
) {
156 arith_excp(env
, GETPC(), EXC_M_INV
| EXC_M_SWC
, 0);
160 /* S floating (single) */
162 /* Taken from linux/arch/alpha/kernel/traps.c, s_mem_to_reg. */
163 static inline uint64_t float32_to_s_int(uint32_t fi
)
165 uint32_t frac
= fi
& 0x7fffff;
166 uint32_t sign
= fi
>> 31;
167 uint32_t exp_msb
= (fi
>> 30) & 1;
168 uint32_t exp_low
= (fi
>> 23) & 0x7f;
171 exp
= (exp_msb
<< 10) | exp_low
;
173 if (exp_low
== 0x7f) {
177 if (exp_low
!= 0x00) {
182 return (((uint64_t)sign
<< 63)
183 | ((uint64_t)exp
<< 52)
184 | ((uint64_t)frac
<< 29));
187 static inline uint64_t float32_to_s(float32 fa
)
191 return float32_to_s_int(a
.l
);
194 static inline uint32_t s_to_float32_int(uint64_t a
)
196 return ((a
>> 32) & 0xc0000000) | ((a
>> 29) & 0x3fffffff);
199 static inline float32
s_to_float32(uint64_t a
)
202 r
.l
= s_to_float32_int(a
);
206 uint32_t helper_s_to_memory(uint64_t a
)
208 return s_to_float32_int(a
);
211 uint64_t helper_memory_to_s(uint32_t a
)
213 return float32_to_s_int(a
);
216 uint64_t helper_adds(CPUAlphaState
*env
, uint64_t a
, uint64_t b
)
220 fa
= s_to_float32(a
);
221 fb
= s_to_float32(b
);
222 fr
= float32_add(fa
, fb
, &FP_STATUS
);
223 env
->error_code
= soft_to_fpcr_exc(env
);
225 return float32_to_s(fr
);
228 uint64_t helper_subs(CPUAlphaState
*env
, uint64_t a
, uint64_t b
)
232 fa
= s_to_float32(a
);
233 fb
= s_to_float32(b
);
234 fr
= float32_sub(fa
, fb
, &FP_STATUS
);
235 env
->error_code
= soft_to_fpcr_exc(env
);
237 return float32_to_s(fr
);
240 uint64_t helper_muls(CPUAlphaState
*env
, uint64_t a
, uint64_t b
)
244 fa
= s_to_float32(a
);
245 fb
= s_to_float32(b
);
246 fr
= float32_mul(fa
, fb
, &FP_STATUS
);
247 env
->error_code
= soft_to_fpcr_exc(env
);
249 return float32_to_s(fr
);
252 uint64_t helper_divs(CPUAlphaState
*env
, uint64_t a
, uint64_t b
)
256 fa
= s_to_float32(a
);
257 fb
= s_to_float32(b
);
258 fr
= float32_div(fa
, fb
, &FP_STATUS
);
259 env
->error_code
= soft_to_fpcr_exc(env
);
261 return float32_to_s(fr
);
264 uint64_t helper_sqrts(CPUAlphaState
*env
, uint64_t a
)
268 fa
= s_to_float32(a
);
269 fr
= float32_sqrt(fa
, &FP_STATUS
);
270 env
->error_code
= soft_to_fpcr_exc(env
);
272 return float32_to_s(fr
);
276 /* T floating (double) */
277 static inline float64
t_to_float64(uint64_t a
)
279 /* Memory format is the same as float64 */
285 static inline uint64_t float64_to_t(float64 fa
)
287 /* Memory format is the same as float64 */
293 uint64_t helper_addt(CPUAlphaState
*env
, uint64_t a
, uint64_t b
)
297 fa
= t_to_float64(a
);
298 fb
= t_to_float64(b
);
299 fr
= float64_add(fa
, fb
, &FP_STATUS
);
300 env
->error_code
= soft_to_fpcr_exc(env
);
302 return float64_to_t(fr
);
305 uint64_t helper_subt(CPUAlphaState
*env
, uint64_t a
, uint64_t b
)
309 fa
= t_to_float64(a
);
310 fb
= t_to_float64(b
);
311 fr
= float64_sub(fa
, fb
, &FP_STATUS
);
312 env
->error_code
= soft_to_fpcr_exc(env
);
314 return float64_to_t(fr
);
317 uint64_t helper_mult(CPUAlphaState
*env
, uint64_t a
, uint64_t b
)
321 fa
= t_to_float64(a
);
322 fb
= t_to_float64(b
);
323 fr
= float64_mul(fa
, fb
, &FP_STATUS
);
324 env
->error_code
= soft_to_fpcr_exc(env
);
326 return float64_to_t(fr
);
329 uint64_t helper_divt(CPUAlphaState
*env
, uint64_t a
, uint64_t b
)
333 fa
= t_to_float64(a
);
334 fb
= t_to_float64(b
);
335 fr
= float64_div(fa
, fb
, &FP_STATUS
);
336 env
->error_code
= soft_to_fpcr_exc(env
);
338 return float64_to_t(fr
);
341 uint64_t helper_sqrtt(CPUAlphaState
*env
, uint64_t a
)
345 fa
= t_to_float64(a
);
346 fr
= float64_sqrt(fa
, &FP_STATUS
);
347 env
->error_code
= soft_to_fpcr_exc(env
);
349 return float64_to_t(fr
);
353 uint64_t helper_cmptun(CPUAlphaState
*env
, uint64_t a
, uint64_t b
)
358 fa
= t_to_float64(a
);
359 fb
= t_to_float64(b
);
361 if (float64_unordered_quiet(fa
, fb
, &FP_STATUS
)) {
362 ret
= 0x4000000000000000ULL
;
364 env
->error_code
= soft_to_fpcr_exc(env
);
369 uint64_t helper_cmpteq(CPUAlphaState
*env
, uint64_t a
, uint64_t b
)
374 fa
= t_to_float64(a
);
375 fb
= t_to_float64(b
);
377 if (float64_eq_quiet(fa
, fb
, &FP_STATUS
)) {
378 ret
= 0x4000000000000000ULL
;
380 env
->error_code
= soft_to_fpcr_exc(env
);
385 uint64_t helper_cmptle(CPUAlphaState
*env
, uint64_t a
, uint64_t b
)
390 fa
= t_to_float64(a
);
391 fb
= t_to_float64(b
);
393 if (float64_le(fa
, fb
, &FP_STATUS
)) {
394 ret
= 0x4000000000000000ULL
;
396 env
->error_code
= soft_to_fpcr_exc(env
);
401 uint64_t helper_cmptlt(CPUAlphaState
*env
, uint64_t a
, uint64_t b
)
406 fa
= t_to_float64(a
);
407 fb
= t_to_float64(b
);
409 if (float64_lt(fa
, fb
, &FP_STATUS
)) {
410 ret
= 0x4000000000000000ULL
;
412 env
->error_code
= soft_to_fpcr_exc(env
);
417 /* Floating point format conversion */
418 uint64_t helper_cvtts(CPUAlphaState
*env
, uint64_t a
)
423 fa
= t_to_float64(a
);
424 fr
= float64_to_float32(fa
, &FP_STATUS
);
425 env
->error_code
= soft_to_fpcr_exc(env
);
427 return float32_to_s(fr
);
430 uint64_t helper_cvtst(CPUAlphaState
*env
, uint64_t a
)
435 fa
= s_to_float32(a
);
436 fr
= float32_to_float64(fa
, &FP_STATUS
);
437 env
->error_code
= soft_to_fpcr_exc(env
);
439 return float64_to_t(fr
);
442 uint64_t helper_cvtqs(CPUAlphaState
*env
, uint64_t a
)
444 float32 fr
= int64_to_float32(a
, &FP_STATUS
);
445 env
->error_code
= soft_to_fpcr_exc(env
);
447 return float32_to_s(fr
);
450 /* Implement float64 to uint64_t conversion without saturation -- we must
451 supply the truncated result. This behaviour is used by the compiler
452 to get unsigned conversion for free with the same instruction. */
454 static uint64_t do_cvttq(CPUAlphaState
*env
, uint64_t a
, int roundmode
)
456 uint64_t frac
, ret
= 0;
457 uint32_t exp
, sign
, exc
= 0;
461 exp
= (uint32_t)(a
>> 52) & 0x7ff;
462 frac
= a
& 0xfffffffffffffull
;
465 if (unlikely(frac
!= 0) && !env
->fp_status
.flush_inputs_to_zero
) {
468 } else if (exp
== 0x7ff) {
471 /* Restore implicit bit. */
472 frac
|= 0x10000000000000ull
;
474 shift
= exp
- 1023 - 52;
476 /* In this case the number is so large that we must shift
477 the fraction left. There is no rounding to do. */
481 /* Check for overflow. Note the special case of -0x1p63. */
482 if (shift
>= 11 && a
!= 0xC3E0000000000000ull
) {
483 exc
= FPCR_IOV
| FPCR_INE
;
488 /* In this case the number is smaller than the fraction as
489 represented by the 52 bit number. Here we must think
490 about rounding the result. Handle this by shifting the
491 fractional part of the number into the high bits of ROUND.
492 This will let us efficiently handle round-to-nearest. */
496 round
= frac
<< (64 - shift
);
498 /* The exponent is so small we shift out everything.
499 Leave a sticky bit for proper rounding below. */
507 case float_round_nearest_even
:
508 if (round
== (1ull << 63)) {
509 /* Fraction is exactly 0.5; round to even. */
511 } else if (round
> (1ull << 63)) {
515 case float_round_to_zero
:
520 case float_round_down
:
530 env
->error_code
= exc
;
535 uint64_t helper_cvttq(CPUAlphaState
*env
, uint64_t a
)
537 return do_cvttq(env
, a
, FP_STATUS
.float_rounding_mode
);
540 uint64_t helper_cvttq_c(CPUAlphaState
*env
, uint64_t a
)
542 return do_cvttq(env
, a
, float_round_to_zero
);
545 uint64_t helper_cvtqt(CPUAlphaState
*env
, uint64_t a
)
547 float64 fr
= int64_to_float64(a
, &FP_STATUS
);
548 env
->error_code
= soft_to_fpcr_exc(env
);
549 return float64_to_t(fr
);
552 uint64_t helper_cvtql(CPUAlphaState
*env
, uint64_t val
)
555 if (val
!= (int32_t)val
) {
556 exc
= FPCR_IOV
| FPCR_INE
;
558 env
->error_code
= exc
;
560 return ((val
& 0xc0000000) << 32) | ((val
& 0x3fffffff) << 29);