vmport: QOM'ify
[qemu/agraf.git] / target-alpha / fpu_helper.c
blobfad35755490eca98877350aca9a58eb07ccf65fd
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 "helper.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 void helper_fp_exc_clear(CPUAlphaState *env)
39 set_float_exception_flags(0, &FP_STATUS);
42 uint32_t helper_fp_exc_get(CPUAlphaState *env)
44 return get_float_exception_flags(&FP_STATUS);
47 static inline void inline_fp_exc_raise(CPUAlphaState *env, uintptr_t retaddr,
48 uint32_t exc, uint32_t regno)
50 if (exc) {
51 uint32_t hw_exc = 0;
53 if (exc & float_flag_invalid) {
54 hw_exc |= EXC_M_INV;
56 if (exc & float_flag_divbyzero) {
57 hw_exc |= EXC_M_DZE;
59 if (exc & float_flag_overflow) {
60 hw_exc |= EXC_M_FOV;
62 if (exc & float_flag_underflow) {
63 hw_exc |= EXC_M_UNF;
65 if (exc & float_flag_inexact) {
66 hw_exc |= EXC_M_INE;
69 arith_excp(env, retaddr, hw_exc, 1ull << regno);
73 /* Raise exceptions for ieee fp insns without software completion.
74 In that case there are no exceptions that don't trap; the mask
75 doesn't apply. */
76 void helper_fp_exc_raise(CPUAlphaState *env, uint32_t exc, uint32_t regno)
78 inline_fp_exc_raise(env, GETPC(), exc, regno);
81 /* Raise exceptions for ieee fp insns with software completion. */
82 void helper_fp_exc_raise_s(CPUAlphaState *env, uint32_t exc, uint32_t regno)
84 if (exc) {
85 env->fpcr_exc_status |= exc;
86 exc &= ~env->fpcr_exc_mask;
87 inline_fp_exc_raise(env, GETPC(), exc, regno);
91 /* Input handing without software completion. Trap for all
92 non-finite numbers. */
93 void helper_ieee_input(CPUAlphaState *env, uint64_t val)
95 uint32_t exp = (uint32_t)(val >> 52) & 0x7ff;
96 uint64_t frac = val & 0xfffffffffffffull;
98 if (exp == 0) {
99 /* Denormals without DNZ set raise an exception. */
100 if (frac != 0 && !env->fp_status.flush_inputs_to_zero) {
101 arith_excp(env, GETPC(), EXC_M_UNF, 0);
103 } else if (exp == 0x7ff) {
104 /* Infinity or NaN. */
105 /* ??? I'm not sure these exception bit flags are correct. I do
106 know that the Linux kernel, at least, doesn't rely on them and
107 just emulates the insn to figure out what exception to use. */
108 arith_excp(env, GETPC(), frac ? EXC_M_INV : EXC_M_FOV, 0);
112 /* Similar, but does not trap for infinities. Used for comparisons. */
113 void helper_ieee_input_cmp(CPUAlphaState *env, uint64_t val)
115 uint32_t exp = (uint32_t)(val >> 52) & 0x7ff;
116 uint64_t frac = val & 0xfffffffffffffull;
118 if (exp == 0) {
119 /* Denormals without DNZ set raise an exception. */
120 if (frac != 0 && !env->fp_status.flush_inputs_to_zero) {
121 arith_excp(env, GETPC(), EXC_M_UNF, 0);
123 } else if (exp == 0x7ff && frac) {
124 /* NaN. */
125 arith_excp(env, GETPC(), EXC_M_INV, 0);
129 /* F floating (VAX) */
130 static uint64_t float32_to_f(float32 fa)
132 uint64_t r, exp, mant, sig;
133 CPU_FloatU a;
135 a.f = fa;
136 sig = ((uint64_t)a.l & 0x80000000) << 32;
137 exp = (a.l >> 23) & 0xff;
138 mant = ((uint64_t)a.l & 0x007fffff) << 29;
140 if (exp == 255) {
141 /* NaN or infinity */
142 r = 1; /* VAX dirty zero */
143 } else if (exp == 0) {
144 if (mant == 0) {
145 /* Zero */
146 r = 0;
147 } else {
148 /* Denormalized */
149 r = sig | ((exp + 1) << 52) | mant;
151 } else {
152 if (exp >= 253) {
153 /* Overflow */
154 r = 1; /* VAX dirty zero */
155 } else {
156 r = sig | ((exp + 2) << 52);
160 return r;
163 static float32 f_to_float32(CPUAlphaState *env, uintptr_t retaddr, uint64_t a)
165 uint32_t exp, mant_sig;
166 CPU_FloatU r;
168 exp = ((a >> 55) & 0x80) | ((a >> 52) & 0x7f);
169 mant_sig = ((a >> 32) & 0x80000000) | ((a >> 29) & 0x007fffff);
171 if (unlikely(!exp && mant_sig)) {
172 /* Reserved operands / Dirty zero */
173 dynamic_excp(env, retaddr, EXCP_OPCDEC, 0);
176 if (exp < 3) {
177 /* Underflow */
178 r.l = 0;
179 } else {
180 r.l = ((exp - 2) << 23) | mant_sig;
183 return r.f;
186 uint32_t helper_f_to_memory(uint64_t a)
188 uint32_t r;
189 r = (a & 0x00001fffe0000000ull) >> 13;
190 r |= (a & 0x07ffe00000000000ull) >> 45;
191 r |= (a & 0xc000000000000000ull) >> 48;
192 return r;
195 uint64_t helper_memory_to_f(uint32_t a)
197 uint64_t r;
198 r = ((uint64_t)(a & 0x0000c000)) << 48;
199 r |= ((uint64_t)(a & 0x003fffff)) << 45;
200 r |= ((uint64_t)(a & 0xffff0000)) << 13;
201 if (!(a & 0x00004000)) {
202 r |= 0x7ll << 59;
204 return r;
207 /* ??? Emulating VAX arithmetic with IEEE arithmetic is wrong. We should
208 either implement VAX arithmetic properly or just signal invalid opcode. */
210 uint64_t helper_addf(CPUAlphaState *env, uint64_t a, uint64_t b)
212 float32 fa, fb, fr;
214 fa = f_to_float32(env, GETPC(), a);
215 fb = f_to_float32(env, GETPC(), b);
216 fr = float32_add(fa, fb, &FP_STATUS);
217 return float32_to_f(fr);
220 uint64_t helper_subf(CPUAlphaState *env, uint64_t a, uint64_t b)
222 float32 fa, fb, fr;
224 fa = f_to_float32(env, GETPC(), a);
225 fb = f_to_float32(env, GETPC(), b);
226 fr = float32_sub(fa, fb, &FP_STATUS);
227 return float32_to_f(fr);
230 uint64_t helper_mulf(CPUAlphaState *env, uint64_t a, uint64_t b)
232 float32 fa, fb, fr;
234 fa = f_to_float32(env, GETPC(), a);
235 fb = f_to_float32(env, GETPC(), b);
236 fr = float32_mul(fa, fb, &FP_STATUS);
237 return float32_to_f(fr);
240 uint64_t helper_divf(CPUAlphaState *env, uint64_t a, uint64_t b)
242 float32 fa, fb, fr;
244 fa = f_to_float32(env, GETPC(), a);
245 fb = f_to_float32(env, GETPC(), b);
246 fr = float32_div(fa, fb, &FP_STATUS);
247 return float32_to_f(fr);
250 uint64_t helper_sqrtf(CPUAlphaState *env, uint64_t t)
252 float32 ft, fr;
254 ft = f_to_float32(env, GETPC(), t);
255 fr = float32_sqrt(ft, &FP_STATUS);
256 return float32_to_f(fr);
260 /* G floating (VAX) */
261 static uint64_t float64_to_g(float64 fa)
263 uint64_t r, exp, mant, sig;
264 CPU_DoubleU a;
266 a.d = fa;
267 sig = a.ll & 0x8000000000000000ull;
268 exp = (a.ll >> 52) & 0x7ff;
269 mant = a.ll & 0x000fffffffffffffull;
271 if (exp == 2047) {
272 /* NaN or infinity */
273 r = 1; /* VAX dirty zero */
274 } else if (exp == 0) {
275 if (mant == 0) {
276 /* Zero */
277 r = 0;
278 } else {
279 /* Denormalized */
280 r = sig | ((exp + 1) << 52) | mant;
282 } else {
283 if (exp >= 2045) {
284 /* Overflow */
285 r = 1; /* VAX dirty zero */
286 } else {
287 r = sig | ((exp + 2) << 52);
291 return r;
294 static float64 g_to_float64(CPUAlphaState *env, uintptr_t retaddr, uint64_t a)
296 uint64_t exp, mant_sig;
297 CPU_DoubleU r;
299 exp = (a >> 52) & 0x7ff;
300 mant_sig = a & 0x800fffffffffffffull;
302 if (!exp && mant_sig) {
303 /* Reserved operands / Dirty zero */
304 dynamic_excp(env, retaddr, EXCP_OPCDEC, 0);
307 if (exp < 3) {
308 /* Underflow */
309 r.ll = 0;
310 } else {
311 r.ll = ((exp - 2) << 52) | mant_sig;
314 return r.d;
317 uint64_t helper_g_to_memory(uint64_t a)
319 uint64_t r;
320 r = (a & 0x000000000000ffffull) << 48;
321 r |= (a & 0x00000000ffff0000ull) << 16;
322 r |= (a & 0x0000ffff00000000ull) >> 16;
323 r |= (a & 0xffff000000000000ull) >> 48;
324 return r;
327 uint64_t helper_memory_to_g(uint64_t a)
329 uint64_t r;
330 r = (a & 0x000000000000ffffull) << 48;
331 r |= (a & 0x00000000ffff0000ull) << 16;
332 r |= (a & 0x0000ffff00000000ull) >> 16;
333 r |= (a & 0xffff000000000000ull) >> 48;
334 return r;
337 uint64_t helper_addg(CPUAlphaState *env, uint64_t a, uint64_t b)
339 float64 fa, fb, fr;
341 fa = g_to_float64(env, GETPC(), a);
342 fb = g_to_float64(env, GETPC(), b);
343 fr = float64_add(fa, fb, &FP_STATUS);
344 return float64_to_g(fr);
347 uint64_t helper_subg(CPUAlphaState *env, uint64_t a, uint64_t b)
349 float64 fa, fb, fr;
351 fa = g_to_float64(env, GETPC(), a);
352 fb = g_to_float64(env, GETPC(), b);
353 fr = float64_sub(fa, fb, &FP_STATUS);
354 return float64_to_g(fr);
357 uint64_t helper_mulg(CPUAlphaState *env, uint64_t a, uint64_t b)
359 float64 fa, fb, fr;
361 fa = g_to_float64(env, GETPC(), a);
362 fb = g_to_float64(env, GETPC(), b);
363 fr = float64_mul(fa, fb, &FP_STATUS);
364 return float64_to_g(fr);
367 uint64_t helper_divg(CPUAlphaState *env, uint64_t a, uint64_t b)
369 float64 fa, fb, fr;
371 fa = g_to_float64(env, GETPC(), a);
372 fb = g_to_float64(env, GETPC(), b);
373 fr = float64_div(fa, fb, &FP_STATUS);
374 return float64_to_g(fr);
377 uint64_t helper_sqrtg(CPUAlphaState *env, uint64_t a)
379 float64 fa, fr;
381 fa = g_to_float64(env, GETPC(), a);
382 fr = float64_sqrt(fa, &FP_STATUS);
383 return float64_to_g(fr);
387 /* S floating (single) */
389 /* Taken from linux/arch/alpha/kernel/traps.c, s_mem_to_reg. */
390 static inline uint64_t float32_to_s_int(uint32_t fi)
392 uint32_t frac = fi & 0x7fffff;
393 uint32_t sign = fi >> 31;
394 uint32_t exp_msb = (fi >> 30) & 1;
395 uint32_t exp_low = (fi >> 23) & 0x7f;
396 uint32_t exp;
398 exp = (exp_msb << 10) | exp_low;
399 if (exp_msb) {
400 if (exp_low == 0x7f) {
401 exp = 0x7ff;
403 } else {
404 if (exp_low != 0x00) {
405 exp |= 0x380;
409 return (((uint64_t)sign << 63)
410 | ((uint64_t)exp << 52)
411 | ((uint64_t)frac << 29));
414 static inline uint64_t float32_to_s(float32 fa)
416 CPU_FloatU a;
417 a.f = fa;
418 return float32_to_s_int(a.l);
421 static inline uint32_t s_to_float32_int(uint64_t a)
423 return ((a >> 32) & 0xc0000000) | ((a >> 29) & 0x3fffffff);
426 static inline float32 s_to_float32(uint64_t a)
428 CPU_FloatU r;
429 r.l = s_to_float32_int(a);
430 return r.f;
433 uint32_t helper_s_to_memory(uint64_t a)
435 return s_to_float32_int(a);
438 uint64_t helper_memory_to_s(uint32_t a)
440 return float32_to_s_int(a);
443 uint64_t helper_adds(CPUAlphaState *env, uint64_t a, uint64_t b)
445 float32 fa, fb, fr;
447 fa = s_to_float32(a);
448 fb = s_to_float32(b);
449 fr = float32_add(fa, fb, &FP_STATUS);
450 return float32_to_s(fr);
453 uint64_t helper_subs(CPUAlphaState *env, uint64_t a, uint64_t b)
455 float32 fa, fb, fr;
457 fa = s_to_float32(a);
458 fb = s_to_float32(b);
459 fr = float32_sub(fa, fb, &FP_STATUS);
460 return float32_to_s(fr);
463 uint64_t helper_muls(CPUAlphaState *env, uint64_t a, uint64_t b)
465 float32 fa, fb, fr;
467 fa = s_to_float32(a);
468 fb = s_to_float32(b);
469 fr = float32_mul(fa, fb, &FP_STATUS);
470 return float32_to_s(fr);
473 uint64_t helper_divs(CPUAlphaState *env, uint64_t a, uint64_t b)
475 float32 fa, fb, fr;
477 fa = s_to_float32(a);
478 fb = s_to_float32(b);
479 fr = float32_div(fa, fb, &FP_STATUS);
480 return float32_to_s(fr);
483 uint64_t helper_sqrts(CPUAlphaState *env, uint64_t a)
485 float32 fa, fr;
487 fa = s_to_float32(a);
488 fr = float32_sqrt(fa, &FP_STATUS);
489 return float32_to_s(fr);
493 /* T floating (double) */
494 static inline float64 t_to_float64(uint64_t a)
496 /* Memory format is the same as float64 */
497 CPU_DoubleU r;
498 r.ll = a;
499 return r.d;
502 static inline uint64_t float64_to_t(float64 fa)
504 /* Memory format is the same as float64 */
505 CPU_DoubleU r;
506 r.d = fa;
507 return r.ll;
510 uint64_t helper_addt(CPUAlphaState *env, uint64_t a, uint64_t b)
512 float64 fa, fb, fr;
514 fa = t_to_float64(a);
515 fb = t_to_float64(b);
516 fr = float64_add(fa, fb, &FP_STATUS);
517 return float64_to_t(fr);
520 uint64_t helper_subt(CPUAlphaState *env, uint64_t a, uint64_t b)
522 float64 fa, fb, fr;
524 fa = t_to_float64(a);
525 fb = t_to_float64(b);
526 fr = float64_sub(fa, fb, &FP_STATUS);
527 return float64_to_t(fr);
530 uint64_t helper_mult(CPUAlphaState *env, uint64_t a, uint64_t b)
532 float64 fa, fb, fr;
534 fa = t_to_float64(a);
535 fb = t_to_float64(b);
536 fr = float64_mul(fa, fb, &FP_STATUS);
537 return float64_to_t(fr);
540 uint64_t helper_divt(CPUAlphaState *env, uint64_t a, uint64_t b)
542 float64 fa, fb, fr;
544 fa = t_to_float64(a);
545 fb = t_to_float64(b);
546 fr = float64_div(fa, fb, &FP_STATUS);
547 return float64_to_t(fr);
550 uint64_t helper_sqrtt(CPUAlphaState *env, uint64_t a)
552 float64 fa, fr;
554 fa = t_to_float64(a);
555 fr = float64_sqrt(fa, &FP_STATUS);
556 return float64_to_t(fr);
559 /* Comparisons */
560 uint64_t helper_cmptun(CPUAlphaState *env, uint64_t a, uint64_t b)
562 float64 fa, fb;
564 fa = t_to_float64(a);
565 fb = t_to_float64(b);
567 if (float64_unordered_quiet(fa, fb, &FP_STATUS)) {
568 return 0x4000000000000000ULL;
569 } else {
570 return 0;
574 uint64_t helper_cmpteq(CPUAlphaState *env, uint64_t a, uint64_t b)
576 float64 fa, fb;
578 fa = t_to_float64(a);
579 fb = t_to_float64(b);
581 if (float64_eq_quiet(fa, fb, &FP_STATUS)) {
582 return 0x4000000000000000ULL;
583 } else {
584 return 0;
588 uint64_t helper_cmptle(CPUAlphaState *env, uint64_t a, uint64_t b)
590 float64 fa, fb;
592 fa = t_to_float64(a);
593 fb = t_to_float64(b);
595 if (float64_le(fa, fb, &FP_STATUS)) {
596 return 0x4000000000000000ULL;
597 } else {
598 return 0;
602 uint64_t helper_cmptlt(CPUAlphaState *env, uint64_t a, uint64_t b)
604 float64 fa, fb;
606 fa = t_to_float64(a);
607 fb = t_to_float64(b);
609 if (float64_lt(fa, fb, &FP_STATUS)) {
610 return 0x4000000000000000ULL;
611 } else {
612 return 0;
616 uint64_t helper_cmpgeq(CPUAlphaState *env, uint64_t a, uint64_t b)
618 float64 fa, fb;
620 fa = g_to_float64(env, GETPC(), a);
621 fb = g_to_float64(env, GETPC(), b);
623 if (float64_eq_quiet(fa, fb, &FP_STATUS)) {
624 return 0x4000000000000000ULL;
625 } else {
626 return 0;
630 uint64_t helper_cmpgle(CPUAlphaState *env, uint64_t a, uint64_t b)
632 float64 fa, fb;
634 fa = g_to_float64(env, GETPC(), a);
635 fb = g_to_float64(env, GETPC(), b);
637 if (float64_le(fa, fb, &FP_STATUS)) {
638 return 0x4000000000000000ULL;
639 } else {
640 return 0;
644 uint64_t helper_cmpglt(CPUAlphaState *env, uint64_t a, uint64_t b)
646 float64 fa, fb;
648 fa = g_to_float64(env, GETPC(), a);
649 fb = g_to_float64(env, GETPC(), b);
651 if (float64_lt(fa, fb, &FP_STATUS)) {
652 return 0x4000000000000000ULL;
653 } else {
654 return 0;
658 /* Floating point format conversion */
659 uint64_t helper_cvtts(CPUAlphaState *env, uint64_t a)
661 float64 fa;
662 float32 fr;
664 fa = t_to_float64(a);
665 fr = float64_to_float32(fa, &FP_STATUS);
666 return float32_to_s(fr);
669 uint64_t helper_cvtst(CPUAlphaState *env, uint64_t a)
671 float32 fa;
672 float64 fr;
674 fa = s_to_float32(a);
675 fr = float32_to_float64(fa, &FP_STATUS);
676 return float64_to_t(fr);
679 uint64_t helper_cvtqs(CPUAlphaState *env, uint64_t a)
681 float32 fr = int64_to_float32(a, &FP_STATUS);
682 return float32_to_s(fr);
685 /* Implement float64 to uint64 conversion without saturation -- we must
686 supply the truncated result. This behaviour is used by the compiler
687 to get unsigned conversion for free with the same instruction.
689 The VI flag is set when overflow or inexact exceptions should be raised. */
691 static inline uint64_t inline_cvttq(CPUAlphaState *env, uint64_t a,
692 int roundmode, int VI)
694 uint64_t frac, ret = 0;
695 uint32_t exp, sign, exc = 0;
696 int shift;
698 sign = (a >> 63);
699 exp = (uint32_t)(a >> 52) & 0x7ff;
700 frac = a & 0xfffffffffffffull;
702 if (exp == 0) {
703 if (unlikely(frac != 0)) {
704 goto do_underflow;
706 } else if (exp == 0x7ff) {
707 exc = (frac ? float_flag_invalid : VI ? float_flag_overflow : 0);
708 } else {
709 /* Restore implicit bit. */
710 frac |= 0x10000000000000ull;
712 shift = exp - 1023 - 52;
713 if (shift >= 0) {
714 /* In this case the number is so large that we must shift
715 the fraction left. There is no rounding to do. */
716 if (shift < 63) {
717 ret = frac << shift;
718 if (VI && (ret >> shift) != frac) {
719 exc = float_flag_overflow;
722 } else {
723 uint64_t round;
725 /* In this case the number is smaller than the fraction as
726 represented by the 52 bit number. Here we must think
727 about rounding the result. Handle this by shifting the
728 fractional part of the number into the high bits of ROUND.
729 This will let us efficiently handle round-to-nearest. */
730 shift = -shift;
731 if (shift < 63) {
732 ret = frac >> shift;
733 round = frac << (64 - shift);
734 } else {
735 /* The exponent is so small we shift out everything.
736 Leave a sticky bit for proper rounding below. */
737 do_underflow:
738 round = 1;
741 if (round) {
742 exc = (VI ? float_flag_inexact : 0);
743 switch (roundmode) {
744 case float_round_nearest_even:
745 if (round == (1ull << 63)) {
746 /* Fraction is exactly 0.5; round to even. */
747 ret += (ret & 1);
748 } else if (round > (1ull << 63)) {
749 ret += 1;
751 break;
752 case float_round_to_zero:
753 break;
754 case float_round_up:
755 ret += 1 - sign;
756 break;
757 case float_round_down:
758 ret += sign;
759 break;
763 if (sign) {
764 ret = -ret;
767 if (unlikely(exc)) {
768 float_raise(exc, &FP_STATUS);
771 return ret;
774 uint64_t helper_cvttq(CPUAlphaState *env, uint64_t a)
776 return inline_cvttq(env, a, FP_STATUS.float_rounding_mode, 1);
779 uint64_t helper_cvttq_c(CPUAlphaState *env, uint64_t a)
781 return inline_cvttq(env, a, float_round_to_zero, 0);
784 uint64_t helper_cvttq_svic(CPUAlphaState *env, uint64_t a)
786 return inline_cvttq(env, a, float_round_to_zero, 1);
789 uint64_t helper_cvtqt(CPUAlphaState *env, uint64_t a)
791 float64 fr = int64_to_float64(a, &FP_STATUS);
792 return float64_to_t(fr);
795 uint64_t helper_cvtqf(CPUAlphaState *env, uint64_t a)
797 float32 fr = int64_to_float32(a, &FP_STATUS);
798 return float32_to_f(fr);
801 uint64_t helper_cvtgf(CPUAlphaState *env, uint64_t a)
803 float64 fa;
804 float32 fr;
806 fa = g_to_float64(env, GETPC(), a);
807 fr = float64_to_float32(fa, &FP_STATUS);
808 return float32_to_f(fr);
811 uint64_t helper_cvtgq(CPUAlphaState *env, uint64_t a)
813 float64 fa = g_to_float64(env, GETPC(), a);
814 return float64_to_int64_round_to_zero(fa, &FP_STATUS);
817 uint64_t helper_cvtqg(CPUAlphaState *env, uint64_t a)
819 float64 fr;
820 fr = int64_to_float64(a, &FP_STATUS);
821 return float64_to_g(fr);