Merge remote-tracking branch 'remotes/vivier2/tags/linux-user-for-4.1-pull-request...
[qemu/ar7.git] / target / alpha / fpu_helper.c
blob62a066d9020305757214e4552b455ff6077a8678
1 /*
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"
21 #include "cpu.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);
45 uint32_t ret = 0;
47 if (unlikely(exc)) {
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);
56 return ret;
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
74 doesn't apply. */
75 void helper_fp_exc_raise(CPUAlphaState *env, uint32_t ignore, uint32_t regno)
77 uint32_t exc = env->error_code;
78 if (exc) {
79 env->fpcr |= exc;
80 exc &= ~ignore;
81 if (exc) {
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;
91 if (exc) {
92 env->fpcr |= exc;
93 exc &= ~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)) {
100 return;
102 #else
104 * In system mode, the software handler gets invoked
105 * for any non-ignored exception.
107 if (!exc) {
108 return;
110 #endif
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;
123 if (exp == 0) {
124 /* Denormals without /S raise an exception. */
125 if (frac != 0) {
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;
141 if (exp == 0) {
142 /* Denormals without /S raise an exception. */
143 if (frac != 0) {
144 arith_excp(env, GETPC(), EXC_M_INV, 0);
146 } else if (exp == 0x7ff && frac) {
147 /* NaN. */
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;
176 uint32_t exp;
178 exp = (exp_msb << 10) | exp_low;
179 if (exp_msb) {
180 if (exp_low == 0x7f) {
181 exp = 0x7ff;
183 } else {
184 if (exp_low != 0x00) {
185 exp |= 0x380;
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)
196 CPU_FloatU a;
197 a.f = 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)
208 CPU_FloatU r;
209 r.l = s_to_float32_int(a);
210 return r.f;
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)
225 float32 fa, fb, fr;
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)
237 float32 fa, fb, fr;
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)
249 float32 fa, fb, fr;
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)
261 float32 fa, fb, fr;
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)
273 float32 fa, fr;
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 */
287 CPU_DoubleU r;
288 r.ll = a;
289 return r.d;
292 static inline uint64_t float64_to_t(float64 fa)
294 /* Memory format is the same as float64 */
295 CPU_DoubleU r;
296 r.d = fa;
297 return r.ll;
300 uint64_t helper_addt(CPUAlphaState *env, uint64_t a, uint64_t b)
302 float64 fa, fb, fr;
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)
314 float64 fa, fb, fr;
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)
326 float64 fa, fb, fr;
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)
338 float64 fa, fb, fr;
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)
350 float64 fa, fr;
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);
359 /* Comparisons */
360 uint64_t helper_cmptun(CPUAlphaState *env, uint64_t a, uint64_t b)
362 float64 fa, fb;
363 uint64_t ret = 0;
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);
373 return ret;
376 uint64_t helper_cmpteq(CPUAlphaState *env, uint64_t a, uint64_t b)
378 float64 fa, fb;
379 uint64_t ret = 0;
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);
389 return ret;
392 uint64_t helper_cmptle(CPUAlphaState *env, uint64_t a, uint64_t b)
394 float64 fa, fb;
395 uint64_t ret = 0;
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);
405 return ret;
408 uint64_t helper_cmptlt(CPUAlphaState *env, uint64_t a, uint64_t b)
410 float64 fa, fb;
411 uint64_t ret = 0;
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);
421 return ret;
424 /* Floating point format conversion */
425 uint64_t helper_cvtts(CPUAlphaState *env, uint64_t a)
427 float64 fa;
428 float32 fr;
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)
439 float32 fa;
440 float64 fr;
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;
465 int shift;
467 sign = (a >> 63);
468 exp = (uint32_t)(a >> 52) & 0x7ff;
469 frac = a & 0xfffffffffffffull;
471 if (exp == 0) {
472 if (unlikely(frac != 0) && !env->fp_status.flush_inputs_to_zero) {
473 goto do_underflow;
475 } else if (exp == 0x7ff) {
476 exc = FPCR_INV;
477 } else {
478 /* Restore implicit bit. */
479 frac |= 0x10000000000000ull;
481 shift = exp - 1023 - 52;
482 if (shift >= 0) {
483 /* In this case the number is so large that we must shift
484 the fraction left. There is no rounding to do. */
485 if (shift < 64) {
486 ret = frac << shift;
488 /* Check for overflow. Note the special case of -0x1p63. */
489 if (shift >= 11 && a != 0xC3E0000000000000ull) {
490 exc = FPCR_IOV | FPCR_INE;
492 } else {
493 uint64_t round;
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. */
500 shift = -shift;
501 if (shift < 63) {
502 ret = frac >> shift;
503 round = frac << (64 - shift);
504 } else {
505 /* The exponent is so small we shift out everything.
506 Leave a sticky bit for proper rounding below. */
507 do_underflow:
508 round = 1;
511 if (round) {
512 exc = FPCR_INE;
513 switch (roundmode) {
514 case float_round_nearest_even:
515 if (round == (1ull << 63)) {
516 /* Fraction is exactly 0.5; round to even. */
517 ret += (ret & 1);
518 } else if (round > (1ull << 63)) {
519 ret += 1;
521 break;
522 case float_round_to_zero:
523 break;
524 case float_round_up:
525 ret += 1 - sign;
526 break;
527 case float_round_down:
528 ret += sign;
529 break;
533 if (sign) {
534 ret = -ret;
537 env->error_code = exc;
539 return ret;
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)
561 uint32_t exc = 0;
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);