kvm-all: trace: strerror fixup
[qemu/ar7.git] / target-alpha / fpu_helper.c
blob5ab7d5e64db92bdc8939021fed09dc88a3d7295f
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/helper-proto.h"
23 #include "fpu/softfloat.h"
25 #define FP_STATUS (env->fp_status)
28 void helper_setroundmode(CPUAlphaState *env, uint32_t val)
30 set_float_rounding_mode(val, &FP_STATUS);
33 void helper_setflushzero(CPUAlphaState *env, uint32_t val)
35 set_flush_to_zero(val, &FP_STATUS);
38 #define CONVERT_BIT(X, SRC, DST) \
39 (SRC > DST ? (X) / (SRC / DST) & (DST) : ((X) & SRC) * (DST / SRC))
41 static uint32_t soft_to_fpcr_exc(CPUAlphaState *env)
43 uint8_t exc = get_float_exception_flags(&FP_STATUS);
44 uint32_t ret = 0;
46 if (unlikely(exc)) {
47 set_float_exception_flags(0, &FP_STATUS);
48 ret |= CONVERT_BIT(exc, float_flag_invalid, FPCR_INV);
49 ret |= CONVERT_BIT(exc, float_flag_divbyzero, FPCR_DZE);
50 ret |= CONVERT_BIT(exc, float_flag_overflow, FPCR_OVF);
51 ret |= CONVERT_BIT(exc, float_flag_underflow, FPCR_UNF);
52 ret |= CONVERT_BIT(exc, float_flag_inexact, FPCR_INE);
55 return ret;
58 static void fp_exc_raise1(CPUAlphaState *env, uintptr_t retaddr,
59 uint32_t exc, uint32_t regno, uint32_t hw_exc)
61 hw_exc |= CONVERT_BIT(exc, FPCR_INV, EXC_M_INV);
62 hw_exc |= CONVERT_BIT(exc, FPCR_DZE, EXC_M_DZE);
63 hw_exc |= CONVERT_BIT(exc, FPCR_OVF, EXC_M_FOV);
64 hw_exc |= CONVERT_BIT(exc, FPCR_UNF, EXC_M_UNF);
65 hw_exc |= CONVERT_BIT(exc, FPCR_INE, EXC_M_INE);
66 hw_exc |= CONVERT_BIT(exc, FPCR_IOV, EXC_M_IOV);
68 arith_excp(env, retaddr, hw_exc, 1ull << regno);
71 /* Raise exceptions for ieee fp insns without software completion.
72 In that case there are no exceptions that don't trap; the mask
73 doesn't apply. */
74 void helper_fp_exc_raise(CPUAlphaState *env, uint32_t ignore, uint32_t regno)
76 uint32_t exc = env->error_code;
77 if (exc) {
78 env->fpcr |= exc;
79 exc &= ~ignore;
80 if (exc) {
81 fp_exc_raise1(env, GETPC(), exc, regno, 0);
86 /* Raise exceptions for ieee fp insns with software completion. */
87 void helper_fp_exc_raise_s(CPUAlphaState *env, uint32_t ignore, uint32_t regno)
89 uint32_t exc = env->error_code & ~ignore;
90 if (exc) {
91 env->fpcr |= exc;
92 exc &= ~ignore;
93 if (exc) {
94 exc &= env->fpcr_exc_enable;
95 fp_exc_raise1(env, GETPC(), exc, regno, EXC_M_SWC);
100 /* Input handing without software completion. Trap for all
101 non-finite numbers. */
102 void helper_ieee_input(CPUAlphaState *env, uint64_t val)
104 uint32_t exp = (uint32_t)(val >> 52) & 0x7ff;
105 uint64_t frac = val & 0xfffffffffffffull;
107 if (exp == 0) {
108 /* Denormals without /S raise an exception. */
109 if (frac != 0) {
110 arith_excp(env, GETPC(), EXC_M_INV, 0);
112 } else if (exp == 0x7ff) {
113 /* Infinity or NaN. */
114 env->fpcr |= FPCR_INV;
115 arith_excp(env, GETPC(), EXC_M_INV, 0);
119 /* Similar, but does not trap for infinities. Used for comparisons. */
120 void helper_ieee_input_cmp(CPUAlphaState *env, uint64_t val)
122 uint32_t exp = (uint32_t)(val >> 52) & 0x7ff;
123 uint64_t frac = val & 0xfffffffffffffull;
125 if (exp == 0) {
126 /* Denormals without /S raise an exception. */
127 if (frac != 0) {
128 arith_excp(env, GETPC(), EXC_M_INV, 0);
130 } else if (exp == 0x7ff && frac) {
131 /* NaN. */
132 env->fpcr |= FPCR_INV;
133 arith_excp(env, GETPC(), EXC_M_INV, 0);
137 /* Input handing with software completion. Trap for denorms, unless DNZ
138 is set. If we try to support DNOD (which none of the produced hardware
139 did, AFAICS), we'll need to suppress the trap when FPCR.DNOD is set;
140 then the code downstream of that will need to cope with denorms sans
141 flush_input_to_zero. Most of it should work sanely, but there's
142 nothing to compare with. */
143 void helper_ieee_input_s(CPUAlphaState *env, uint64_t val)
145 if (unlikely(2 * val - 1 < 0x1fffffffffffffull)
146 && !env->fp_status.flush_inputs_to_zero) {
147 arith_excp(env, GETPC(), EXC_M_INV | EXC_M_SWC, 0);
151 /* S floating (single) */
153 /* Taken from linux/arch/alpha/kernel/traps.c, s_mem_to_reg. */
154 static inline uint64_t float32_to_s_int(uint32_t fi)
156 uint32_t frac = fi & 0x7fffff;
157 uint32_t sign = fi >> 31;
158 uint32_t exp_msb = (fi >> 30) & 1;
159 uint32_t exp_low = (fi >> 23) & 0x7f;
160 uint32_t exp;
162 exp = (exp_msb << 10) | exp_low;
163 if (exp_msb) {
164 if (exp_low == 0x7f) {
165 exp = 0x7ff;
167 } else {
168 if (exp_low != 0x00) {
169 exp |= 0x380;
173 return (((uint64_t)sign << 63)
174 | ((uint64_t)exp << 52)
175 | ((uint64_t)frac << 29));
178 static inline uint64_t float32_to_s(float32 fa)
180 CPU_FloatU a;
181 a.f = fa;
182 return float32_to_s_int(a.l);
185 static inline uint32_t s_to_float32_int(uint64_t a)
187 return ((a >> 32) & 0xc0000000) | ((a >> 29) & 0x3fffffff);
190 static inline float32 s_to_float32(uint64_t a)
192 CPU_FloatU r;
193 r.l = s_to_float32_int(a);
194 return r.f;
197 uint32_t helper_s_to_memory(uint64_t a)
199 return s_to_float32_int(a);
202 uint64_t helper_memory_to_s(uint32_t a)
204 return float32_to_s_int(a);
207 uint64_t helper_adds(CPUAlphaState *env, uint64_t a, uint64_t b)
209 float32 fa, fb, fr;
211 fa = s_to_float32(a);
212 fb = s_to_float32(b);
213 fr = float32_add(fa, fb, &FP_STATUS);
214 env->error_code = soft_to_fpcr_exc(env);
216 return float32_to_s(fr);
219 uint64_t helper_subs(CPUAlphaState *env, uint64_t a, uint64_t b)
221 float32 fa, fb, fr;
223 fa = s_to_float32(a);
224 fb = s_to_float32(b);
225 fr = float32_sub(fa, fb, &FP_STATUS);
226 env->error_code = soft_to_fpcr_exc(env);
228 return float32_to_s(fr);
231 uint64_t helper_muls(CPUAlphaState *env, uint64_t a, uint64_t b)
233 float32 fa, fb, fr;
235 fa = s_to_float32(a);
236 fb = s_to_float32(b);
237 fr = float32_mul(fa, fb, &FP_STATUS);
238 env->error_code = soft_to_fpcr_exc(env);
240 return float32_to_s(fr);
243 uint64_t helper_divs(CPUAlphaState *env, uint64_t a, uint64_t b)
245 float32 fa, fb, fr;
247 fa = s_to_float32(a);
248 fb = s_to_float32(b);
249 fr = float32_div(fa, fb, &FP_STATUS);
250 env->error_code = soft_to_fpcr_exc(env);
252 return float32_to_s(fr);
255 uint64_t helper_sqrts(CPUAlphaState *env, uint64_t a)
257 float32 fa, fr;
259 fa = s_to_float32(a);
260 fr = float32_sqrt(fa, &FP_STATUS);
261 env->error_code = soft_to_fpcr_exc(env);
263 return float32_to_s(fr);
267 /* T floating (double) */
268 static inline float64 t_to_float64(uint64_t a)
270 /* Memory format is the same as float64 */
271 CPU_DoubleU r;
272 r.ll = a;
273 return r.d;
276 static inline uint64_t float64_to_t(float64 fa)
278 /* Memory format is the same as float64 */
279 CPU_DoubleU r;
280 r.d = fa;
281 return r.ll;
284 uint64_t helper_addt(CPUAlphaState *env, uint64_t a, uint64_t b)
286 float64 fa, fb, fr;
288 fa = t_to_float64(a);
289 fb = t_to_float64(b);
290 fr = float64_add(fa, fb, &FP_STATUS);
291 env->error_code = soft_to_fpcr_exc(env);
293 return float64_to_t(fr);
296 uint64_t helper_subt(CPUAlphaState *env, uint64_t a, uint64_t b)
298 float64 fa, fb, fr;
300 fa = t_to_float64(a);
301 fb = t_to_float64(b);
302 fr = float64_sub(fa, fb, &FP_STATUS);
303 env->error_code = soft_to_fpcr_exc(env);
305 return float64_to_t(fr);
308 uint64_t helper_mult(CPUAlphaState *env, uint64_t a, uint64_t b)
310 float64 fa, fb, fr;
312 fa = t_to_float64(a);
313 fb = t_to_float64(b);
314 fr = float64_mul(fa, fb, &FP_STATUS);
315 env->error_code = soft_to_fpcr_exc(env);
317 return float64_to_t(fr);
320 uint64_t helper_divt(CPUAlphaState *env, uint64_t a, uint64_t b)
322 float64 fa, fb, fr;
324 fa = t_to_float64(a);
325 fb = t_to_float64(b);
326 fr = float64_div(fa, fb, &FP_STATUS);
327 env->error_code = soft_to_fpcr_exc(env);
329 return float64_to_t(fr);
332 uint64_t helper_sqrtt(CPUAlphaState *env, uint64_t a)
334 float64 fa, fr;
336 fa = t_to_float64(a);
337 fr = float64_sqrt(fa, &FP_STATUS);
338 env->error_code = soft_to_fpcr_exc(env);
340 return float64_to_t(fr);
343 /* Comparisons */
344 uint64_t helper_cmptun(CPUAlphaState *env, uint64_t a, uint64_t b)
346 float64 fa, fb;
347 uint64_t ret = 0;
349 fa = t_to_float64(a);
350 fb = t_to_float64(b);
352 if (float64_unordered_quiet(fa, fb, &FP_STATUS)) {
353 ret = 0x4000000000000000ULL;
355 env->error_code = soft_to_fpcr_exc(env);
357 return ret;
360 uint64_t helper_cmpteq(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_eq_quiet(fa, fb, &FP_STATUS)) {
369 ret = 0x4000000000000000ULL;
371 env->error_code = soft_to_fpcr_exc(env);
373 return ret;
376 uint64_t helper_cmptle(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_le(fa, fb, &FP_STATUS)) {
385 ret = 0x4000000000000000ULL;
387 env->error_code = soft_to_fpcr_exc(env);
389 return ret;
392 uint64_t helper_cmptlt(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_lt(fa, fb, &FP_STATUS)) {
401 ret = 0x4000000000000000ULL;
403 env->error_code = soft_to_fpcr_exc(env);
405 return ret;
408 /* Floating point format conversion */
409 uint64_t helper_cvtts(CPUAlphaState *env, uint64_t a)
411 float64 fa;
412 float32 fr;
414 fa = t_to_float64(a);
415 fr = float64_to_float32(fa, &FP_STATUS);
416 env->error_code = soft_to_fpcr_exc(env);
418 return float32_to_s(fr);
421 uint64_t helper_cvtst(CPUAlphaState *env, uint64_t a)
423 float32 fa;
424 float64 fr;
426 fa = s_to_float32(a);
427 fr = float32_to_float64(fa, &FP_STATUS);
428 env->error_code = soft_to_fpcr_exc(env);
430 return float64_to_t(fr);
433 uint64_t helper_cvtqs(CPUAlphaState *env, uint64_t a)
435 float32 fr = int64_to_float32(a, &FP_STATUS);
436 env->error_code = soft_to_fpcr_exc(env);
438 return float32_to_s(fr);
441 /* Implement float64 to uint64_t conversion without saturation -- we must
442 supply the truncated result. This behaviour is used by the compiler
443 to get unsigned conversion for free with the same instruction. */
445 static uint64_t do_cvttq(CPUAlphaState *env, uint64_t a, int roundmode)
447 uint64_t frac, ret = 0;
448 uint32_t exp, sign, exc = 0;
449 int shift;
451 sign = (a >> 63);
452 exp = (uint32_t)(a >> 52) & 0x7ff;
453 frac = a & 0xfffffffffffffull;
455 if (exp == 0) {
456 if (unlikely(frac != 0) && !env->fp_status.flush_inputs_to_zero) {
457 goto do_underflow;
459 } else if (exp == 0x7ff) {
460 exc = FPCR_INV;
461 } else {
462 /* Restore implicit bit. */
463 frac |= 0x10000000000000ull;
465 shift = exp - 1023 - 52;
466 if (shift >= 0) {
467 /* In this case the number is so large that we must shift
468 the fraction left. There is no rounding to do. */
469 if (shift < 64) {
470 ret = frac << shift;
472 /* Check for overflow. Note the special case of -0x1p63. */
473 if (shift >= 11 && a != 0xC3E0000000000000ull) {
474 exc = FPCR_IOV | FPCR_INE;
476 } else {
477 uint64_t round;
479 /* In this case the number is smaller than the fraction as
480 represented by the 52 bit number. Here we must think
481 about rounding the result. Handle this by shifting the
482 fractional part of the number into the high bits of ROUND.
483 This will let us efficiently handle round-to-nearest. */
484 shift = -shift;
485 if (shift < 63) {
486 ret = frac >> shift;
487 round = frac << (64 - shift);
488 } else {
489 /* The exponent is so small we shift out everything.
490 Leave a sticky bit for proper rounding below. */
491 do_underflow:
492 round = 1;
495 if (round) {
496 exc = FPCR_INE;
497 switch (roundmode) {
498 case float_round_nearest_even:
499 if (round == (1ull << 63)) {
500 /* Fraction is exactly 0.5; round to even. */
501 ret += (ret & 1);
502 } else if (round > (1ull << 63)) {
503 ret += 1;
505 break;
506 case float_round_to_zero:
507 break;
508 case float_round_up:
509 ret += 1 - sign;
510 break;
511 case float_round_down:
512 ret += sign;
513 break;
517 if (sign) {
518 ret = -ret;
521 env->error_code = exc;
523 return ret;
526 uint64_t helper_cvttq(CPUAlphaState *env, uint64_t a)
528 return do_cvttq(env, a, FP_STATUS.float_rounding_mode);
531 uint64_t helper_cvttq_c(CPUAlphaState *env, uint64_t a)
533 return do_cvttq(env, a, float_round_to_zero);
536 uint64_t helper_cvtqt(CPUAlphaState *env, uint64_t a)
538 float64 fr = int64_to_float64(a, &FP_STATUS);
539 env->error_code = soft_to_fpcr_exc(env);
540 return float64_to_t(fr);
543 uint64_t helper_cvtql(CPUAlphaState *env, uint64_t val)
545 uint32_t exc = 0;
546 if (val != (int32_t)val) {
547 exc = FPCR_IOV | FPCR_INE;
549 env->error_code = exc;
551 return ((val & 0xc0000000) << 32) | ((val & 0x3fffffff) << 29);