Merge remote-tracking branch 'remotes/juanquintela/tags/migration/20150715-1' into...
[qemu.git] / target-alpha / fpu_helper.c
blobb091aa842a33cc409591836902294ba66b5eb806
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 "cpu.h"
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 #define CONVERT_BIT(X, SRC, DST) \
38 (SRC > DST ? (X) / (SRC / DST) & (DST) : ((X) & SRC) * (DST / SRC))
40 static uint32_t soft_to_fpcr_exc(CPUAlphaState *env)
42 uint8_t exc = get_float_exception_flags(&FP_STATUS);
43 uint32_t ret = 0;
45 if (unlikely(exc)) {
46 set_float_exception_flags(0, &FP_STATUS);
47 ret |= CONVERT_BIT(exc, float_flag_invalid, FPCR_INV);
48 ret |= CONVERT_BIT(exc, float_flag_divbyzero, FPCR_DZE);
49 ret |= CONVERT_BIT(exc, float_flag_overflow, FPCR_OVF);
50 ret |= CONVERT_BIT(exc, float_flag_underflow, FPCR_UNF);
51 ret |= CONVERT_BIT(exc, float_flag_inexact, FPCR_INE);
54 return ret;
57 static void fp_exc_raise1(CPUAlphaState *env, uintptr_t retaddr,
58 uint32_t exc, uint32_t regno, uint32_t hw_exc)
60 hw_exc |= CONVERT_BIT(exc, FPCR_INV, EXC_M_INV);
61 hw_exc |= CONVERT_BIT(exc, FPCR_DZE, EXC_M_DZE);
62 hw_exc |= CONVERT_BIT(exc, FPCR_OVF, EXC_M_FOV);
63 hw_exc |= CONVERT_BIT(exc, FPCR_UNF, EXC_M_UNF);
64 hw_exc |= CONVERT_BIT(exc, FPCR_INE, EXC_M_INE);
65 hw_exc |= CONVERT_BIT(exc, FPCR_IOV, EXC_M_IOV);
67 arith_excp(env, retaddr, hw_exc, 1ull << regno);
70 /* Raise exceptions for ieee fp insns without software completion.
71 In that case there are no exceptions that don't trap; the mask
72 doesn't apply. */
73 void helper_fp_exc_raise(CPUAlphaState *env, uint32_t ignore, uint32_t regno)
75 uint32_t exc = env->error_code;
76 if (exc) {
77 env->fpcr |= exc;
78 exc &= ~ignore;
79 if (exc) {
80 fp_exc_raise1(env, GETPC(), exc, regno, 0);
85 /* Raise exceptions for ieee fp insns with software completion. */
86 void helper_fp_exc_raise_s(CPUAlphaState *env, uint32_t ignore, uint32_t regno)
88 uint32_t exc = env->error_code & ~ignore;
89 if (exc) {
90 env->fpcr |= exc;
91 exc &= ~ignore;
92 if (exc) {
93 exc &= env->fpcr_exc_enable;
94 fp_exc_raise1(env, GETPC(), exc, regno, EXC_M_SWC);
99 /* Input handing without software completion. Trap for all
100 non-finite numbers. */
101 void helper_ieee_input(CPUAlphaState *env, uint64_t val)
103 uint32_t exp = (uint32_t)(val >> 52) & 0x7ff;
104 uint64_t frac = val & 0xfffffffffffffull;
106 if (exp == 0) {
107 /* Denormals without /S raise an exception. */
108 if (frac != 0) {
109 arith_excp(env, GETPC(), EXC_M_INV, 0);
111 } else if (exp == 0x7ff) {
112 /* Infinity or NaN. */
113 env->fpcr |= FPCR_INV;
114 arith_excp(env, GETPC(), EXC_M_INV, 0);
118 /* Similar, but does not trap for infinities. Used for comparisons. */
119 void helper_ieee_input_cmp(CPUAlphaState *env, uint64_t val)
121 uint32_t exp = (uint32_t)(val >> 52) & 0x7ff;
122 uint64_t frac = val & 0xfffffffffffffull;
124 if (exp == 0) {
125 /* Denormals without /S raise an exception. */
126 if (frac != 0) {
127 arith_excp(env, GETPC(), EXC_M_INV, 0);
129 } else if (exp == 0x7ff && frac) {
130 /* NaN. */
131 env->fpcr |= FPCR_INV;
132 arith_excp(env, GETPC(), EXC_M_INV, 0);
136 /* Input handing with software completion. Trap for denorms, unless DNZ
137 is set. If we try to support DNOD (which none of the produced hardware
138 did, AFAICS), we'll need to suppress the trap when FPCR.DNOD is set;
139 then the code downstream of that will need to cope with denorms sans
140 flush_input_to_zero. Most of it should work sanely, but there's
141 nothing to compare with. */
142 void helper_ieee_input_s(CPUAlphaState *env, uint64_t val)
144 if (unlikely(2 * val - 1 < 0x1fffffffffffffull)
145 && !env->fp_status.flush_inputs_to_zero) {
146 arith_excp(env, GETPC(), EXC_M_INV | EXC_M_SWC, 0);
150 /* S floating (single) */
152 /* Taken from linux/arch/alpha/kernel/traps.c, s_mem_to_reg. */
153 static inline uint64_t float32_to_s_int(uint32_t fi)
155 uint32_t frac = fi & 0x7fffff;
156 uint32_t sign = fi >> 31;
157 uint32_t exp_msb = (fi >> 30) & 1;
158 uint32_t exp_low = (fi >> 23) & 0x7f;
159 uint32_t exp;
161 exp = (exp_msb << 10) | exp_low;
162 if (exp_msb) {
163 if (exp_low == 0x7f) {
164 exp = 0x7ff;
166 } else {
167 if (exp_low != 0x00) {
168 exp |= 0x380;
172 return (((uint64_t)sign << 63)
173 | ((uint64_t)exp << 52)
174 | ((uint64_t)frac << 29));
177 static inline uint64_t float32_to_s(float32 fa)
179 CPU_FloatU a;
180 a.f = fa;
181 return float32_to_s_int(a.l);
184 static inline uint32_t s_to_float32_int(uint64_t a)
186 return ((a >> 32) & 0xc0000000) | ((a >> 29) & 0x3fffffff);
189 static inline float32 s_to_float32(uint64_t a)
191 CPU_FloatU r;
192 r.l = s_to_float32_int(a);
193 return r.f;
196 uint32_t helper_s_to_memory(uint64_t a)
198 return s_to_float32_int(a);
201 uint64_t helper_memory_to_s(uint32_t a)
203 return float32_to_s_int(a);
206 uint64_t helper_adds(CPUAlphaState *env, uint64_t a, uint64_t b)
208 float32 fa, fb, fr;
210 fa = s_to_float32(a);
211 fb = s_to_float32(b);
212 fr = float32_add(fa, fb, &FP_STATUS);
213 env->error_code = soft_to_fpcr_exc(env);
215 return float32_to_s(fr);
218 uint64_t helper_subs(CPUAlphaState *env, uint64_t a, uint64_t b)
220 float32 fa, fb, fr;
222 fa = s_to_float32(a);
223 fb = s_to_float32(b);
224 fr = float32_sub(fa, fb, &FP_STATUS);
225 env->error_code = soft_to_fpcr_exc(env);
227 return float32_to_s(fr);
230 uint64_t helper_muls(CPUAlphaState *env, uint64_t a, uint64_t b)
232 float32 fa, fb, fr;
234 fa = s_to_float32(a);
235 fb = s_to_float32(b);
236 fr = float32_mul(fa, fb, &FP_STATUS);
237 env->error_code = soft_to_fpcr_exc(env);
239 return float32_to_s(fr);
242 uint64_t helper_divs(CPUAlphaState *env, uint64_t a, uint64_t b)
244 float32 fa, fb, fr;
246 fa = s_to_float32(a);
247 fb = s_to_float32(b);
248 fr = float32_div(fa, fb, &FP_STATUS);
249 env->error_code = soft_to_fpcr_exc(env);
251 return float32_to_s(fr);
254 uint64_t helper_sqrts(CPUAlphaState *env, uint64_t a)
256 float32 fa, fr;
258 fa = s_to_float32(a);
259 fr = float32_sqrt(fa, &FP_STATUS);
260 env->error_code = soft_to_fpcr_exc(env);
262 return float32_to_s(fr);
266 /* T floating (double) */
267 static inline float64 t_to_float64(uint64_t a)
269 /* Memory format is the same as float64 */
270 CPU_DoubleU r;
271 r.ll = a;
272 return r.d;
275 static inline uint64_t float64_to_t(float64 fa)
277 /* Memory format is the same as float64 */
278 CPU_DoubleU r;
279 r.d = fa;
280 return r.ll;
283 uint64_t helper_addt(CPUAlphaState *env, uint64_t a, uint64_t b)
285 float64 fa, fb, fr;
287 fa = t_to_float64(a);
288 fb = t_to_float64(b);
289 fr = float64_add(fa, fb, &FP_STATUS);
290 env->error_code = soft_to_fpcr_exc(env);
292 return float64_to_t(fr);
295 uint64_t helper_subt(CPUAlphaState *env, uint64_t a, uint64_t b)
297 float64 fa, fb, fr;
299 fa = t_to_float64(a);
300 fb = t_to_float64(b);
301 fr = float64_sub(fa, fb, &FP_STATUS);
302 env->error_code = soft_to_fpcr_exc(env);
304 return float64_to_t(fr);
307 uint64_t helper_mult(CPUAlphaState *env, uint64_t a, uint64_t b)
309 float64 fa, fb, fr;
311 fa = t_to_float64(a);
312 fb = t_to_float64(b);
313 fr = float64_mul(fa, fb, &FP_STATUS);
314 env->error_code = soft_to_fpcr_exc(env);
316 return float64_to_t(fr);
319 uint64_t helper_divt(CPUAlphaState *env, uint64_t a, uint64_t b)
321 float64 fa, fb, fr;
323 fa = t_to_float64(a);
324 fb = t_to_float64(b);
325 fr = float64_div(fa, fb, &FP_STATUS);
326 env->error_code = soft_to_fpcr_exc(env);
328 return float64_to_t(fr);
331 uint64_t helper_sqrtt(CPUAlphaState *env, uint64_t a)
333 float64 fa, fr;
335 fa = t_to_float64(a);
336 fr = float64_sqrt(fa, &FP_STATUS);
337 env->error_code = soft_to_fpcr_exc(env);
339 return float64_to_t(fr);
342 /* Comparisons */
343 uint64_t helper_cmptun(CPUAlphaState *env, uint64_t a, uint64_t b)
345 float64 fa, fb;
346 uint64_t ret = 0;
348 fa = t_to_float64(a);
349 fb = t_to_float64(b);
351 if (float64_unordered_quiet(fa, fb, &FP_STATUS)) {
352 ret = 0x4000000000000000ULL;
354 env->error_code = soft_to_fpcr_exc(env);
356 return ret;
359 uint64_t helper_cmpteq(CPUAlphaState *env, uint64_t a, uint64_t b)
361 float64 fa, fb;
362 uint64_t ret = 0;
364 fa = t_to_float64(a);
365 fb = t_to_float64(b);
367 if (float64_eq_quiet(fa, fb, &FP_STATUS)) {
368 ret = 0x4000000000000000ULL;
370 env->error_code = soft_to_fpcr_exc(env);
372 return ret;
375 uint64_t helper_cmptle(CPUAlphaState *env, uint64_t a, uint64_t b)
377 float64 fa, fb;
378 uint64_t ret = 0;
380 fa = t_to_float64(a);
381 fb = t_to_float64(b);
383 if (float64_le(fa, fb, &FP_STATUS)) {
384 ret = 0x4000000000000000ULL;
386 env->error_code = soft_to_fpcr_exc(env);
388 return ret;
391 uint64_t helper_cmptlt(CPUAlphaState *env, uint64_t a, uint64_t b)
393 float64 fa, fb;
394 uint64_t ret = 0;
396 fa = t_to_float64(a);
397 fb = t_to_float64(b);
399 if (float64_lt(fa, fb, &FP_STATUS)) {
400 ret = 0x4000000000000000ULL;
402 env->error_code = soft_to_fpcr_exc(env);
404 return ret;
407 /* Floating point format conversion */
408 uint64_t helper_cvtts(CPUAlphaState *env, uint64_t a)
410 float64 fa;
411 float32 fr;
413 fa = t_to_float64(a);
414 fr = float64_to_float32(fa, &FP_STATUS);
415 env->error_code = soft_to_fpcr_exc(env);
417 return float32_to_s(fr);
420 uint64_t helper_cvtst(CPUAlphaState *env, uint64_t a)
422 float32 fa;
423 float64 fr;
425 fa = s_to_float32(a);
426 fr = float32_to_float64(fa, &FP_STATUS);
427 env->error_code = soft_to_fpcr_exc(env);
429 return float64_to_t(fr);
432 uint64_t helper_cvtqs(CPUAlphaState *env, uint64_t a)
434 float32 fr = int64_to_float32(a, &FP_STATUS);
435 env->error_code = soft_to_fpcr_exc(env);
437 return float32_to_s(fr);
440 /* Implement float64 to uint64 conversion without saturation -- we must
441 supply the truncated result. This behaviour is used by the compiler
442 to get unsigned conversion for free with the same instruction. */
444 static uint64_t do_cvttq(CPUAlphaState *env, uint64_t a, int roundmode)
446 uint64_t frac, ret = 0;
447 uint32_t exp, sign, exc = 0;
448 int shift;
450 sign = (a >> 63);
451 exp = (uint32_t)(a >> 52) & 0x7ff;
452 frac = a & 0xfffffffffffffull;
454 if (exp == 0) {
455 if (unlikely(frac != 0) && !env->fp_status.flush_inputs_to_zero) {
456 goto do_underflow;
458 } else if (exp == 0x7ff) {
459 exc = FPCR_INV;
460 } else {
461 /* Restore implicit bit. */
462 frac |= 0x10000000000000ull;
464 shift = exp - 1023 - 52;
465 if (shift >= 0) {
466 /* In this case the number is so large that we must shift
467 the fraction left. There is no rounding to do. */
468 if (shift < 64) {
469 ret = frac << shift;
471 /* Check for overflow. Note the special case of -0x1p63. */
472 if (shift >= 11 && a != 0xC3E0000000000000ull) {
473 exc = FPCR_IOV | FPCR_INE;
475 } else {
476 uint64_t round;
478 /* In this case the number is smaller than the fraction as
479 represented by the 52 bit number. Here we must think
480 about rounding the result. Handle this by shifting the
481 fractional part of the number into the high bits of ROUND.
482 This will let us efficiently handle round-to-nearest. */
483 shift = -shift;
484 if (shift < 63) {
485 ret = frac >> shift;
486 round = frac << (64 - shift);
487 } else {
488 /* The exponent is so small we shift out everything.
489 Leave a sticky bit for proper rounding below. */
490 do_underflow:
491 round = 1;
494 if (round) {
495 exc = FPCR_INE;
496 switch (roundmode) {
497 case float_round_nearest_even:
498 if (round == (1ull << 63)) {
499 /* Fraction is exactly 0.5; round to even. */
500 ret += (ret & 1);
501 } else if (round > (1ull << 63)) {
502 ret += 1;
504 break;
505 case float_round_to_zero:
506 break;
507 case float_round_up:
508 ret += 1 - sign;
509 break;
510 case float_round_down:
511 ret += sign;
512 break;
516 if (sign) {
517 ret = -ret;
520 env->error_code = exc;
522 return ret;
525 uint64_t helper_cvttq(CPUAlphaState *env, uint64_t a)
527 return do_cvttq(env, a, FP_STATUS.float_rounding_mode);
530 uint64_t helper_cvttq_c(CPUAlphaState *env, uint64_t a)
532 return do_cvttq(env, a, float_round_to_zero);
535 uint64_t helper_cvtqt(CPUAlphaState *env, uint64_t a)
537 float64 fr = int64_to_float64(a, &FP_STATUS);
538 env->error_code = soft_to_fpcr_exc(env);
539 return float64_to_t(fr);
542 uint64_t helper_cvtql(CPUAlphaState *env, uint64_t val)
544 uint32_t exc = 0;
545 if (val != (int32_t)val) {
546 exc = FPCR_IOV | FPCR_INE;
548 env->error_code = exc;
550 return ((val & 0xc0000000) << 32) | ((val & 0x3fffffff) << 29);