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, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA
22 #include "host-utils.h"
25 #include "helper_regs.h"
28 //#define DEBUG_EXCEPTIONS
29 //#define DEBUG_SOFTWARE_TLB
31 /*****************************************************************************/
32 /* Exceptions processing helpers */
34 void helper_raise_exception_err (uint32_t exception, uint32_t error_code)
37 printf("Raise exception %3x code : %d\n", exception, error_code);
39 env->exception_index = exception;
40 env->error_code = error_code;
44 void helper_raise_exception (uint32_t exception)
46 helper_raise_exception_err(exception, 0);
49 /*****************************************************************************/
50 /* Registers load and stores */
51 target_ulong helper_load_cr (void)
53 return (env->crf[0] << 28) |
63 void helper_store_cr (target_ulong val, uint32_t mask)
67 for (i = 0, sh = 7; i < 8; i++, sh--) {
69 env->crf[i] = (val >> (sh * 4)) & 0xFUL;
73 /*****************************************************************************/
75 void helper_load_dump_spr (uint32_t sprn)
78 fprintf(logfile, "Read SPR %d %03x => " ADDRX "\n",
79 sprn, sprn, env->spr[sprn]);
83 void helper_store_dump_spr (uint32_t sprn)
86 fprintf(logfile, "Write SPR %d %03x <= " ADDRX "\n",
87 sprn, sprn, env->spr[sprn]);
91 target_ulong helper_load_tbl (void)
93 return cpu_ppc_load_tbl(env);
96 target_ulong helper_load_tbu (void)
98 return cpu_ppc_load_tbu(env);
101 target_ulong helper_load_atbl (void)
103 return cpu_ppc_load_atbl(env);
106 target_ulong helper_load_atbu (void)
108 return cpu_ppc_load_atbu(env);
111 target_ulong helper_load_601_rtcl (void)
113 return cpu_ppc601_load_rtcl(env);
116 target_ulong helper_load_601_rtcu (void)
118 return cpu_ppc601_load_rtcu(env);
121 #if !defined(CONFIG_USER_ONLY)
122 #if defined (TARGET_PPC64)
123 void helper_store_asr (target_ulong val)
125 ppc_store_asr(env, val);
129 void helper_store_sdr1 (target_ulong val)
131 ppc_store_sdr1(env, val);
134 void helper_store_tbl (target_ulong val)
136 cpu_ppc_store_tbl(env, val);
139 void helper_store_tbu (target_ulong val)
141 cpu_ppc_store_tbu(env, val);
144 void helper_store_atbl (target_ulong val)
146 cpu_ppc_store_atbl(env, val);
149 void helper_store_atbu (target_ulong val)
151 cpu_ppc_store_atbu(env, val);
154 void helper_store_601_rtcl (target_ulong val)
156 cpu_ppc601_store_rtcl(env, val);
159 void helper_store_601_rtcu (target_ulong val)
161 cpu_ppc601_store_rtcu(env, val);
164 target_ulong helper_load_decr (void)
166 return cpu_ppc_load_decr(env);
169 void helper_store_decr (target_ulong val)
171 cpu_ppc_store_decr(env, val);
174 void helper_store_hid0_601 (target_ulong val)
178 hid0 = env->spr[SPR_HID0];
179 if ((val ^ hid0) & 0x00000008) {
180 /* Change current endianness */
181 env->hflags &= ~(1 << MSR_LE);
182 env->hflags_nmsr &= ~(1 << MSR_LE);
183 env->hflags_nmsr |= (1 << MSR_LE) & (((val >> 3) & 1) << MSR_LE);
184 env->hflags |= env->hflags_nmsr;
186 fprintf(logfile, "%s: set endianness to %c => " ADDRX "\n",
187 __func__, val & 0x8 ? 'l' : 'b', env->hflags);
190 env->spr[SPR_HID0] = (uint32_t)val;
193 void helper_store_403_pbr (uint32_t num, target_ulong value)
195 if (likely(env->pb[num] != value)) {
196 env->pb[num] = value;
197 /* Should be optimized */
202 target_ulong helper_load_40x_pit (void)
204 return load_40x_pit(env);
207 void helper_store_40x_pit (target_ulong val)
209 store_40x_pit(env, val);
212 void helper_store_40x_dbcr0 (target_ulong val)
214 store_40x_dbcr0(env, val);
217 void helper_store_40x_sler (target_ulong val)
219 store_40x_sler(env, val);
222 void helper_store_booke_tcr (target_ulong val)
224 store_booke_tcr(env, val);
227 void helper_store_booke_tsr (target_ulong val)
229 store_booke_tsr(env, val);
232 void helper_store_ibatu (uint32_t nr, target_ulong val)
234 ppc_store_ibatu(env, nr, val);
237 void helper_store_ibatl (uint32_t nr, target_ulong val)
239 ppc_store_ibatl(env, nr, val);
242 void helper_store_dbatu (uint32_t nr, target_ulong val)
244 ppc_store_dbatu(env, nr, val);
247 void helper_store_dbatl (uint32_t nr, target_ulong val)
249 ppc_store_dbatl(env, nr, val);
252 void helper_store_601_batl (uint32_t nr, target_ulong val)
254 ppc_store_ibatl_601(env, nr, val);
257 void helper_store_601_batu (uint32_t nr, target_ulong val)
259 ppc_store_ibatu_601(env, nr, val);
263 /*****************************************************************************/
264 /* Memory load and stores */
266 static always_inline target_ulong addr_add(target_ulong addr, target_long arg)
268 #if defined(TARGET_PPC64)
270 return (uint32_t)(addr + arg);
276 void helper_lmw (target_ulong addr, uint32_t reg)
278 for (; reg < 32; reg++) {
280 env->gpr[reg] = bswap32(ldl(addr));
282 env->gpr[reg] = ldl(addr);
283 addr = addr_add(addr, 4);
287 void helper_stmw (target_ulong addr, uint32_t reg)
289 for (; reg < 32; reg++) {
291 stl(addr, bswap32((uint32_t)env->gpr[reg]));
293 stl(addr, (uint32_t)env->gpr[reg]);
294 addr = addr_add(addr, 4);
298 void helper_lsw(target_ulong addr, uint32_t nb, uint32_t reg)
301 for (; nb > 3; nb -= 4) {
302 env->gpr[reg] = ldl(addr);
303 reg = (reg + 1) % 32;
304 addr = addr_add(addr, 4);
306 if (unlikely(nb > 0)) {
308 for (sh = 24; nb > 0; nb--, sh -= 8) {
309 env->gpr[reg] |= ldub(addr) << sh;
310 addr = addr_add(addr, 1);
314 /* PPC32 specification says we must generate an exception if
315 * rA is in the range of registers to be loaded.
316 * In an other hand, IBM says this is valid, but rA won't be loaded.
317 * For now, I'll follow the spec...
319 void helper_lswx(target_ulong addr, uint32_t reg, uint32_t ra, uint32_t rb)
321 if (likely(xer_bc != 0)) {
322 if (unlikely((ra != 0 && reg < ra && (reg + xer_bc) > ra) ||
323 (reg < rb && (reg + xer_bc) > rb))) {
324 helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
326 POWERPC_EXCP_INVAL_LSWX);
328 helper_lsw(addr, xer_bc, reg);
333 void helper_stsw(target_ulong addr, uint32_t nb, uint32_t reg)
336 for (; nb > 3; nb -= 4) {
337 stl(addr, env->gpr[reg]);
338 reg = (reg + 1) % 32;
339 addr = addr_add(addr, 4);
341 if (unlikely(nb > 0)) {
342 for (sh = 24; nb > 0; nb--, sh -= 8) {
343 stb(addr, (env->gpr[reg] >> sh) & 0xFF);
344 addr = addr_add(addr, 1);
349 static void do_dcbz(target_ulong addr, int dcache_line_size)
351 addr &= ~(dcache_line_size - 1);
353 for (i = 0 ; i < dcache_line_size ; i += 4) {
356 if (env->reserve == addr)
357 env->reserve = (target_ulong)-1ULL;
360 void helper_dcbz(target_ulong addr)
362 do_dcbz(addr, env->dcache_line_size);
365 void helper_dcbz_970(target_ulong addr)
367 if (((env->spr[SPR_970_HID5] >> 7) & 0x3) == 1)
370 do_dcbz(addr, env->dcache_line_size);
373 void helper_icbi(target_ulong addr)
377 addr &= ~(env->dcache_line_size - 1);
378 /* Invalidate one cache line :
379 * PowerPC specification says this is to be treated like a load
380 * (not a fetch) by the MMU. To be sure it will be so,
381 * do the load "by hand".
384 tb_invalidate_page_range(addr, addr + env->icache_line_size);
388 target_ulong helper_lscbx (target_ulong addr, uint32_t reg, uint32_t ra, uint32_t rb)
392 for (i = 0; i < xer_bc; i++) {
394 addr = addr_add(addr, 1);
395 /* ra (if not 0) and rb are never modified */
396 if (likely(reg != rb && (ra == 0 || reg != ra))) {
397 env->gpr[reg] = (env->gpr[reg] & ~(0xFF << d)) | (c << d);
399 if (unlikely(c == xer_cmp))
401 if (likely(d != 0)) {
412 /*****************************************************************************/
413 /* Fixed point operations helpers */
414 #if defined(TARGET_PPC64)
416 /* multiply high word */
417 uint64_t helper_mulhd (uint64_t arg1, uint64_t arg2)
421 muls64(&tl, &th, arg1, arg2);
425 /* multiply high word unsigned */
426 uint64_t helper_mulhdu (uint64_t arg1, uint64_t arg2)
430 mulu64(&tl, &th, arg1, arg2);
434 uint64_t helper_mulldo (uint64_t arg1, uint64_t arg2)
439 muls64(&tl, (uint64_t *)&th, arg1, arg2);
440 /* If th != 0 && th != -1, then we had an overflow */
441 if (likely((uint64_t)(th + 1) <= 1)) {
442 env->xer &= ~(1 << XER_OV);
444 env->xer |= (1 << XER_OV) | (1 << XER_SO);
450 target_ulong helper_cntlzw (target_ulong t)
455 #if defined(TARGET_PPC64)
456 target_ulong helper_cntlzd (target_ulong t)
462 /* shift right arithmetic helper */
463 target_ulong helper_sraw (target_ulong value, target_ulong shift)
467 if (likely(!(shift & 0x20))) {
468 if (likely((uint32_t)shift != 0)) {
470 ret = (int32_t)value >> shift;
471 if (likely(ret >= 0 || (value & ((1 << shift) - 1)) == 0)) {
472 env->xer &= ~(1 << XER_CA);
474 env->xer |= (1 << XER_CA);
477 ret = (int32_t)value;
478 env->xer &= ~(1 << XER_CA);
481 ret = (int32_t)value >> 31;
483 env->xer |= (1 << XER_CA);
485 env->xer &= ~(1 << XER_CA);
488 return (target_long)ret;
491 #if defined(TARGET_PPC64)
492 target_ulong helper_srad (target_ulong value, target_ulong shift)
496 if (likely(!(shift & 0x40))) {
497 if (likely((uint64_t)shift != 0)) {
499 ret = (int64_t)value >> shift;
500 if (likely(ret >= 0 || (value & ((1 << shift) - 1)) == 0)) {
501 env->xer &= ~(1 << XER_CA);
503 env->xer |= (1 << XER_CA);
506 ret = (int64_t)value;
507 env->xer &= ~(1 << XER_CA);
510 ret = (int64_t)value >> 63;
512 env->xer |= (1 << XER_CA);
514 env->xer &= ~(1 << XER_CA);
521 target_ulong helper_popcntb (target_ulong val)
523 val = (val & 0x55555555) + ((val >> 1) & 0x55555555);
524 val = (val & 0x33333333) + ((val >> 2) & 0x33333333);
525 val = (val & 0x0f0f0f0f) + ((val >> 4) & 0x0f0f0f0f);
529 #if defined(TARGET_PPC64)
530 target_ulong helper_popcntb_64 (target_ulong val)
532 val = (val & 0x5555555555555555ULL) + ((val >> 1) & 0x5555555555555555ULL);
533 val = (val & 0x3333333333333333ULL) + ((val >> 2) & 0x3333333333333333ULL);
534 val = (val & 0x0f0f0f0f0f0f0f0fULL) + ((val >> 4) & 0x0f0f0f0f0f0f0f0fULL);
539 /*****************************************************************************/
540 /* Floating point operations helpers */
541 uint64_t helper_float32_to_float64(uint32_t arg)
546 d.d = float32_to_float64(f.f, &env->fp_status);
550 uint32_t helper_float64_to_float32(uint64_t arg)
555 f.f = float64_to_float32(d.d, &env->fp_status);
559 static always_inline int isden (float64 d)
565 return ((u.ll >> 52) & 0x7FF) == 0;
568 uint32_t helper_compute_fprf (uint64_t arg, uint32_t set_fprf)
574 isneg = float64_is_neg(farg.d);
575 if (unlikely(float64_is_nan(farg.d))) {
576 if (float64_is_signaling_nan(farg.d)) {
577 /* Signaling NaN: flags are undefined */
583 } else if (unlikely(float64_is_infinity(farg.d))) {
590 if (float64_is_zero(farg.d)) {
598 /* Denormalized numbers */
601 /* Normalized numbers */
612 /* We update FPSCR_FPRF */
613 env->fpscr &= ~(0x1F << FPSCR_FPRF);
614 env->fpscr |= ret << FPSCR_FPRF;
616 /* We just need fpcc to update Rc1 */
620 /* Floating-point invalid operations exception */
621 static always_inline uint64_t fload_invalid_op_excp (int op)
628 case POWERPC_EXCP_FP_VXSNAN:
629 env->fpscr |= 1 << FPSCR_VXSNAN;
631 case POWERPC_EXCP_FP_VXSOFT:
632 env->fpscr |= 1 << FPSCR_VXSOFT;
634 case POWERPC_EXCP_FP_VXISI:
635 /* Magnitude subtraction of infinities */
636 env->fpscr |= 1 << FPSCR_VXISI;
638 case POWERPC_EXCP_FP_VXIDI:
639 /* Division of infinity by infinity */
640 env->fpscr |= 1 << FPSCR_VXIDI;
642 case POWERPC_EXCP_FP_VXZDZ:
643 /* Division of zero by zero */
644 env->fpscr |= 1 << FPSCR_VXZDZ;
646 case POWERPC_EXCP_FP_VXIMZ:
647 /* Multiplication of zero by infinity */
648 env->fpscr |= 1 << FPSCR_VXIMZ;
650 case POWERPC_EXCP_FP_VXVC:
651 /* Ordered comparison of NaN */
652 env->fpscr |= 1 << FPSCR_VXVC;
653 env->fpscr &= ~(0xF << FPSCR_FPCC);
654 env->fpscr |= 0x11 << FPSCR_FPCC;
655 /* We must update the target FPR before raising the exception */
657 env->exception_index = POWERPC_EXCP_PROGRAM;
658 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_VXVC;
659 /* Update the floating-point enabled exception summary */
660 env->fpscr |= 1 << FPSCR_FEX;
661 /* Exception is differed */
665 case POWERPC_EXCP_FP_VXSQRT:
666 /* Square root of a negative number */
667 env->fpscr |= 1 << FPSCR_VXSQRT;
669 env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
671 /* Set the result to quiet NaN */
672 ret = 0xFFF8000000000000ULL;
673 env->fpscr &= ~(0xF << FPSCR_FPCC);
674 env->fpscr |= 0x11 << FPSCR_FPCC;
677 case POWERPC_EXCP_FP_VXCVI:
678 /* Invalid conversion */
679 env->fpscr |= 1 << FPSCR_VXCVI;
680 env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
682 /* Set the result to quiet NaN */
683 ret = 0xFFF8000000000000ULL;
684 env->fpscr &= ~(0xF << FPSCR_FPCC);
685 env->fpscr |= 0x11 << FPSCR_FPCC;
689 /* Update the floating-point invalid operation summary */
690 env->fpscr |= 1 << FPSCR_VX;
691 /* Update the floating-point exception summary */
692 env->fpscr |= 1 << FPSCR_FX;
694 /* Update the floating-point enabled exception summary */
695 env->fpscr |= 1 << FPSCR_FEX;
696 if (msr_fe0 != 0 || msr_fe1 != 0)
697 helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_FP | op);
702 static always_inline void float_zero_divide_excp (void)
704 env->fpscr |= 1 << FPSCR_ZX;
705 env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
706 /* Update the floating-point exception summary */
707 env->fpscr |= 1 << FPSCR_FX;
709 /* Update the floating-point enabled exception summary */
710 env->fpscr |= 1 << FPSCR_FEX;
711 if (msr_fe0 != 0 || msr_fe1 != 0) {
712 helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
713 POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX);
718 static always_inline void float_overflow_excp (void)
720 env->fpscr |= 1 << FPSCR_OX;
721 /* Update the floating-point exception summary */
722 env->fpscr |= 1 << FPSCR_FX;
724 /* XXX: should adjust the result */
725 /* Update the floating-point enabled exception summary */
726 env->fpscr |= 1 << FPSCR_FEX;
727 /* We must update the target FPR before raising the exception */
728 env->exception_index = POWERPC_EXCP_PROGRAM;
729 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_OX;
731 env->fpscr |= 1 << FPSCR_XX;
732 env->fpscr |= 1 << FPSCR_FI;
736 static always_inline void float_underflow_excp (void)
738 env->fpscr |= 1 << FPSCR_UX;
739 /* Update the floating-point exception summary */
740 env->fpscr |= 1 << FPSCR_FX;
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_UX;
751 static always_inline void float_inexact_excp (void)
753 env->fpscr |= 1 << FPSCR_XX;
754 /* Update the floating-point exception summary */
755 env->fpscr |= 1 << FPSCR_FX;
757 /* Update the floating-point enabled exception summary */
758 env->fpscr |= 1 << FPSCR_FEX;
759 /* We must update the target FPR before raising the exception */
760 env->exception_index = POWERPC_EXCP_PROGRAM;
761 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_XX;
765 static always_inline void fpscr_set_rounding_mode (void)
769 /* Set rounding mode */
772 /* Best approximation (round to nearest) */
773 rnd_type = float_round_nearest_even;
776 /* Smaller magnitude (round toward zero) */
777 rnd_type = float_round_to_zero;
780 /* Round toward +infinite */
781 rnd_type = float_round_up;
785 /* Round toward -infinite */
786 rnd_type = float_round_down;
789 set_float_rounding_mode(rnd_type, &env->fp_status);
792 void helper_fpscr_clrbit (uint32_t bit)
796 prev = (env->fpscr >> bit) & 1;
797 env->fpscr &= ~(1 << bit);
802 fpscr_set_rounding_mode();
810 void helper_fpscr_setbit (uint32_t bit)
814 prev = (env->fpscr >> bit) & 1;
815 env->fpscr |= 1 << bit;
819 env->fpscr |= 1 << FPSCR_FX;
823 env->fpscr |= 1 << FPSCR_FX;
828 env->fpscr |= 1 << FPSCR_FX;
833 env->fpscr |= 1 << FPSCR_FX;
838 env->fpscr |= 1 << FPSCR_FX;
851 env->fpscr |= 1 << FPSCR_VX;
852 env->fpscr |= 1 << FPSCR_FX;
859 env->error_code = POWERPC_EXCP_FP;
861 env->error_code |= POWERPC_EXCP_FP_VXSNAN;
863 env->error_code |= POWERPC_EXCP_FP_VXISI;
865 env->error_code |= POWERPC_EXCP_FP_VXIDI;
867 env->error_code |= POWERPC_EXCP_FP_VXZDZ;
869 env->error_code |= POWERPC_EXCP_FP_VXIMZ;
871 env->error_code |= POWERPC_EXCP_FP_VXVC;
873 env->error_code |= POWERPC_EXCP_FP_VXSOFT;
875 env->error_code |= POWERPC_EXCP_FP_VXSQRT;
877 env->error_code |= POWERPC_EXCP_FP_VXCVI;
884 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_OX;
891 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_UX;
898 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX;
905 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_XX;
911 fpscr_set_rounding_mode();
916 /* Update the floating-point enabled exception summary */
917 env->fpscr |= 1 << FPSCR_FEX;
918 /* We have to update Rc1 before raising the exception */
919 env->exception_index = POWERPC_EXCP_PROGRAM;
925 void helper_store_fpscr (uint64_t arg, uint32_t mask)
928 * We use only the 32 LSB of the incoming fpr
936 new |= prev & 0x60000000;
937 for (i = 0; i < 8; i++) {
938 if (mask & (1 << i)) {
939 env->fpscr &= ~(0xF << (4 * i));
940 env->fpscr |= new & (0xF << (4 * i));
943 /* Update VX and FEX */
945 env->fpscr |= 1 << FPSCR_VX;
947 env->fpscr &= ~(1 << FPSCR_VX);
948 if ((fpscr_ex & fpscr_eex) != 0) {
949 env->fpscr |= 1 << FPSCR_FEX;
950 env->exception_index = POWERPC_EXCP_PROGRAM;
951 /* XXX: we should compute it properly */
952 env->error_code = POWERPC_EXCP_FP;
955 env->fpscr &= ~(1 << FPSCR_FEX);
956 fpscr_set_rounding_mode();
959 void helper_float_check_status (void)
961 #ifdef CONFIG_SOFTFLOAT
962 if (env->exception_index == POWERPC_EXCP_PROGRAM &&
963 (env->error_code & POWERPC_EXCP_FP)) {
964 /* Differred floating-point exception after target FPR update */
965 if (msr_fe0 != 0 || msr_fe1 != 0)
966 helper_raise_exception_err(env->exception_index, env->error_code);
968 int status = get_float_exception_flags(&env->fp_status);
969 if (status & float_flag_divbyzero) {
970 float_zero_divide_excp();
971 } else if (status & float_flag_overflow) {
972 float_overflow_excp();
973 } else if (status & float_flag_underflow) {
974 float_underflow_excp();
975 } else if (status & float_flag_inexact) {
976 float_inexact_excp();
980 if (env->exception_index == POWERPC_EXCP_PROGRAM &&
981 (env->error_code & POWERPC_EXCP_FP)) {
982 /* Differred floating-point exception after target FPR update */
983 if (msr_fe0 != 0 || msr_fe1 != 0)
984 helper_raise_exception_err(env->exception_index, env->error_code);
989 #ifdef CONFIG_SOFTFLOAT
990 void helper_reset_fpstatus (void)
992 set_float_exception_flags(0, &env->fp_status);
997 uint64_t helper_fadd (uint64_t arg1, uint64_t arg2)
999 CPU_DoubleU farg1, farg2;
1003 #if USE_PRECISE_EMULATION
1004 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1005 float64_is_signaling_nan(farg2.d))) {
1007 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1008 } else if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d) &&
1009 float64_is_neg(farg1.d) != float64_is_neg(farg2.d))) {
1010 /* Magnitude subtraction of infinities */
1011 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
1013 farg1.d = float64_add(farg1.d, farg2.d, &env->fp_status);
1016 farg1.d = float64_add(farg1.d, farg2.d, &env->fp_status);
1022 uint64_t helper_fsub (uint64_t arg1, uint64_t arg2)
1024 CPU_DoubleU farg1, farg2;
1028 #if USE_PRECISE_EMULATION
1030 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1031 float64_is_signaling_nan(farg2.d))) {
1032 /* sNaN subtraction */
1033 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1034 } else if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d) &&
1035 float64_is_neg(farg1.d) == float64_is_neg(farg2.d))) {
1036 /* Magnitude subtraction of infinities */
1037 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
1039 farg1.d = float64_sub(farg1.d, farg2.d, &env->fp_status);
1043 farg1.d = float64_sub(farg1.d, farg2.d, &env->fp_status);
1049 uint64_t helper_fmul (uint64_t arg1, uint64_t arg2)
1051 CPU_DoubleU farg1, farg2;
1055 #if USE_PRECISE_EMULATION
1056 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1057 float64_is_signaling_nan(farg2.d))) {
1058 /* sNaN multiplication */
1059 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1060 } else if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
1061 (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
1062 /* Multiplication of zero by infinity */
1063 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
1065 farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
1068 farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
1074 uint64_t helper_fdiv (uint64_t arg1, uint64_t arg2)
1076 CPU_DoubleU farg1, farg2;
1080 #if USE_PRECISE_EMULATION
1081 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1082 float64_is_signaling_nan(farg2.d))) {
1084 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1085 } else if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d))) {
1086 /* Division of infinity by infinity */
1087 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIDI);
1088 } else if (unlikely(float64_is_zero(farg1.d) && float64_is_zero(farg2.d))) {
1089 /* Division of zero by zero */
1090 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXZDZ);
1092 farg1.d = float64_div(farg1.d, farg2.d, &env->fp_status);
1095 farg1.d = float64_div(farg1.d, farg2.d, &env->fp_status);
1101 uint64_t helper_fabs (uint64_t arg)
1106 farg.d = float64_abs(farg.d);
1111 uint64_t helper_fnabs (uint64_t arg)
1116 farg.d = float64_abs(farg.d);
1117 farg.d = float64_chs(farg.d);
1122 uint64_t helper_fneg (uint64_t arg)
1127 farg.d = float64_chs(farg.d);
1131 /* fctiw - fctiw. */
1132 uint64_t helper_fctiw (uint64_t arg)
1137 if (unlikely(float64_is_signaling_nan(farg.d))) {
1138 /* sNaN conversion */
1139 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
1140 } else if (unlikely(float64_is_nan(farg.d) || float64_is_infinity(farg.d))) {
1141 /* qNan / infinity conversion */
1142 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
1144 farg.ll = float64_to_int32(farg.d, &env->fp_status);
1145 #if USE_PRECISE_EMULATION
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;
1155 /* fctiwz - fctiwz. */
1156 uint64_t helper_fctiwz (uint64_t arg)
1161 if (unlikely(float64_is_signaling_nan(farg.d))) {
1162 /* sNaN conversion */
1163 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
1164 } else if (unlikely(float64_is_nan(farg.d) || float64_is_infinity(farg.d))) {
1165 /* qNan / infinity conversion */
1166 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
1168 farg.ll = float64_to_int32_round_to_zero(farg.d, &env->fp_status);
1169 #if USE_PRECISE_EMULATION
1170 /* XXX: higher bits are not supposed to be significant.
1171 * to make tests easier, return the same as a real PowerPC 750
1173 farg.ll |= 0xFFF80000ULL << 32;
1179 #if defined(TARGET_PPC64)
1180 /* fcfid - fcfid. */
1181 uint64_t helper_fcfid (uint64_t arg)
1184 farg.d = int64_to_float64(arg, &env->fp_status);
1188 /* fctid - fctid. */
1189 uint64_t helper_fctid (uint64_t arg)
1194 if (unlikely(float64_is_signaling_nan(farg.d))) {
1195 /* sNaN conversion */
1196 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
1197 } else if (unlikely(float64_is_nan(farg.d) || float64_is_infinity(farg.d))) {
1198 /* qNan / infinity conversion */
1199 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
1201 farg.ll = float64_to_int64(farg.d, &env->fp_status);
1206 /* fctidz - fctidz. */
1207 uint64_t helper_fctidz (uint64_t arg)
1212 if (unlikely(float64_is_signaling_nan(farg.d))) {
1213 /* sNaN conversion */
1214 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
1215 } else if (unlikely(float64_is_nan(farg.d) || float64_is_infinity(farg.d))) {
1216 /* qNan / infinity conversion */
1217 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
1219 farg.ll = float64_to_int64_round_to_zero(farg.d, &env->fp_status);
1226 static always_inline uint64_t do_fri (uint64_t arg, int rounding_mode)
1231 if (unlikely(float64_is_signaling_nan(farg.d))) {
1233 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
1234 } else if (unlikely(float64_is_nan(farg.d) || float64_is_infinity(farg.d))) {
1235 /* qNan / infinity round */
1236 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
1238 set_float_rounding_mode(rounding_mode, &env->fp_status);
1239 farg.ll = float64_round_to_int(farg.d, &env->fp_status);
1240 /* Restore rounding mode from FPSCR */
1241 fpscr_set_rounding_mode();
1246 uint64_t helper_frin (uint64_t arg)
1248 return do_fri(arg, float_round_nearest_even);
1251 uint64_t helper_friz (uint64_t arg)
1253 return do_fri(arg, float_round_to_zero);
1256 uint64_t helper_frip (uint64_t arg)
1258 return do_fri(arg, float_round_up);
1261 uint64_t helper_frim (uint64_t arg)
1263 return do_fri(arg, float_round_down);
1266 /* fmadd - fmadd. */
1267 uint64_t helper_fmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3)
1269 CPU_DoubleU farg1, farg2, farg3;
1274 #if USE_PRECISE_EMULATION
1275 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1276 float64_is_signaling_nan(farg2.d) ||
1277 float64_is_signaling_nan(farg3.d))) {
1278 /* sNaN operation */
1279 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1280 } else if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
1281 (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
1282 /* Multiplication of zero by infinity */
1283 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
1286 /* This is the way the PowerPC specification defines it */
1287 float128 ft0_128, ft1_128;
1289 ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
1290 ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
1291 ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
1292 if (unlikely(float128_is_infinity(ft0_128) && float64_is_infinity(farg3.d) &&
1293 float128_is_neg(ft0_128) != float64_is_neg(farg3.d))) {
1294 /* Magnitude subtraction of infinities */
1295 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
1297 ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
1298 ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
1299 farg1.d = float128_to_float64(ft0_128, &env->fp_status);
1302 /* This is OK on x86 hosts */
1303 farg1.d = (farg1.d * farg2.d) + farg3.d;
1307 farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
1308 farg1.d = float64_add(farg1.d, farg3.d, &env->fp_status);
1313 /* fmsub - fmsub. */
1314 uint64_t helper_fmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3)
1316 CPU_DoubleU farg1, farg2, farg3;
1321 #if USE_PRECISE_EMULATION
1322 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1323 float64_is_signaling_nan(farg2.d) ||
1324 float64_is_signaling_nan(farg3.d))) {
1325 /* sNaN operation */
1326 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1327 } else if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
1328 (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
1329 /* Multiplication of zero by infinity */
1330 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
1333 /* This is the way the PowerPC specification defines it */
1334 float128 ft0_128, ft1_128;
1336 ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
1337 ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
1338 ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
1339 if (unlikely(float128_is_infinity(ft0_128) && float64_is_infinity(farg3.d) &&
1340 float128_is_neg(ft0_128) == float64_is_neg(farg3.d))) {
1341 /* Magnitude subtraction of infinities */
1342 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
1344 ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
1345 ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
1346 farg1.d = float128_to_float64(ft0_128, &env->fp_status);
1349 /* This is OK on x86 hosts */
1350 farg1.d = (farg1.d * farg2.d) - farg3.d;
1354 farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
1355 farg1.d = float64_sub(farg1.d, farg3.d, &env->fp_status);
1360 /* fnmadd - fnmadd. */
1361 uint64_t helper_fnmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3)
1363 CPU_DoubleU farg1, farg2, farg3;
1369 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1370 float64_is_signaling_nan(farg2.d) ||
1371 float64_is_signaling_nan(farg3.d))) {
1372 /* sNaN operation */
1373 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1374 } else if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
1375 (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
1376 /* Multiplication of zero by infinity */
1377 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
1379 #if USE_PRECISE_EMULATION
1381 /* This is the way the PowerPC specification defines it */
1382 float128 ft0_128, ft1_128;
1384 ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
1385 ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
1386 ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
1387 if (unlikely(float128_is_infinity(ft0_128) && float64_is_infinity(farg3.d) &&
1388 float128_is_neg(ft0_128) != float64_is_neg(farg3.d))) {
1389 /* Magnitude subtraction of infinities */
1390 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
1392 ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
1393 ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
1394 farg1.d = float128_to_float64(ft0_128, &env->fp_status);
1397 /* This is OK on x86 hosts */
1398 farg1.d = (farg1.d * farg2.d) + farg3.d;
1401 farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
1402 farg1.d = float64_add(farg1.d, farg3.d, &env->fp_status);
1404 if (likely(!float64_is_nan(farg1.d)))
1405 farg1.d = float64_chs(farg1.d);
1410 /* fnmsub - fnmsub. */
1411 uint64_t helper_fnmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3)
1413 CPU_DoubleU farg1, farg2, farg3;
1419 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1420 float64_is_signaling_nan(farg2.d) ||
1421 float64_is_signaling_nan(farg3.d))) {
1422 /* sNaN operation */
1423 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1424 } else if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
1425 (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
1426 /* Multiplication of zero by infinity */
1427 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
1429 #if USE_PRECISE_EMULATION
1431 /* This is the way the PowerPC specification defines it */
1432 float128 ft0_128, ft1_128;
1434 ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
1435 ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
1436 ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
1437 if (unlikely(float128_is_infinity(ft0_128) && float64_is_infinity(farg3.d) &&
1438 float128_is_neg(ft0_128) == float64_is_neg(farg3.d))) {
1439 /* Magnitude subtraction of infinities */
1440 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
1442 ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
1443 ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
1444 farg1.d = float128_to_float64(ft0_128, &env->fp_status);
1447 /* This is OK on x86 hosts */
1448 farg1.d = (farg1.d * farg2.d) - farg3.d;
1451 farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
1452 farg1.d = float64_sub(farg1.d, farg3.d, &env->fp_status);
1454 if (likely(!float64_is_nan(farg1.d)))
1455 farg1.d = float64_chs(farg1.d);
1461 uint64_t helper_frsp (uint64_t arg)
1467 #if USE_PRECISE_EMULATION
1468 if (unlikely(float64_is_signaling_nan(farg.d))) {
1469 /* sNaN square root */
1470 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1472 f32 = float64_to_float32(farg.d, &env->fp_status);
1473 farg.d = float32_to_float64(f32, &env->fp_status);
1476 f32 = float64_to_float32(farg.d, &env->fp_status);
1477 farg.d = float32_to_float64(f32, &env->fp_status);
1482 /* fsqrt - fsqrt. */
1483 uint64_t helper_fsqrt (uint64_t arg)
1488 if (unlikely(float64_is_signaling_nan(farg.d))) {
1489 /* sNaN square root */
1490 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1491 } else if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) {
1492 /* Square root of a negative nonzero number */
1493 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSQRT);
1495 farg.d = float64_sqrt(farg.d, &env->fp_status);
1501 uint64_t helper_fre (uint64_t arg)
1503 CPU_DoubleU fone, farg;
1504 fone.ll = 0x3FF0000000000000ULL; /* 1.0 */
1507 if (unlikely(float64_is_signaling_nan(farg.d))) {
1508 /* sNaN reciprocal */
1509 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1511 farg.d = float64_div(fone.d, farg.d, &env->fp_status);
1517 uint64_t helper_fres (uint64_t arg)
1519 CPU_DoubleU fone, farg;
1521 fone.ll = 0x3FF0000000000000ULL; /* 1.0 */
1524 if (unlikely(float64_is_signaling_nan(farg.d))) {
1525 /* sNaN reciprocal */
1526 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1528 farg.d = float64_div(fone.d, farg.d, &env->fp_status);
1529 f32 = float64_to_float32(farg.d, &env->fp_status);
1530 farg.d = float32_to_float64(f32, &env->fp_status);
1535 /* frsqrte - frsqrte. */
1536 uint64_t helper_frsqrte (uint64_t arg)
1538 CPU_DoubleU fone, farg;
1540 fone.ll = 0x3FF0000000000000ULL; /* 1.0 */
1543 if (unlikely(float64_is_signaling_nan(farg.d))) {
1544 /* sNaN reciprocal square root */
1545 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1546 } else if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) {
1547 /* Reciprocal square root of a negative nonzero number */
1548 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSQRT);
1550 farg.d = float64_sqrt(farg.d, &env->fp_status);
1551 farg.d = float64_div(fone.d, farg.d, &env->fp_status);
1552 f32 = float64_to_float32(farg.d, &env->fp_status);
1553 farg.d = float32_to_float64(f32, &env->fp_status);
1559 uint64_t helper_fsel (uint64_t arg1, uint64_t arg2, uint64_t arg3)
1565 if ((!float64_is_neg(farg1.d) || float64_is_zero(farg1.d)) && !float64_is_nan(farg1.d))
1571 void helper_fcmpu (uint64_t arg1, uint64_t arg2, uint32_t crfD)
1573 CPU_DoubleU farg1, farg2;
1578 if (unlikely(float64_is_nan(farg1.d) ||
1579 float64_is_nan(farg2.d))) {
1581 } else if (float64_lt(farg1.d, farg2.d, &env->fp_status)) {
1583 } else if (!float64_le(farg1.d, farg2.d, &env->fp_status)) {
1589 env->fpscr &= ~(0x0F << FPSCR_FPRF);
1590 env->fpscr |= ret << FPSCR_FPRF;
1591 env->crf[crfD] = ret;
1592 if (unlikely(ret == 0x01UL
1593 && (float64_is_signaling_nan(farg1.d) ||
1594 float64_is_signaling_nan(farg2.d)))) {
1595 /* sNaN comparison */
1596 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1600 void helper_fcmpo (uint64_t arg1, uint64_t arg2, uint32_t crfD)
1602 CPU_DoubleU farg1, farg2;
1607 if (unlikely(float64_is_nan(farg1.d) ||
1608 float64_is_nan(farg2.d))) {
1610 } else if (float64_lt(farg1.d, farg2.d, &env->fp_status)) {
1612 } else if (!float64_le(farg1.d, farg2.d, &env->fp_status)) {
1618 env->fpscr &= ~(0x0F << FPSCR_FPRF);
1619 env->fpscr |= ret << FPSCR_FPRF;
1620 env->crf[crfD] = ret;
1621 if (unlikely (ret == 0x01UL)) {
1622 if (float64_is_signaling_nan(farg1.d) ||
1623 float64_is_signaling_nan(farg2.d)) {
1624 /* sNaN comparison */
1625 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN |
1626 POWERPC_EXCP_FP_VXVC);
1628 /* qNaN comparison */
1629 fload_invalid_op_excp(POWERPC_EXCP_FP_VXVC);
1634 #if !defined (CONFIG_USER_ONLY)
1635 void helper_store_msr (target_ulong val)
1637 val = hreg_store_msr(env, val, 0);
1639 env->interrupt_request |= CPU_INTERRUPT_EXITTB;
1640 helper_raise_exception(val);
1644 static always_inline void do_rfi (target_ulong nip, target_ulong msr,
1645 target_ulong msrm, int keep_msrh)
1647 #if defined(TARGET_PPC64)
1648 if (msr & (1ULL << MSR_SF)) {
1649 nip = (uint64_t)nip;
1650 msr &= (uint64_t)msrm;
1652 nip = (uint32_t)nip;
1653 msr = (uint32_t)(msr & msrm);
1655 msr |= env->msr & ~((uint64_t)0xFFFFFFFF);
1658 nip = (uint32_t)nip;
1659 msr &= (uint32_t)msrm;
1661 /* XXX: beware: this is false if VLE is supported */
1662 env->nip = nip & ~((target_ulong)0x00000003);
1663 hreg_store_msr(env, msr, 1);
1664 #if defined (DEBUG_OP)
1665 cpu_dump_rfi(env->nip, env->msr);
1667 /* No need to raise an exception here,
1668 * as rfi is always the last insn of a TB
1670 env->interrupt_request |= CPU_INTERRUPT_EXITTB;
1673 void helper_rfi (void)
1675 do_rfi(env->spr[SPR_SRR0], env->spr[SPR_SRR1],
1676 ~((target_ulong)0xFFFF0000), 1);
1679 #if defined(TARGET_PPC64)
1680 void helper_rfid (void)
1682 do_rfi(env->spr[SPR_SRR0], env->spr[SPR_SRR1],
1683 ~((target_ulong)0xFFFF0000), 0);
1686 void helper_hrfid (void)
1688 do_rfi(env->spr[SPR_HSRR0], env->spr[SPR_HSRR1],
1689 ~((target_ulong)0xFFFF0000), 0);
1694 void helper_tw (target_ulong arg1, target_ulong arg2, uint32_t flags)
1696 if (!likely(!(((int32_t)arg1 < (int32_t)arg2 && (flags & 0x10)) ||
1697 ((int32_t)arg1 > (int32_t)arg2 && (flags & 0x08)) ||
1698 ((int32_t)arg1 == (int32_t)arg2 && (flags & 0x04)) ||
1699 ((uint32_t)arg1 < (uint32_t)arg2 && (flags & 0x02)) ||
1700 ((uint32_t)arg1 > (uint32_t)arg2 && (flags & 0x01))))) {
1701 helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_TRAP);
1705 #if defined(TARGET_PPC64)
1706 void helper_td (target_ulong arg1, target_ulong arg2, uint32_t flags)
1708 if (!likely(!(((int64_t)arg1 < (int64_t)arg2 && (flags & 0x10)) ||
1709 ((int64_t)arg1 > (int64_t)arg2 && (flags & 0x08)) ||
1710 ((int64_t)arg1 == (int64_t)arg2 && (flags & 0x04)) ||
1711 ((uint64_t)arg1 < (uint64_t)arg2 && (flags & 0x02)) ||
1712 ((uint64_t)arg1 > (uint64_t)arg2 && (flags & 0x01)))))
1713 helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_TRAP);
1717 /*****************************************************************************/
1718 /* PowerPC 601 specific instructions (POWER bridge) */
1720 target_ulong helper_clcs (uint32_t arg)
1724 /* Instruction cache line size */
1725 return env->icache_line_size;
1728 /* Data cache line size */
1729 return env->dcache_line_size;
1732 /* Minimum cache line size */
1733 return (env->icache_line_size < env->dcache_line_size) ?
1734 env->icache_line_size : env->dcache_line_size;
1737 /* Maximum cache line size */
1738 return (env->icache_line_size > env->dcache_line_size) ?
1739 env->icache_line_size : env->dcache_line_size;
1748 target_ulong helper_div (target_ulong arg1, target_ulong arg2)
1750 uint64_t tmp = (uint64_t)arg1 << 32 | env->spr[SPR_MQ];
1752 if (((int32_t)tmp == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
1753 (int32_t)arg2 == 0) {
1754 env->spr[SPR_MQ] = 0;
1757 env->spr[SPR_MQ] = tmp % arg2;
1758 return tmp / (int32_t)arg2;
1762 target_ulong helper_divo (target_ulong arg1, target_ulong arg2)
1764 uint64_t tmp = (uint64_t)arg1 << 32 | env->spr[SPR_MQ];
1766 if (((int32_t)tmp == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
1767 (int32_t)arg2 == 0) {
1768 env->xer |= (1 << XER_OV) | (1 << XER_SO);
1769 env->spr[SPR_MQ] = 0;
1772 env->spr[SPR_MQ] = tmp % arg2;
1773 tmp /= (int32_t)arg2;
1774 if ((int32_t)tmp != tmp) {
1775 env->xer |= (1 << XER_OV) | (1 << XER_SO);
1777 env->xer &= ~(1 << XER_OV);
1783 target_ulong helper_divs (target_ulong arg1, target_ulong arg2)
1785 if (((int32_t)arg1 == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
1786 (int32_t)arg2 == 0) {
1787 env->spr[SPR_MQ] = 0;
1790 env->spr[SPR_MQ] = (int32_t)arg1 % (int32_t)arg2;
1791 return (int32_t)arg1 / (int32_t)arg2;
1795 target_ulong helper_divso (target_ulong arg1, target_ulong arg2)
1797 if (((int32_t)arg1 == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
1798 (int32_t)arg2 == 0) {
1799 env->xer |= (1 << XER_OV) | (1 << XER_SO);
1800 env->spr[SPR_MQ] = 0;
1803 env->xer &= ~(1 << XER_OV);
1804 env->spr[SPR_MQ] = (int32_t)arg1 % (int32_t)arg2;
1805 return (int32_t)arg1 / (int32_t)arg2;
1809 #if !defined (CONFIG_USER_ONLY)
1810 target_ulong helper_rac (target_ulong addr)
1814 target_ulong ret = 0;
1816 /* We don't have to generate many instances of this instruction,
1817 * as rac is supervisor only.
1819 /* XXX: FIX THIS: Pretend we have no BAT */
1820 nb_BATs = env->nb_BATs;
1822 if (get_physical_address(env, &ctx, addr, 0, ACCESS_INT) == 0)
1824 env->nb_BATs = nb_BATs;
1828 void helper_rfsvc (void)
1830 do_rfi(env->lr, env->ctr, 0x0000FFFF, 0);
1834 /*****************************************************************************/
1835 /* 602 specific instructions */
1836 /* mfrom is the most crazy instruction ever seen, imho ! */
1837 /* Real implementation uses a ROM table. Do the same */
1838 /* Extremly decomposed:
1840 * return 256 * log10(10 + 1.0) + 0.5
1842 #if !defined (CONFIG_USER_ONLY)
1843 target_ulong helper_602_mfrom (target_ulong arg)
1845 if (likely(arg < 602)) {
1846 #include "mfrom_table.c"
1847 return mfrom_ROM_table[arg];
1854 /*****************************************************************************/
1855 /* Embedded PowerPC specific helpers */
1857 /* XXX: to be improved to check access rights when in user-mode */
1858 target_ulong helper_load_dcr (target_ulong dcrn)
1860 target_ulong val = 0;
1862 if (unlikely(env->dcr_env == NULL)) {
1863 if (loglevel != 0) {
1864 fprintf(logfile, "No DCR environment\n");
1866 helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
1867 POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL);
1868 } else if (unlikely(ppc_dcr_read(env->dcr_env, dcrn, &val) != 0)) {
1869 if (loglevel != 0) {
1870 fprintf(logfile, "DCR read error %d %03x\n", (int)dcrn, (int)dcrn);
1872 helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
1873 POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG);
1878 void helper_store_dcr (target_ulong dcrn, target_ulong val)
1880 if (unlikely(env->dcr_env == NULL)) {
1881 if (loglevel != 0) {
1882 fprintf(logfile, "No DCR environment\n");
1884 helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
1885 POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL);
1886 } else if (unlikely(ppc_dcr_write(env->dcr_env, dcrn, val) != 0)) {
1887 if (loglevel != 0) {
1888 fprintf(logfile, "DCR write error %d %03x\n", (int)dcrn, (int)dcrn);
1890 helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
1891 POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG);
1895 #if !defined(CONFIG_USER_ONLY)
1896 void helper_40x_rfci (void)
1898 do_rfi(env->spr[SPR_40x_SRR2], env->spr[SPR_40x_SRR3],
1899 ~((target_ulong)0xFFFF0000), 0);
1902 void helper_rfci (void)
1904 do_rfi(env->spr[SPR_BOOKE_CSRR0], SPR_BOOKE_CSRR1,
1905 ~((target_ulong)0x3FFF0000), 0);
1908 void helper_rfdi (void)
1910 do_rfi(env->spr[SPR_BOOKE_DSRR0], SPR_BOOKE_DSRR1,
1911 ~((target_ulong)0x3FFF0000), 0);
1914 void helper_rfmci (void)
1916 do_rfi(env->spr[SPR_BOOKE_MCSRR0], SPR_BOOKE_MCSRR1,
1917 ~((target_ulong)0x3FFF0000), 0);
1922 target_ulong helper_dlmzb (target_ulong high, target_ulong low, uint32_t update_Rc)
1928 for (mask = 0xFF000000; mask != 0; mask = mask >> 8) {
1929 if ((high & mask) == 0) {
1937 for (mask = 0xFF000000; mask != 0; mask = mask >> 8) {
1938 if ((low & mask) == 0) {
1950 env->xer = (env->xer & ~0x7F) | i;
1952 env->crf[0] |= xer_so;
1957 /*****************************************************************************/
1958 /* Altivec extension helpers */
1959 #if defined(WORDS_BIGENDIAN)
1967 #if defined(WORDS_BIGENDIAN)
1968 #define VECTOR_FOR_INORDER_I(index, element) \
1969 for (index = 0; index < ARRAY_SIZE(r->element); index++)
1971 #define VECTOR_FOR_INORDER_I(index, element) \
1972 for (index = ARRAY_SIZE(r->element)-1; index >= 0; index--)
1975 /* Saturating arithmetic helpers. */
1976 #define SATCVT(from, to, from_type, to_type, min, max, use_min, use_max) \
1977 static always_inline to_type cvt##from##to (from_type x, int *sat) \
1980 if (use_min && x < min) { \
1983 } else if (use_max && x > max) { \
1991 SATCVT(sh, sb, int16_t, int8_t, INT8_MIN, INT8_MAX, 1, 1)
1992 SATCVT(sw, sh, int32_t, int16_t, INT16_MIN, INT16_MAX, 1, 1)
1993 SATCVT(sd, sw, int64_t, int32_t, INT32_MIN, INT32_MAX, 1, 1)
1994 SATCVT(uh, ub, uint16_t, uint8_t, 0, UINT8_MAX, 0, 1)
1995 SATCVT(uw, uh, uint32_t, uint16_t, 0, UINT16_MAX, 0, 1)
1996 SATCVT(ud, uw, uint64_t, uint32_t, 0, UINT32_MAX, 0, 1)
1997 SATCVT(sh, ub, int16_t, uint8_t, 0, UINT8_MAX, 1, 1)
1998 SATCVT(sw, uh, int32_t, uint16_t, 0, UINT16_MAX, 1, 1)
1999 SATCVT(sd, uw, int64_t, uint32_t, 0, UINT32_MAX, 1, 1)
2002 #define LVE(name, access, swap, element) \
2003 void helper_##name (ppc_avr_t *r, target_ulong addr) \
2005 size_t n_elems = ARRAY_SIZE(r->element); \
2006 int adjust = HI_IDX*(n_elems-1); \
2007 int sh = sizeof(r->element[0]) >> 1; \
2008 int index = (addr & 0xf) >> sh; \
2010 r->element[LO_IDX ? index : (adjust - index)] = swap(access(addr)); \
2012 r->element[LO_IDX ? index : (adjust - index)] = access(addr); \
2016 LVE(lvebx, ldub, I, u8)
2017 LVE(lvehx, lduw, bswap16, u16)
2018 LVE(lvewx, ldl, bswap32, u32)
2022 void helper_lvsl (ppc_avr_t *r, target_ulong sh)
2024 int i, j = (sh & 0xf);
2026 VECTOR_FOR_INORDER_I (i, u8) {
2031 void helper_lvsr (ppc_avr_t *r, target_ulong sh)
2033 int i, j = 0x10 - (sh & 0xf);
2035 VECTOR_FOR_INORDER_I (i, u8) {
2040 #define STVE(name, access, swap, element) \
2041 void helper_##name (ppc_avr_t *r, target_ulong addr) \
2043 size_t n_elems = ARRAY_SIZE(r->element); \
2044 int adjust = HI_IDX*(n_elems-1); \
2045 int sh = sizeof(r->element[0]) >> 1; \
2046 int index = (addr & 0xf) >> sh; \
2048 access(addr, swap(r->element[LO_IDX ? index : (adjust - index)])); \
2050 access(addr, r->element[LO_IDX ? index : (adjust - index)]); \
2054 STVE(stvebx, stb, I, u8)
2055 STVE(stvehx, stw, bswap16, u16)
2056 STVE(stvewx, stl, bswap32, u32)
2060 void helper_vaddcuw (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2063 for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
2064 r->u32[i] = ~a->u32[i] < b->u32[i];
2068 #define VARITH_DO(name, op, element) \
2069 void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2072 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2073 r->element[i] = a->element[i] op b->element[i]; \
2076 #define VARITH(suffix, element) \
2077 VARITH_DO(add##suffix, +, element) \
2078 VARITH_DO(sub##suffix, -, element)
2085 #define VAVG_DO(name, element, etype) \
2086 void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2089 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2090 etype x = (etype)a->element[i] + (etype)b->element[i] + 1; \
2091 r->element[i] = x >> 1; \
2095 #define VAVG(type, signed_element, signed_type, unsigned_element, unsigned_type) \
2096 VAVG_DO(avgs##type, signed_element, signed_type) \
2097 VAVG_DO(avgu##type, unsigned_element, unsigned_type)
2098 VAVG(b, s8, int16_t, u8, uint16_t)
2099 VAVG(h, s16, int32_t, u16, uint32_t)
2100 VAVG(w, s32, int64_t, u32, uint64_t)
2104 #define VCMP_DO(suffix, compare, element, record) \
2105 void helper_vcmp##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2107 uint32_t ones = (uint32_t)-1; \
2108 uint32_t all = ones; \
2109 uint32_t none = 0; \
2111 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2112 uint32_t result = (a->element[i] compare b->element[i] ? ones : 0x0); \
2113 switch (sizeof (a->element[0])) { \
2114 case 4: r->u32[i] = result; break; \
2115 case 2: r->u16[i] = result; break; \
2116 case 1: r->u8[i] = result; break; \
2122 env->crf[6] = ((all != 0) << 3) | ((none == 0) << 1); \
2125 #define VCMP(suffix, compare, element) \
2126 VCMP_DO(suffix, compare, element, 0) \
2127 VCMP_DO(suffix##_dot, compare, element, 1)
2140 void helper_vmhaddshs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2145 for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
2146 int32_t prod = a->s16[i] * b->s16[i];
2147 int32_t t = (int32_t)c->s16[i] + (prod >> 15);
2148 r->s16[i] = cvtswsh (t, &sat);
2152 env->vscr |= (1 << VSCR_SAT);
2156 void helper_vmhraddshs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2161 for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
2162 int32_t prod = a->s16[i] * b->s16[i] + 0x00004000;
2163 int32_t t = (int32_t)c->s16[i] + (prod >> 15);
2164 r->s16[i] = cvtswsh (t, &sat);
2168 env->vscr |= (1 << VSCR_SAT);
2172 #define VMINMAX_DO(name, compare, element) \
2173 void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2176 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2177 if (a->element[i] compare b->element[i]) { \
2178 r->element[i] = b->element[i]; \
2180 r->element[i] = a->element[i]; \
2184 #define VMINMAX(suffix, element) \
2185 VMINMAX_DO(min##suffix, >, element) \
2186 VMINMAX_DO(max##suffix, <, element)
2196 void helper_vmladduhm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2199 for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
2200 int32_t prod = a->s16[i] * b->s16[i];
2201 r->s16[i] = (int16_t) (prod + c->s16[i]);
2205 #define VMRG_DO(name, element, highp) \
2206 void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2210 size_t n_elems = ARRAY_SIZE(r->element); \
2211 for (i = 0; i < n_elems/2; i++) { \
2213 result.element[i*2+HI_IDX] = a->element[i]; \
2214 result.element[i*2+LO_IDX] = b->element[i]; \
2216 result.element[n_elems - i*2 - (1+HI_IDX)] = b->element[n_elems - i - 1]; \
2217 result.element[n_elems - i*2 - (1+LO_IDX)] = a->element[n_elems - i - 1]; \
2222 #if defined(WORDS_BIGENDIAN)
2229 #define VMRG(suffix, element) \
2230 VMRG_DO(mrgl##suffix, element, MRGHI) \
2231 VMRG_DO(mrgh##suffix, element, MRGLO)
2240 void helper_vmsummbm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2245 for (i = 0; i < ARRAY_SIZE(r->s8); i++) {
2246 prod[i] = (int32_t)a->s8[i] * b->u8[i];
2249 VECTOR_FOR_INORDER_I(i, s32) {
2250 r->s32[i] = c->s32[i] + prod[4*i] + prod[4*i+1] + prod[4*i+2] + prod[4*i+3];
2254 void helper_vmsumshm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2259 for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
2260 prod[i] = a->s16[i] * b->s16[i];
2263 VECTOR_FOR_INORDER_I(i, s32) {
2264 r->s32[i] = c->s32[i] + prod[2*i] + prod[2*i+1];
2268 void helper_vmsumshs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2274 for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
2275 prod[i] = (int32_t)a->s16[i] * b->s16[i];
2278 VECTOR_FOR_INORDER_I (i, s32) {
2279 int64_t t = (int64_t)c->s32[i] + prod[2*i] + prod[2*i+1];
2280 r->u32[i] = cvtsdsw(t, &sat);
2284 env->vscr |= (1 << VSCR_SAT);
2288 void helper_vmsumubm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2293 for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
2294 prod[i] = a->u8[i] * b->u8[i];
2297 VECTOR_FOR_INORDER_I(i, u32) {
2298 r->u32[i] = c->u32[i] + prod[4*i] + prod[4*i+1] + prod[4*i+2] + prod[4*i+3];
2302 void helper_vmsumuhm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2307 for (i = 0; i < ARRAY_SIZE(r->u16); i++) {
2308 prod[i] = a->u16[i] * b->u16[i];
2311 VECTOR_FOR_INORDER_I(i, u32) {
2312 r->u32[i] = c->u32[i] + prod[2*i] + prod[2*i+1];
2316 void helper_vmsumuhs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2322 for (i = 0; i < ARRAY_SIZE(r->u16); i++) {
2323 prod[i] = a->u16[i] * b->u16[i];
2326 VECTOR_FOR_INORDER_I (i, s32) {
2327 uint64_t t = (uint64_t)c->u32[i] + prod[2*i] + prod[2*i+1];
2328 r->u32[i] = cvtuduw(t, &sat);
2332 env->vscr |= (1 << VSCR_SAT);
2336 #define VMUL_DO(name, mul_element, prod_element, evenp) \
2337 void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2340 VECTOR_FOR_INORDER_I(i, prod_element) { \
2342 r->prod_element[i] = a->mul_element[i*2+HI_IDX] * b->mul_element[i*2+HI_IDX]; \
2344 r->prod_element[i] = a->mul_element[i*2+LO_IDX] * b->mul_element[i*2+LO_IDX]; \
2348 #define VMUL(suffix, mul_element, prod_element) \
2349 VMUL_DO(mule##suffix, mul_element, prod_element, 1) \
2350 VMUL_DO(mulo##suffix, mul_element, prod_element, 0)
2358 void helper_vperm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2362 VECTOR_FOR_INORDER_I (i, u8) {
2363 int s = c->u8[i] & 0x1f;
2364 #if defined(WORDS_BIGENDIAN)
2365 int index = s & 0xf;
2367 int index = 15 - (s & 0xf);
2370 result.u8[i] = b->u8[index];
2372 result.u8[i] = a->u8[index];
2378 #if defined(WORDS_BIGENDIAN)
2383 void helper_vpkpx (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2387 #if defined(WORDS_BIGENDIAN)
2388 const ppc_avr_t *x[2] = { a, b };
2390 const ppc_avr_t *x[2] = { b, a };
2393 VECTOR_FOR_INORDER_I (i, u64) {
2394 VECTOR_FOR_INORDER_I (j, u32){
2395 uint32_t e = x[i]->u32[j];
2396 result.u16[4*i+j] = (((e >> 9) & 0xfc00) |
2397 ((e >> 6) & 0x3e0) |
2404 #define VPK(suffix, from, to, cvt, dosat) \
2405 void helper_vpk##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2410 ppc_avr_t *a0 = PKBIG ? a : b; \
2411 ppc_avr_t *a1 = PKBIG ? b : a; \
2412 VECTOR_FOR_INORDER_I (i, from) { \
2413 result.to[i] = cvt(a0->from[i], &sat); \
2414 result.to[i+ARRAY_SIZE(r->from)] = cvt(a1->from[i], &sat); \
2417 if (dosat && sat) { \
2418 env->vscr |= (1 << VSCR_SAT); \
2422 VPK(shss, s16, s8, cvtshsb, 1)
2423 VPK(shus, s16, u8, cvtshub, 1)
2424 VPK(swss, s32, s16, cvtswsh, 1)
2425 VPK(swus, s32, u16, cvtswuh, 1)
2426 VPK(uhus, u16, u8, cvtuhub, 1)
2427 VPK(uwus, u32, u16, cvtuwuh, 1)
2428 VPK(uhum, u16, u8, I, 0)
2429 VPK(uwum, u32, u16, I, 0)
2434 #define VROTATE(suffix, element) \
2435 void helper_vrl##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2438 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2439 unsigned int mask = ((1 << (3 + (sizeof (a->element[0]) >> 1))) - 1); \
2440 unsigned int shift = b->element[i] & mask; \
2441 r->element[i] = (a->element[i] << shift) | (a->element[i] >> (sizeof(a->element[0]) * 8 - shift)); \
2449 void helper_vsel (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2451 r->u64[0] = (a->u64[0] & ~c->u64[0]) | (b->u64[0] & c->u64[0]);
2452 r->u64[1] = (a->u64[1] & ~c->u64[1]) | (b->u64[1] & c->u64[1]);
2455 #if defined(WORDS_BIGENDIAN)
2462 /* The specification says that the results are undefined if all of the
2463 * shift counts are not identical. We check to make sure that they are
2464 * to conform to what real hardware appears to do. */
2465 #define VSHIFT(suffix, leftp) \
2466 void helper_vs##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2468 int shift = b->u8[LO_IDX*0x15] & 0x7; \
2471 for (i = 0; i < ARRAY_SIZE(r->u8); i++) { \
2472 doit = doit && ((b->u8[i] & 0x7) == shift); \
2477 } else if (leftp) { \
2478 uint64_t carry = a->u64[LO_IDX] >> (64 - shift); \
2479 r->u64[HI_IDX] = (a->u64[HI_IDX] << shift) | carry; \
2480 r->u64[LO_IDX] = a->u64[LO_IDX] << shift; \
2482 uint64_t carry = a->u64[HI_IDX] << (64 - shift); \
2483 r->u64[LO_IDX] = (a->u64[LO_IDX] >> shift) | carry; \
2484 r->u64[HI_IDX] = a->u64[HI_IDX] >> shift; \
2494 #define VSL(suffix, element) \
2495 void helper_vsl##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2498 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2499 unsigned int mask = ((1 << (3 + (sizeof (a->element[0]) >> 1))) - 1); \
2500 unsigned int shift = b->element[i] & mask; \
2501 r->element[i] = a->element[i] << shift; \
2509 void helper_vsldoi (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t shift)
2511 int sh = shift & 0xf;
2515 #if defined(WORDS_BIGENDIAN)
2516 for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
2519 result.u8[i] = b->u8[index-0x10];
2521 result.u8[i] = a->u8[index];
2525 for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
2526 int index = (16 - sh) + i;
2528 result.u8[i] = a->u8[index-0x10];
2530 result.u8[i] = b->u8[index];
2537 void helper_vslo (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2539 int sh = (b->u8[LO_IDX*0xf] >> 3) & 0xf;
2541 #if defined (WORDS_BIGENDIAN)
2542 memmove (&r->u8[0], &a->u8[sh], 16-sh);
2543 memset (&r->u8[16-sh], 0, sh);
2545 memmove (&r->u8[sh], &a->u8[0], 16-sh);
2546 memset (&r->u8[0], 0, sh);
2550 /* Experimental testing shows that hardware masks the immediate. */
2551 #define _SPLAT_MASKED(element) (splat & (ARRAY_SIZE(r->element) - 1))
2552 #if defined(WORDS_BIGENDIAN)
2553 #define SPLAT_ELEMENT(element) _SPLAT_MASKED(element)
2555 #define SPLAT_ELEMENT(element) (ARRAY_SIZE(r->element)-1 - _SPLAT_MASKED(element))
2557 #define VSPLT(suffix, element) \
2558 void helper_vsplt##suffix (ppc_avr_t *r, ppc_avr_t *b, uint32_t splat) \
2560 uint32_t s = b->element[SPLAT_ELEMENT(element)]; \
2562 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2563 r->element[i] = s; \
2570 #undef SPLAT_ELEMENT
2571 #undef _SPLAT_MASKED
2573 #define VSPLTI(suffix, element, splat_type) \
2574 void helper_vspltis##suffix (ppc_avr_t *r, uint32_t splat) \
2576 splat_type x = (int8_t)(splat << 3) >> 3; \
2578 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2579 r->element[i] = x; \
2582 VSPLTI(b, s8, int8_t)
2583 VSPLTI(h, s16, int16_t)
2584 VSPLTI(w, s32, int32_t)
2587 #define VSR(suffix, element) \
2588 void helper_vsr##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2591 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2592 unsigned int mask = ((1 << (3 + (sizeof (a->element[0]) >> 1))) - 1); \
2593 unsigned int shift = b->element[i] & mask; \
2594 r->element[i] = a->element[i] >> shift; \
2605 void helper_vsro (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2607 int sh = (b->u8[LO_IDX*0xf] >> 3) & 0xf;
2609 #if defined (WORDS_BIGENDIAN)
2610 memmove (&r->u8[sh], &a->u8[0], 16-sh);
2611 memset (&r->u8[0], 0, sh);
2613 memmove (&r->u8[0], &a->u8[sh], 16-sh);
2614 memset (&r->u8[16-sh], 0, sh);
2618 void helper_vsubcuw (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2621 for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
2622 r->u32[i] = a->u32[i] >= b->u32[i];
2626 void helper_vsumsws (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2633 #if defined(WORDS_BIGENDIAN)
2634 upper = ARRAY_SIZE(r->s32)-1;
2638 t = (int64_t)b->s32[upper];
2639 for (i = 0; i < ARRAY_SIZE(r->s32); i++) {
2643 result.s32[upper] = cvtsdsw(t, &sat);
2647 env->vscr |= (1 << VSCR_SAT);
2651 void helper_vsum2sws (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2657 #if defined(WORDS_BIGENDIAN)
2662 for (i = 0; i < ARRAY_SIZE(r->u64); i++) {
2663 int64_t t = (int64_t)b->s32[upper+i*2];
2665 for (j = 0; j < ARRAY_SIZE(r->u64); j++) {
2668 result.s32[upper+i*2] = cvtsdsw(t, &sat);
2673 env->vscr |= (1 << VSCR_SAT);
2677 void helper_vsum4sbs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2682 for (i = 0; i < ARRAY_SIZE(r->s32); i++) {
2683 int64_t t = (int64_t)b->s32[i];
2684 for (j = 0; j < ARRAY_SIZE(r->s32); j++) {
2687 r->s32[i] = cvtsdsw(t, &sat);
2691 env->vscr |= (1 << VSCR_SAT);
2695 void helper_vsum4shs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2700 for (i = 0; i < ARRAY_SIZE(r->s32); i++) {
2701 int64_t t = (int64_t)b->s32[i];
2702 t += a->s16[2*i] + a->s16[2*i+1];
2703 r->s32[i] = cvtsdsw(t, &sat);
2707 env->vscr |= (1 << VSCR_SAT);
2711 void helper_vsum4ubs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2716 for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
2717 uint64_t t = (uint64_t)b->u32[i];
2718 for (j = 0; j < ARRAY_SIZE(r->u32); j++) {
2721 r->u32[i] = cvtuduw(t, &sat);
2725 env->vscr |= (1 << VSCR_SAT);
2729 #if defined(WORDS_BIGENDIAN)
2736 #define VUPKPX(suffix, hi) \
2737 void helper_vupk##suffix (ppc_avr_t *r, ppc_avr_t *b) \
2741 for (i = 0; i < ARRAY_SIZE(r->u32); i++) { \
2742 uint16_t e = b->u16[hi ? i : i+4]; \
2743 uint8_t a = (e >> 15) ? 0xff : 0; \
2744 uint8_t r = (e >> 10) & 0x1f; \
2745 uint8_t g = (e >> 5) & 0x1f; \
2746 uint8_t b = e & 0x1f; \
2747 result.u32[i] = (a << 24) | (r << 16) | (g << 8) | b; \
2755 #define VUPK(suffix, unpacked, packee, hi) \
2756 void helper_vupk##suffix (ppc_avr_t *r, ppc_avr_t *b) \
2761 for (i = 0; i < ARRAY_SIZE(r->unpacked); i++) { \
2762 result.unpacked[i] = b->packee[i]; \
2765 for (i = ARRAY_SIZE(r->unpacked); i < ARRAY_SIZE(r->packee); i++) { \
2766 result.unpacked[i-ARRAY_SIZE(r->unpacked)] = b->packee[i]; \
2771 VUPK(hsb, s16, s8, UPKHI)
2772 VUPK(hsh, s32, s16, UPKHI)
2773 VUPK(lsb, s16, s8, UPKLO)
2774 VUPK(lsh, s32, s16, UPKLO)
2779 #undef VECTOR_FOR_INORDER_I
2783 /*****************************************************************************/
2784 /* SPE extension helpers */
2785 /* Use a table to make this quicker */
2786 static uint8_t hbrev[16] = {
2787 0x0, 0x8, 0x4, 0xC, 0x2, 0xA, 0x6, 0xE,
2788 0x1, 0x9, 0x5, 0xD, 0x3, 0xB, 0x7, 0xF,
2791 static always_inline uint8_t byte_reverse (uint8_t val)
2793 return hbrev[val >> 4] | (hbrev[val & 0xF] << 4);
2796 static always_inline uint32_t word_reverse (uint32_t val)
2798 return byte_reverse(val >> 24) | (byte_reverse(val >> 16) << 8) |
2799 (byte_reverse(val >> 8) << 16) | (byte_reverse(val) << 24);
2802 #define MASKBITS 16 // Random value - to be fixed (implementation dependant)
2803 target_ulong helper_brinc (target_ulong arg1, target_ulong arg2)
2805 uint32_t a, b, d, mask;
2807 mask = UINT32_MAX >> (32 - MASKBITS);
2810 d = word_reverse(1 + word_reverse(a | ~b));
2811 return (arg1 & ~mask) | (d & b);
2814 uint32_t helper_cntlsw32 (uint32_t val)
2816 if (val & 0x80000000)
2822 uint32_t helper_cntlzw32 (uint32_t val)
2827 /* Single-precision floating-point conversions */
2828 static always_inline uint32_t efscfsi (uint32_t val)
2832 u.f = int32_to_float32(val, &env->spe_status);
2837 static always_inline uint32_t efscfui (uint32_t val)
2841 u.f = uint32_to_float32(val, &env->spe_status);
2846 static always_inline int32_t efsctsi (uint32_t val)
2851 /* NaN are not treated the same way IEEE 754 does */
2852 if (unlikely(float32_is_nan(u.f)))
2855 return float32_to_int32(u.f, &env->spe_status);
2858 static always_inline uint32_t efsctui (uint32_t val)
2863 /* NaN are not treated the same way IEEE 754 does */
2864 if (unlikely(float32_is_nan(u.f)))
2867 return float32_to_uint32(u.f, &env->spe_status);
2870 static always_inline uint32_t efsctsiz (uint32_t val)
2875 /* NaN are not treated the same way IEEE 754 does */
2876 if (unlikely(float32_is_nan(u.f)))
2879 return float32_to_int32_round_to_zero(u.f, &env->spe_status);
2882 static always_inline uint32_t efsctuiz (uint32_t val)
2887 /* NaN are not treated the same way IEEE 754 does */
2888 if (unlikely(float32_is_nan(u.f)))
2891 return float32_to_uint32_round_to_zero(u.f, &env->spe_status);
2894 static always_inline uint32_t efscfsf (uint32_t val)
2899 u.f = int32_to_float32(val, &env->spe_status);
2900 tmp = int64_to_float32(1ULL << 32, &env->spe_status);
2901 u.f = float32_div(u.f, tmp, &env->spe_status);
2906 static always_inline uint32_t efscfuf (uint32_t val)
2911 u.f = uint32_to_float32(val, &env->spe_status);
2912 tmp = uint64_to_float32(1ULL << 32, &env->spe_status);
2913 u.f = float32_div(u.f, tmp, &env->spe_status);
2918 static always_inline uint32_t efsctsf (uint32_t val)
2924 /* NaN are not treated the same way IEEE 754 does */
2925 if (unlikely(float32_is_nan(u.f)))
2927 tmp = uint64_to_float32(1ULL << 32, &env->spe_status);
2928 u.f = float32_mul(u.f, tmp, &env->spe_status);
2930 return float32_to_int32(u.f, &env->spe_status);
2933 static always_inline uint32_t efsctuf (uint32_t val)
2939 /* NaN are not treated the same way IEEE 754 does */
2940 if (unlikely(float32_is_nan(u.f)))
2942 tmp = uint64_to_float32(1ULL << 32, &env->spe_status);
2943 u.f = float32_mul(u.f, tmp, &env->spe_status);
2945 return float32_to_uint32(u.f, &env->spe_status);
2948 #define HELPER_SPE_SINGLE_CONV(name) \
2949 uint32_t helper_e##name (uint32_t val) \
2951 return e##name(val); \
2954 HELPER_SPE_SINGLE_CONV(fscfsi);
2956 HELPER_SPE_SINGLE_CONV(fscfui);
2958 HELPER_SPE_SINGLE_CONV(fscfuf);
2960 HELPER_SPE_SINGLE_CONV(fscfsf);
2962 HELPER_SPE_SINGLE_CONV(fsctsi);
2964 HELPER_SPE_SINGLE_CONV(fsctui);
2966 HELPER_SPE_SINGLE_CONV(fsctsiz);
2968 HELPER_SPE_SINGLE_CONV(fsctuiz);
2970 HELPER_SPE_SINGLE_CONV(fsctsf);
2972 HELPER_SPE_SINGLE_CONV(fsctuf);
2974 #define HELPER_SPE_VECTOR_CONV(name) \
2975 uint64_t helper_ev##name (uint64_t val) \
2977 return ((uint64_t)e##name(val >> 32) << 32) | \
2978 (uint64_t)e##name(val); \
2981 HELPER_SPE_VECTOR_CONV(fscfsi);
2983 HELPER_SPE_VECTOR_CONV(fscfui);
2985 HELPER_SPE_VECTOR_CONV(fscfuf);
2987 HELPER_SPE_VECTOR_CONV(fscfsf);
2989 HELPER_SPE_VECTOR_CONV(fsctsi);
2991 HELPER_SPE_VECTOR_CONV(fsctui);
2993 HELPER_SPE_VECTOR_CONV(fsctsiz);
2995 HELPER_SPE_VECTOR_CONV(fsctuiz);
2997 HELPER_SPE_VECTOR_CONV(fsctsf);
2999 HELPER_SPE_VECTOR_CONV(fsctuf);
3001 /* Single-precision floating-point arithmetic */
3002 static always_inline uint32_t efsadd (uint32_t op1, uint32_t op2)
3007 u1.f = float32_add(u1.f, u2.f, &env->spe_status);
3011 static always_inline uint32_t efssub (uint32_t op1, uint32_t op2)
3016 u1.f = float32_sub(u1.f, u2.f, &env->spe_status);
3020 static always_inline uint32_t efsmul (uint32_t op1, uint32_t op2)
3025 u1.f = float32_mul(u1.f, u2.f, &env->spe_status);
3029 static always_inline uint32_t efsdiv (uint32_t op1, uint32_t op2)
3034 u1.f = float32_div(u1.f, u2.f, &env->spe_status);
3038 #define HELPER_SPE_SINGLE_ARITH(name) \
3039 uint32_t helper_e##name (uint32_t op1, uint32_t op2) \
3041 return e##name(op1, op2); \
3044 HELPER_SPE_SINGLE_ARITH(fsadd);
3046 HELPER_SPE_SINGLE_ARITH(fssub);
3048 HELPER_SPE_SINGLE_ARITH(fsmul);
3050 HELPER_SPE_SINGLE_ARITH(fsdiv);
3052 #define HELPER_SPE_VECTOR_ARITH(name) \
3053 uint64_t helper_ev##name (uint64_t op1, uint64_t op2) \
3055 return ((uint64_t)e##name(op1 >> 32, op2 >> 32) << 32) | \
3056 (uint64_t)e##name(op1, op2); \
3059 HELPER_SPE_VECTOR_ARITH(fsadd);
3061 HELPER_SPE_VECTOR_ARITH(fssub);
3063 HELPER_SPE_VECTOR_ARITH(fsmul);
3065 HELPER_SPE_VECTOR_ARITH(fsdiv);
3067 /* Single-precision floating-point comparisons */
3068 static always_inline uint32_t efststlt (uint32_t op1, uint32_t op2)
3073 return float32_lt(u1.f, u2.f, &env->spe_status) ? 4 : 0;
3076 static always_inline uint32_t efststgt (uint32_t op1, uint32_t op2)
3081 return float32_le(u1.f, u2.f, &env->spe_status) ? 0 : 4;
3084 static always_inline uint32_t efststeq (uint32_t op1, uint32_t op2)
3089 return float32_eq(u1.f, u2.f, &env->spe_status) ? 4 : 0;
3092 static always_inline uint32_t efscmplt (uint32_t op1, uint32_t op2)
3094 /* XXX: TODO: test special values (NaN, infinites, ...) */
3095 return efststlt(op1, op2);
3098 static always_inline uint32_t efscmpgt (uint32_t op1, uint32_t op2)
3100 /* XXX: TODO: test special values (NaN, infinites, ...) */
3101 return efststgt(op1, op2);
3104 static always_inline uint32_t efscmpeq (uint32_t op1, uint32_t op2)
3106 /* XXX: TODO: test special values (NaN, infinites, ...) */
3107 return efststeq(op1, op2);
3110 #define HELPER_SINGLE_SPE_CMP(name) \
3111 uint32_t helper_e##name (uint32_t op1, uint32_t op2) \
3113 return e##name(op1, op2) << 2; \
3116 HELPER_SINGLE_SPE_CMP(fststlt);
3118 HELPER_SINGLE_SPE_CMP(fststgt);
3120 HELPER_SINGLE_SPE_CMP(fststeq);
3122 HELPER_SINGLE_SPE_CMP(fscmplt);
3124 HELPER_SINGLE_SPE_CMP(fscmpgt);
3126 HELPER_SINGLE_SPE_CMP(fscmpeq);
3128 static always_inline uint32_t evcmp_merge (int t0, int t1)
3130 return (t0 << 3) | (t1 << 2) | ((t0 | t1) << 1) | (t0 & t1);
3133 #define HELPER_VECTOR_SPE_CMP(name) \
3134 uint32_t helper_ev##name (uint64_t op1, uint64_t op2) \
3136 return evcmp_merge(e##name(op1 >> 32, op2 >> 32), e##name(op1, op2)); \
3139 HELPER_VECTOR_SPE_CMP(fststlt);
3141 HELPER_VECTOR_SPE_CMP(fststgt);
3143 HELPER_VECTOR_SPE_CMP(fststeq);
3145 HELPER_VECTOR_SPE_CMP(fscmplt);
3147 HELPER_VECTOR_SPE_CMP(fscmpgt);
3149 HELPER_VECTOR_SPE_CMP(fscmpeq);
3151 /* Double-precision floating-point conversion */
3152 uint64_t helper_efdcfsi (uint32_t val)
3156 u.d = int32_to_float64(val, &env->spe_status);
3161 uint64_t helper_efdcfsid (uint64_t val)
3165 u.d = int64_to_float64(val, &env->spe_status);
3170 uint64_t helper_efdcfui (uint32_t val)
3174 u.d = uint32_to_float64(val, &env->spe_status);
3179 uint64_t helper_efdcfuid (uint64_t val)
3183 u.d = uint64_to_float64(val, &env->spe_status);
3188 uint32_t helper_efdctsi (uint64_t val)
3193 /* NaN are not treated the same way IEEE 754 does */
3194 if (unlikely(float64_is_nan(u.d)))
3197 return float64_to_int32(u.d, &env->spe_status);
3200 uint32_t helper_efdctui (uint64_t val)
3205 /* NaN are not treated the same way IEEE 754 does */
3206 if (unlikely(float64_is_nan(u.d)))
3209 return float64_to_uint32(u.d, &env->spe_status);
3212 uint32_t helper_efdctsiz (uint64_t val)
3217 /* NaN are not treated the same way IEEE 754 does */
3218 if (unlikely(float64_is_nan(u.d)))
3221 return float64_to_int32_round_to_zero(u.d, &env->spe_status);
3224 uint64_t helper_efdctsidz (uint64_t val)
3229 /* NaN are not treated the same way IEEE 754 does */
3230 if (unlikely(float64_is_nan(u.d)))
3233 return float64_to_int64_round_to_zero(u.d, &env->spe_status);
3236 uint32_t helper_efdctuiz (uint64_t val)
3241 /* NaN are not treated the same way IEEE 754 does */
3242 if (unlikely(float64_is_nan(u.d)))
3245 return float64_to_uint32_round_to_zero(u.d, &env->spe_status);
3248 uint64_t helper_efdctuidz (uint64_t val)
3253 /* NaN are not treated the same way IEEE 754 does */
3254 if (unlikely(float64_is_nan(u.d)))
3257 return float64_to_uint64_round_to_zero(u.d, &env->spe_status);
3260 uint64_t helper_efdcfsf (uint32_t val)
3265 u.d = int32_to_float64(val, &env->spe_status);
3266 tmp = int64_to_float64(1ULL << 32, &env->spe_status);
3267 u.d = float64_div(u.d, tmp, &env->spe_status);
3272 uint64_t helper_efdcfuf (uint32_t val)
3277 u.d = uint32_to_float64(val, &env->spe_status);
3278 tmp = int64_to_float64(1ULL << 32, &env->spe_status);
3279 u.d = float64_div(u.d, tmp, &env->spe_status);
3284 uint32_t helper_efdctsf (uint64_t val)
3290 /* NaN are not treated the same way IEEE 754 does */
3291 if (unlikely(float64_is_nan(u.d)))
3293 tmp = uint64_to_float64(1ULL << 32, &env->spe_status);
3294 u.d = float64_mul(u.d, tmp, &env->spe_status);
3296 return float64_to_int32(u.d, &env->spe_status);
3299 uint32_t helper_efdctuf (uint64_t val)
3305 /* NaN are not treated the same way IEEE 754 does */
3306 if (unlikely(float64_is_nan(u.d)))
3308 tmp = uint64_to_float64(1ULL << 32, &env->spe_status);
3309 u.d = float64_mul(u.d, tmp, &env->spe_status);
3311 return float64_to_uint32(u.d, &env->spe_status);
3314 uint32_t helper_efscfd (uint64_t val)
3320 u2.f = float64_to_float32(u1.d, &env->spe_status);
3325 uint64_t helper_efdcfs (uint32_t val)
3331 u2.d = float32_to_float64(u1.f, &env->spe_status);
3336 /* Double precision fixed-point arithmetic */
3337 uint64_t helper_efdadd (uint64_t op1, uint64_t op2)
3342 u1.d = float64_add(u1.d, u2.d, &env->spe_status);
3346 uint64_t helper_efdsub (uint64_t op1, uint64_t op2)
3351 u1.d = float64_sub(u1.d, u2.d, &env->spe_status);
3355 uint64_t helper_efdmul (uint64_t op1, uint64_t op2)
3360 u1.d = float64_mul(u1.d, u2.d, &env->spe_status);
3364 uint64_t helper_efddiv (uint64_t op1, uint64_t op2)
3369 u1.d = float64_div(u1.d, u2.d, &env->spe_status);
3373 /* Double precision floating point helpers */
3374 uint32_t helper_efdtstlt (uint64_t op1, uint64_t op2)
3379 return float64_lt(u1.d, u2.d, &env->spe_status) ? 4 : 0;
3382 uint32_t helper_efdtstgt (uint64_t op1, uint64_t op2)
3387 return float64_le(u1.d, u2.d, &env->spe_status) ? 0 : 4;
3390 uint32_t helper_efdtsteq (uint64_t op1, uint64_t op2)
3395 return float64_eq(u1.d, u2.d, &env->spe_status) ? 4 : 0;
3398 uint32_t helper_efdcmplt (uint64_t op1, uint64_t op2)
3400 /* XXX: TODO: test special values (NaN, infinites, ...) */
3401 return helper_efdtstlt(op1, op2);
3404 uint32_t helper_efdcmpgt (uint64_t op1, uint64_t op2)
3406 /* XXX: TODO: test special values (NaN, infinites, ...) */
3407 return helper_efdtstgt(op1, op2);
3410 uint32_t helper_efdcmpeq (uint64_t op1, uint64_t op2)
3412 /* XXX: TODO: test special values (NaN, infinites, ...) */
3413 return helper_efdtsteq(op1, op2);
3416 /*****************************************************************************/
3417 /* Softmmu support */
3418 #if !defined (CONFIG_USER_ONLY)
3420 #define MMUSUFFIX _mmu
3423 #include "softmmu_template.h"
3426 #include "softmmu_template.h"
3429 #include "softmmu_template.h"
3432 #include "softmmu_template.h"
3434 /* try to fill the TLB and return an exception if error. If retaddr is
3435 NULL, it means that the function was called in C code (i.e. not
3436 from generated code or from helper.c) */
3437 /* XXX: fix it to restore all registers */
3438 void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
3440 TranslationBlock *tb;
3441 CPUState *saved_env;
3445 /* XXX: hack to restore env in all cases, even if not called from
3448 env = cpu_single_env;
3449 ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
3450 if (unlikely(ret != 0)) {
3451 if (likely(retaddr)) {
3452 /* now we have a real cpu fault */
3453 pc = (unsigned long)retaddr;
3454 tb = tb_find_pc(pc);
3456 /* the PC is inside the translated code. It means that we have
3457 a virtual CPU fault */
3458 cpu_restore_state(tb, env, pc, NULL);
3461 helper_raise_exception_err(env->exception_index, env->error_code);
3466 /* Segment registers load and store */
3467 target_ulong helper_load_sr (target_ulong sr_num)
3469 return env->sr[sr_num];
3472 void helper_store_sr (target_ulong sr_num, target_ulong val)
3474 ppc_store_sr(env, sr_num, val);
3477 /* SLB management */
3478 #if defined(TARGET_PPC64)
3479 target_ulong helper_load_slb (target_ulong slb_nr)
3481 return ppc_load_slb(env, slb_nr);
3484 void helper_store_slb (target_ulong slb_nr, target_ulong rs)
3486 ppc_store_slb(env, slb_nr, rs);
3489 void helper_slbia (void)
3491 ppc_slb_invalidate_all(env);
3494 void helper_slbie (target_ulong addr)
3496 ppc_slb_invalidate_one(env, addr);
3499 #endif /* defined(TARGET_PPC64) */
3501 /* TLB management */
3502 void helper_tlbia (void)
3504 ppc_tlb_invalidate_all(env);
3507 void helper_tlbie (target_ulong addr)
3509 ppc_tlb_invalidate_one(env, addr);
3512 /* Software driven TLBs management */
3513 /* PowerPC 602/603 software TLB load instructions helpers */
3514 static void do_6xx_tlb (target_ulong new_EPN, int is_code)
3516 target_ulong RPN, CMP, EPN;
3519 RPN = env->spr[SPR_RPA];
3521 CMP = env->spr[SPR_ICMP];
3522 EPN = env->spr[SPR_IMISS];
3524 CMP = env->spr[SPR_DCMP];
3525 EPN = env->spr[SPR_DMISS];
3527 way = (env->spr[SPR_SRR1] >> 17) & 1;
3528 #if defined (DEBUG_SOFTWARE_TLB)
3529 if (loglevel != 0) {
3530 fprintf(logfile, "%s: EPN " ADDRX " " ADDRX " PTE0 " ADDRX
3531 " PTE1 " ADDRX " way %d\n",
3532 __func__, new_EPN, EPN, CMP, RPN, way);
3535 /* Store this TLB */
3536 ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
3537 way, is_code, CMP, RPN);
3540 void helper_6xx_tlbd (target_ulong EPN)
3545 void helper_6xx_tlbi (target_ulong EPN)
3550 /* PowerPC 74xx software TLB load instructions helpers */
3551 static void do_74xx_tlb (target_ulong new_EPN, int is_code)
3553 target_ulong RPN, CMP, EPN;
3556 RPN = env->spr[SPR_PTELO];
3557 CMP = env->spr[SPR_PTEHI];
3558 EPN = env->spr[SPR_TLBMISS] & ~0x3;
3559 way = env->spr[SPR_TLBMISS] & 0x3;
3560 #if defined (DEBUG_SOFTWARE_TLB)
3561 if (loglevel != 0) {
3562 fprintf(logfile, "%s: EPN " ADDRX " " ADDRX " PTE0 " ADDRX
3563 " PTE1 " ADDRX " way %d\n",
3564 __func__, new_EPN, EPN, CMP, RPN, way);
3567 /* Store this TLB */
3568 ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
3569 way, is_code, CMP, RPN);
3572 void helper_74xx_tlbd (target_ulong EPN)
3574 do_74xx_tlb(EPN, 0);
3577 void helper_74xx_tlbi (target_ulong EPN)
3579 do_74xx_tlb(EPN, 1);
3582 static always_inline target_ulong booke_tlb_to_page_size (int size)
3584 return 1024 << (2 * size);
3587 static always_inline int booke_page_size_to_tlb (target_ulong page_size)
3591 switch (page_size) {
3625 #if defined (TARGET_PPC64)
3626 case 0x000100000000ULL:
3629 case 0x000400000000ULL:
3632 case 0x001000000000ULL:
3635 case 0x004000000000ULL:
3638 case 0x010000000000ULL:
3650 /* Helpers for 4xx TLB management */
3651 target_ulong helper_4xx_tlbre_lo (target_ulong entry)
3658 tlb = &env->tlb[entry].tlbe;
3660 if (tlb->prot & PAGE_VALID)
3662 size = booke_page_size_to_tlb(tlb->size);
3663 if (size < 0 || size > 0x7)
3666 env->spr[SPR_40x_PID] = tlb->PID;
3670 target_ulong helper_4xx_tlbre_hi (target_ulong entry)
3676 tlb = &env->tlb[entry].tlbe;
3678 if (tlb->prot & PAGE_EXEC)
3680 if (tlb->prot & PAGE_WRITE)
3685 void helper_4xx_tlbwe_hi (target_ulong entry, target_ulong val)
3688 target_ulong page, end;
3690 #if defined (DEBUG_SOFTWARE_TLB)
3691 if (loglevel != 0) {
3692 fprintf(logfile, "%s entry %d val " ADDRX "\n", __func__, (int)entry, val);
3696 tlb = &env->tlb[entry].tlbe;
3697 /* Invalidate previous TLB (if it's valid) */
3698 if (tlb->prot & PAGE_VALID) {
3699 end = tlb->EPN + tlb->size;
3700 #if defined (DEBUG_SOFTWARE_TLB)
3701 if (loglevel != 0) {
3702 fprintf(logfile, "%s: invalidate old TLB %d start " ADDRX
3703 " end " ADDRX "\n", __func__, (int)entry, tlb->EPN, end);
3706 for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE)
3707 tlb_flush_page(env, page);
3709 tlb->size = booke_tlb_to_page_size((val >> 7) & 0x7);
3710 /* We cannot handle TLB size < TARGET_PAGE_SIZE.
3711 * If this ever occurs, one should use the ppcemb target instead
3712 * of the ppc or ppc64 one
3714 if ((val & 0x40) && tlb->size < TARGET_PAGE_SIZE) {
3715 cpu_abort(env, "TLB size " TARGET_FMT_lu " < %u "
3716 "are not supported (%d)\n",
3717 tlb->size, TARGET_PAGE_SIZE, (int)((val >> 7) & 0x7));
3719 tlb->EPN = val & ~(tlb->size - 1);
3721 tlb->prot |= PAGE_VALID;
3723 tlb->prot &= ~PAGE_VALID;
3725 /* XXX: TO BE FIXED */
3726 cpu_abort(env, "Little-endian TLB entries are not supported by now\n");
3728 tlb->PID = env->spr[SPR_40x_PID]; /* PID */
3729 tlb->attr = val & 0xFF;
3730 #if defined (DEBUG_SOFTWARE_TLB)
3731 if (loglevel != 0) {
3732 fprintf(logfile, "%s: set up TLB %d RPN " PADDRX " EPN " ADDRX
3733 " size " ADDRX " prot %c%c%c%c PID %d\n", __func__,
3734 (int)entry, tlb->RPN, tlb->EPN, tlb->size,
3735 tlb->prot & PAGE_READ ? 'r' : '-',
3736 tlb->prot & PAGE_WRITE ? 'w' : '-',
3737 tlb->prot & PAGE_EXEC ? 'x' : '-',
3738 tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
3741 /* Invalidate new TLB (if valid) */
3742 if (tlb->prot & PAGE_VALID) {
3743 end = tlb->EPN + tlb->size;
3744 #if defined (DEBUG_SOFTWARE_TLB)
3745 if (loglevel != 0) {
3746 fprintf(logfile, "%s: invalidate TLB %d start " ADDRX
3747 " end " ADDRX "\n", __func__, (int)entry, tlb->EPN, end);
3750 for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE)
3751 tlb_flush_page(env, page);
3755 void helper_4xx_tlbwe_lo (target_ulong entry, target_ulong val)
3759 #if defined (DEBUG_SOFTWARE_TLB)
3760 if (loglevel != 0) {
3761 fprintf(logfile, "%s entry %i val " ADDRX "\n", __func__, (int)entry, val);
3765 tlb = &env->tlb[entry].tlbe;
3766 tlb->RPN = val & 0xFFFFFC00;
3767 tlb->prot = PAGE_READ;
3769 tlb->prot |= PAGE_EXEC;
3771 tlb->prot |= PAGE_WRITE;
3772 #if defined (DEBUG_SOFTWARE_TLB)
3773 if (loglevel != 0) {
3774 fprintf(logfile, "%s: set up TLB %d RPN " PADDRX " EPN " ADDRX
3775 " size " ADDRX " prot %c%c%c%c PID %d\n", __func__,
3776 (int)entry, tlb->RPN, tlb->EPN, tlb->size,
3777 tlb->prot & PAGE_READ ? 'r' : '-',
3778 tlb->prot & PAGE_WRITE ? 'w' : '-',
3779 tlb->prot & PAGE_EXEC ? 'x' : '-',
3780 tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
3785 target_ulong helper_4xx_tlbsx (target_ulong address)
3787 return ppcemb_tlb_search(env, address, env->spr[SPR_40x_PID]);
3790 /* PowerPC 440 TLB management */
3791 void helper_440_tlbwe (uint32_t word, target_ulong entry, target_ulong value)
3794 target_ulong EPN, RPN, size;
3797 #if defined (DEBUG_SOFTWARE_TLB)
3798 if (loglevel != 0) {
3799 fprintf(logfile, "%s word %d entry %d value " ADDRX "\n",
3800 __func__, word, (int)entry, value);
3805 tlb = &env->tlb[entry].tlbe;
3808 /* Just here to please gcc */
3810 EPN = value & 0xFFFFFC00;
3811 if ((tlb->prot & PAGE_VALID) && EPN != tlb->EPN)
3814 size = booke_tlb_to_page_size((value >> 4) & 0xF);
3815 if ((tlb->prot & PAGE_VALID) && tlb->size < size)
3819 tlb->attr |= (value >> 8) & 1;
3820 if (value & 0x200) {
3821 tlb->prot |= PAGE_VALID;
3823 if (tlb->prot & PAGE_VALID) {
3824 tlb->prot &= ~PAGE_VALID;
3828 tlb->PID = env->spr[SPR_440_MMUCR] & 0x000000FF;
3833 RPN = value & 0xFFFFFC0F;
3834 if ((tlb->prot & PAGE_VALID) && tlb->RPN != RPN)
3839 tlb->attr = (tlb->attr & 0x1) | (value & 0x0000FF00);
3840 tlb->prot = tlb->prot & PAGE_VALID;
3842 tlb->prot |= PAGE_READ << 4;
3844 tlb->prot |= PAGE_WRITE << 4;
3846 tlb->prot |= PAGE_EXEC << 4;
3848 tlb->prot |= PAGE_READ;
3850 tlb->prot |= PAGE_WRITE;
3852 tlb->prot |= PAGE_EXEC;
3857 target_ulong helper_440_tlbre (uint32_t word, target_ulong entry)
3864 tlb = &env->tlb[entry].tlbe;
3867 /* Just here to please gcc */
3870 size = booke_page_size_to_tlb(tlb->size);
3871 if (size < 0 || size > 0xF)
3874 if (tlb->attr & 0x1)
3876 if (tlb->prot & PAGE_VALID)
3878 env->spr[SPR_440_MMUCR] &= ~0x000000FF;
3879 env->spr[SPR_440_MMUCR] |= tlb->PID;
3885 ret = tlb->attr & ~0x1;
3886 if (tlb->prot & (PAGE_READ << 4))
3888 if (tlb->prot & (PAGE_WRITE << 4))
3890 if (tlb->prot & (PAGE_EXEC << 4))
3892 if (tlb->prot & PAGE_READ)
3894 if (tlb->prot & PAGE_WRITE)
3896 if (tlb->prot & PAGE_EXEC)
3903 target_ulong helper_440_tlbsx (target_ulong address)
3905 return ppcemb_tlb_search(env, address, env->spr[SPR_440_MMUCR] & 0xFF);
3908 #endif /* !CONFIG_USER_ONLY */