]>
git.proxmox.com Git - mirror_qemu.git/blob - target/alpha/fpu_helper.c
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
;
94 #ifdef CONFIG_USER_ONLY
96 * In user mode, the kernel's software handler only
97 * delivers a signal if the exception is enabled.
99 if (!(exc
& env
->fpcr_exc_enable
)) {
104 * In system mode, the software handler gets invoked
105 * for any non-ignored exception.
111 exc
&= env
->fpcr_exc_enable
;
112 fp_exc_raise1(env
, GETPC(), exc
, regno
, EXC_M_SWC
);
116 /* Input handing without software completion. Trap for all
117 non-finite numbers. */
118 void helper_ieee_input(CPUAlphaState
*env
, uint64_t val
)
120 uint32_t exp
= (uint32_t)(val
>> 52) & 0x7ff;
121 uint64_t frac
= val
& 0xfffffffffffffull
;
124 /* Denormals without /S raise an exception. */
126 arith_excp(env
, GETPC(), EXC_M_INV
, 0);
128 } else if (exp
== 0x7ff) {
129 /* Infinity or NaN. */
130 env
->fpcr
|= FPCR_INV
;
131 arith_excp(env
, GETPC(), EXC_M_INV
, 0);
135 /* Similar, but does not trap for infinities. Used for comparisons. */
136 void helper_ieee_input_cmp(CPUAlphaState
*env
, uint64_t val
)
138 uint32_t exp
= (uint32_t)(val
>> 52) & 0x7ff;
139 uint64_t frac
= val
& 0xfffffffffffffull
;
142 /* Denormals without /S raise an exception. */
144 arith_excp(env
, GETPC(), EXC_M_INV
, 0);
146 } else if (exp
== 0x7ff && frac
) {
148 env
->fpcr
|= FPCR_INV
;
149 arith_excp(env
, GETPC(), EXC_M_INV
, 0);
153 /* Input handing with software completion. Trap for denorms, unless DNZ
154 is set. If we try to support DNOD (which none of the produced hardware
155 did, AFAICS), we'll need to suppress the trap when FPCR.DNOD is set;
156 then the code downstream of that will need to cope with denorms sans
157 flush_input_to_zero. Most of it should work sanely, but there's
158 nothing to compare with. */
159 void helper_ieee_input_s(CPUAlphaState
*env
, uint64_t val
)
161 if (unlikely(2 * val
- 1 < 0x1fffffffffffffull
)
162 && !env
->fp_status
.flush_inputs_to_zero
) {
163 arith_excp(env
, GETPC(), EXC_M_INV
| EXC_M_SWC
, 0);
167 /* S floating (single) */
169 /* Taken from linux/arch/alpha/kernel/traps.c, s_mem_to_reg. */
170 static inline uint64_t float32_to_s_int(uint32_t fi
)
172 uint32_t frac
= fi
& 0x7fffff;
173 uint32_t sign
= fi
>> 31;
174 uint32_t exp_msb
= (fi
>> 30) & 1;
175 uint32_t exp_low
= (fi
>> 23) & 0x7f;
178 exp
= (exp_msb
<< 10) | exp_low
;
180 if (exp_low
== 0x7f) {
184 if (exp_low
!= 0x00) {
189 return (((uint64_t)sign
<< 63)
190 | ((uint64_t)exp
<< 52)
191 | ((uint64_t)frac
<< 29));
194 static inline uint64_t float32_to_s(float32 fa
)
198 return float32_to_s_int(a
.l
);
201 static inline uint32_t s_to_float32_int(uint64_t a
)
203 return ((a
>> 32) & 0xc0000000) | ((a
>> 29) & 0x3fffffff);
206 static inline float32
s_to_float32(uint64_t a
)
209 r
.l
= s_to_float32_int(a
);
213 uint32_t helper_s_to_memory(uint64_t a
)
215 return s_to_float32_int(a
);
218 uint64_t helper_memory_to_s(uint32_t a
)
220 return float32_to_s_int(a
);
223 uint64_t helper_adds(CPUAlphaState
*env
, uint64_t a
, uint64_t b
)
227 fa
= s_to_float32(a
);
228 fb
= s_to_float32(b
);
229 fr
= float32_add(fa
, fb
, &FP_STATUS
);
230 env
->error_code
= soft_to_fpcr_exc(env
);
232 return float32_to_s(fr
);
235 uint64_t helper_subs(CPUAlphaState
*env
, uint64_t a
, uint64_t b
)
239 fa
= s_to_float32(a
);
240 fb
= s_to_float32(b
);
241 fr
= float32_sub(fa
, fb
, &FP_STATUS
);
242 env
->error_code
= soft_to_fpcr_exc(env
);
244 return float32_to_s(fr
);
247 uint64_t helper_muls(CPUAlphaState
*env
, uint64_t a
, uint64_t b
)
251 fa
= s_to_float32(a
);
252 fb
= s_to_float32(b
);
253 fr
= float32_mul(fa
, fb
, &FP_STATUS
);
254 env
->error_code
= soft_to_fpcr_exc(env
);
256 return float32_to_s(fr
);
259 uint64_t helper_divs(CPUAlphaState
*env
, uint64_t a
, uint64_t b
)
263 fa
= s_to_float32(a
);
264 fb
= s_to_float32(b
);
265 fr
= float32_div(fa
, fb
, &FP_STATUS
);
266 env
->error_code
= soft_to_fpcr_exc(env
);
268 return float32_to_s(fr
);
271 uint64_t helper_sqrts(CPUAlphaState
*env
, uint64_t a
)
275 fa
= s_to_float32(a
);
276 fr
= float32_sqrt(fa
, &FP_STATUS
);
277 env
->error_code
= soft_to_fpcr_exc(env
);
279 return float32_to_s(fr
);
283 /* T floating (double) */
284 static inline float64
t_to_float64(uint64_t a
)
286 /* Memory format is the same as float64 */
292 static inline uint64_t float64_to_t(float64 fa
)
294 /* Memory format is the same as float64 */
300 uint64_t helper_addt(CPUAlphaState
*env
, uint64_t a
, uint64_t b
)
304 fa
= t_to_float64(a
);
305 fb
= t_to_float64(b
);
306 fr
= float64_add(fa
, fb
, &FP_STATUS
);
307 env
->error_code
= soft_to_fpcr_exc(env
);
309 return float64_to_t(fr
);
312 uint64_t helper_subt(CPUAlphaState
*env
, uint64_t a
, uint64_t b
)
316 fa
= t_to_float64(a
);
317 fb
= t_to_float64(b
);
318 fr
= float64_sub(fa
, fb
, &FP_STATUS
);
319 env
->error_code
= soft_to_fpcr_exc(env
);
321 return float64_to_t(fr
);
324 uint64_t helper_mult(CPUAlphaState
*env
, uint64_t a
, uint64_t b
)
328 fa
= t_to_float64(a
);
329 fb
= t_to_float64(b
);
330 fr
= float64_mul(fa
, fb
, &FP_STATUS
);
331 env
->error_code
= soft_to_fpcr_exc(env
);
333 return float64_to_t(fr
);
336 uint64_t helper_divt(CPUAlphaState
*env
, uint64_t a
, uint64_t b
)
340 fa
= t_to_float64(a
);
341 fb
= t_to_float64(b
);
342 fr
= float64_div(fa
, fb
, &FP_STATUS
);
343 env
->error_code
= soft_to_fpcr_exc(env
);
345 return float64_to_t(fr
);
348 uint64_t helper_sqrtt(CPUAlphaState
*env
, uint64_t a
)
352 fa
= t_to_float64(a
);
353 fr
= float64_sqrt(fa
, &FP_STATUS
);
354 env
->error_code
= soft_to_fpcr_exc(env
);
356 return float64_to_t(fr
);
360 uint64_t helper_cmptun(CPUAlphaState
*env
, uint64_t a
, uint64_t b
)
365 fa
= t_to_float64(a
);
366 fb
= t_to_float64(b
);
368 if (float64_unordered_quiet(fa
, fb
, &FP_STATUS
)) {
369 ret
= 0x4000000000000000ULL
;
371 env
->error_code
= soft_to_fpcr_exc(env
);
376 uint64_t helper_cmpteq(CPUAlphaState
*env
, uint64_t a
, uint64_t b
)
381 fa
= t_to_float64(a
);
382 fb
= t_to_float64(b
);
384 if (float64_eq_quiet(fa
, fb
, &FP_STATUS
)) {
385 ret
= 0x4000000000000000ULL
;
387 env
->error_code
= soft_to_fpcr_exc(env
);
392 uint64_t helper_cmptle(CPUAlphaState
*env
, uint64_t a
, uint64_t b
)
397 fa
= t_to_float64(a
);
398 fb
= t_to_float64(b
);
400 if (float64_le(fa
, fb
, &FP_STATUS
)) {
401 ret
= 0x4000000000000000ULL
;
403 env
->error_code
= soft_to_fpcr_exc(env
);
408 uint64_t helper_cmptlt(CPUAlphaState
*env
, uint64_t a
, uint64_t b
)
413 fa
= t_to_float64(a
);
414 fb
= t_to_float64(b
);
416 if (float64_lt(fa
, fb
, &FP_STATUS
)) {
417 ret
= 0x4000000000000000ULL
;
419 env
->error_code
= soft_to_fpcr_exc(env
);
424 /* Floating point format conversion */
425 uint64_t helper_cvtts(CPUAlphaState
*env
, uint64_t a
)
430 fa
= t_to_float64(a
);
431 fr
= float64_to_float32(fa
, &FP_STATUS
);
432 env
->error_code
= soft_to_fpcr_exc(env
);
434 return float32_to_s(fr
);
437 uint64_t helper_cvtst(CPUAlphaState
*env
, uint64_t a
)
442 fa
= s_to_float32(a
);
443 fr
= float32_to_float64(fa
, &FP_STATUS
);
444 env
->error_code
= soft_to_fpcr_exc(env
);
446 return float64_to_t(fr
);
449 uint64_t helper_cvtqs(CPUAlphaState
*env
, uint64_t a
)
451 float32 fr
= int64_to_float32(a
, &FP_STATUS
);
452 env
->error_code
= soft_to_fpcr_exc(env
);
454 return float32_to_s(fr
);
457 /* Implement float64 to uint64_t conversion without saturation -- we must
458 supply the truncated result. This behaviour is used by the compiler
459 to get unsigned conversion for free with the same instruction. */
461 static uint64_t do_cvttq(CPUAlphaState
*env
, uint64_t a
, int roundmode
)
463 uint64_t frac
, ret
= 0;
464 uint32_t exp
, sign
, exc
= 0;
468 exp
= (uint32_t)(a
>> 52) & 0x7ff;
469 frac
= a
& 0xfffffffffffffull
;
472 if (unlikely(frac
!= 0) && !env
->fp_status
.flush_inputs_to_zero
) {
475 } else if (exp
== 0x7ff) {
478 /* Restore implicit bit. */
479 frac
|= 0x10000000000000ull
;
481 shift
= exp
- 1023 - 52;
483 /* In this case the number is so large that we must shift
484 the fraction left. There is no rounding to do. */
488 /* Check for overflow. Note the special case of -0x1p63. */
489 if (shift
>= 11 && a
!= 0xC3E0000000000000ull
) {
490 exc
= FPCR_IOV
| FPCR_INE
;
495 /* In this case the number is smaller than the fraction as
496 represented by the 52 bit number. Here we must think
497 about rounding the result. Handle this by shifting the
498 fractional part of the number into the high bits of ROUND.
499 This will let us efficiently handle round-to-nearest. */
503 round
= frac
<< (64 - shift
);
505 /* The exponent is so small we shift out everything.
506 Leave a sticky bit for proper rounding below. */
514 case float_round_nearest_even
:
515 if (round
== (1ull << 63)) {
516 /* Fraction is exactly 0.5; round to even. */
518 } else if (round
> (1ull << 63)) {
522 case float_round_to_zero
:
527 case float_round_down
:
537 env
->error_code
= exc
;
542 uint64_t helper_cvttq(CPUAlphaState
*env
, uint64_t a
)
544 return do_cvttq(env
, a
, FP_STATUS
.float_rounding_mode
);
547 uint64_t helper_cvttq_c(CPUAlphaState
*env
, uint64_t a
)
549 return do_cvttq(env
, a
, float_round_to_zero
);
552 uint64_t helper_cvtqt(CPUAlphaState
*env
, uint64_t a
)
554 float64 fr
= int64_to_float64(a
, &FP_STATUS
);
555 env
->error_code
= soft_to_fpcr_exc(env
);
556 return float64_to_t(fr
);
559 uint64_t helper_cvtql(CPUAlphaState
*env
, uint64_t val
)
562 if (val
!= (int32_t)val
) {
563 exc
= FPCR_IOV
| FPCR_INE
;
565 env
->error_code
= exc
;
567 return ((val
& 0xc0000000) << 32) | ((val
& 0x3fffffff) << 29);