qemu-ga: fix bsd build, and re-org linux-specific implementations
[qemu/ar7.git] / target-ppc / op_helper.c
blob40927b65b13e3d3a93960418913cae8a5eda3985
1 /*
2 * PowerPC emulation helpers for qemu.
4 * Copyright (c) 2003-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/>.
19 #include <string.h>
20 #include "cpu.h"
21 #include "dyngen-exec.h"
22 #include "host-utils.h"
23 #include "helper.h"
25 #include "helper_regs.h"
27 #if !defined(CONFIG_USER_ONLY)
28 #include "softmmu_exec.h"
29 #endif /* !defined(CONFIG_USER_ONLY) */
31 //#define DEBUG_OP
32 //#define DEBUG_EXCEPTIONS
33 //#define DEBUG_SOFTWARE_TLB
35 #ifdef DEBUG_SOFTWARE_TLB
36 # define LOG_SWTLB(...) qemu_log(__VA_ARGS__)
37 #else
38 # define LOG_SWTLB(...) do { } while (0)
39 #endif
42 /*****************************************************************************/
43 /* Exceptions processing helpers */
45 void helper_raise_exception_err (uint32_t exception, uint32_t error_code)
47 #if 0
48 printf("Raise exception %3x code : %d\n", exception, error_code);
49 #endif
50 env->exception_index = exception;
51 env->error_code = error_code;
52 cpu_loop_exit(env);
55 void helper_raise_exception (uint32_t exception)
57 helper_raise_exception_err(exception, 0);
60 /*****************************************************************************/
61 /* SPR accesses */
62 void helper_load_dump_spr (uint32_t sprn)
64 qemu_log("Read SPR %d %03x => " TARGET_FMT_lx "\n", sprn, sprn,
65 env->spr[sprn]);
68 void helper_store_dump_spr (uint32_t sprn)
70 qemu_log("Write SPR %d %03x <= " TARGET_FMT_lx "\n", sprn, sprn,
71 env->spr[sprn]);
74 target_ulong helper_load_tbl (void)
76 return (target_ulong)cpu_ppc_load_tbl(env);
79 target_ulong helper_load_tbu (void)
81 return cpu_ppc_load_tbu(env);
84 target_ulong helper_load_atbl (void)
86 return (target_ulong)cpu_ppc_load_atbl(env);
89 target_ulong helper_load_atbu (void)
91 return cpu_ppc_load_atbu(env);
94 #if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY)
95 target_ulong helper_load_purr (void)
97 return (target_ulong)cpu_ppc_load_purr(env);
99 #endif
101 target_ulong helper_load_601_rtcl (void)
103 return cpu_ppc601_load_rtcl(env);
106 target_ulong helper_load_601_rtcu (void)
108 return cpu_ppc601_load_rtcu(env);
111 #if !defined(CONFIG_USER_ONLY)
112 #if defined (TARGET_PPC64)
113 void helper_store_asr (target_ulong val)
115 ppc_store_asr(env, val);
117 #endif
119 void helper_store_sdr1 (target_ulong val)
121 ppc_store_sdr1(env, val);
124 void helper_store_tbl (target_ulong val)
126 cpu_ppc_store_tbl(env, val);
129 void helper_store_tbu (target_ulong val)
131 cpu_ppc_store_tbu(env, val);
134 void helper_store_atbl (target_ulong val)
136 cpu_ppc_store_atbl(env, val);
139 void helper_store_atbu (target_ulong val)
141 cpu_ppc_store_atbu(env, val);
144 void helper_store_601_rtcl (target_ulong val)
146 cpu_ppc601_store_rtcl(env, val);
149 void helper_store_601_rtcu (target_ulong val)
151 cpu_ppc601_store_rtcu(env, val);
154 target_ulong helper_load_decr (void)
156 return cpu_ppc_load_decr(env);
159 void helper_store_decr (target_ulong val)
161 cpu_ppc_store_decr(env, val);
164 void helper_store_hid0_601 (target_ulong val)
166 target_ulong hid0;
168 hid0 = env->spr[SPR_HID0];
169 if ((val ^ hid0) & 0x00000008) {
170 /* Change current endianness */
171 env->hflags &= ~(1 << MSR_LE);
172 env->hflags_nmsr &= ~(1 << MSR_LE);
173 env->hflags_nmsr |= (1 << MSR_LE) & (((val >> 3) & 1) << MSR_LE);
174 env->hflags |= env->hflags_nmsr;
175 qemu_log("%s: set endianness to %c => " TARGET_FMT_lx "\n", __func__,
176 val & 0x8 ? 'l' : 'b', env->hflags);
178 env->spr[SPR_HID0] = (uint32_t)val;
181 void helper_store_403_pbr (uint32_t num, target_ulong value)
183 if (likely(env->pb[num] != value)) {
184 env->pb[num] = value;
185 /* Should be optimized */
186 tlb_flush(env, 1);
190 target_ulong helper_load_40x_pit (void)
192 return load_40x_pit(env);
195 void helper_store_40x_pit (target_ulong val)
197 store_40x_pit(env, val);
200 void helper_store_40x_dbcr0 (target_ulong val)
202 store_40x_dbcr0(env, val);
205 void helper_store_40x_sler (target_ulong val)
207 store_40x_sler(env, val);
210 void helper_store_booke_tcr (target_ulong val)
212 store_booke_tcr(env, val);
215 void helper_store_booke_tsr (target_ulong val)
217 store_booke_tsr(env, val);
220 void helper_store_ibatu (uint32_t nr, target_ulong val)
222 ppc_store_ibatu(env, nr, val);
225 void helper_store_ibatl (uint32_t nr, target_ulong val)
227 ppc_store_ibatl(env, nr, val);
230 void helper_store_dbatu (uint32_t nr, target_ulong val)
232 ppc_store_dbatu(env, nr, val);
235 void helper_store_dbatl (uint32_t nr, target_ulong val)
237 ppc_store_dbatl(env, nr, val);
240 void helper_store_601_batl (uint32_t nr, target_ulong val)
242 ppc_store_ibatl_601(env, nr, val);
245 void helper_store_601_batu (uint32_t nr, target_ulong val)
247 ppc_store_ibatu_601(env, nr, val);
249 #endif
251 /*****************************************************************************/
252 /* Memory load and stores */
254 static inline target_ulong addr_add(target_ulong addr, target_long arg)
256 #if defined(TARGET_PPC64)
257 if (!msr_sf)
258 return (uint32_t)(addr + arg);
259 else
260 #endif
261 return addr + arg;
264 void helper_lmw (target_ulong addr, uint32_t reg)
266 for (; reg < 32; reg++) {
267 if (msr_le)
268 env->gpr[reg] = bswap32(ldl(addr));
269 else
270 env->gpr[reg] = ldl(addr);
271 addr = addr_add(addr, 4);
275 void helper_stmw (target_ulong addr, uint32_t reg)
277 for (; reg < 32; reg++) {
278 if (msr_le)
279 stl(addr, bswap32((uint32_t)env->gpr[reg]));
280 else
281 stl(addr, (uint32_t)env->gpr[reg]);
282 addr = addr_add(addr, 4);
286 void helper_lsw(target_ulong addr, uint32_t nb, uint32_t reg)
288 int sh;
289 for (; nb > 3; nb -= 4) {
290 env->gpr[reg] = ldl(addr);
291 reg = (reg + 1) % 32;
292 addr = addr_add(addr, 4);
294 if (unlikely(nb > 0)) {
295 env->gpr[reg] = 0;
296 for (sh = 24; nb > 0; nb--, sh -= 8) {
297 env->gpr[reg] |= ldub(addr) << sh;
298 addr = addr_add(addr, 1);
302 /* PPC32 specification says we must generate an exception if
303 * rA is in the range of registers to be loaded.
304 * In an other hand, IBM says this is valid, but rA won't be loaded.
305 * For now, I'll follow the spec...
307 void helper_lswx(target_ulong addr, uint32_t reg, uint32_t ra, uint32_t rb)
309 if (likely(xer_bc != 0)) {
310 if (unlikely((ra != 0 && reg < ra && (reg + xer_bc) > ra) ||
311 (reg < rb && (reg + xer_bc) > rb))) {
312 helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
313 POWERPC_EXCP_INVAL |
314 POWERPC_EXCP_INVAL_LSWX);
315 } else {
316 helper_lsw(addr, xer_bc, reg);
321 void helper_stsw(target_ulong addr, uint32_t nb, uint32_t reg)
323 int sh;
324 for (; nb > 3; nb -= 4) {
325 stl(addr, env->gpr[reg]);
326 reg = (reg + 1) % 32;
327 addr = addr_add(addr, 4);
329 if (unlikely(nb > 0)) {
330 for (sh = 24; nb > 0; nb--, sh -= 8) {
331 stb(addr, (env->gpr[reg] >> sh) & 0xFF);
332 addr = addr_add(addr, 1);
337 static void do_dcbz(target_ulong addr, int dcache_line_size)
339 addr &= ~(dcache_line_size - 1);
340 int i;
341 for (i = 0 ; i < dcache_line_size ; i += 4) {
342 stl(addr + i , 0);
344 if (env->reserve_addr == addr)
345 env->reserve_addr = (target_ulong)-1ULL;
348 void helper_dcbz(target_ulong addr)
350 do_dcbz(addr, env->dcache_line_size);
353 void helper_dcbz_970(target_ulong addr)
355 if (((env->spr[SPR_970_HID5] >> 7) & 0x3) == 1)
356 do_dcbz(addr, 32);
357 else
358 do_dcbz(addr, env->dcache_line_size);
361 void helper_icbi(target_ulong addr)
363 addr &= ~(env->dcache_line_size - 1);
364 /* Invalidate one cache line :
365 * PowerPC specification says this is to be treated like a load
366 * (not a fetch) by the MMU. To be sure it will be so,
367 * do the load "by hand".
369 ldl(addr);
372 // XXX: to be tested
373 target_ulong helper_lscbx (target_ulong addr, uint32_t reg, uint32_t ra, uint32_t rb)
375 int i, c, d;
376 d = 24;
377 for (i = 0; i < xer_bc; i++) {
378 c = ldub(addr);
379 addr = addr_add(addr, 1);
380 /* ra (if not 0) and rb are never modified */
381 if (likely(reg != rb && (ra == 0 || reg != ra))) {
382 env->gpr[reg] = (env->gpr[reg] & ~(0xFF << d)) | (c << d);
384 if (unlikely(c == xer_cmp))
385 break;
386 if (likely(d != 0)) {
387 d -= 8;
388 } else {
389 d = 24;
390 reg++;
391 reg = reg & 0x1F;
394 return i;
397 /*****************************************************************************/
398 /* Fixed point operations helpers */
399 #if defined(TARGET_PPC64)
401 /* multiply high word */
402 uint64_t helper_mulhd (uint64_t arg1, uint64_t arg2)
404 uint64_t tl, th;
406 muls64(&tl, &th, arg1, arg2);
407 return th;
410 /* multiply high word unsigned */
411 uint64_t helper_mulhdu (uint64_t arg1, uint64_t arg2)
413 uint64_t tl, th;
415 mulu64(&tl, &th, arg1, arg2);
416 return th;
419 uint64_t helper_mulldo (uint64_t arg1, uint64_t arg2)
421 int64_t th;
422 uint64_t tl;
424 muls64(&tl, (uint64_t *)&th, arg1, arg2);
425 /* If th != 0 && th != -1, then we had an overflow */
426 if (likely((uint64_t)(th + 1) <= 1)) {
427 env->xer &= ~(1 << XER_OV);
428 } else {
429 env->xer |= (1 << XER_OV) | (1 << XER_SO);
431 return (int64_t)tl;
433 #endif
435 target_ulong helper_cntlzw (target_ulong t)
437 return clz32(t);
440 #if defined(TARGET_PPC64)
441 target_ulong helper_cntlzd (target_ulong t)
443 return clz64(t);
445 #endif
447 /* shift right arithmetic helper */
448 target_ulong helper_sraw (target_ulong value, target_ulong shift)
450 int32_t ret;
452 if (likely(!(shift & 0x20))) {
453 if (likely((uint32_t)shift != 0)) {
454 shift &= 0x1f;
455 ret = (int32_t)value >> shift;
456 if (likely(ret >= 0 || (value & ((1 << shift) - 1)) == 0)) {
457 env->xer &= ~(1 << XER_CA);
458 } else {
459 env->xer |= (1 << XER_CA);
461 } else {
462 ret = (int32_t)value;
463 env->xer &= ~(1 << XER_CA);
465 } else {
466 ret = (int32_t)value >> 31;
467 if (ret) {
468 env->xer |= (1 << XER_CA);
469 } else {
470 env->xer &= ~(1 << XER_CA);
473 return (target_long)ret;
476 #if defined(TARGET_PPC64)
477 target_ulong helper_srad (target_ulong value, target_ulong shift)
479 int64_t ret;
481 if (likely(!(shift & 0x40))) {
482 if (likely((uint64_t)shift != 0)) {
483 shift &= 0x3f;
484 ret = (int64_t)value >> shift;
485 if (likely(ret >= 0 || (value & ((1 << shift) - 1)) == 0)) {
486 env->xer &= ~(1 << XER_CA);
487 } else {
488 env->xer |= (1 << XER_CA);
490 } else {
491 ret = (int64_t)value;
492 env->xer &= ~(1 << XER_CA);
494 } else {
495 ret = (int64_t)value >> 63;
496 if (ret) {
497 env->xer |= (1 << XER_CA);
498 } else {
499 env->xer &= ~(1 << XER_CA);
502 return ret;
504 #endif
506 #if defined(TARGET_PPC64)
507 target_ulong helper_popcntb (target_ulong val)
509 val = (val & 0x5555555555555555ULL) + ((val >> 1) &
510 0x5555555555555555ULL);
511 val = (val & 0x3333333333333333ULL) + ((val >> 2) &
512 0x3333333333333333ULL);
513 val = (val & 0x0f0f0f0f0f0f0f0fULL) + ((val >> 4) &
514 0x0f0f0f0f0f0f0f0fULL);
515 return val;
518 target_ulong helper_popcntw (target_ulong val)
520 val = (val & 0x5555555555555555ULL) + ((val >> 1) &
521 0x5555555555555555ULL);
522 val = (val & 0x3333333333333333ULL) + ((val >> 2) &
523 0x3333333333333333ULL);
524 val = (val & 0x0f0f0f0f0f0f0f0fULL) + ((val >> 4) &
525 0x0f0f0f0f0f0f0f0fULL);
526 val = (val & 0x00ff00ff00ff00ffULL) + ((val >> 8) &
527 0x00ff00ff00ff00ffULL);
528 val = (val & 0x0000ffff0000ffffULL) + ((val >> 16) &
529 0x0000ffff0000ffffULL);
530 return val;
533 target_ulong helper_popcntd (target_ulong val)
535 return ctpop64(val);
537 #else
538 target_ulong helper_popcntb (target_ulong val)
540 val = (val & 0x55555555) + ((val >> 1) & 0x55555555);
541 val = (val & 0x33333333) + ((val >> 2) & 0x33333333);
542 val = (val & 0x0f0f0f0f) + ((val >> 4) & 0x0f0f0f0f);
543 return val;
546 target_ulong helper_popcntw (target_ulong val)
548 val = (val & 0x55555555) + ((val >> 1) & 0x55555555);
549 val = (val & 0x33333333) + ((val >> 2) & 0x33333333);
550 val = (val & 0x0f0f0f0f) + ((val >> 4) & 0x0f0f0f0f);
551 val = (val & 0x00ff00ff) + ((val >> 8) & 0x00ff00ff);
552 val = (val & 0x0000ffff) + ((val >> 16) & 0x0000ffff);
553 return val;
555 #endif
557 /*****************************************************************************/
558 /* Floating point operations helpers */
559 uint64_t helper_float32_to_float64(uint32_t arg)
561 CPU_FloatU f;
562 CPU_DoubleU d;
563 f.l = arg;
564 d.d = float32_to_float64(f.f, &env->fp_status);
565 return d.ll;
568 uint32_t helper_float64_to_float32(uint64_t arg)
570 CPU_FloatU f;
571 CPU_DoubleU d;
572 d.ll = arg;
573 f.f = float64_to_float32(d.d, &env->fp_status);
574 return f.l;
577 static inline int isden(float64 d)
579 CPU_DoubleU u;
581 u.d = d;
583 return ((u.ll >> 52) & 0x7FF) == 0;
586 uint32_t helper_compute_fprf (uint64_t arg, uint32_t set_fprf)
588 CPU_DoubleU farg;
589 int isneg;
590 int ret;
591 farg.ll = arg;
592 isneg = float64_is_neg(farg.d);
593 if (unlikely(float64_is_any_nan(farg.d))) {
594 if (float64_is_signaling_nan(farg.d)) {
595 /* Signaling NaN: flags are undefined */
596 ret = 0x00;
597 } else {
598 /* Quiet NaN */
599 ret = 0x11;
601 } else if (unlikely(float64_is_infinity(farg.d))) {
602 /* +/- infinity */
603 if (isneg)
604 ret = 0x09;
605 else
606 ret = 0x05;
607 } else {
608 if (float64_is_zero(farg.d)) {
609 /* +/- zero */
610 if (isneg)
611 ret = 0x12;
612 else
613 ret = 0x02;
614 } else {
615 if (isden(farg.d)) {
616 /* Denormalized numbers */
617 ret = 0x10;
618 } else {
619 /* Normalized numbers */
620 ret = 0x00;
622 if (isneg) {
623 ret |= 0x08;
624 } else {
625 ret |= 0x04;
629 if (set_fprf) {
630 /* We update FPSCR_FPRF */
631 env->fpscr &= ~(0x1F << FPSCR_FPRF);
632 env->fpscr |= ret << FPSCR_FPRF;
634 /* We just need fpcc to update Rc1 */
635 return ret & 0xF;
638 /* Floating-point invalid operations exception */
639 static inline uint64_t fload_invalid_op_excp(int op)
641 uint64_t ret = 0;
642 int ve;
644 ve = fpscr_ve;
645 switch (op) {
646 case POWERPC_EXCP_FP_VXSNAN:
647 env->fpscr |= 1 << FPSCR_VXSNAN;
648 break;
649 case POWERPC_EXCP_FP_VXSOFT:
650 env->fpscr |= 1 << FPSCR_VXSOFT;
651 break;
652 case POWERPC_EXCP_FP_VXISI:
653 /* Magnitude subtraction of infinities */
654 env->fpscr |= 1 << FPSCR_VXISI;
655 goto update_arith;
656 case POWERPC_EXCP_FP_VXIDI:
657 /* Division of infinity by infinity */
658 env->fpscr |= 1 << FPSCR_VXIDI;
659 goto update_arith;
660 case POWERPC_EXCP_FP_VXZDZ:
661 /* Division of zero by zero */
662 env->fpscr |= 1 << FPSCR_VXZDZ;
663 goto update_arith;
664 case POWERPC_EXCP_FP_VXIMZ:
665 /* Multiplication of zero by infinity */
666 env->fpscr |= 1 << FPSCR_VXIMZ;
667 goto update_arith;
668 case POWERPC_EXCP_FP_VXVC:
669 /* Ordered comparison of NaN */
670 env->fpscr |= 1 << FPSCR_VXVC;
671 env->fpscr &= ~(0xF << FPSCR_FPCC);
672 env->fpscr |= 0x11 << FPSCR_FPCC;
673 /* We must update the target FPR before raising the exception */
674 if (ve != 0) {
675 env->exception_index = POWERPC_EXCP_PROGRAM;
676 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_VXVC;
677 /* Update the floating-point enabled exception summary */
678 env->fpscr |= 1 << FPSCR_FEX;
679 /* Exception is differed */
680 ve = 0;
682 break;
683 case POWERPC_EXCP_FP_VXSQRT:
684 /* Square root of a negative number */
685 env->fpscr |= 1 << FPSCR_VXSQRT;
686 update_arith:
687 env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
688 if (ve == 0) {
689 /* Set the result to quiet NaN */
690 ret = 0x7FF8000000000000ULL;
691 env->fpscr &= ~(0xF << FPSCR_FPCC);
692 env->fpscr |= 0x11 << FPSCR_FPCC;
694 break;
695 case POWERPC_EXCP_FP_VXCVI:
696 /* Invalid conversion */
697 env->fpscr |= 1 << FPSCR_VXCVI;
698 env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
699 if (ve == 0) {
700 /* Set the result to quiet NaN */
701 ret = 0x7FF8000000000000ULL;
702 env->fpscr &= ~(0xF << FPSCR_FPCC);
703 env->fpscr |= 0x11 << FPSCR_FPCC;
705 break;
707 /* Update the floating-point invalid operation summary */
708 env->fpscr |= 1 << FPSCR_VX;
709 /* Update the floating-point exception summary */
710 env->fpscr |= 1 << FPSCR_FX;
711 if (ve != 0) {
712 /* Update the floating-point enabled exception summary */
713 env->fpscr |= 1 << FPSCR_FEX;
714 if (msr_fe0 != 0 || msr_fe1 != 0)
715 helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_FP | op);
717 return ret;
720 static inline void float_zero_divide_excp(void)
722 env->fpscr |= 1 << FPSCR_ZX;
723 env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
724 /* Update the floating-point exception summary */
725 env->fpscr |= 1 << FPSCR_FX;
726 if (fpscr_ze != 0) {
727 /* Update the floating-point enabled exception summary */
728 env->fpscr |= 1 << FPSCR_FEX;
729 if (msr_fe0 != 0 || msr_fe1 != 0) {
730 helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
731 POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX);
736 static inline void float_overflow_excp(void)
738 env->fpscr |= 1 << FPSCR_OX;
739 /* Update the floating-point exception summary */
740 env->fpscr |= 1 << FPSCR_FX;
741 if (fpscr_oe != 0) {
742 /* XXX: should adjust the result */
743 /* Update the floating-point enabled exception summary */
744 env->fpscr |= 1 << FPSCR_FEX;
745 /* We must update the target FPR before raising the exception */
746 env->exception_index = POWERPC_EXCP_PROGRAM;
747 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_OX;
748 } else {
749 env->fpscr |= 1 << FPSCR_XX;
750 env->fpscr |= 1 << FPSCR_FI;
754 static inline void float_underflow_excp(void)
756 env->fpscr |= 1 << FPSCR_UX;
757 /* Update the floating-point exception summary */
758 env->fpscr |= 1 << FPSCR_FX;
759 if (fpscr_ue != 0) {
760 /* XXX: should adjust the result */
761 /* Update the floating-point enabled exception summary */
762 env->fpscr |= 1 << FPSCR_FEX;
763 /* We must update the target FPR before raising the exception */
764 env->exception_index = POWERPC_EXCP_PROGRAM;
765 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_UX;
769 static inline void float_inexact_excp(void)
771 env->fpscr |= 1 << FPSCR_XX;
772 /* Update the floating-point exception summary */
773 env->fpscr |= 1 << FPSCR_FX;
774 if (fpscr_xe != 0) {
775 /* Update the floating-point enabled exception summary */
776 env->fpscr |= 1 << FPSCR_FEX;
777 /* We must update the target FPR before raising the exception */
778 env->exception_index = POWERPC_EXCP_PROGRAM;
779 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_XX;
783 static inline void fpscr_set_rounding_mode(void)
785 int rnd_type;
787 /* Set rounding mode */
788 switch (fpscr_rn) {
789 case 0:
790 /* Best approximation (round to nearest) */
791 rnd_type = float_round_nearest_even;
792 break;
793 case 1:
794 /* Smaller magnitude (round toward zero) */
795 rnd_type = float_round_to_zero;
796 break;
797 case 2:
798 /* Round toward +infinite */
799 rnd_type = float_round_up;
800 break;
801 default:
802 case 3:
803 /* Round toward -infinite */
804 rnd_type = float_round_down;
805 break;
807 set_float_rounding_mode(rnd_type, &env->fp_status);
810 void helper_fpscr_clrbit (uint32_t bit)
812 int prev;
814 prev = (env->fpscr >> bit) & 1;
815 env->fpscr &= ~(1 << bit);
816 if (prev == 1) {
817 switch (bit) {
818 case FPSCR_RN1:
819 case FPSCR_RN:
820 fpscr_set_rounding_mode();
821 break;
822 default:
823 break;
828 void helper_fpscr_setbit (uint32_t bit)
830 int prev;
832 prev = (env->fpscr >> bit) & 1;
833 env->fpscr |= 1 << bit;
834 if (prev == 0) {
835 switch (bit) {
836 case FPSCR_VX:
837 env->fpscr |= 1 << FPSCR_FX;
838 if (fpscr_ve)
839 goto raise_ve;
840 case FPSCR_OX:
841 env->fpscr |= 1 << FPSCR_FX;
842 if (fpscr_oe)
843 goto raise_oe;
844 break;
845 case FPSCR_UX:
846 env->fpscr |= 1 << FPSCR_FX;
847 if (fpscr_ue)
848 goto raise_ue;
849 break;
850 case FPSCR_ZX:
851 env->fpscr |= 1 << FPSCR_FX;
852 if (fpscr_ze)
853 goto raise_ze;
854 break;
855 case FPSCR_XX:
856 env->fpscr |= 1 << FPSCR_FX;
857 if (fpscr_xe)
858 goto raise_xe;
859 break;
860 case FPSCR_VXSNAN:
861 case FPSCR_VXISI:
862 case FPSCR_VXIDI:
863 case FPSCR_VXZDZ:
864 case FPSCR_VXIMZ:
865 case FPSCR_VXVC:
866 case FPSCR_VXSOFT:
867 case FPSCR_VXSQRT:
868 case FPSCR_VXCVI:
869 env->fpscr |= 1 << FPSCR_VX;
870 env->fpscr |= 1 << FPSCR_FX;
871 if (fpscr_ve != 0)
872 goto raise_ve;
873 break;
874 case FPSCR_VE:
875 if (fpscr_vx != 0) {
876 raise_ve:
877 env->error_code = POWERPC_EXCP_FP;
878 if (fpscr_vxsnan)
879 env->error_code |= POWERPC_EXCP_FP_VXSNAN;
880 if (fpscr_vxisi)
881 env->error_code |= POWERPC_EXCP_FP_VXISI;
882 if (fpscr_vxidi)
883 env->error_code |= POWERPC_EXCP_FP_VXIDI;
884 if (fpscr_vxzdz)
885 env->error_code |= POWERPC_EXCP_FP_VXZDZ;
886 if (fpscr_vximz)
887 env->error_code |= POWERPC_EXCP_FP_VXIMZ;
888 if (fpscr_vxvc)
889 env->error_code |= POWERPC_EXCP_FP_VXVC;
890 if (fpscr_vxsoft)
891 env->error_code |= POWERPC_EXCP_FP_VXSOFT;
892 if (fpscr_vxsqrt)
893 env->error_code |= POWERPC_EXCP_FP_VXSQRT;
894 if (fpscr_vxcvi)
895 env->error_code |= POWERPC_EXCP_FP_VXCVI;
896 goto raise_excp;
898 break;
899 case FPSCR_OE:
900 if (fpscr_ox != 0) {
901 raise_oe:
902 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_OX;
903 goto raise_excp;
905 break;
906 case FPSCR_UE:
907 if (fpscr_ux != 0) {
908 raise_ue:
909 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_UX;
910 goto raise_excp;
912 break;
913 case FPSCR_ZE:
914 if (fpscr_zx != 0) {
915 raise_ze:
916 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX;
917 goto raise_excp;
919 break;
920 case FPSCR_XE:
921 if (fpscr_xx != 0) {
922 raise_xe:
923 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_XX;
924 goto raise_excp;
926 break;
927 case FPSCR_RN1:
928 case FPSCR_RN:
929 fpscr_set_rounding_mode();
930 break;
931 default:
932 break;
933 raise_excp:
934 /* Update the floating-point enabled exception summary */
935 env->fpscr |= 1 << FPSCR_FEX;
936 /* We have to update Rc1 before raising the exception */
937 env->exception_index = POWERPC_EXCP_PROGRAM;
938 break;
943 void helper_store_fpscr (uint64_t arg, uint32_t mask)
946 * We use only the 32 LSB of the incoming fpr
948 uint32_t prev, new;
949 int i;
951 prev = env->fpscr;
952 new = (uint32_t)arg;
953 new &= ~0x60000000;
954 new |= prev & 0x60000000;
955 for (i = 0; i < 8; i++) {
956 if (mask & (1 << i)) {
957 env->fpscr &= ~(0xF << (4 * i));
958 env->fpscr |= new & (0xF << (4 * i));
961 /* Update VX and FEX */
962 if (fpscr_ix != 0)
963 env->fpscr |= 1 << FPSCR_VX;
964 else
965 env->fpscr &= ~(1 << FPSCR_VX);
966 if ((fpscr_ex & fpscr_eex) != 0) {
967 env->fpscr |= 1 << FPSCR_FEX;
968 env->exception_index = POWERPC_EXCP_PROGRAM;
969 /* XXX: we should compute it properly */
970 env->error_code = POWERPC_EXCP_FP;
972 else
973 env->fpscr &= ~(1 << FPSCR_FEX);
974 fpscr_set_rounding_mode();
977 void helper_float_check_status (void)
979 if (env->exception_index == POWERPC_EXCP_PROGRAM &&
980 (env->error_code & POWERPC_EXCP_FP)) {
981 /* Differred floating-point exception after target FPR update */
982 if (msr_fe0 != 0 || msr_fe1 != 0)
983 helper_raise_exception_err(env->exception_index, env->error_code);
984 } else {
985 int status = get_float_exception_flags(&env->fp_status);
986 if (status & float_flag_divbyzero) {
987 float_zero_divide_excp();
988 } else if (status & float_flag_overflow) {
989 float_overflow_excp();
990 } else if (status & float_flag_underflow) {
991 float_underflow_excp();
992 } else if (status & float_flag_inexact) {
993 float_inexact_excp();
998 void helper_reset_fpstatus (void)
1000 set_float_exception_flags(0, &env->fp_status);
1003 /* fadd - fadd. */
1004 uint64_t helper_fadd (uint64_t arg1, uint64_t arg2)
1006 CPU_DoubleU farg1, farg2;
1008 farg1.ll = arg1;
1009 farg2.ll = arg2;
1011 if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d) &&
1012 float64_is_neg(farg1.d) != float64_is_neg(farg2.d))) {
1013 /* Magnitude subtraction of infinities */
1014 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
1015 } else {
1016 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1017 float64_is_signaling_nan(farg2.d))) {
1018 /* sNaN addition */
1019 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1021 farg1.d = float64_add(farg1.d, farg2.d, &env->fp_status);
1024 return farg1.ll;
1027 /* fsub - fsub. */
1028 uint64_t helper_fsub (uint64_t arg1, uint64_t arg2)
1030 CPU_DoubleU farg1, farg2;
1032 farg1.ll = arg1;
1033 farg2.ll = arg2;
1035 if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d) &&
1036 float64_is_neg(farg1.d) == float64_is_neg(farg2.d))) {
1037 /* Magnitude subtraction of infinities */
1038 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
1039 } else {
1040 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1041 float64_is_signaling_nan(farg2.d))) {
1042 /* sNaN subtraction */
1043 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1045 farg1.d = float64_sub(farg1.d, farg2.d, &env->fp_status);
1048 return farg1.ll;
1051 /* fmul - fmul. */
1052 uint64_t helper_fmul (uint64_t arg1, uint64_t arg2)
1054 CPU_DoubleU farg1, farg2;
1056 farg1.ll = arg1;
1057 farg2.ll = arg2;
1059 if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
1060 (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
1061 /* Multiplication of zero by infinity */
1062 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
1063 } else {
1064 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1065 float64_is_signaling_nan(farg2.d))) {
1066 /* sNaN multiplication */
1067 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1069 farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
1072 return farg1.ll;
1075 /* fdiv - fdiv. */
1076 uint64_t helper_fdiv (uint64_t arg1, uint64_t arg2)
1078 CPU_DoubleU farg1, farg2;
1080 farg1.ll = arg1;
1081 farg2.ll = arg2;
1083 if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d))) {
1084 /* Division of infinity by infinity */
1085 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIDI);
1086 } else if (unlikely(float64_is_zero(farg1.d) && float64_is_zero(farg2.d))) {
1087 /* Division of zero by zero */
1088 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXZDZ);
1089 } else {
1090 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1091 float64_is_signaling_nan(farg2.d))) {
1092 /* sNaN division */
1093 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1095 farg1.d = float64_div(farg1.d, farg2.d, &env->fp_status);
1098 return farg1.ll;
1101 /* fabs */
1102 uint64_t helper_fabs (uint64_t arg)
1104 CPU_DoubleU farg;
1106 farg.ll = arg;
1107 farg.d = float64_abs(farg.d);
1108 return farg.ll;
1111 /* fnabs */
1112 uint64_t helper_fnabs (uint64_t arg)
1114 CPU_DoubleU farg;
1116 farg.ll = arg;
1117 farg.d = float64_abs(farg.d);
1118 farg.d = float64_chs(farg.d);
1119 return farg.ll;
1122 /* fneg */
1123 uint64_t helper_fneg (uint64_t arg)
1125 CPU_DoubleU farg;
1127 farg.ll = arg;
1128 farg.d = float64_chs(farg.d);
1129 return farg.ll;
1132 /* fctiw - fctiw. */
1133 uint64_t helper_fctiw (uint64_t arg)
1135 CPU_DoubleU farg;
1136 farg.ll = arg;
1138 if (unlikely(float64_is_signaling_nan(farg.d))) {
1139 /* sNaN conversion */
1140 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
1141 } else if (unlikely(float64_is_quiet_nan(farg.d) || float64_is_infinity(farg.d))) {
1142 /* qNan / infinity conversion */
1143 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
1144 } else {
1145 farg.ll = float64_to_int32(farg.d, &env->fp_status);
1146 /* XXX: higher bits are not supposed to be significant.
1147 * to make tests easier, return the same as a real PowerPC 750
1149 farg.ll |= 0xFFF80000ULL << 32;
1151 return farg.ll;
1154 /* fctiwz - fctiwz. */
1155 uint64_t helper_fctiwz (uint64_t arg)
1157 CPU_DoubleU farg;
1158 farg.ll = arg;
1160 if (unlikely(float64_is_signaling_nan(farg.d))) {
1161 /* sNaN conversion */
1162 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
1163 } else if (unlikely(float64_is_quiet_nan(farg.d) || float64_is_infinity(farg.d))) {
1164 /* qNan / infinity conversion */
1165 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
1166 } else {
1167 farg.ll = float64_to_int32_round_to_zero(farg.d, &env->fp_status);
1168 /* XXX: higher bits are not supposed to be significant.
1169 * to make tests easier, return the same as a real PowerPC 750
1171 farg.ll |= 0xFFF80000ULL << 32;
1173 return farg.ll;
1176 #if defined(TARGET_PPC64)
1177 /* fcfid - fcfid. */
1178 uint64_t helper_fcfid (uint64_t arg)
1180 CPU_DoubleU farg;
1181 farg.d = int64_to_float64(arg, &env->fp_status);
1182 return farg.ll;
1185 /* fctid - fctid. */
1186 uint64_t helper_fctid (uint64_t arg)
1188 CPU_DoubleU farg;
1189 farg.ll = arg;
1191 if (unlikely(float64_is_signaling_nan(farg.d))) {
1192 /* sNaN conversion */
1193 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
1194 } else if (unlikely(float64_is_quiet_nan(farg.d) || float64_is_infinity(farg.d))) {
1195 /* qNan / infinity conversion */
1196 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
1197 } else {
1198 farg.ll = float64_to_int64(farg.d, &env->fp_status);
1200 return farg.ll;
1203 /* fctidz - fctidz. */
1204 uint64_t helper_fctidz (uint64_t arg)
1206 CPU_DoubleU farg;
1207 farg.ll = arg;
1209 if (unlikely(float64_is_signaling_nan(farg.d))) {
1210 /* sNaN conversion */
1211 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
1212 } else if (unlikely(float64_is_quiet_nan(farg.d) || float64_is_infinity(farg.d))) {
1213 /* qNan / infinity conversion */
1214 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
1215 } else {
1216 farg.ll = float64_to_int64_round_to_zero(farg.d, &env->fp_status);
1218 return farg.ll;
1221 #endif
1223 static inline uint64_t do_fri(uint64_t arg, int rounding_mode)
1225 CPU_DoubleU farg;
1226 farg.ll = arg;
1228 if (unlikely(float64_is_signaling_nan(farg.d))) {
1229 /* sNaN round */
1230 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
1231 } else if (unlikely(float64_is_quiet_nan(farg.d) || float64_is_infinity(farg.d))) {
1232 /* qNan / infinity round */
1233 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
1234 } else {
1235 set_float_rounding_mode(rounding_mode, &env->fp_status);
1236 farg.ll = float64_round_to_int(farg.d, &env->fp_status);
1237 /* Restore rounding mode from FPSCR */
1238 fpscr_set_rounding_mode();
1240 return farg.ll;
1243 uint64_t helper_frin (uint64_t arg)
1245 return do_fri(arg, float_round_nearest_even);
1248 uint64_t helper_friz (uint64_t arg)
1250 return do_fri(arg, float_round_to_zero);
1253 uint64_t helper_frip (uint64_t arg)
1255 return do_fri(arg, float_round_up);
1258 uint64_t helper_frim (uint64_t arg)
1260 return do_fri(arg, float_round_down);
1263 /* fmadd - fmadd. */
1264 uint64_t helper_fmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3)
1266 CPU_DoubleU farg1, farg2, farg3;
1268 farg1.ll = arg1;
1269 farg2.ll = arg2;
1270 farg3.ll = arg3;
1272 if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
1273 (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
1274 /* Multiplication of zero by infinity */
1275 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
1276 } else {
1277 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1278 float64_is_signaling_nan(farg2.d) ||
1279 float64_is_signaling_nan(farg3.d))) {
1280 /* sNaN operation */
1281 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1283 /* This is the way the PowerPC specification defines it */
1284 float128 ft0_128, ft1_128;
1286 ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
1287 ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
1288 ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
1289 if (unlikely(float128_is_infinity(ft0_128) && float64_is_infinity(farg3.d) &&
1290 float128_is_neg(ft0_128) != float64_is_neg(farg3.d))) {
1291 /* Magnitude subtraction of infinities */
1292 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
1293 } else {
1294 ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
1295 ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
1296 farg1.d = float128_to_float64(ft0_128, &env->fp_status);
1300 return farg1.ll;
1303 /* fmsub - fmsub. */
1304 uint64_t helper_fmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3)
1306 CPU_DoubleU farg1, farg2, farg3;
1308 farg1.ll = arg1;
1309 farg2.ll = arg2;
1310 farg3.ll = arg3;
1312 if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
1313 (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
1314 /* Multiplication of zero by infinity */
1315 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
1316 } else {
1317 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1318 float64_is_signaling_nan(farg2.d) ||
1319 float64_is_signaling_nan(farg3.d))) {
1320 /* sNaN operation */
1321 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1323 /* This is the way the PowerPC specification defines it */
1324 float128 ft0_128, ft1_128;
1326 ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
1327 ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
1328 ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
1329 if (unlikely(float128_is_infinity(ft0_128) && float64_is_infinity(farg3.d) &&
1330 float128_is_neg(ft0_128) == float64_is_neg(farg3.d))) {
1331 /* Magnitude subtraction of infinities */
1332 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
1333 } else {
1334 ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
1335 ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
1336 farg1.d = float128_to_float64(ft0_128, &env->fp_status);
1339 return farg1.ll;
1342 /* fnmadd - fnmadd. */
1343 uint64_t helper_fnmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3)
1345 CPU_DoubleU farg1, farg2, farg3;
1347 farg1.ll = arg1;
1348 farg2.ll = arg2;
1349 farg3.ll = arg3;
1351 if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
1352 (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
1353 /* Multiplication of zero by infinity */
1354 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
1355 } else {
1356 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1357 float64_is_signaling_nan(farg2.d) ||
1358 float64_is_signaling_nan(farg3.d))) {
1359 /* sNaN operation */
1360 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1362 /* This is the way the PowerPC specification defines it */
1363 float128 ft0_128, ft1_128;
1365 ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
1366 ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
1367 ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
1368 if (unlikely(float128_is_infinity(ft0_128) && float64_is_infinity(farg3.d) &&
1369 float128_is_neg(ft0_128) != float64_is_neg(farg3.d))) {
1370 /* Magnitude subtraction of infinities */
1371 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
1372 } else {
1373 ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
1374 ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
1375 farg1.d = float128_to_float64(ft0_128, &env->fp_status);
1377 if (likely(!float64_is_any_nan(farg1.d))) {
1378 farg1.d = float64_chs(farg1.d);
1381 return farg1.ll;
1384 /* fnmsub - fnmsub. */
1385 uint64_t helper_fnmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3)
1387 CPU_DoubleU farg1, farg2, farg3;
1389 farg1.ll = arg1;
1390 farg2.ll = arg2;
1391 farg3.ll = arg3;
1393 if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
1394 (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
1395 /* Multiplication of zero by infinity */
1396 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
1397 } else {
1398 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1399 float64_is_signaling_nan(farg2.d) ||
1400 float64_is_signaling_nan(farg3.d))) {
1401 /* sNaN operation */
1402 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1404 /* This is the way the PowerPC specification defines it */
1405 float128 ft0_128, ft1_128;
1407 ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
1408 ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
1409 ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
1410 if (unlikely(float128_is_infinity(ft0_128) && float64_is_infinity(farg3.d) &&
1411 float128_is_neg(ft0_128) == float64_is_neg(farg3.d))) {
1412 /* Magnitude subtraction of infinities */
1413 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
1414 } else {
1415 ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
1416 ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
1417 farg1.d = float128_to_float64(ft0_128, &env->fp_status);
1419 if (likely(!float64_is_any_nan(farg1.d))) {
1420 farg1.d = float64_chs(farg1.d);
1423 return farg1.ll;
1426 /* frsp - frsp. */
1427 uint64_t helper_frsp (uint64_t arg)
1429 CPU_DoubleU farg;
1430 float32 f32;
1431 farg.ll = arg;
1433 if (unlikely(float64_is_signaling_nan(farg.d))) {
1434 /* sNaN square root */
1435 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1437 f32 = float64_to_float32(farg.d, &env->fp_status);
1438 farg.d = float32_to_float64(f32, &env->fp_status);
1440 return farg.ll;
1443 /* fsqrt - fsqrt. */
1444 uint64_t helper_fsqrt (uint64_t arg)
1446 CPU_DoubleU farg;
1447 farg.ll = arg;
1449 if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) {
1450 /* Square root of a negative nonzero number */
1451 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSQRT);
1452 } else {
1453 if (unlikely(float64_is_signaling_nan(farg.d))) {
1454 /* sNaN square root */
1455 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1457 farg.d = float64_sqrt(farg.d, &env->fp_status);
1459 return farg.ll;
1462 /* fre - fre. */
1463 uint64_t helper_fre (uint64_t arg)
1465 CPU_DoubleU farg;
1466 farg.ll = arg;
1468 if (unlikely(float64_is_signaling_nan(farg.d))) {
1469 /* sNaN reciprocal */
1470 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1472 farg.d = float64_div(float64_one, farg.d, &env->fp_status);
1473 return farg.d;
1476 /* fres - fres. */
1477 uint64_t helper_fres (uint64_t arg)
1479 CPU_DoubleU farg;
1480 float32 f32;
1481 farg.ll = arg;
1483 if (unlikely(float64_is_signaling_nan(farg.d))) {
1484 /* sNaN reciprocal */
1485 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1487 farg.d = float64_div(float64_one, farg.d, &env->fp_status);
1488 f32 = float64_to_float32(farg.d, &env->fp_status);
1489 farg.d = float32_to_float64(f32, &env->fp_status);
1491 return farg.ll;
1494 /* frsqrte - frsqrte. */
1495 uint64_t helper_frsqrte (uint64_t arg)
1497 CPU_DoubleU farg;
1498 float32 f32;
1499 farg.ll = arg;
1501 if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) {
1502 /* Reciprocal square root of a negative nonzero number */
1503 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSQRT);
1504 } else {
1505 if (unlikely(float64_is_signaling_nan(farg.d))) {
1506 /* sNaN reciprocal square root */
1507 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1509 farg.d = float64_sqrt(farg.d, &env->fp_status);
1510 farg.d = float64_div(float64_one, farg.d, &env->fp_status);
1511 f32 = float64_to_float32(farg.d, &env->fp_status);
1512 farg.d = float32_to_float64(f32, &env->fp_status);
1514 return farg.ll;
1517 /* fsel - fsel. */
1518 uint64_t helper_fsel (uint64_t arg1, uint64_t arg2, uint64_t arg3)
1520 CPU_DoubleU farg1;
1522 farg1.ll = arg1;
1524 if ((!float64_is_neg(farg1.d) || float64_is_zero(farg1.d)) && !float64_is_any_nan(farg1.d)) {
1525 return arg2;
1526 } else {
1527 return arg3;
1531 void helper_fcmpu (uint64_t arg1, uint64_t arg2, uint32_t crfD)
1533 CPU_DoubleU farg1, farg2;
1534 uint32_t ret = 0;
1535 farg1.ll = arg1;
1536 farg2.ll = arg2;
1538 if (unlikely(float64_is_any_nan(farg1.d) ||
1539 float64_is_any_nan(farg2.d))) {
1540 ret = 0x01UL;
1541 } else if (float64_lt(farg1.d, farg2.d, &env->fp_status)) {
1542 ret = 0x08UL;
1543 } else if (!float64_le(farg1.d, farg2.d, &env->fp_status)) {
1544 ret = 0x04UL;
1545 } else {
1546 ret = 0x02UL;
1549 env->fpscr &= ~(0x0F << FPSCR_FPRF);
1550 env->fpscr |= ret << FPSCR_FPRF;
1551 env->crf[crfD] = ret;
1552 if (unlikely(ret == 0x01UL
1553 && (float64_is_signaling_nan(farg1.d) ||
1554 float64_is_signaling_nan(farg2.d)))) {
1555 /* sNaN comparison */
1556 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1560 void helper_fcmpo (uint64_t arg1, uint64_t arg2, uint32_t crfD)
1562 CPU_DoubleU farg1, farg2;
1563 uint32_t ret = 0;
1564 farg1.ll = arg1;
1565 farg2.ll = arg2;
1567 if (unlikely(float64_is_any_nan(farg1.d) ||
1568 float64_is_any_nan(farg2.d))) {
1569 ret = 0x01UL;
1570 } else if (float64_lt(farg1.d, farg2.d, &env->fp_status)) {
1571 ret = 0x08UL;
1572 } else if (!float64_le(farg1.d, farg2.d, &env->fp_status)) {
1573 ret = 0x04UL;
1574 } else {
1575 ret = 0x02UL;
1578 env->fpscr &= ~(0x0F << FPSCR_FPRF);
1579 env->fpscr |= ret << FPSCR_FPRF;
1580 env->crf[crfD] = ret;
1581 if (unlikely (ret == 0x01UL)) {
1582 if (float64_is_signaling_nan(farg1.d) ||
1583 float64_is_signaling_nan(farg2.d)) {
1584 /* sNaN comparison */
1585 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN |
1586 POWERPC_EXCP_FP_VXVC);
1587 } else {
1588 /* qNaN comparison */
1589 fload_invalid_op_excp(POWERPC_EXCP_FP_VXVC);
1594 #if !defined (CONFIG_USER_ONLY)
1595 void helper_store_msr (target_ulong val)
1597 val = hreg_store_msr(env, val, 0);
1598 if (val != 0) {
1599 env->interrupt_request |= CPU_INTERRUPT_EXITTB;
1600 helper_raise_exception(val);
1604 static inline void do_rfi(target_ulong nip, target_ulong msr,
1605 target_ulong msrm, int keep_msrh)
1607 #if defined(TARGET_PPC64)
1608 if (msr & (1ULL << MSR_SF)) {
1609 nip = (uint64_t)nip;
1610 msr &= (uint64_t)msrm;
1611 } else {
1612 nip = (uint32_t)nip;
1613 msr = (uint32_t)(msr & msrm);
1614 if (keep_msrh)
1615 msr |= env->msr & ~((uint64_t)0xFFFFFFFF);
1617 #else
1618 nip = (uint32_t)nip;
1619 msr &= (uint32_t)msrm;
1620 #endif
1621 /* XXX: beware: this is false if VLE is supported */
1622 env->nip = nip & ~((target_ulong)0x00000003);
1623 hreg_store_msr(env, msr, 1);
1624 #if defined (DEBUG_OP)
1625 cpu_dump_rfi(env->nip, env->msr);
1626 #endif
1627 /* No need to raise an exception here,
1628 * as rfi is always the last insn of a TB
1630 env->interrupt_request |= CPU_INTERRUPT_EXITTB;
1633 void helper_rfi (void)
1635 do_rfi(env->spr[SPR_SRR0], env->spr[SPR_SRR1],
1636 ~((target_ulong)0x783F0000), 1);
1639 #if defined(TARGET_PPC64)
1640 void helper_rfid (void)
1642 do_rfi(env->spr[SPR_SRR0], env->spr[SPR_SRR1],
1643 ~((target_ulong)0x783F0000), 0);
1646 void helper_hrfid (void)
1648 do_rfi(env->spr[SPR_HSRR0], env->spr[SPR_HSRR1],
1649 ~((target_ulong)0x783F0000), 0);
1651 #endif
1652 #endif
1654 void helper_tw (target_ulong arg1, target_ulong arg2, uint32_t flags)
1656 if (!likely(!(((int32_t)arg1 < (int32_t)arg2 && (flags & 0x10)) ||
1657 ((int32_t)arg1 > (int32_t)arg2 && (flags & 0x08)) ||
1658 ((int32_t)arg1 == (int32_t)arg2 && (flags & 0x04)) ||
1659 ((uint32_t)arg1 < (uint32_t)arg2 && (flags & 0x02)) ||
1660 ((uint32_t)arg1 > (uint32_t)arg2 && (flags & 0x01))))) {
1661 helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_TRAP);
1665 #if defined(TARGET_PPC64)
1666 void helper_td (target_ulong arg1, target_ulong arg2, uint32_t flags)
1668 if (!likely(!(((int64_t)arg1 < (int64_t)arg2 && (flags & 0x10)) ||
1669 ((int64_t)arg1 > (int64_t)arg2 && (flags & 0x08)) ||
1670 ((int64_t)arg1 == (int64_t)arg2 && (flags & 0x04)) ||
1671 ((uint64_t)arg1 < (uint64_t)arg2 && (flags & 0x02)) ||
1672 ((uint64_t)arg1 > (uint64_t)arg2 && (flags & 0x01)))))
1673 helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_TRAP);
1675 #endif
1677 /*****************************************************************************/
1678 /* PowerPC 601 specific instructions (POWER bridge) */
1680 target_ulong helper_clcs (uint32_t arg)
1682 switch (arg) {
1683 case 0x0CUL:
1684 /* Instruction cache line size */
1685 return env->icache_line_size;
1686 break;
1687 case 0x0DUL:
1688 /* Data cache line size */
1689 return env->dcache_line_size;
1690 break;
1691 case 0x0EUL:
1692 /* Minimum cache line size */
1693 return (env->icache_line_size < env->dcache_line_size) ?
1694 env->icache_line_size : env->dcache_line_size;
1695 break;
1696 case 0x0FUL:
1697 /* Maximum cache line size */
1698 return (env->icache_line_size > env->dcache_line_size) ?
1699 env->icache_line_size : env->dcache_line_size;
1700 break;
1701 default:
1702 /* Undefined */
1703 return 0;
1704 break;
1708 target_ulong helper_div (target_ulong arg1, target_ulong arg2)
1710 uint64_t tmp = (uint64_t)arg1 << 32 | env->spr[SPR_MQ];
1712 if (((int32_t)tmp == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
1713 (int32_t)arg2 == 0) {
1714 env->spr[SPR_MQ] = 0;
1715 return INT32_MIN;
1716 } else {
1717 env->spr[SPR_MQ] = tmp % arg2;
1718 return tmp / (int32_t)arg2;
1722 target_ulong helper_divo (target_ulong arg1, target_ulong arg2)
1724 uint64_t tmp = (uint64_t)arg1 << 32 | env->spr[SPR_MQ];
1726 if (((int32_t)tmp == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
1727 (int32_t)arg2 == 0) {
1728 env->xer |= (1 << XER_OV) | (1 << XER_SO);
1729 env->spr[SPR_MQ] = 0;
1730 return INT32_MIN;
1731 } else {
1732 env->spr[SPR_MQ] = tmp % arg2;
1733 tmp /= (int32_t)arg2;
1734 if ((int32_t)tmp != tmp) {
1735 env->xer |= (1 << XER_OV) | (1 << XER_SO);
1736 } else {
1737 env->xer &= ~(1 << XER_OV);
1739 return tmp;
1743 target_ulong helper_divs (target_ulong arg1, target_ulong arg2)
1745 if (((int32_t)arg1 == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
1746 (int32_t)arg2 == 0) {
1747 env->spr[SPR_MQ] = 0;
1748 return INT32_MIN;
1749 } else {
1750 env->spr[SPR_MQ] = (int32_t)arg1 % (int32_t)arg2;
1751 return (int32_t)arg1 / (int32_t)arg2;
1755 target_ulong helper_divso (target_ulong arg1, target_ulong arg2)
1757 if (((int32_t)arg1 == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
1758 (int32_t)arg2 == 0) {
1759 env->xer |= (1 << XER_OV) | (1 << XER_SO);
1760 env->spr[SPR_MQ] = 0;
1761 return INT32_MIN;
1762 } else {
1763 env->xer &= ~(1 << XER_OV);
1764 env->spr[SPR_MQ] = (int32_t)arg1 % (int32_t)arg2;
1765 return (int32_t)arg1 / (int32_t)arg2;
1769 #if !defined (CONFIG_USER_ONLY)
1770 target_ulong helper_rac (target_ulong addr)
1772 mmu_ctx_t ctx;
1773 int nb_BATs;
1774 target_ulong ret = 0;
1776 /* We don't have to generate many instances of this instruction,
1777 * as rac is supervisor only.
1779 /* XXX: FIX THIS: Pretend we have no BAT */
1780 nb_BATs = env->nb_BATs;
1781 env->nb_BATs = 0;
1782 if (get_physical_address(env, &ctx, addr, 0, ACCESS_INT) == 0)
1783 ret = ctx.raddr;
1784 env->nb_BATs = nb_BATs;
1785 return ret;
1788 void helper_rfsvc (void)
1790 do_rfi(env->lr, env->ctr, 0x0000FFFF, 0);
1792 #endif
1794 /*****************************************************************************/
1795 /* 602 specific instructions */
1796 /* mfrom is the most crazy instruction ever seen, imho ! */
1797 /* Real implementation uses a ROM table. Do the same */
1798 /* Extremely decomposed:
1799 * -arg / 256
1800 * return 256 * log10(10 + 1.0) + 0.5
1802 #if !defined (CONFIG_USER_ONLY)
1803 target_ulong helper_602_mfrom (target_ulong arg)
1805 if (likely(arg < 602)) {
1806 #include "mfrom_table.c"
1807 return mfrom_ROM_table[arg];
1808 } else {
1809 return 0;
1812 #endif
1814 /*****************************************************************************/
1815 /* Embedded PowerPC specific helpers */
1817 /* XXX: to be improved to check access rights when in user-mode */
1818 target_ulong helper_load_dcr (target_ulong dcrn)
1820 uint32_t val = 0;
1822 if (unlikely(env->dcr_env == NULL)) {
1823 qemu_log("No DCR environment\n");
1824 helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
1825 POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL);
1826 } else if (unlikely(ppc_dcr_read(env->dcr_env, (uint32_t)dcrn, &val) != 0)) {
1827 qemu_log("DCR read error %d %03x\n", (uint32_t)dcrn, (uint32_t)dcrn);
1828 helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
1829 POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG);
1831 return val;
1834 void helper_store_dcr (target_ulong dcrn, target_ulong val)
1836 if (unlikely(env->dcr_env == NULL)) {
1837 qemu_log("No DCR environment\n");
1838 helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
1839 POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL);
1840 } else if (unlikely(ppc_dcr_write(env->dcr_env, (uint32_t)dcrn, (uint32_t)val) != 0)) {
1841 qemu_log("DCR write error %d %03x\n", (uint32_t)dcrn, (uint32_t)dcrn);
1842 helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
1843 POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG);
1847 #if !defined(CONFIG_USER_ONLY)
1848 void helper_40x_rfci (void)
1850 do_rfi(env->spr[SPR_40x_SRR2], env->spr[SPR_40x_SRR3],
1851 ~((target_ulong)0xFFFF0000), 0);
1854 void helper_rfci (void)
1856 do_rfi(env->spr[SPR_BOOKE_CSRR0], SPR_BOOKE_CSRR1,
1857 ~((target_ulong)0x3FFF0000), 0);
1860 void helper_rfdi (void)
1862 do_rfi(env->spr[SPR_BOOKE_DSRR0], SPR_BOOKE_DSRR1,
1863 ~((target_ulong)0x3FFF0000), 0);
1866 void helper_rfmci (void)
1868 do_rfi(env->spr[SPR_BOOKE_MCSRR0], SPR_BOOKE_MCSRR1,
1869 ~((target_ulong)0x3FFF0000), 0);
1871 #endif
1873 /* 440 specific */
1874 target_ulong helper_dlmzb (target_ulong high, target_ulong low, uint32_t update_Rc)
1876 target_ulong mask;
1877 int i;
1879 i = 1;
1880 for (mask = 0xFF000000; mask != 0; mask = mask >> 8) {
1881 if ((high & mask) == 0) {
1882 if (update_Rc) {
1883 env->crf[0] = 0x4;
1885 goto done;
1887 i++;
1889 for (mask = 0xFF000000; mask != 0; mask = mask >> 8) {
1890 if ((low & mask) == 0) {
1891 if (update_Rc) {
1892 env->crf[0] = 0x8;
1894 goto done;
1896 i++;
1898 if (update_Rc) {
1899 env->crf[0] = 0x2;
1901 done:
1902 env->xer = (env->xer & ~0x7F) | i;
1903 if (update_Rc) {
1904 env->crf[0] |= xer_so;
1906 return i;
1909 /*****************************************************************************/
1910 /* Altivec extension helpers */
1911 #if defined(HOST_WORDS_BIGENDIAN)
1912 #define HI_IDX 0
1913 #define LO_IDX 1
1914 #else
1915 #define HI_IDX 1
1916 #define LO_IDX 0
1917 #endif
1919 #if defined(HOST_WORDS_BIGENDIAN)
1920 #define VECTOR_FOR_INORDER_I(index, element) \
1921 for (index = 0; index < ARRAY_SIZE(r->element); index++)
1922 #else
1923 #define VECTOR_FOR_INORDER_I(index, element) \
1924 for (index = ARRAY_SIZE(r->element)-1; index >= 0; index--)
1925 #endif
1927 /* If X is a NaN, store the corresponding QNaN into RESULT. Otherwise,
1928 * execute the following block. */
1929 #define DO_HANDLE_NAN(result, x) \
1930 if (float32_is_any_nan(x)) { \
1931 CPU_FloatU __f; \
1932 __f.f = x; \
1933 __f.l = __f.l | (1 << 22); /* Set QNaN bit. */ \
1934 result = __f.f; \
1935 } else
1937 #define HANDLE_NAN1(result, x) \
1938 DO_HANDLE_NAN(result, x)
1939 #define HANDLE_NAN2(result, x, y) \
1940 DO_HANDLE_NAN(result, x) DO_HANDLE_NAN(result, y)
1941 #define HANDLE_NAN3(result, x, y, z) \
1942 DO_HANDLE_NAN(result, x) DO_HANDLE_NAN(result, y) DO_HANDLE_NAN(result, z)
1944 /* Saturating arithmetic helpers. */
1945 #define SATCVT(from, to, from_type, to_type, min, max) \
1946 static inline to_type cvt##from##to(from_type x, int *sat) \
1948 to_type r; \
1949 if (x < (from_type)min) { \
1950 r = min; \
1951 *sat = 1; \
1952 } else if (x > (from_type)max) { \
1953 r = max; \
1954 *sat = 1; \
1955 } else { \
1956 r = x; \
1958 return r; \
1960 #define SATCVTU(from, to, from_type, to_type, min, max) \
1961 static inline to_type cvt##from##to(from_type x, int *sat) \
1963 to_type r; \
1964 if (x > (from_type)max) { \
1965 r = max; \
1966 *sat = 1; \
1967 } else { \
1968 r = x; \
1970 return r; \
1972 SATCVT(sh, sb, int16_t, int8_t, INT8_MIN, INT8_MAX)
1973 SATCVT(sw, sh, int32_t, int16_t, INT16_MIN, INT16_MAX)
1974 SATCVT(sd, sw, int64_t, int32_t, INT32_MIN, INT32_MAX)
1976 SATCVTU(uh, ub, uint16_t, uint8_t, 0, UINT8_MAX)
1977 SATCVTU(uw, uh, uint32_t, uint16_t, 0, UINT16_MAX)
1978 SATCVTU(ud, uw, uint64_t, uint32_t, 0, UINT32_MAX)
1979 SATCVT(sh, ub, int16_t, uint8_t, 0, UINT8_MAX)
1980 SATCVT(sw, uh, int32_t, uint16_t, 0, UINT16_MAX)
1981 SATCVT(sd, uw, int64_t, uint32_t, 0, UINT32_MAX)
1982 #undef SATCVT
1983 #undef SATCVTU
1985 #define LVE(name, access, swap, element) \
1986 void helper_##name (ppc_avr_t *r, target_ulong addr) \
1988 size_t n_elems = ARRAY_SIZE(r->element); \
1989 int adjust = HI_IDX*(n_elems-1); \
1990 int sh = sizeof(r->element[0]) >> 1; \
1991 int index = (addr & 0xf) >> sh; \
1992 if(msr_le) { \
1993 r->element[LO_IDX ? index : (adjust - index)] = swap(access(addr)); \
1994 } else { \
1995 r->element[LO_IDX ? index : (adjust - index)] = access(addr); \
1998 #define I(x) (x)
1999 LVE(lvebx, ldub, I, u8)
2000 LVE(lvehx, lduw, bswap16, u16)
2001 LVE(lvewx, ldl, bswap32, u32)
2002 #undef I
2003 #undef LVE
2005 void helper_lvsl (ppc_avr_t *r, target_ulong sh)
2007 int i, j = (sh & 0xf);
2009 VECTOR_FOR_INORDER_I (i, u8) {
2010 r->u8[i] = j++;
2014 void helper_lvsr (ppc_avr_t *r, target_ulong sh)
2016 int i, j = 0x10 - (sh & 0xf);
2018 VECTOR_FOR_INORDER_I (i, u8) {
2019 r->u8[i] = j++;
2023 #define STVE(name, access, swap, element) \
2024 void helper_##name (ppc_avr_t *r, target_ulong addr) \
2026 size_t n_elems = ARRAY_SIZE(r->element); \
2027 int adjust = HI_IDX*(n_elems-1); \
2028 int sh = sizeof(r->element[0]) >> 1; \
2029 int index = (addr & 0xf) >> sh; \
2030 if(msr_le) { \
2031 access(addr, swap(r->element[LO_IDX ? index : (adjust - index)])); \
2032 } else { \
2033 access(addr, r->element[LO_IDX ? index : (adjust - index)]); \
2036 #define I(x) (x)
2037 STVE(stvebx, stb, I, u8)
2038 STVE(stvehx, stw, bswap16, u16)
2039 STVE(stvewx, stl, bswap32, u32)
2040 #undef I
2041 #undef LVE
2043 void helper_mtvscr (ppc_avr_t *r)
2045 #if defined(HOST_WORDS_BIGENDIAN)
2046 env->vscr = r->u32[3];
2047 #else
2048 env->vscr = r->u32[0];
2049 #endif
2050 set_flush_to_zero(vscr_nj, &env->vec_status);
2053 void helper_vaddcuw (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2055 int i;
2056 for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
2057 r->u32[i] = ~a->u32[i] < b->u32[i];
2061 #define VARITH_DO(name, op, element) \
2062 void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2064 int i; \
2065 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2066 r->element[i] = a->element[i] op b->element[i]; \
2069 #define VARITH(suffix, element) \
2070 VARITH_DO(add##suffix, +, element) \
2071 VARITH_DO(sub##suffix, -, element)
2072 VARITH(ubm, u8)
2073 VARITH(uhm, u16)
2074 VARITH(uwm, u32)
2075 #undef VARITH_DO
2076 #undef VARITH
2078 #define VARITHFP(suffix, func) \
2079 void helper_v##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2081 int i; \
2082 for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
2083 HANDLE_NAN2(r->f[i], a->f[i], b->f[i]) { \
2084 r->f[i] = func(a->f[i], b->f[i], &env->vec_status); \
2088 VARITHFP(addfp, float32_add)
2089 VARITHFP(subfp, float32_sub)
2090 #undef VARITHFP
2092 #define VARITHSAT_CASE(type, op, cvt, element) \
2094 type result = (type)a->element[i] op (type)b->element[i]; \
2095 r->element[i] = cvt(result, &sat); \
2098 #define VARITHSAT_DO(name, op, optype, cvt, element) \
2099 void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2101 int sat = 0; \
2102 int i; \
2103 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2104 switch (sizeof(r->element[0])) { \
2105 case 1: VARITHSAT_CASE(optype, op, cvt, element); break; \
2106 case 2: VARITHSAT_CASE(optype, op, cvt, element); break; \
2107 case 4: VARITHSAT_CASE(optype, op, cvt, element); break; \
2110 if (sat) { \
2111 env->vscr |= (1 << VSCR_SAT); \
2114 #define VARITHSAT_SIGNED(suffix, element, optype, cvt) \
2115 VARITHSAT_DO(adds##suffix##s, +, optype, cvt, element) \
2116 VARITHSAT_DO(subs##suffix##s, -, optype, cvt, element)
2117 #define VARITHSAT_UNSIGNED(suffix, element, optype, cvt) \
2118 VARITHSAT_DO(addu##suffix##s, +, optype, cvt, element) \
2119 VARITHSAT_DO(subu##suffix##s, -, optype, cvt, element)
2120 VARITHSAT_SIGNED(b, s8, int16_t, cvtshsb)
2121 VARITHSAT_SIGNED(h, s16, int32_t, cvtswsh)
2122 VARITHSAT_SIGNED(w, s32, int64_t, cvtsdsw)
2123 VARITHSAT_UNSIGNED(b, u8, uint16_t, cvtshub)
2124 VARITHSAT_UNSIGNED(h, u16, uint32_t, cvtswuh)
2125 VARITHSAT_UNSIGNED(w, u32, uint64_t, cvtsduw)
2126 #undef VARITHSAT_CASE
2127 #undef VARITHSAT_DO
2128 #undef VARITHSAT_SIGNED
2129 #undef VARITHSAT_UNSIGNED
2131 #define VAVG_DO(name, element, etype) \
2132 void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2134 int i; \
2135 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2136 etype x = (etype)a->element[i] + (etype)b->element[i] + 1; \
2137 r->element[i] = x >> 1; \
2141 #define VAVG(type, signed_element, signed_type, unsigned_element, unsigned_type) \
2142 VAVG_DO(avgs##type, signed_element, signed_type) \
2143 VAVG_DO(avgu##type, unsigned_element, unsigned_type)
2144 VAVG(b, s8, int16_t, u8, uint16_t)
2145 VAVG(h, s16, int32_t, u16, uint32_t)
2146 VAVG(w, s32, int64_t, u32, uint64_t)
2147 #undef VAVG_DO
2148 #undef VAVG
2150 #define VCF(suffix, cvt, element) \
2151 void helper_vcf##suffix (ppc_avr_t *r, ppc_avr_t *b, uint32_t uim) \
2153 int i; \
2154 for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
2155 float32 t = cvt(b->element[i], &env->vec_status); \
2156 r->f[i] = float32_scalbn (t, -uim, &env->vec_status); \
2159 VCF(ux, uint32_to_float32, u32)
2160 VCF(sx, int32_to_float32, s32)
2161 #undef VCF
2163 #define VCMP_DO(suffix, compare, element, record) \
2164 void helper_vcmp##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2166 uint32_t ones = (uint32_t)-1; \
2167 uint32_t all = ones; \
2168 uint32_t none = 0; \
2169 int i; \
2170 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2171 uint32_t result = (a->element[i] compare b->element[i] ? ones : 0x0); \
2172 switch (sizeof (a->element[0])) { \
2173 case 4: r->u32[i] = result; break; \
2174 case 2: r->u16[i] = result; break; \
2175 case 1: r->u8[i] = result; break; \
2177 all &= result; \
2178 none |= result; \
2180 if (record) { \
2181 env->crf[6] = ((all != 0) << 3) | ((none == 0) << 1); \
2184 #define VCMP(suffix, compare, element) \
2185 VCMP_DO(suffix, compare, element, 0) \
2186 VCMP_DO(suffix##_dot, compare, element, 1)
2187 VCMP(equb, ==, u8)
2188 VCMP(equh, ==, u16)
2189 VCMP(equw, ==, u32)
2190 VCMP(gtub, >, u8)
2191 VCMP(gtuh, >, u16)
2192 VCMP(gtuw, >, u32)
2193 VCMP(gtsb, >, s8)
2194 VCMP(gtsh, >, s16)
2195 VCMP(gtsw, >, s32)
2196 #undef VCMP_DO
2197 #undef VCMP
2199 #define VCMPFP_DO(suffix, compare, order, record) \
2200 void helper_vcmp##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2202 uint32_t ones = (uint32_t)-1; \
2203 uint32_t all = ones; \
2204 uint32_t none = 0; \
2205 int i; \
2206 for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
2207 uint32_t result; \
2208 int rel = float32_compare_quiet(a->f[i], b->f[i], &env->vec_status); \
2209 if (rel == float_relation_unordered) { \
2210 result = 0; \
2211 } else if (rel compare order) { \
2212 result = ones; \
2213 } else { \
2214 result = 0; \
2216 r->u32[i] = result; \
2217 all &= result; \
2218 none |= result; \
2220 if (record) { \
2221 env->crf[6] = ((all != 0) << 3) | ((none == 0) << 1); \
2224 #define VCMPFP(suffix, compare, order) \
2225 VCMPFP_DO(suffix, compare, order, 0) \
2226 VCMPFP_DO(suffix##_dot, compare, order, 1)
2227 VCMPFP(eqfp, ==, float_relation_equal)
2228 VCMPFP(gefp, !=, float_relation_less)
2229 VCMPFP(gtfp, ==, float_relation_greater)
2230 #undef VCMPFP_DO
2231 #undef VCMPFP
2233 static inline void vcmpbfp_internal(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b,
2234 int record)
2236 int i;
2237 int all_in = 0;
2238 for (i = 0; i < ARRAY_SIZE(r->f); i++) {
2239 int le_rel = float32_compare_quiet(a->f[i], b->f[i], &env->vec_status);
2240 if (le_rel == float_relation_unordered) {
2241 r->u32[i] = 0xc0000000;
2242 /* ALL_IN does not need to be updated here. */
2243 } else {
2244 float32 bneg = float32_chs(b->f[i]);
2245 int ge_rel = float32_compare_quiet(a->f[i], bneg, &env->vec_status);
2246 int le = le_rel != float_relation_greater;
2247 int ge = ge_rel != float_relation_less;
2248 r->u32[i] = ((!le) << 31) | ((!ge) << 30);
2249 all_in |= (!le | !ge);
2252 if (record) {
2253 env->crf[6] = (all_in == 0) << 1;
2257 void helper_vcmpbfp (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2259 vcmpbfp_internal(r, a, b, 0);
2262 void helper_vcmpbfp_dot (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2264 vcmpbfp_internal(r, a, b, 1);
2267 #define VCT(suffix, satcvt, element) \
2268 void helper_vct##suffix (ppc_avr_t *r, ppc_avr_t *b, uint32_t uim) \
2270 int i; \
2271 int sat = 0; \
2272 float_status s = env->vec_status; \
2273 set_float_rounding_mode(float_round_to_zero, &s); \
2274 for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
2275 if (float32_is_any_nan(b->f[i])) { \
2276 r->element[i] = 0; \
2277 } else { \
2278 float64 t = float32_to_float64(b->f[i], &s); \
2279 int64_t j; \
2280 t = float64_scalbn(t, uim, &s); \
2281 j = float64_to_int64(t, &s); \
2282 r->element[i] = satcvt(j, &sat); \
2285 if (sat) { \
2286 env->vscr |= (1 << VSCR_SAT); \
2289 VCT(uxs, cvtsduw, u32)
2290 VCT(sxs, cvtsdsw, s32)
2291 #undef VCT
2293 void helper_vmaddfp (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2295 int i;
2296 for (i = 0; i < ARRAY_SIZE(r->f); i++) {
2297 HANDLE_NAN3(r->f[i], a->f[i], b->f[i], c->f[i]) {
2298 /* Need to do the computation in higher precision and round
2299 * once at the end. */
2300 float64 af, bf, cf, t;
2301 af = float32_to_float64(a->f[i], &env->vec_status);
2302 bf = float32_to_float64(b->f[i], &env->vec_status);
2303 cf = float32_to_float64(c->f[i], &env->vec_status);
2304 t = float64_mul(af, cf, &env->vec_status);
2305 t = float64_add(t, bf, &env->vec_status);
2306 r->f[i] = float64_to_float32(t, &env->vec_status);
2311 void helper_vmhaddshs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2313 int sat = 0;
2314 int i;
2316 for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
2317 int32_t prod = a->s16[i] * b->s16[i];
2318 int32_t t = (int32_t)c->s16[i] + (prod >> 15);
2319 r->s16[i] = cvtswsh (t, &sat);
2322 if (sat) {
2323 env->vscr |= (1 << VSCR_SAT);
2327 void helper_vmhraddshs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2329 int sat = 0;
2330 int i;
2332 for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
2333 int32_t prod = a->s16[i] * b->s16[i] + 0x00004000;
2334 int32_t t = (int32_t)c->s16[i] + (prod >> 15);
2335 r->s16[i] = cvtswsh (t, &sat);
2338 if (sat) {
2339 env->vscr |= (1 << VSCR_SAT);
2343 #define VMINMAX_DO(name, compare, element) \
2344 void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2346 int i; \
2347 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2348 if (a->element[i] compare b->element[i]) { \
2349 r->element[i] = b->element[i]; \
2350 } else { \
2351 r->element[i] = a->element[i]; \
2355 #define VMINMAX(suffix, element) \
2356 VMINMAX_DO(min##suffix, >, element) \
2357 VMINMAX_DO(max##suffix, <, element)
2358 VMINMAX(sb, s8)
2359 VMINMAX(sh, s16)
2360 VMINMAX(sw, s32)
2361 VMINMAX(ub, u8)
2362 VMINMAX(uh, u16)
2363 VMINMAX(uw, u32)
2364 #undef VMINMAX_DO
2365 #undef VMINMAX
2367 #define VMINMAXFP(suffix, rT, rF) \
2368 void helper_v##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2370 int i; \
2371 for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
2372 HANDLE_NAN2(r->f[i], a->f[i], b->f[i]) { \
2373 if (float32_lt_quiet(a->f[i], b->f[i], &env->vec_status)) { \
2374 r->f[i] = rT->f[i]; \
2375 } else { \
2376 r->f[i] = rF->f[i]; \
2381 VMINMAXFP(minfp, a, b)
2382 VMINMAXFP(maxfp, b, a)
2383 #undef VMINMAXFP
2385 void helper_vmladduhm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2387 int i;
2388 for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
2389 int32_t prod = a->s16[i] * b->s16[i];
2390 r->s16[i] = (int16_t) (prod + c->s16[i]);
2394 #define VMRG_DO(name, element, highp) \
2395 void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2397 ppc_avr_t result; \
2398 int i; \
2399 size_t n_elems = ARRAY_SIZE(r->element); \
2400 for (i = 0; i < n_elems/2; i++) { \
2401 if (highp) { \
2402 result.element[i*2+HI_IDX] = a->element[i]; \
2403 result.element[i*2+LO_IDX] = b->element[i]; \
2404 } else { \
2405 result.element[n_elems - i*2 - (1+HI_IDX)] = b->element[n_elems - i - 1]; \
2406 result.element[n_elems - i*2 - (1+LO_IDX)] = a->element[n_elems - i - 1]; \
2409 *r = result; \
2411 #if defined(HOST_WORDS_BIGENDIAN)
2412 #define MRGHI 0
2413 #define MRGLO 1
2414 #else
2415 #define MRGHI 1
2416 #define MRGLO 0
2417 #endif
2418 #define VMRG(suffix, element) \
2419 VMRG_DO(mrgl##suffix, element, MRGHI) \
2420 VMRG_DO(mrgh##suffix, element, MRGLO)
2421 VMRG(b, u8)
2422 VMRG(h, u16)
2423 VMRG(w, u32)
2424 #undef VMRG_DO
2425 #undef VMRG
2426 #undef MRGHI
2427 #undef MRGLO
2429 void helper_vmsummbm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2431 int32_t prod[16];
2432 int i;
2434 for (i = 0; i < ARRAY_SIZE(r->s8); i++) {
2435 prod[i] = (int32_t)a->s8[i] * b->u8[i];
2438 VECTOR_FOR_INORDER_I(i, s32) {
2439 r->s32[i] = c->s32[i] + prod[4*i] + prod[4*i+1] + prod[4*i+2] + prod[4*i+3];
2443 void helper_vmsumshm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2445 int32_t prod[8];
2446 int i;
2448 for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
2449 prod[i] = a->s16[i] * b->s16[i];
2452 VECTOR_FOR_INORDER_I(i, s32) {
2453 r->s32[i] = c->s32[i] + prod[2*i] + prod[2*i+1];
2457 void helper_vmsumshs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2459 int32_t prod[8];
2460 int i;
2461 int sat = 0;
2463 for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
2464 prod[i] = (int32_t)a->s16[i] * b->s16[i];
2467 VECTOR_FOR_INORDER_I (i, s32) {
2468 int64_t t = (int64_t)c->s32[i] + prod[2*i] + prod[2*i+1];
2469 r->u32[i] = cvtsdsw(t, &sat);
2472 if (sat) {
2473 env->vscr |= (1 << VSCR_SAT);
2477 void helper_vmsumubm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2479 uint16_t prod[16];
2480 int i;
2482 for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
2483 prod[i] = a->u8[i] * b->u8[i];
2486 VECTOR_FOR_INORDER_I(i, u32) {
2487 r->u32[i] = c->u32[i] + prod[4*i] + prod[4*i+1] + prod[4*i+2] + prod[4*i+3];
2491 void helper_vmsumuhm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2493 uint32_t prod[8];
2494 int i;
2496 for (i = 0; i < ARRAY_SIZE(r->u16); i++) {
2497 prod[i] = a->u16[i] * b->u16[i];
2500 VECTOR_FOR_INORDER_I(i, u32) {
2501 r->u32[i] = c->u32[i] + prod[2*i] + prod[2*i+1];
2505 void helper_vmsumuhs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2507 uint32_t prod[8];
2508 int i;
2509 int sat = 0;
2511 for (i = 0; i < ARRAY_SIZE(r->u16); i++) {
2512 prod[i] = a->u16[i] * b->u16[i];
2515 VECTOR_FOR_INORDER_I (i, s32) {
2516 uint64_t t = (uint64_t)c->u32[i] + prod[2*i] + prod[2*i+1];
2517 r->u32[i] = cvtuduw(t, &sat);
2520 if (sat) {
2521 env->vscr |= (1 << VSCR_SAT);
2525 #define VMUL_DO(name, mul_element, prod_element, evenp) \
2526 void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2528 int i; \
2529 VECTOR_FOR_INORDER_I(i, prod_element) { \
2530 if (evenp) { \
2531 r->prod_element[i] = a->mul_element[i*2+HI_IDX] * b->mul_element[i*2+HI_IDX]; \
2532 } else { \
2533 r->prod_element[i] = a->mul_element[i*2+LO_IDX] * b->mul_element[i*2+LO_IDX]; \
2537 #define VMUL(suffix, mul_element, prod_element) \
2538 VMUL_DO(mule##suffix, mul_element, prod_element, 1) \
2539 VMUL_DO(mulo##suffix, mul_element, prod_element, 0)
2540 VMUL(sb, s8, s16)
2541 VMUL(sh, s16, s32)
2542 VMUL(ub, u8, u16)
2543 VMUL(uh, u16, u32)
2544 #undef VMUL_DO
2545 #undef VMUL
2547 void helper_vnmsubfp (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2549 int i;
2550 for (i = 0; i < ARRAY_SIZE(r->f); i++) {
2551 HANDLE_NAN3(r->f[i], a->f[i], b->f[i], c->f[i]) {
2552 /* Need to do the computation is higher precision and round
2553 * once at the end. */
2554 float64 af, bf, cf, t;
2555 af = float32_to_float64(a->f[i], &env->vec_status);
2556 bf = float32_to_float64(b->f[i], &env->vec_status);
2557 cf = float32_to_float64(c->f[i], &env->vec_status);
2558 t = float64_mul(af, cf, &env->vec_status);
2559 t = float64_sub(t, bf, &env->vec_status);
2560 t = float64_chs(t);
2561 r->f[i] = float64_to_float32(t, &env->vec_status);
2566 void helper_vperm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2568 ppc_avr_t result;
2569 int i;
2570 VECTOR_FOR_INORDER_I (i, u8) {
2571 int s = c->u8[i] & 0x1f;
2572 #if defined(HOST_WORDS_BIGENDIAN)
2573 int index = s & 0xf;
2574 #else
2575 int index = 15 - (s & 0xf);
2576 #endif
2577 if (s & 0x10) {
2578 result.u8[i] = b->u8[index];
2579 } else {
2580 result.u8[i] = a->u8[index];
2583 *r = result;
2586 #if defined(HOST_WORDS_BIGENDIAN)
2587 #define PKBIG 1
2588 #else
2589 #define PKBIG 0
2590 #endif
2591 void helper_vpkpx (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2593 int i, j;
2594 ppc_avr_t result;
2595 #if defined(HOST_WORDS_BIGENDIAN)
2596 const ppc_avr_t *x[2] = { a, b };
2597 #else
2598 const ppc_avr_t *x[2] = { b, a };
2599 #endif
2601 VECTOR_FOR_INORDER_I (i, u64) {
2602 VECTOR_FOR_INORDER_I (j, u32){
2603 uint32_t e = x[i]->u32[j];
2604 result.u16[4*i+j] = (((e >> 9) & 0xfc00) |
2605 ((e >> 6) & 0x3e0) |
2606 ((e >> 3) & 0x1f));
2609 *r = result;
2612 #define VPK(suffix, from, to, cvt, dosat) \
2613 void helper_vpk##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2615 int i; \
2616 int sat = 0; \
2617 ppc_avr_t result; \
2618 ppc_avr_t *a0 = PKBIG ? a : b; \
2619 ppc_avr_t *a1 = PKBIG ? b : a; \
2620 VECTOR_FOR_INORDER_I (i, from) { \
2621 result.to[i] = cvt(a0->from[i], &sat); \
2622 result.to[i+ARRAY_SIZE(r->from)] = cvt(a1->from[i], &sat); \
2624 *r = result; \
2625 if (dosat && sat) { \
2626 env->vscr |= (1 << VSCR_SAT); \
2629 #define I(x, y) (x)
2630 VPK(shss, s16, s8, cvtshsb, 1)
2631 VPK(shus, s16, u8, cvtshub, 1)
2632 VPK(swss, s32, s16, cvtswsh, 1)
2633 VPK(swus, s32, u16, cvtswuh, 1)
2634 VPK(uhus, u16, u8, cvtuhub, 1)
2635 VPK(uwus, u32, u16, cvtuwuh, 1)
2636 VPK(uhum, u16, u8, I, 0)
2637 VPK(uwum, u32, u16, I, 0)
2638 #undef I
2639 #undef VPK
2640 #undef PKBIG
2642 void helper_vrefp (ppc_avr_t *r, ppc_avr_t *b)
2644 int i;
2645 for (i = 0; i < ARRAY_SIZE(r->f); i++) {
2646 HANDLE_NAN1(r->f[i], b->f[i]) {
2647 r->f[i] = float32_div(float32_one, b->f[i], &env->vec_status);
2652 #define VRFI(suffix, rounding) \
2653 void helper_vrfi##suffix (ppc_avr_t *r, ppc_avr_t *b) \
2655 int i; \
2656 float_status s = env->vec_status; \
2657 set_float_rounding_mode(rounding, &s); \
2658 for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
2659 HANDLE_NAN1(r->f[i], b->f[i]) { \
2660 r->f[i] = float32_round_to_int (b->f[i], &s); \
2664 VRFI(n, float_round_nearest_even)
2665 VRFI(m, float_round_down)
2666 VRFI(p, float_round_up)
2667 VRFI(z, float_round_to_zero)
2668 #undef VRFI
2670 #define VROTATE(suffix, element) \
2671 void helper_vrl##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2673 int i; \
2674 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2675 unsigned int mask = ((1 << (3 + (sizeof (a->element[0]) >> 1))) - 1); \
2676 unsigned int shift = b->element[i] & mask; \
2677 r->element[i] = (a->element[i] << shift) | (a->element[i] >> (sizeof(a->element[0]) * 8 - shift)); \
2680 VROTATE(b, u8)
2681 VROTATE(h, u16)
2682 VROTATE(w, u32)
2683 #undef VROTATE
2685 void helper_vrsqrtefp (ppc_avr_t *r, ppc_avr_t *b)
2687 int i;
2688 for (i = 0; i < ARRAY_SIZE(r->f); i++) {
2689 HANDLE_NAN1(r->f[i], b->f[i]) {
2690 float32 t = float32_sqrt(b->f[i], &env->vec_status);
2691 r->f[i] = float32_div(float32_one, t, &env->vec_status);
2696 void helper_vsel (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2698 r->u64[0] = (a->u64[0] & ~c->u64[0]) | (b->u64[0] & c->u64[0]);
2699 r->u64[1] = (a->u64[1] & ~c->u64[1]) | (b->u64[1] & c->u64[1]);
2702 void helper_vexptefp (ppc_avr_t *r, ppc_avr_t *b)
2704 int i;
2705 for (i = 0; i < ARRAY_SIZE(r->f); i++) {
2706 HANDLE_NAN1(r->f[i], b->f[i]) {
2707 r->f[i] = float32_exp2(b->f[i], &env->vec_status);
2712 void helper_vlogefp (ppc_avr_t *r, ppc_avr_t *b)
2714 int i;
2715 for (i = 0; i < ARRAY_SIZE(r->f); i++) {
2716 HANDLE_NAN1(r->f[i], b->f[i]) {
2717 r->f[i] = float32_log2(b->f[i], &env->vec_status);
2722 #if defined(HOST_WORDS_BIGENDIAN)
2723 #define LEFT 0
2724 #define RIGHT 1
2725 #else
2726 #define LEFT 1
2727 #define RIGHT 0
2728 #endif
2729 /* The specification says that the results are undefined if all of the
2730 * shift counts are not identical. We check to make sure that they are
2731 * to conform to what real hardware appears to do. */
2732 #define VSHIFT(suffix, leftp) \
2733 void helper_vs##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2735 int shift = b->u8[LO_IDX*15] & 0x7; \
2736 int doit = 1; \
2737 int i; \
2738 for (i = 0; i < ARRAY_SIZE(r->u8); i++) { \
2739 doit = doit && ((b->u8[i] & 0x7) == shift); \
2741 if (doit) { \
2742 if (shift == 0) { \
2743 *r = *a; \
2744 } else if (leftp) { \
2745 uint64_t carry = a->u64[LO_IDX] >> (64 - shift); \
2746 r->u64[HI_IDX] = (a->u64[HI_IDX] << shift) | carry; \
2747 r->u64[LO_IDX] = a->u64[LO_IDX] << shift; \
2748 } else { \
2749 uint64_t carry = a->u64[HI_IDX] << (64 - shift); \
2750 r->u64[LO_IDX] = (a->u64[LO_IDX] >> shift) | carry; \
2751 r->u64[HI_IDX] = a->u64[HI_IDX] >> shift; \
2755 VSHIFT(l, LEFT)
2756 VSHIFT(r, RIGHT)
2757 #undef VSHIFT
2758 #undef LEFT
2759 #undef RIGHT
2761 #define VSL(suffix, element) \
2762 void helper_vsl##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2764 int i; \
2765 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2766 unsigned int mask = ((1 << (3 + (sizeof (a->element[0]) >> 1))) - 1); \
2767 unsigned int shift = b->element[i] & mask; \
2768 r->element[i] = a->element[i] << shift; \
2771 VSL(b, u8)
2772 VSL(h, u16)
2773 VSL(w, u32)
2774 #undef VSL
2776 void helper_vsldoi (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t shift)
2778 int sh = shift & 0xf;
2779 int i;
2780 ppc_avr_t result;
2782 #if defined(HOST_WORDS_BIGENDIAN)
2783 for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
2784 int index = sh + i;
2785 if (index > 0xf) {
2786 result.u8[i] = b->u8[index-0x10];
2787 } else {
2788 result.u8[i] = a->u8[index];
2791 #else
2792 for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
2793 int index = (16 - sh) + i;
2794 if (index > 0xf) {
2795 result.u8[i] = a->u8[index-0x10];
2796 } else {
2797 result.u8[i] = b->u8[index];
2800 #endif
2801 *r = result;
2804 void helper_vslo (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2806 int sh = (b->u8[LO_IDX*0xf] >> 3) & 0xf;
2808 #if defined (HOST_WORDS_BIGENDIAN)
2809 memmove (&r->u8[0], &a->u8[sh], 16-sh);
2810 memset (&r->u8[16-sh], 0, sh);
2811 #else
2812 memmove (&r->u8[sh], &a->u8[0], 16-sh);
2813 memset (&r->u8[0], 0, sh);
2814 #endif
2817 /* Experimental testing shows that hardware masks the immediate. */
2818 #define _SPLAT_MASKED(element) (splat & (ARRAY_SIZE(r->element) - 1))
2819 #if defined(HOST_WORDS_BIGENDIAN)
2820 #define SPLAT_ELEMENT(element) _SPLAT_MASKED(element)
2821 #else
2822 #define SPLAT_ELEMENT(element) (ARRAY_SIZE(r->element)-1 - _SPLAT_MASKED(element))
2823 #endif
2824 #define VSPLT(suffix, element) \
2825 void helper_vsplt##suffix (ppc_avr_t *r, ppc_avr_t *b, uint32_t splat) \
2827 uint32_t s = b->element[SPLAT_ELEMENT(element)]; \
2828 int i; \
2829 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2830 r->element[i] = s; \
2833 VSPLT(b, u8)
2834 VSPLT(h, u16)
2835 VSPLT(w, u32)
2836 #undef VSPLT
2837 #undef SPLAT_ELEMENT
2838 #undef _SPLAT_MASKED
2840 #define VSPLTI(suffix, element, splat_type) \
2841 void helper_vspltis##suffix (ppc_avr_t *r, uint32_t splat) \
2843 splat_type x = (int8_t)(splat << 3) >> 3; \
2844 int i; \
2845 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2846 r->element[i] = x; \
2849 VSPLTI(b, s8, int8_t)
2850 VSPLTI(h, s16, int16_t)
2851 VSPLTI(w, s32, int32_t)
2852 #undef VSPLTI
2854 #define VSR(suffix, element) \
2855 void helper_vsr##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2857 int i; \
2858 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2859 unsigned int mask = ((1 << (3 + (sizeof (a->element[0]) >> 1))) - 1); \
2860 unsigned int shift = b->element[i] & mask; \
2861 r->element[i] = a->element[i] >> shift; \
2864 VSR(ab, s8)
2865 VSR(ah, s16)
2866 VSR(aw, s32)
2867 VSR(b, u8)
2868 VSR(h, u16)
2869 VSR(w, u32)
2870 #undef VSR
2872 void helper_vsro (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2874 int sh = (b->u8[LO_IDX*0xf] >> 3) & 0xf;
2876 #if defined (HOST_WORDS_BIGENDIAN)
2877 memmove (&r->u8[sh], &a->u8[0], 16-sh);
2878 memset (&r->u8[0], 0, sh);
2879 #else
2880 memmove (&r->u8[0], &a->u8[sh], 16-sh);
2881 memset (&r->u8[16-sh], 0, sh);
2882 #endif
2885 void helper_vsubcuw (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2887 int i;
2888 for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
2889 r->u32[i] = a->u32[i] >= b->u32[i];
2893 void helper_vsumsws (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2895 int64_t t;
2896 int i, upper;
2897 ppc_avr_t result;
2898 int sat = 0;
2900 #if defined(HOST_WORDS_BIGENDIAN)
2901 upper = ARRAY_SIZE(r->s32)-1;
2902 #else
2903 upper = 0;
2904 #endif
2905 t = (int64_t)b->s32[upper];
2906 for (i = 0; i < ARRAY_SIZE(r->s32); i++) {
2907 t += a->s32[i];
2908 result.s32[i] = 0;
2910 result.s32[upper] = cvtsdsw(t, &sat);
2911 *r = result;
2913 if (sat) {
2914 env->vscr |= (1 << VSCR_SAT);
2918 void helper_vsum2sws (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2920 int i, j, upper;
2921 ppc_avr_t result;
2922 int sat = 0;
2924 #if defined(HOST_WORDS_BIGENDIAN)
2925 upper = 1;
2926 #else
2927 upper = 0;
2928 #endif
2929 for (i = 0; i < ARRAY_SIZE(r->u64); i++) {
2930 int64_t t = (int64_t)b->s32[upper+i*2];
2931 result.u64[i] = 0;
2932 for (j = 0; j < ARRAY_SIZE(r->u64); j++) {
2933 t += a->s32[2*i+j];
2935 result.s32[upper+i*2] = cvtsdsw(t, &sat);
2938 *r = result;
2939 if (sat) {
2940 env->vscr |= (1 << VSCR_SAT);
2944 void helper_vsum4sbs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2946 int i, j;
2947 int sat = 0;
2949 for (i = 0; i < ARRAY_SIZE(r->s32); i++) {
2950 int64_t t = (int64_t)b->s32[i];
2951 for (j = 0; j < ARRAY_SIZE(r->s32); j++) {
2952 t += a->s8[4*i+j];
2954 r->s32[i] = cvtsdsw(t, &sat);
2957 if (sat) {
2958 env->vscr |= (1 << VSCR_SAT);
2962 void helper_vsum4shs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2964 int sat = 0;
2965 int i;
2967 for (i = 0; i < ARRAY_SIZE(r->s32); i++) {
2968 int64_t t = (int64_t)b->s32[i];
2969 t += a->s16[2*i] + a->s16[2*i+1];
2970 r->s32[i] = cvtsdsw(t, &sat);
2973 if (sat) {
2974 env->vscr |= (1 << VSCR_SAT);
2978 void helper_vsum4ubs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2980 int i, j;
2981 int sat = 0;
2983 for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
2984 uint64_t t = (uint64_t)b->u32[i];
2985 for (j = 0; j < ARRAY_SIZE(r->u32); j++) {
2986 t += a->u8[4*i+j];
2988 r->u32[i] = cvtuduw(t, &sat);
2991 if (sat) {
2992 env->vscr |= (1 << VSCR_SAT);
2996 #if defined(HOST_WORDS_BIGENDIAN)
2997 #define UPKHI 1
2998 #define UPKLO 0
2999 #else
3000 #define UPKHI 0
3001 #define UPKLO 1
3002 #endif
3003 #define VUPKPX(suffix, hi) \
3004 void helper_vupk##suffix (ppc_avr_t *r, ppc_avr_t *b) \
3006 int i; \
3007 ppc_avr_t result; \
3008 for (i = 0; i < ARRAY_SIZE(r->u32); i++) { \
3009 uint16_t e = b->u16[hi ? i : i+4]; \
3010 uint8_t a = (e >> 15) ? 0xff : 0; \
3011 uint8_t r = (e >> 10) & 0x1f; \
3012 uint8_t g = (e >> 5) & 0x1f; \
3013 uint8_t b = e & 0x1f; \
3014 result.u32[i] = (a << 24) | (r << 16) | (g << 8) | b; \
3016 *r = result; \
3018 VUPKPX(lpx, UPKLO)
3019 VUPKPX(hpx, UPKHI)
3020 #undef VUPKPX
3022 #define VUPK(suffix, unpacked, packee, hi) \
3023 void helper_vupk##suffix (ppc_avr_t *r, ppc_avr_t *b) \
3025 int i; \
3026 ppc_avr_t result; \
3027 if (hi) { \
3028 for (i = 0; i < ARRAY_SIZE(r->unpacked); i++) { \
3029 result.unpacked[i] = b->packee[i]; \
3031 } else { \
3032 for (i = ARRAY_SIZE(r->unpacked); i < ARRAY_SIZE(r->packee); i++) { \
3033 result.unpacked[i-ARRAY_SIZE(r->unpacked)] = b->packee[i]; \
3036 *r = result; \
3038 VUPK(hsb, s16, s8, UPKHI)
3039 VUPK(hsh, s32, s16, UPKHI)
3040 VUPK(lsb, s16, s8, UPKLO)
3041 VUPK(lsh, s32, s16, UPKLO)
3042 #undef VUPK
3043 #undef UPKHI
3044 #undef UPKLO
3046 #undef DO_HANDLE_NAN
3047 #undef HANDLE_NAN1
3048 #undef HANDLE_NAN2
3049 #undef HANDLE_NAN3
3050 #undef VECTOR_FOR_INORDER_I
3051 #undef HI_IDX
3052 #undef LO_IDX
3054 /*****************************************************************************/
3055 /* SPE extension helpers */
3056 /* Use a table to make this quicker */
3057 static uint8_t hbrev[16] = {
3058 0x0, 0x8, 0x4, 0xC, 0x2, 0xA, 0x6, 0xE,
3059 0x1, 0x9, 0x5, 0xD, 0x3, 0xB, 0x7, 0xF,
3062 static inline uint8_t byte_reverse(uint8_t val)
3064 return hbrev[val >> 4] | (hbrev[val & 0xF] << 4);
3067 static inline uint32_t word_reverse(uint32_t val)
3069 return byte_reverse(val >> 24) | (byte_reverse(val >> 16) << 8) |
3070 (byte_reverse(val >> 8) << 16) | (byte_reverse(val) << 24);
3073 #define MASKBITS 16 // Random value - to be fixed (implementation dependent)
3074 target_ulong helper_brinc (target_ulong arg1, target_ulong arg2)
3076 uint32_t a, b, d, mask;
3078 mask = UINT32_MAX >> (32 - MASKBITS);
3079 a = arg1 & mask;
3080 b = arg2 & mask;
3081 d = word_reverse(1 + word_reverse(a | ~b));
3082 return (arg1 & ~mask) | (d & b);
3085 uint32_t helper_cntlsw32 (uint32_t val)
3087 if (val & 0x80000000)
3088 return clz32(~val);
3089 else
3090 return clz32(val);
3093 uint32_t helper_cntlzw32 (uint32_t val)
3095 return clz32(val);
3098 /* Single-precision floating-point conversions */
3099 static inline uint32_t efscfsi(uint32_t val)
3101 CPU_FloatU u;
3103 u.f = int32_to_float32(val, &env->vec_status);
3105 return u.l;
3108 static inline uint32_t efscfui(uint32_t val)
3110 CPU_FloatU u;
3112 u.f = uint32_to_float32(val, &env->vec_status);
3114 return u.l;
3117 static inline int32_t efsctsi(uint32_t val)
3119 CPU_FloatU u;
3121 u.l = val;
3122 /* NaN are not treated the same way IEEE 754 does */
3123 if (unlikely(float32_is_quiet_nan(u.f)))
3124 return 0;
3126 return float32_to_int32(u.f, &env->vec_status);
3129 static inline uint32_t efsctui(uint32_t val)
3131 CPU_FloatU u;
3133 u.l = val;
3134 /* NaN are not treated the same way IEEE 754 does */
3135 if (unlikely(float32_is_quiet_nan(u.f)))
3136 return 0;
3138 return float32_to_uint32(u.f, &env->vec_status);
3141 static inline uint32_t efsctsiz(uint32_t val)
3143 CPU_FloatU u;
3145 u.l = val;
3146 /* NaN are not treated the same way IEEE 754 does */
3147 if (unlikely(float32_is_quiet_nan(u.f)))
3148 return 0;
3150 return float32_to_int32_round_to_zero(u.f, &env->vec_status);
3153 static inline uint32_t efsctuiz(uint32_t val)
3155 CPU_FloatU u;
3157 u.l = val;
3158 /* NaN are not treated the same way IEEE 754 does */
3159 if (unlikely(float32_is_quiet_nan(u.f)))
3160 return 0;
3162 return float32_to_uint32_round_to_zero(u.f, &env->vec_status);
3165 static inline uint32_t efscfsf(uint32_t val)
3167 CPU_FloatU u;
3168 float32 tmp;
3170 u.f = int32_to_float32(val, &env->vec_status);
3171 tmp = int64_to_float32(1ULL << 32, &env->vec_status);
3172 u.f = float32_div(u.f, tmp, &env->vec_status);
3174 return u.l;
3177 static inline uint32_t efscfuf(uint32_t val)
3179 CPU_FloatU u;
3180 float32 tmp;
3182 u.f = uint32_to_float32(val, &env->vec_status);
3183 tmp = uint64_to_float32(1ULL << 32, &env->vec_status);
3184 u.f = float32_div(u.f, tmp, &env->vec_status);
3186 return u.l;
3189 static inline uint32_t efsctsf(uint32_t val)
3191 CPU_FloatU u;
3192 float32 tmp;
3194 u.l = val;
3195 /* NaN are not treated the same way IEEE 754 does */
3196 if (unlikely(float32_is_quiet_nan(u.f)))
3197 return 0;
3198 tmp = uint64_to_float32(1ULL << 32, &env->vec_status);
3199 u.f = float32_mul(u.f, tmp, &env->vec_status);
3201 return float32_to_int32(u.f, &env->vec_status);
3204 static inline uint32_t efsctuf(uint32_t val)
3206 CPU_FloatU u;
3207 float32 tmp;
3209 u.l = val;
3210 /* NaN are not treated the same way IEEE 754 does */
3211 if (unlikely(float32_is_quiet_nan(u.f)))
3212 return 0;
3213 tmp = uint64_to_float32(1ULL << 32, &env->vec_status);
3214 u.f = float32_mul(u.f, tmp, &env->vec_status);
3216 return float32_to_uint32(u.f, &env->vec_status);
3219 #define HELPER_SPE_SINGLE_CONV(name) \
3220 uint32_t helper_e##name (uint32_t val) \
3222 return e##name(val); \
3224 /* efscfsi */
3225 HELPER_SPE_SINGLE_CONV(fscfsi);
3226 /* efscfui */
3227 HELPER_SPE_SINGLE_CONV(fscfui);
3228 /* efscfuf */
3229 HELPER_SPE_SINGLE_CONV(fscfuf);
3230 /* efscfsf */
3231 HELPER_SPE_SINGLE_CONV(fscfsf);
3232 /* efsctsi */
3233 HELPER_SPE_SINGLE_CONV(fsctsi);
3234 /* efsctui */
3235 HELPER_SPE_SINGLE_CONV(fsctui);
3236 /* efsctsiz */
3237 HELPER_SPE_SINGLE_CONV(fsctsiz);
3238 /* efsctuiz */
3239 HELPER_SPE_SINGLE_CONV(fsctuiz);
3240 /* efsctsf */
3241 HELPER_SPE_SINGLE_CONV(fsctsf);
3242 /* efsctuf */
3243 HELPER_SPE_SINGLE_CONV(fsctuf);
3245 #define HELPER_SPE_VECTOR_CONV(name) \
3246 uint64_t helper_ev##name (uint64_t val) \
3248 return ((uint64_t)e##name(val >> 32) << 32) | \
3249 (uint64_t)e##name(val); \
3251 /* evfscfsi */
3252 HELPER_SPE_VECTOR_CONV(fscfsi);
3253 /* evfscfui */
3254 HELPER_SPE_VECTOR_CONV(fscfui);
3255 /* evfscfuf */
3256 HELPER_SPE_VECTOR_CONV(fscfuf);
3257 /* evfscfsf */
3258 HELPER_SPE_VECTOR_CONV(fscfsf);
3259 /* evfsctsi */
3260 HELPER_SPE_VECTOR_CONV(fsctsi);
3261 /* evfsctui */
3262 HELPER_SPE_VECTOR_CONV(fsctui);
3263 /* evfsctsiz */
3264 HELPER_SPE_VECTOR_CONV(fsctsiz);
3265 /* evfsctuiz */
3266 HELPER_SPE_VECTOR_CONV(fsctuiz);
3267 /* evfsctsf */
3268 HELPER_SPE_VECTOR_CONV(fsctsf);
3269 /* evfsctuf */
3270 HELPER_SPE_VECTOR_CONV(fsctuf);
3272 /* Single-precision floating-point arithmetic */
3273 static inline uint32_t efsadd(uint32_t op1, uint32_t op2)
3275 CPU_FloatU u1, u2;
3276 u1.l = op1;
3277 u2.l = op2;
3278 u1.f = float32_add(u1.f, u2.f, &env->vec_status);
3279 return u1.l;
3282 static inline uint32_t efssub(uint32_t op1, uint32_t op2)
3284 CPU_FloatU u1, u2;
3285 u1.l = op1;
3286 u2.l = op2;
3287 u1.f = float32_sub(u1.f, u2.f, &env->vec_status);
3288 return u1.l;
3291 static inline uint32_t efsmul(uint32_t op1, uint32_t op2)
3293 CPU_FloatU u1, u2;
3294 u1.l = op1;
3295 u2.l = op2;
3296 u1.f = float32_mul(u1.f, u2.f, &env->vec_status);
3297 return u1.l;
3300 static inline uint32_t efsdiv(uint32_t op1, uint32_t op2)
3302 CPU_FloatU u1, u2;
3303 u1.l = op1;
3304 u2.l = op2;
3305 u1.f = float32_div(u1.f, u2.f, &env->vec_status);
3306 return u1.l;
3309 #define HELPER_SPE_SINGLE_ARITH(name) \
3310 uint32_t helper_e##name (uint32_t op1, uint32_t op2) \
3312 return e##name(op1, op2); \
3314 /* efsadd */
3315 HELPER_SPE_SINGLE_ARITH(fsadd);
3316 /* efssub */
3317 HELPER_SPE_SINGLE_ARITH(fssub);
3318 /* efsmul */
3319 HELPER_SPE_SINGLE_ARITH(fsmul);
3320 /* efsdiv */
3321 HELPER_SPE_SINGLE_ARITH(fsdiv);
3323 #define HELPER_SPE_VECTOR_ARITH(name) \
3324 uint64_t helper_ev##name (uint64_t op1, uint64_t op2) \
3326 return ((uint64_t)e##name(op1 >> 32, op2 >> 32) << 32) | \
3327 (uint64_t)e##name(op1, op2); \
3329 /* evfsadd */
3330 HELPER_SPE_VECTOR_ARITH(fsadd);
3331 /* evfssub */
3332 HELPER_SPE_VECTOR_ARITH(fssub);
3333 /* evfsmul */
3334 HELPER_SPE_VECTOR_ARITH(fsmul);
3335 /* evfsdiv */
3336 HELPER_SPE_VECTOR_ARITH(fsdiv);
3338 /* Single-precision floating-point comparisons */
3339 static inline uint32_t efscmplt(uint32_t op1, uint32_t op2)
3341 CPU_FloatU u1, u2;
3342 u1.l = op1;
3343 u2.l = op2;
3344 return float32_lt(u1.f, u2.f, &env->vec_status) ? 4 : 0;
3347 static inline uint32_t efscmpgt(uint32_t op1, uint32_t op2)
3349 CPU_FloatU u1, u2;
3350 u1.l = op1;
3351 u2.l = op2;
3352 return float32_le(u1.f, u2.f, &env->vec_status) ? 0 : 4;
3355 static inline uint32_t efscmpeq(uint32_t op1, uint32_t op2)
3357 CPU_FloatU u1, u2;
3358 u1.l = op1;
3359 u2.l = op2;
3360 return float32_eq(u1.f, u2.f, &env->vec_status) ? 4 : 0;
3363 static inline uint32_t efststlt(uint32_t op1, uint32_t op2)
3365 /* XXX: TODO: ignore special values (NaN, infinites, ...) */
3366 return efscmplt(op1, op2);
3369 static inline uint32_t efststgt(uint32_t op1, uint32_t op2)
3371 /* XXX: TODO: ignore special values (NaN, infinites, ...) */
3372 return efscmpgt(op1, op2);
3375 static inline uint32_t efststeq(uint32_t op1, uint32_t op2)
3377 /* XXX: TODO: ignore special values (NaN, infinites, ...) */
3378 return efscmpeq(op1, op2);
3381 #define HELPER_SINGLE_SPE_CMP(name) \
3382 uint32_t helper_e##name (uint32_t op1, uint32_t op2) \
3384 return e##name(op1, op2) << 2; \
3386 /* efststlt */
3387 HELPER_SINGLE_SPE_CMP(fststlt);
3388 /* efststgt */
3389 HELPER_SINGLE_SPE_CMP(fststgt);
3390 /* efststeq */
3391 HELPER_SINGLE_SPE_CMP(fststeq);
3392 /* efscmplt */
3393 HELPER_SINGLE_SPE_CMP(fscmplt);
3394 /* efscmpgt */
3395 HELPER_SINGLE_SPE_CMP(fscmpgt);
3396 /* efscmpeq */
3397 HELPER_SINGLE_SPE_CMP(fscmpeq);
3399 static inline uint32_t evcmp_merge(int t0, int t1)
3401 return (t0 << 3) | (t1 << 2) | ((t0 | t1) << 1) | (t0 & t1);
3404 #define HELPER_VECTOR_SPE_CMP(name) \
3405 uint32_t helper_ev##name (uint64_t op1, uint64_t op2) \
3407 return evcmp_merge(e##name(op1 >> 32, op2 >> 32), e##name(op1, op2)); \
3409 /* evfststlt */
3410 HELPER_VECTOR_SPE_CMP(fststlt);
3411 /* evfststgt */
3412 HELPER_VECTOR_SPE_CMP(fststgt);
3413 /* evfststeq */
3414 HELPER_VECTOR_SPE_CMP(fststeq);
3415 /* evfscmplt */
3416 HELPER_VECTOR_SPE_CMP(fscmplt);
3417 /* evfscmpgt */
3418 HELPER_VECTOR_SPE_CMP(fscmpgt);
3419 /* evfscmpeq */
3420 HELPER_VECTOR_SPE_CMP(fscmpeq);
3422 /* Double-precision floating-point conversion */
3423 uint64_t helper_efdcfsi (uint32_t val)
3425 CPU_DoubleU u;
3427 u.d = int32_to_float64(val, &env->vec_status);
3429 return u.ll;
3432 uint64_t helper_efdcfsid (uint64_t val)
3434 CPU_DoubleU u;
3436 u.d = int64_to_float64(val, &env->vec_status);
3438 return u.ll;
3441 uint64_t helper_efdcfui (uint32_t val)
3443 CPU_DoubleU u;
3445 u.d = uint32_to_float64(val, &env->vec_status);
3447 return u.ll;
3450 uint64_t helper_efdcfuid (uint64_t val)
3452 CPU_DoubleU u;
3454 u.d = uint64_to_float64(val, &env->vec_status);
3456 return u.ll;
3459 uint32_t helper_efdctsi (uint64_t val)
3461 CPU_DoubleU u;
3463 u.ll = val;
3464 /* NaN are not treated the same way IEEE 754 does */
3465 if (unlikely(float64_is_any_nan(u.d))) {
3466 return 0;
3469 return float64_to_int32(u.d, &env->vec_status);
3472 uint32_t helper_efdctui (uint64_t val)
3474 CPU_DoubleU u;
3476 u.ll = val;
3477 /* NaN are not treated the same way IEEE 754 does */
3478 if (unlikely(float64_is_any_nan(u.d))) {
3479 return 0;
3482 return float64_to_uint32(u.d, &env->vec_status);
3485 uint32_t helper_efdctsiz (uint64_t val)
3487 CPU_DoubleU u;
3489 u.ll = val;
3490 /* NaN are not treated the same way IEEE 754 does */
3491 if (unlikely(float64_is_any_nan(u.d))) {
3492 return 0;
3495 return float64_to_int32_round_to_zero(u.d, &env->vec_status);
3498 uint64_t helper_efdctsidz (uint64_t val)
3500 CPU_DoubleU u;
3502 u.ll = val;
3503 /* NaN are not treated the same way IEEE 754 does */
3504 if (unlikely(float64_is_any_nan(u.d))) {
3505 return 0;
3508 return float64_to_int64_round_to_zero(u.d, &env->vec_status);
3511 uint32_t helper_efdctuiz (uint64_t val)
3513 CPU_DoubleU u;
3515 u.ll = val;
3516 /* NaN are not treated the same way IEEE 754 does */
3517 if (unlikely(float64_is_any_nan(u.d))) {
3518 return 0;
3521 return float64_to_uint32_round_to_zero(u.d, &env->vec_status);
3524 uint64_t helper_efdctuidz (uint64_t val)
3526 CPU_DoubleU u;
3528 u.ll = val;
3529 /* NaN are not treated the same way IEEE 754 does */
3530 if (unlikely(float64_is_any_nan(u.d))) {
3531 return 0;
3534 return float64_to_uint64_round_to_zero(u.d, &env->vec_status);
3537 uint64_t helper_efdcfsf (uint32_t val)
3539 CPU_DoubleU u;
3540 float64 tmp;
3542 u.d = int32_to_float64(val, &env->vec_status);
3543 tmp = int64_to_float64(1ULL << 32, &env->vec_status);
3544 u.d = float64_div(u.d, tmp, &env->vec_status);
3546 return u.ll;
3549 uint64_t helper_efdcfuf (uint32_t val)
3551 CPU_DoubleU u;
3552 float64 tmp;
3554 u.d = uint32_to_float64(val, &env->vec_status);
3555 tmp = int64_to_float64(1ULL << 32, &env->vec_status);
3556 u.d = float64_div(u.d, tmp, &env->vec_status);
3558 return u.ll;
3561 uint32_t helper_efdctsf (uint64_t val)
3563 CPU_DoubleU u;
3564 float64 tmp;
3566 u.ll = val;
3567 /* NaN are not treated the same way IEEE 754 does */
3568 if (unlikely(float64_is_any_nan(u.d))) {
3569 return 0;
3571 tmp = uint64_to_float64(1ULL << 32, &env->vec_status);
3572 u.d = float64_mul(u.d, tmp, &env->vec_status);
3574 return float64_to_int32(u.d, &env->vec_status);
3577 uint32_t helper_efdctuf (uint64_t val)
3579 CPU_DoubleU u;
3580 float64 tmp;
3582 u.ll = val;
3583 /* NaN are not treated the same way IEEE 754 does */
3584 if (unlikely(float64_is_any_nan(u.d))) {
3585 return 0;
3587 tmp = uint64_to_float64(1ULL << 32, &env->vec_status);
3588 u.d = float64_mul(u.d, tmp, &env->vec_status);
3590 return float64_to_uint32(u.d, &env->vec_status);
3593 uint32_t helper_efscfd (uint64_t val)
3595 CPU_DoubleU u1;
3596 CPU_FloatU u2;
3598 u1.ll = val;
3599 u2.f = float64_to_float32(u1.d, &env->vec_status);
3601 return u2.l;
3604 uint64_t helper_efdcfs (uint32_t val)
3606 CPU_DoubleU u2;
3607 CPU_FloatU u1;
3609 u1.l = val;
3610 u2.d = float32_to_float64(u1.f, &env->vec_status);
3612 return u2.ll;
3615 /* Double precision fixed-point arithmetic */
3616 uint64_t helper_efdadd (uint64_t op1, uint64_t op2)
3618 CPU_DoubleU u1, u2;
3619 u1.ll = op1;
3620 u2.ll = op2;
3621 u1.d = float64_add(u1.d, u2.d, &env->vec_status);
3622 return u1.ll;
3625 uint64_t helper_efdsub (uint64_t op1, uint64_t op2)
3627 CPU_DoubleU u1, u2;
3628 u1.ll = op1;
3629 u2.ll = op2;
3630 u1.d = float64_sub(u1.d, u2.d, &env->vec_status);
3631 return u1.ll;
3634 uint64_t helper_efdmul (uint64_t op1, uint64_t op2)
3636 CPU_DoubleU u1, u2;
3637 u1.ll = op1;
3638 u2.ll = op2;
3639 u1.d = float64_mul(u1.d, u2.d, &env->vec_status);
3640 return u1.ll;
3643 uint64_t helper_efddiv (uint64_t op1, uint64_t op2)
3645 CPU_DoubleU u1, u2;
3646 u1.ll = op1;
3647 u2.ll = op2;
3648 u1.d = float64_div(u1.d, u2.d, &env->vec_status);
3649 return u1.ll;
3652 /* Double precision floating point helpers */
3653 uint32_t helper_efdtstlt (uint64_t op1, uint64_t op2)
3655 CPU_DoubleU u1, u2;
3656 u1.ll = op1;
3657 u2.ll = op2;
3658 return float64_lt(u1.d, u2.d, &env->vec_status) ? 4 : 0;
3661 uint32_t helper_efdtstgt (uint64_t op1, uint64_t op2)
3663 CPU_DoubleU u1, u2;
3664 u1.ll = op1;
3665 u2.ll = op2;
3666 return float64_le(u1.d, u2.d, &env->vec_status) ? 0 : 4;
3669 uint32_t helper_efdtsteq (uint64_t op1, uint64_t op2)
3671 CPU_DoubleU u1, u2;
3672 u1.ll = op1;
3673 u2.ll = op2;
3674 return float64_eq_quiet(u1.d, u2.d, &env->vec_status) ? 4 : 0;
3677 uint32_t helper_efdcmplt (uint64_t op1, uint64_t op2)
3679 /* XXX: TODO: test special values (NaN, infinites, ...) */
3680 return helper_efdtstlt(op1, op2);
3683 uint32_t helper_efdcmpgt (uint64_t op1, uint64_t op2)
3685 /* XXX: TODO: test special values (NaN, infinites, ...) */
3686 return helper_efdtstgt(op1, op2);
3689 uint32_t helper_efdcmpeq (uint64_t op1, uint64_t op2)
3691 /* XXX: TODO: test special values (NaN, infinites, ...) */
3692 return helper_efdtsteq(op1, op2);
3695 /*****************************************************************************/
3696 /* Softmmu support */
3697 #if !defined (CONFIG_USER_ONLY)
3699 #define MMUSUFFIX _mmu
3701 #define SHIFT 0
3702 #include "softmmu_template.h"
3704 #define SHIFT 1
3705 #include "softmmu_template.h"
3707 #define SHIFT 2
3708 #include "softmmu_template.h"
3710 #define SHIFT 3
3711 #include "softmmu_template.h"
3713 /* try to fill the TLB and return an exception if error. If retaddr is
3714 NULL, it means that the function was called in C code (i.e. not
3715 from generated code or from helper.c) */
3716 /* XXX: fix it to restore all registers */
3717 void tlb_fill(CPUPPCState *env1, target_ulong addr, int is_write, int mmu_idx,
3718 void *retaddr)
3720 TranslationBlock *tb;
3721 CPUPPCState *saved_env;
3722 unsigned long pc;
3723 int ret;
3725 saved_env = env;
3726 env = env1;
3727 ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, mmu_idx);
3728 if (unlikely(ret != 0)) {
3729 if (likely(retaddr)) {
3730 /* now we have a real cpu fault */
3731 pc = (unsigned long)retaddr;
3732 tb = tb_find_pc(pc);
3733 if (likely(tb)) {
3734 /* the PC is inside the translated code. It means that we have
3735 a virtual CPU fault */
3736 cpu_restore_state(tb, env, pc);
3739 helper_raise_exception_err(env->exception_index, env->error_code);
3741 env = saved_env;
3744 /* Segment registers load and store */
3745 target_ulong helper_load_sr (target_ulong sr_num)
3747 #if defined(TARGET_PPC64)
3748 if (env->mmu_model & POWERPC_MMU_64)
3749 return ppc_load_sr(env, sr_num);
3750 #endif
3751 return env->sr[sr_num];
3754 void helper_store_sr (target_ulong sr_num, target_ulong val)
3756 ppc_store_sr(env, sr_num, val);
3759 /* SLB management */
3760 #if defined(TARGET_PPC64)
3761 void helper_store_slb (target_ulong rb, target_ulong rs)
3763 if (ppc_store_slb(env, rb, rs) < 0) {
3764 helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_INVAL);
3768 target_ulong helper_load_slb_esid (target_ulong rb)
3770 target_ulong rt;
3772 if (ppc_load_slb_esid(env, rb, &rt) < 0) {
3773 helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_INVAL);
3775 return rt;
3778 target_ulong helper_load_slb_vsid (target_ulong rb)
3780 target_ulong rt;
3782 if (ppc_load_slb_vsid(env, rb, &rt) < 0) {
3783 helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_INVAL);
3785 return rt;
3788 void helper_slbia (void)
3790 ppc_slb_invalidate_all(env);
3793 void helper_slbie (target_ulong addr)
3795 ppc_slb_invalidate_one(env, addr);
3798 #endif /* defined(TARGET_PPC64) */
3800 /* TLB management */
3801 void helper_tlbia (void)
3803 ppc_tlb_invalidate_all(env);
3806 void helper_tlbie (target_ulong addr)
3808 ppc_tlb_invalidate_one(env, addr);
3811 /* Software driven TLBs management */
3812 /* PowerPC 602/603 software TLB load instructions helpers */
3813 static void do_6xx_tlb (target_ulong new_EPN, int is_code)
3815 target_ulong RPN, CMP, EPN;
3816 int way;
3818 RPN = env->spr[SPR_RPA];
3819 if (is_code) {
3820 CMP = env->spr[SPR_ICMP];
3821 EPN = env->spr[SPR_IMISS];
3822 } else {
3823 CMP = env->spr[SPR_DCMP];
3824 EPN = env->spr[SPR_DMISS];
3826 way = (env->spr[SPR_SRR1] >> 17) & 1;
3827 (void)EPN; /* avoid a compiler warning */
3828 LOG_SWTLB("%s: EPN " TARGET_FMT_lx " " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
3829 " PTE1 " TARGET_FMT_lx " way %d\n", __func__, new_EPN, EPN, CMP,
3830 RPN, way);
3831 /* Store this TLB */
3832 ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
3833 way, is_code, CMP, RPN);
3836 void helper_6xx_tlbd (target_ulong EPN)
3838 do_6xx_tlb(EPN, 0);
3841 void helper_6xx_tlbi (target_ulong EPN)
3843 do_6xx_tlb(EPN, 1);
3846 /* PowerPC 74xx software TLB load instructions helpers */
3847 static void do_74xx_tlb (target_ulong new_EPN, int is_code)
3849 target_ulong RPN, CMP, EPN;
3850 int way;
3852 RPN = env->spr[SPR_PTELO];
3853 CMP = env->spr[SPR_PTEHI];
3854 EPN = env->spr[SPR_TLBMISS] & ~0x3;
3855 way = env->spr[SPR_TLBMISS] & 0x3;
3856 (void)EPN; /* avoid a compiler warning */
3857 LOG_SWTLB("%s: EPN " TARGET_FMT_lx " " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
3858 " PTE1 " TARGET_FMT_lx " way %d\n", __func__, new_EPN, EPN, CMP,
3859 RPN, way);
3860 /* Store this TLB */
3861 ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
3862 way, is_code, CMP, RPN);
3865 void helper_74xx_tlbd (target_ulong EPN)
3867 do_74xx_tlb(EPN, 0);
3870 void helper_74xx_tlbi (target_ulong EPN)
3872 do_74xx_tlb(EPN, 1);
3875 static inline target_ulong booke_tlb_to_page_size(int size)
3877 return 1024 << (2 * size);
3880 static inline int booke_page_size_to_tlb(target_ulong page_size)
3882 int size;
3884 switch (page_size) {
3885 case 0x00000400UL:
3886 size = 0x0;
3887 break;
3888 case 0x00001000UL:
3889 size = 0x1;
3890 break;
3891 case 0x00004000UL:
3892 size = 0x2;
3893 break;
3894 case 0x00010000UL:
3895 size = 0x3;
3896 break;
3897 case 0x00040000UL:
3898 size = 0x4;
3899 break;
3900 case 0x00100000UL:
3901 size = 0x5;
3902 break;
3903 case 0x00400000UL:
3904 size = 0x6;
3905 break;
3906 case 0x01000000UL:
3907 size = 0x7;
3908 break;
3909 case 0x04000000UL:
3910 size = 0x8;
3911 break;
3912 case 0x10000000UL:
3913 size = 0x9;
3914 break;
3915 case 0x40000000UL:
3916 size = 0xA;
3917 break;
3918 #if defined (TARGET_PPC64)
3919 case 0x000100000000ULL:
3920 size = 0xB;
3921 break;
3922 case 0x000400000000ULL:
3923 size = 0xC;
3924 break;
3925 case 0x001000000000ULL:
3926 size = 0xD;
3927 break;
3928 case 0x004000000000ULL:
3929 size = 0xE;
3930 break;
3931 case 0x010000000000ULL:
3932 size = 0xF;
3933 break;
3934 #endif
3935 default:
3936 size = -1;
3937 break;
3940 return size;
3943 /* Helpers for 4xx TLB management */
3944 #define PPC4XX_TLB_ENTRY_MASK 0x0000003f /* Mask for 64 TLB entries */
3946 #define PPC4XX_TLBHI_V 0x00000040
3947 #define PPC4XX_TLBHI_E 0x00000020
3948 #define PPC4XX_TLBHI_SIZE_MIN 0
3949 #define PPC4XX_TLBHI_SIZE_MAX 7
3950 #define PPC4XX_TLBHI_SIZE_DEFAULT 1
3951 #define PPC4XX_TLBHI_SIZE_SHIFT 7
3952 #define PPC4XX_TLBHI_SIZE_MASK 0x00000007
3954 #define PPC4XX_TLBLO_EX 0x00000200
3955 #define PPC4XX_TLBLO_WR 0x00000100
3956 #define PPC4XX_TLBLO_ATTR_MASK 0x000000FF
3957 #define PPC4XX_TLBLO_RPN_MASK 0xFFFFFC00
3959 target_ulong helper_4xx_tlbre_hi (target_ulong entry)
3961 ppcemb_tlb_t *tlb;
3962 target_ulong ret;
3963 int size;
3965 entry &= PPC4XX_TLB_ENTRY_MASK;
3966 tlb = &env->tlb.tlbe[entry];
3967 ret = tlb->EPN;
3968 if (tlb->prot & PAGE_VALID) {
3969 ret |= PPC4XX_TLBHI_V;
3971 size = booke_page_size_to_tlb(tlb->size);
3972 if (size < PPC4XX_TLBHI_SIZE_MIN || size > PPC4XX_TLBHI_SIZE_MAX) {
3973 size = PPC4XX_TLBHI_SIZE_DEFAULT;
3975 ret |= size << PPC4XX_TLBHI_SIZE_SHIFT;
3976 env->spr[SPR_40x_PID] = tlb->PID;
3977 return ret;
3980 target_ulong helper_4xx_tlbre_lo (target_ulong entry)
3982 ppcemb_tlb_t *tlb;
3983 target_ulong ret;
3985 entry &= PPC4XX_TLB_ENTRY_MASK;
3986 tlb = &env->tlb.tlbe[entry];
3987 ret = tlb->RPN;
3988 if (tlb->prot & PAGE_EXEC) {
3989 ret |= PPC4XX_TLBLO_EX;
3991 if (tlb->prot & PAGE_WRITE) {
3992 ret |= PPC4XX_TLBLO_WR;
3994 return ret;
3997 void helper_4xx_tlbwe_hi (target_ulong entry, target_ulong val)
3999 ppcemb_tlb_t *tlb;
4000 target_ulong page, end;
4002 LOG_SWTLB("%s entry %d val " TARGET_FMT_lx "\n", __func__, (int)entry,
4003 val);
4004 entry &= PPC4XX_TLB_ENTRY_MASK;
4005 tlb = &env->tlb.tlbe[entry];
4006 /* Invalidate previous TLB (if it's valid) */
4007 if (tlb->prot & PAGE_VALID) {
4008 end = tlb->EPN + tlb->size;
4009 LOG_SWTLB("%s: invalidate old TLB %d start " TARGET_FMT_lx " end "
4010 TARGET_FMT_lx "\n", __func__, (int)entry, tlb->EPN, end);
4011 for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) {
4012 tlb_flush_page(env, page);
4015 tlb->size = booke_tlb_to_page_size((val >> PPC4XX_TLBHI_SIZE_SHIFT)
4016 & PPC4XX_TLBHI_SIZE_MASK);
4017 /* We cannot handle TLB size < TARGET_PAGE_SIZE.
4018 * If this ever occurs, one should use the ppcemb target instead
4019 * of the ppc or ppc64 one
4021 if ((val & PPC4XX_TLBHI_V) && tlb->size < TARGET_PAGE_SIZE) {
4022 cpu_abort(env, "TLB size " TARGET_FMT_lu " < %u "
4023 "are not supported (%d)\n",
4024 tlb->size, TARGET_PAGE_SIZE, (int)((val >> 7) & 0x7));
4026 tlb->EPN = val & ~(tlb->size - 1);
4027 if (val & PPC4XX_TLBHI_V) {
4028 tlb->prot |= PAGE_VALID;
4029 if (val & PPC4XX_TLBHI_E) {
4030 /* XXX: TO BE FIXED */
4031 cpu_abort(env,
4032 "Little-endian TLB entries are not supported by now\n");
4034 } else {
4035 tlb->prot &= ~PAGE_VALID;
4037 tlb->PID = env->spr[SPR_40x_PID]; /* PID */
4038 LOG_SWTLB("%s: set up TLB %d RPN " TARGET_FMT_plx " EPN " TARGET_FMT_lx
4039 " size " TARGET_FMT_lx " prot %c%c%c%c PID %d\n", __func__,
4040 (int)entry, tlb->RPN, tlb->EPN, tlb->size,
4041 tlb->prot & PAGE_READ ? 'r' : '-',
4042 tlb->prot & PAGE_WRITE ? 'w' : '-',
4043 tlb->prot & PAGE_EXEC ? 'x' : '-',
4044 tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
4045 /* Invalidate new TLB (if valid) */
4046 if (tlb->prot & PAGE_VALID) {
4047 end = tlb->EPN + tlb->size;
4048 LOG_SWTLB("%s: invalidate TLB %d start " TARGET_FMT_lx " end "
4049 TARGET_FMT_lx "\n", __func__, (int)entry, tlb->EPN, end);
4050 for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) {
4051 tlb_flush_page(env, page);
4056 void helper_4xx_tlbwe_lo (target_ulong entry, target_ulong val)
4058 ppcemb_tlb_t *tlb;
4060 LOG_SWTLB("%s entry %i val " TARGET_FMT_lx "\n", __func__, (int)entry,
4061 val);
4062 entry &= PPC4XX_TLB_ENTRY_MASK;
4063 tlb = &env->tlb.tlbe[entry];
4064 tlb->attr = val & PPC4XX_TLBLO_ATTR_MASK;
4065 tlb->RPN = val & PPC4XX_TLBLO_RPN_MASK;
4066 tlb->prot = PAGE_READ;
4067 if (val & PPC4XX_TLBLO_EX) {
4068 tlb->prot |= PAGE_EXEC;
4070 if (val & PPC4XX_TLBLO_WR) {
4071 tlb->prot |= PAGE_WRITE;
4073 LOG_SWTLB("%s: set up TLB %d RPN " TARGET_FMT_plx " EPN " TARGET_FMT_lx
4074 " size " TARGET_FMT_lx " prot %c%c%c%c PID %d\n", __func__,
4075 (int)entry, tlb->RPN, tlb->EPN, tlb->size,
4076 tlb->prot & PAGE_READ ? 'r' : '-',
4077 tlb->prot & PAGE_WRITE ? 'w' : '-',
4078 tlb->prot & PAGE_EXEC ? 'x' : '-',
4079 tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
4082 target_ulong helper_4xx_tlbsx (target_ulong address)
4084 return ppcemb_tlb_search(env, address, env->spr[SPR_40x_PID]);
4087 /* PowerPC 440 TLB management */
4088 void helper_440_tlbwe (uint32_t word, target_ulong entry, target_ulong value)
4090 ppcemb_tlb_t *tlb;
4091 target_ulong EPN, RPN, size;
4092 int do_flush_tlbs;
4094 LOG_SWTLB("%s word %d entry %d value " TARGET_FMT_lx "\n",
4095 __func__, word, (int)entry, value);
4096 do_flush_tlbs = 0;
4097 entry &= 0x3F;
4098 tlb = &env->tlb.tlbe[entry];
4099 switch (word) {
4100 default:
4101 /* Just here to please gcc */
4102 case 0:
4103 EPN = value & 0xFFFFFC00;
4104 if ((tlb->prot & PAGE_VALID) && EPN != tlb->EPN)
4105 do_flush_tlbs = 1;
4106 tlb->EPN = EPN;
4107 size = booke_tlb_to_page_size((value >> 4) & 0xF);
4108 if ((tlb->prot & PAGE_VALID) && tlb->size < size)
4109 do_flush_tlbs = 1;
4110 tlb->size = size;
4111 tlb->attr &= ~0x1;
4112 tlb->attr |= (value >> 8) & 1;
4113 if (value & 0x200) {
4114 tlb->prot |= PAGE_VALID;
4115 } else {
4116 if (tlb->prot & PAGE_VALID) {
4117 tlb->prot &= ~PAGE_VALID;
4118 do_flush_tlbs = 1;
4121 tlb->PID = env->spr[SPR_440_MMUCR] & 0x000000FF;
4122 if (do_flush_tlbs)
4123 tlb_flush(env, 1);
4124 break;
4125 case 1:
4126 RPN = value & 0xFFFFFC0F;
4127 if ((tlb->prot & PAGE_VALID) && tlb->RPN != RPN)
4128 tlb_flush(env, 1);
4129 tlb->RPN = RPN;
4130 break;
4131 case 2:
4132 tlb->attr = (tlb->attr & 0x1) | (value & 0x0000FF00);
4133 tlb->prot = tlb->prot & PAGE_VALID;
4134 if (value & 0x1)
4135 tlb->prot |= PAGE_READ << 4;
4136 if (value & 0x2)
4137 tlb->prot |= PAGE_WRITE << 4;
4138 if (value & 0x4)
4139 tlb->prot |= PAGE_EXEC << 4;
4140 if (value & 0x8)
4141 tlb->prot |= PAGE_READ;
4142 if (value & 0x10)
4143 tlb->prot |= PAGE_WRITE;
4144 if (value & 0x20)
4145 tlb->prot |= PAGE_EXEC;
4146 break;
4150 target_ulong helper_440_tlbre (uint32_t word, target_ulong entry)
4152 ppcemb_tlb_t *tlb;
4153 target_ulong ret;
4154 int size;
4156 entry &= 0x3F;
4157 tlb = &env->tlb.tlbe[entry];
4158 switch (word) {
4159 default:
4160 /* Just here to please gcc */
4161 case 0:
4162 ret = tlb->EPN;
4163 size = booke_page_size_to_tlb(tlb->size);
4164 if (size < 0 || size > 0xF)
4165 size = 1;
4166 ret |= size << 4;
4167 if (tlb->attr & 0x1)
4168 ret |= 0x100;
4169 if (tlb->prot & PAGE_VALID)
4170 ret |= 0x200;
4171 env->spr[SPR_440_MMUCR] &= ~0x000000FF;
4172 env->spr[SPR_440_MMUCR] |= tlb->PID;
4173 break;
4174 case 1:
4175 ret = tlb->RPN;
4176 break;
4177 case 2:
4178 ret = tlb->attr & ~0x1;
4179 if (tlb->prot & (PAGE_READ << 4))
4180 ret |= 0x1;
4181 if (tlb->prot & (PAGE_WRITE << 4))
4182 ret |= 0x2;
4183 if (tlb->prot & (PAGE_EXEC << 4))
4184 ret |= 0x4;
4185 if (tlb->prot & PAGE_READ)
4186 ret |= 0x8;
4187 if (tlb->prot & PAGE_WRITE)
4188 ret |= 0x10;
4189 if (tlb->prot & PAGE_EXEC)
4190 ret |= 0x20;
4191 break;
4193 return ret;
4196 target_ulong helper_440_tlbsx (target_ulong address)
4198 return ppcemb_tlb_search(env, address, env->spr[SPR_440_MMUCR] & 0xFF);
4201 /* PowerPC BookE 2.06 TLB management */
4203 static ppcmas_tlb_t *booke206_cur_tlb(CPUPPCState *env)
4205 uint32_t tlbncfg = 0;
4206 int esel = (env->spr[SPR_BOOKE_MAS0] & MAS0_ESEL_MASK) >> MAS0_ESEL_SHIFT;
4207 int ea = (env->spr[SPR_BOOKE_MAS2] & MAS2_EPN_MASK);
4208 int tlb;
4210 tlb = (env->spr[SPR_BOOKE_MAS0] & MAS0_TLBSEL_MASK) >> MAS0_TLBSEL_SHIFT;
4211 tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlb];
4213 if ((tlbncfg & TLBnCFG_HES) && (env->spr[SPR_BOOKE_MAS0] & MAS0_HES)) {
4214 cpu_abort(env, "we don't support HES yet\n");
4217 return booke206_get_tlbm(env, tlb, ea, esel);
4220 void helper_booke_setpid(uint32_t pidn, target_ulong pid)
4222 env->spr[pidn] = pid;
4223 /* changing PIDs mean we're in a different address space now */
4224 tlb_flush(env, 1);
4227 void helper_booke206_tlbwe(void)
4229 uint32_t tlbncfg, tlbn;
4230 ppcmas_tlb_t *tlb;
4231 uint32_t size_tlb, size_ps;
4233 switch (env->spr[SPR_BOOKE_MAS0] & MAS0_WQ_MASK) {
4234 case MAS0_WQ_ALWAYS:
4235 /* good to go, write that entry */
4236 break;
4237 case MAS0_WQ_COND:
4238 /* XXX check if reserved */
4239 if (0) {
4240 return;
4242 break;
4243 case MAS0_WQ_CLR_RSRV:
4244 /* XXX clear entry */
4245 return;
4246 default:
4247 /* no idea what to do */
4248 return;
4251 if (((env->spr[SPR_BOOKE_MAS0] & MAS0_ATSEL) == MAS0_ATSEL_LRAT) &&
4252 !msr_gs) {
4253 /* XXX we don't support direct LRAT setting yet */
4254 fprintf(stderr, "cpu: don't support LRAT setting yet\n");
4255 return;
4258 tlbn = (env->spr[SPR_BOOKE_MAS0] & MAS0_TLBSEL_MASK) >> MAS0_TLBSEL_SHIFT;
4259 tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlbn];
4261 tlb = booke206_cur_tlb(env);
4263 if (!tlb) {
4264 helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
4265 POWERPC_EXCP_INVAL |
4266 POWERPC_EXCP_INVAL_INVAL);
4269 /* check that we support the targeted size */
4270 size_tlb = (env->spr[SPR_BOOKE_MAS1] & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
4271 size_ps = booke206_tlbnps(env, tlbn);
4272 if ((env->spr[SPR_BOOKE_MAS1] & MAS1_VALID) && (tlbncfg & TLBnCFG_AVAIL) &&
4273 !(size_ps & (1 << size_tlb))) {
4274 helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
4275 POWERPC_EXCP_INVAL |
4276 POWERPC_EXCP_INVAL_INVAL);
4279 if (msr_gs) {
4280 cpu_abort(env, "missing HV implementation\n");
4282 tlb->mas7_3 = ((uint64_t)env->spr[SPR_BOOKE_MAS7] << 32) |
4283 env->spr[SPR_BOOKE_MAS3];
4284 tlb->mas1 = env->spr[SPR_BOOKE_MAS1];
4286 /* MAV 1.0 only */
4287 if (!(tlbncfg & TLBnCFG_AVAIL)) {
4288 /* force !AVAIL TLB entries to correct page size */
4289 tlb->mas1 &= ~MAS1_TSIZE_MASK;
4290 /* XXX can be configured in MMUCSR0 */
4291 tlb->mas1 |= (tlbncfg & TLBnCFG_MINSIZE) >> 12;
4294 /* XXX needs to change when supporting 64-bit e500 */
4295 tlb->mas2 = env->spr[SPR_BOOKE_MAS2] & 0xffffffff;
4297 if (!(tlbncfg & TLBnCFG_IPROT)) {
4298 /* no IPROT supported by TLB */
4299 tlb->mas1 &= ~MAS1_IPROT;
4302 if (booke206_tlb_to_page_size(env, tlb) == TARGET_PAGE_SIZE) {
4303 tlb_flush_page(env, tlb->mas2 & MAS2_EPN_MASK);
4304 } else {
4305 tlb_flush(env, 1);
4309 static inline void booke206_tlb_to_mas(CPUPPCState *env, ppcmas_tlb_t *tlb)
4311 int tlbn = booke206_tlbm_to_tlbn(env, tlb);
4312 int way = booke206_tlbm_to_way(env, tlb);
4314 env->spr[SPR_BOOKE_MAS0] = tlbn << MAS0_TLBSEL_SHIFT;
4315 env->spr[SPR_BOOKE_MAS0] |= way << MAS0_ESEL_SHIFT;
4316 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
4318 env->spr[SPR_BOOKE_MAS1] = tlb->mas1;
4319 env->spr[SPR_BOOKE_MAS2] = tlb->mas2;
4320 env->spr[SPR_BOOKE_MAS3] = tlb->mas7_3;
4321 env->spr[SPR_BOOKE_MAS7] = tlb->mas7_3 >> 32;
4324 void helper_booke206_tlbre(void)
4326 ppcmas_tlb_t *tlb = NULL;
4328 tlb = booke206_cur_tlb(env);
4329 if (!tlb) {
4330 env->spr[SPR_BOOKE_MAS1] = 0;
4331 } else {
4332 booke206_tlb_to_mas(env, tlb);
4336 void helper_booke206_tlbsx(target_ulong address)
4338 ppcmas_tlb_t *tlb = NULL;
4339 int i, j;
4340 target_phys_addr_t raddr;
4341 uint32_t spid, sas;
4343 spid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID_MASK) >> MAS6_SPID_SHIFT;
4344 sas = env->spr[SPR_BOOKE_MAS6] & MAS6_SAS;
4346 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
4347 int ways = booke206_tlb_ways(env, i);
4349 for (j = 0; j < ways; j++) {
4350 tlb = booke206_get_tlbm(env, i, address, j);
4352 if (!tlb) {
4353 continue;
4356 if (ppcmas_tlb_check(env, tlb, &raddr, address, spid)) {
4357 continue;
4360 if (sas != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) {
4361 continue;
4364 booke206_tlb_to_mas(env, tlb);
4365 return;
4369 /* no entry found, fill with defaults */
4370 env->spr[SPR_BOOKE_MAS0] = env->spr[SPR_BOOKE_MAS4] & MAS4_TLBSELD_MASK;
4371 env->spr[SPR_BOOKE_MAS1] = env->spr[SPR_BOOKE_MAS4] & MAS4_TSIZED_MASK;
4372 env->spr[SPR_BOOKE_MAS2] = env->spr[SPR_BOOKE_MAS4] & MAS4_WIMGED_MASK;
4373 env->spr[SPR_BOOKE_MAS3] = 0;
4374 env->spr[SPR_BOOKE_MAS7] = 0;
4376 if (env->spr[SPR_BOOKE_MAS6] & MAS6_SAS) {
4377 env->spr[SPR_BOOKE_MAS1] |= MAS1_TS;
4380 env->spr[SPR_BOOKE_MAS1] |= (env->spr[SPR_BOOKE_MAS6] >> 16)
4381 << MAS1_TID_SHIFT;
4383 /* next victim logic */
4384 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_ESEL_SHIFT;
4385 env->last_way++;
4386 env->last_way &= booke206_tlb_ways(env, 0) - 1;
4387 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
4390 static inline void booke206_invalidate_ea_tlb(CPUPPCState *env, int tlbn,
4391 uint32_t ea)
4393 int i;
4394 int ways = booke206_tlb_ways(env, tlbn);
4395 target_ulong mask;
4397 for (i = 0; i < ways; i++) {
4398 ppcmas_tlb_t *tlb = booke206_get_tlbm(env, tlbn, ea, i);
4399 if (!tlb) {
4400 continue;
4402 mask = ~(booke206_tlb_to_page_size(env, tlb) - 1);
4403 if (((tlb->mas2 & MAS2_EPN_MASK) == (ea & mask)) &&
4404 !(tlb->mas1 & MAS1_IPROT)) {
4405 tlb->mas1 &= ~MAS1_VALID;
4410 void helper_booke206_tlbivax(target_ulong address)
4412 if (address & 0x4) {
4413 /* flush all entries */
4414 if (address & 0x8) {
4415 /* flush all of TLB1 */
4416 booke206_flush_tlb(env, BOOKE206_FLUSH_TLB1, 1);
4417 } else {
4418 /* flush all of TLB0 */
4419 booke206_flush_tlb(env, BOOKE206_FLUSH_TLB0, 0);
4421 return;
4424 if (address & 0x8) {
4425 /* flush TLB1 entries */
4426 booke206_invalidate_ea_tlb(env, 1, address);
4427 tlb_flush(env, 1);
4428 } else {
4429 /* flush TLB0 entries */
4430 booke206_invalidate_ea_tlb(env, 0, address);
4431 tlb_flush_page(env, address & MAS2_EPN_MASK);
4435 void helper_booke206_tlbilx0(target_ulong address)
4437 /* XXX missing LPID handling */
4438 booke206_flush_tlb(env, -1, 1);
4441 void helper_booke206_tlbilx1(target_ulong address)
4443 int i, j;
4444 int tid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID);
4445 ppcmas_tlb_t *tlb = env->tlb.tlbm;
4446 int tlb_size;
4448 /* XXX missing LPID handling */
4449 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
4450 tlb_size = booke206_tlb_size(env, i);
4451 for (j = 0; j < tlb_size; j++) {
4452 if (!(tlb[j].mas1 & MAS1_IPROT) &&
4453 ((tlb[j].mas1 & MAS1_TID_MASK) == tid)) {
4454 tlb[j].mas1 &= ~MAS1_VALID;
4457 tlb += booke206_tlb_size(env, i);
4459 tlb_flush(env, 1);
4462 void helper_booke206_tlbilx3(target_ulong address)
4464 int i, j;
4465 ppcmas_tlb_t *tlb;
4466 int tid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID);
4467 int pid = tid >> MAS6_SPID_SHIFT;
4468 int sgs = env->spr[SPR_BOOKE_MAS5] & MAS5_SGS;
4469 int ind = (env->spr[SPR_BOOKE_MAS6] & MAS6_SIND) ? MAS1_IND : 0;
4470 /* XXX check for unsupported isize and raise an invalid opcode then */
4471 int size = env->spr[SPR_BOOKE_MAS6] & MAS6_ISIZE_MASK;
4472 /* XXX implement MAV2 handling */
4473 bool mav2 = false;
4475 /* XXX missing LPID handling */
4476 /* flush by pid and ea */
4477 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
4478 int ways = booke206_tlb_ways(env, i);
4480 for (j = 0; j < ways; j++) {
4481 tlb = booke206_get_tlbm(env, i, address, j);
4482 if (!tlb) {
4483 continue;
4485 if ((ppcmas_tlb_check(env, tlb, NULL, address, pid) != 0) ||
4486 (tlb->mas1 & MAS1_IPROT) ||
4487 ((tlb->mas1 & MAS1_IND) != ind) ||
4488 ((tlb->mas8 & MAS8_TGS) != sgs)) {
4489 continue;
4491 if (mav2 && ((tlb->mas1 & MAS1_TSIZE_MASK) != size)) {
4492 /* XXX only check when MMUCFG[TWC] || TLBnCFG[HES] */
4493 continue;
4495 /* XXX e500mc doesn't match SAS, but other cores might */
4496 tlb->mas1 &= ~MAS1_VALID;
4499 tlb_flush(env, 1);
4502 void helper_booke206_tlbflush(uint32_t type)
4504 int flags = 0;
4506 if (type & 2) {
4507 flags |= BOOKE206_FLUSH_TLB1;
4510 if (type & 4) {
4511 flags |= BOOKE206_FLUSH_TLB0;
4514 booke206_flush_tlb(env, flags, 1);
4517 /* Embedded.Processor Control */
4518 static int dbell2irq(target_ulong rb)
4520 int msg = rb & DBELL_TYPE_MASK;
4521 int irq = -1;
4523 switch (msg) {
4524 case DBELL_TYPE_DBELL:
4525 irq = PPC_INTERRUPT_DOORBELL;
4526 break;
4527 case DBELL_TYPE_DBELL_CRIT:
4528 irq = PPC_INTERRUPT_CDOORBELL;
4529 break;
4530 case DBELL_TYPE_G_DBELL:
4531 case DBELL_TYPE_G_DBELL_CRIT:
4532 case DBELL_TYPE_G_DBELL_MC:
4533 /* XXX implement */
4534 default:
4535 break;
4538 return irq;
4541 void helper_msgclr(target_ulong rb)
4543 int irq = dbell2irq(rb);
4545 if (irq < 0) {
4546 return;
4549 env->pending_interrupts &= ~(1 << irq);
4552 void helper_msgsnd(target_ulong rb)
4554 int irq = dbell2irq(rb);
4555 int pir = rb & DBELL_PIRTAG_MASK;
4556 CPUPPCState *cenv;
4558 if (irq < 0) {
4559 return;
4562 for (cenv = first_cpu; cenv != NULL; cenv = cenv->next_cpu) {
4563 if ((rb & DBELL_BRDCAST) || (cenv->spr[SPR_BOOKE_PIR] == pir)) {
4564 cenv->pending_interrupts |= 1 << irq;
4565 cpu_interrupt(cenv, CPU_INTERRUPT_HARD);
4570 #endif /* !CONFIG_USER_ONLY */