Add vmsumsh{m,s} instructions.
[qemu/qemu-JZ.git] / target-ppc / op_helper.c
blob6ff215675a019de3c0541aea634a29156e44055f
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, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA
20 #include <string.h>
21 #include "exec.h"
22 #include "host-utils.h"
23 #include "helper.h"
25 #include "helper_regs.h"
27 //#define DEBUG_OP
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)
36 #if 0
37 printf("Raise exception %3x code : %d\n", exception, error_code);
38 #endif
39 env->exception_index = exception;
40 env->error_code = error_code;
41 cpu_loop_exit();
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) |
54 (env->crf[1] << 24) |
55 (env->crf[2] << 20) |
56 (env->crf[3] << 16) |
57 (env->crf[4] << 12) |
58 (env->crf[5] << 8) |
59 (env->crf[6] << 4) |
60 (env->crf[7] << 0);
63 void helper_store_cr (target_ulong val, uint32_t mask)
65 int i, sh;
67 for (i = 0, sh = 7; i < 8; i++, sh--) {
68 if (mask & (1 << sh))
69 env->crf[i] = (val >> (sh * 4)) & 0xFUL;
73 /*****************************************************************************/
74 /* SPR accesses */
75 void helper_load_dump_spr (uint32_t sprn)
77 if (loglevel != 0) {
78 fprintf(logfile, "Read SPR %d %03x => " ADDRX "\n",
79 sprn, sprn, env->spr[sprn]);
83 void helper_store_dump_spr (uint32_t sprn)
85 if (loglevel != 0) {
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);
127 #endif
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)
176 target_ulong hid0;
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;
185 if (loglevel != 0) {
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 */
198 tlb_flush(env, 1);
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);
261 #endif
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)
269 if (!msr_sf)
270 return (uint32_t)(addr + arg);
271 else
272 #endif
273 return addr + arg;
276 void helper_lmw (target_ulong addr, uint32_t reg)
278 for (; reg < 32; reg++) {
279 if (msr_le)
280 env->gpr[reg] = bswap32(ldl(addr));
281 else
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++) {
290 if (msr_le)
291 stl(addr, bswap32((uint32_t)env->gpr[reg]));
292 else
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)
300 int sh;
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)) {
307 env->gpr[reg] = 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,
325 POWERPC_EXCP_INVAL |
326 POWERPC_EXCP_INVAL_LSWX);
327 } else {
328 helper_lsw(addr, xer_bc, reg);
333 void helper_stsw(target_ulong addr, uint32_t nb, uint32_t reg)
335 int sh;
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);
352 int i;
353 for (i = 0 ; i < dcache_line_size ; i += 4) {
354 stl(addr + i , 0);
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)
368 do_dcbz(addr, 32);
369 else
370 do_dcbz(addr, env->dcache_line_size);
373 void helper_icbi(target_ulong addr)
375 uint32_t tmp;
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".
383 tmp = ldl(addr);
384 tb_invalidate_page_range(addr, addr + env->icache_line_size);
387 // XXX: to be tested
388 target_ulong helper_lscbx (target_ulong addr, uint32_t reg, uint32_t ra, uint32_t rb)
390 int i, c, d;
391 d = 24;
392 for (i = 0; i < xer_bc; i++) {
393 c = ldub(addr);
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))
400 break;
401 if (likely(d != 0)) {
402 d -= 8;
403 } else {
404 d = 24;
405 reg++;
406 reg = reg & 0x1F;
409 return i;
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)
419 uint64_t tl, th;
421 muls64(&tl, &th, arg1, arg2);
422 return th;
425 /* multiply high word unsigned */
426 uint64_t helper_mulhdu (uint64_t arg1, uint64_t arg2)
428 uint64_t tl, th;
430 mulu64(&tl, &th, arg1, arg2);
431 return th;
434 uint64_t helper_mulldo (uint64_t arg1, uint64_t arg2)
436 int64_t th;
437 uint64_t tl;
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);
443 } else {
444 env->xer |= (1 << XER_OV) | (1 << XER_SO);
446 return (int64_t)tl;
448 #endif
450 target_ulong helper_cntlzw (target_ulong t)
452 return clz32(t);
455 #if defined(TARGET_PPC64)
456 target_ulong helper_cntlzd (target_ulong t)
458 return clz64(t);
460 #endif
462 /* shift right arithmetic helper */
463 target_ulong helper_sraw (target_ulong value, target_ulong shift)
465 int32_t ret;
467 if (likely(!(shift & 0x20))) {
468 if (likely((uint32_t)shift != 0)) {
469 shift &= 0x1f;
470 ret = (int32_t)value >> shift;
471 if (likely(ret >= 0 || (value & ((1 << shift) - 1)) == 0)) {
472 env->xer &= ~(1 << XER_CA);
473 } else {
474 env->xer |= (1 << XER_CA);
476 } else {
477 ret = (int32_t)value;
478 env->xer &= ~(1 << XER_CA);
480 } else {
481 ret = (int32_t)value >> 31;
482 if (ret) {
483 env->xer |= (1 << XER_CA);
484 } else {
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)
494 int64_t ret;
496 if (likely(!(shift & 0x40))) {
497 if (likely((uint64_t)shift != 0)) {
498 shift &= 0x3f;
499 ret = (int64_t)value >> shift;
500 if (likely(ret >= 0 || (value & ((1 << shift) - 1)) == 0)) {
501 env->xer &= ~(1 << XER_CA);
502 } else {
503 env->xer |= (1 << XER_CA);
505 } else {
506 ret = (int64_t)value;
507 env->xer &= ~(1 << XER_CA);
509 } else {
510 ret = (int64_t)value >> 63;
511 if (ret) {
512 env->xer |= (1 << XER_CA);
513 } else {
514 env->xer &= ~(1 << XER_CA);
517 return ret;
519 #endif
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);
526 return val;
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);
535 return val;
537 #endif
539 /*****************************************************************************/
540 /* Floating point operations helpers */
541 uint64_t helper_float32_to_float64(uint32_t arg)
543 CPU_FloatU f;
544 CPU_DoubleU d;
545 f.l = arg;
546 d.d = float32_to_float64(f.f, &env->fp_status);
547 return d.ll;
550 uint32_t helper_float64_to_float32(uint64_t arg)
552 CPU_FloatU f;
553 CPU_DoubleU d;
554 d.ll = arg;
555 f.f = float64_to_float32(d.d, &env->fp_status);
556 return f.l;
559 static always_inline int isden (float64 d)
561 CPU_DoubleU u;
563 u.d = d;
565 return ((u.ll >> 52) & 0x7FF) == 0;
568 uint32_t helper_compute_fprf (uint64_t arg, uint32_t set_fprf)
570 CPU_DoubleU farg;
571 int isneg;
572 int ret;
573 farg.ll = arg;
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 */
578 ret = 0x00;
579 } else {
580 /* Quiet NaN */
581 ret = 0x11;
583 } else if (unlikely(float64_is_infinity(farg.d))) {
584 /* +/- infinity */
585 if (isneg)
586 ret = 0x09;
587 else
588 ret = 0x05;
589 } else {
590 if (float64_is_zero(farg.d)) {
591 /* +/- zero */
592 if (isneg)
593 ret = 0x12;
594 else
595 ret = 0x02;
596 } else {
597 if (isden(farg.d)) {
598 /* Denormalized numbers */
599 ret = 0x10;
600 } else {
601 /* Normalized numbers */
602 ret = 0x00;
604 if (isneg) {
605 ret |= 0x08;
606 } else {
607 ret |= 0x04;
611 if (set_fprf) {
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 */
617 return ret & 0xF;
620 /* Floating-point invalid operations exception */
621 static always_inline uint64_t fload_invalid_op_excp (int op)
623 uint64_t ret = 0;
624 int ve;
626 ve = fpscr_ve;
627 switch (op) {
628 case POWERPC_EXCP_FP_VXSNAN:
629 env->fpscr |= 1 << FPSCR_VXSNAN;
630 break;
631 case POWERPC_EXCP_FP_VXSOFT:
632 env->fpscr |= 1 << FPSCR_VXSOFT;
633 break;
634 case POWERPC_EXCP_FP_VXISI:
635 /* Magnitude subtraction of infinities */
636 env->fpscr |= 1 << FPSCR_VXISI;
637 goto update_arith;
638 case POWERPC_EXCP_FP_VXIDI:
639 /* Division of infinity by infinity */
640 env->fpscr |= 1 << FPSCR_VXIDI;
641 goto update_arith;
642 case POWERPC_EXCP_FP_VXZDZ:
643 /* Division of zero by zero */
644 env->fpscr |= 1 << FPSCR_VXZDZ;
645 goto update_arith;
646 case POWERPC_EXCP_FP_VXIMZ:
647 /* Multiplication of zero by infinity */
648 env->fpscr |= 1 << FPSCR_VXIMZ;
649 goto update_arith;
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 */
656 if (ve != 0) {
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 */
662 ve = 0;
664 break;
665 case POWERPC_EXCP_FP_VXSQRT:
666 /* Square root of a negative number */
667 env->fpscr |= 1 << FPSCR_VXSQRT;
668 update_arith:
669 env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
670 if (ve == 0) {
671 /* Set the result to quiet NaN */
672 ret = 0xFFF8000000000000ULL;
673 env->fpscr &= ~(0xF << FPSCR_FPCC);
674 env->fpscr |= 0x11 << FPSCR_FPCC;
676 break;
677 case POWERPC_EXCP_FP_VXCVI:
678 /* Invalid conversion */
679 env->fpscr |= 1 << FPSCR_VXCVI;
680 env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
681 if (ve == 0) {
682 /* Set the result to quiet NaN */
683 ret = 0xFFF8000000000000ULL;
684 env->fpscr &= ~(0xF << FPSCR_FPCC);
685 env->fpscr |= 0x11 << FPSCR_FPCC;
687 break;
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;
693 if (ve != 0) {
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);
699 return ret;
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;
708 if (fpscr_ze != 0) {
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;
723 if (fpscr_oe != 0) {
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;
730 } else {
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;
741 if (fpscr_ue != 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_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;
756 if (fpscr_xe != 0) {
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)
767 int rnd_type;
769 /* Set rounding mode */
770 switch (fpscr_rn) {
771 case 0:
772 /* Best approximation (round to nearest) */
773 rnd_type = float_round_nearest_even;
774 break;
775 case 1:
776 /* Smaller magnitude (round toward zero) */
777 rnd_type = float_round_to_zero;
778 break;
779 case 2:
780 /* Round toward +infinite */
781 rnd_type = float_round_up;
782 break;
783 default:
784 case 3:
785 /* Round toward -infinite */
786 rnd_type = float_round_down;
787 break;
789 set_float_rounding_mode(rnd_type, &env->fp_status);
792 void helper_fpscr_clrbit (uint32_t bit)
794 int prev;
796 prev = (env->fpscr >> bit) & 1;
797 env->fpscr &= ~(1 << bit);
798 if (prev == 1) {
799 switch (bit) {
800 case FPSCR_RN1:
801 case FPSCR_RN:
802 fpscr_set_rounding_mode();
803 break;
804 default:
805 break;
810 void helper_fpscr_setbit (uint32_t bit)
812 int prev;
814 prev = (env->fpscr >> bit) & 1;
815 env->fpscr |= 1 << bit;
816 if (prev == 0) {
817 switch (bit) {
818 case FPSCR_VX:
819 env->fpscr |= 1 << FPSCR_FX;
820 if (fpscr_ve)
821 goto raise_ve;
822 case FPSCR_OX:
823 env->fpscr |= 1 << FPSCR_FX;
824 if (fpscr_oe)
825 goto raise_oe;
826 break;
827 case FPSCR_UX:
828 env->fpscr |= 1 << FPSCR_FX;
829 if (fpscr_ue)
830 goto raise_ue;
831 break;
832 case FPSCR_ZX:
833 env->fpscr |= 1 << FPSCR_FX;
834 if (fpscr_ze)
835 goto raise_ze;
836 break;
837 case FPSCR_XX:
838 env->fpscr |= 1 << FPSCR_FX;
839 if (fpscr_xe)
840 goto raise_xe;
841 break;
842 case FPSCR_VXSNAN:
843 case FPSCR_VXISI:
844 case FPSCR_VXIDI:
845 case FPSCR_VXZDZ:
846 case FPSCR_VXIMZ:
847 case FPSCR_VXVC:
848 case FPSCR_VXSOFT:
849 case FPSCR_VXSQRT:
850 case FPSCR_VXCVI:
851 env->fpscr |= 1 << FPSCR_VX;
852 env->fpscr |= 1 << FPSCR_FX;
853 if (fpscr_ve != 0)
854 goto raise_ve;
855 break;
856 case FPSCR_VE:
857 if (fpscr_vx != 0) {
858 raise_ve:
859 env->error_code = POWERPC_EXCP_FP;
860 if (fpscr_vxsnan)
861 env->error_code |= POWERPC_EXCP_FP_VXSNAN;
862 if (fpscr_vxisi)
863 env->error_code |= POWERPC_EXCP_FP_VXISI;
864 if (fpscr_vxidi)
865 env->error_code |= POWERPC_EXCP_FP_VXIDI;
866 if (fpscr_vxzdz)
867 env->error_code |= POWERPC_EXCP_FP_VXZDZ;
868 if (fpscr_vximz)
869 env->error_code |= POWERPC_EXCP_FP_VXIMZ;
870 if (fpscr_vxvc)
871 env->error_code |= POWERPC_EXCP_FP_VXVC;
872 if (fpscr_vxsoft)
873 env->error_code |= POWERPC_EXCP_FP_VXSOFT;
874 if (fpscr_vxsqrt)
875 env->error_code |= POWERPC_EXCP_FP_VXSQRT;
876 if (fpscr_vxcvi)
877 env->error_code |= POWERPC_EXCP_FP_VXCVI;
878 goto raise_excp;
880 break;
881 case FPSCR_OE:
882 if (fpscr_ox != 0) {
883 raise_oe:
884 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_OX;
885 goto raise_excp;
887 break;
888 case FPSCR_UE:
889 if (fpscr_ux != 0) {
890 raise_ue:
891 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_UX;
892 goto raise_excp;
894 break;
895 case FPSCR_ZE:
896 if (fpscr_zx != 0) {
897 raise_ze:
898 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX;
899 goto raise_excp;
901 break;
902 case FPSCR_XE:
903 if (fpscr_xx != 0) {
904 raise_xe:
905 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_XX;
906 goto raise_excp;
908 break;
909 case FPSCR_RN1:
910 case FPSCR_RN:
911 fpscr_set_rounding_mode();
912 break;
913 default:
914 break;
915 raise_excp:
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;
920 break;
925 void helper_store_fpscr (uint64_t arg, uint32_t mask)
928 * We use only the 32 LSB of the incoming fpr
930 uint32_t prev, new;
931 int i;
933 prev = env->fpscr;
934 new = (uint32_t)arg;
935 new &= ~0x60000000;
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 */
944 if (fpscr_ix != 0)
945 env->fpscr |= 1 << FPSCR_VX;
946 else
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;
954 else
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);
967 } else {
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();
979 #else
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);
986 #endif
989 #ifdef CONFIG_SOFTFLOAT
990 void helper_reset_fpstatus (void)
992 set_float_exception_flags(0, &env->fp_status);
994 #endif
996 /* fadd - fadd. */
997 uint64_t helper_fadd (uint64_t arg1, uint64_t arg2)
999 CPU_DoubleU farg1, farg2;
1001 farg1.ll = arg1;
1002 farg2.ll = arg2;
1003 #if USE_PRECISE_EMULATION
1004 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1005 float64_is_signaling_nan(farg2.d))) {
1006 /* sNaN addition */
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);
1012 } else {
1013 farg1.d = float64_add(farg1.d, farg2.d, &env->fp_status);
1015 #else
1016 farg1.d = float64_add(farg1.d, farg2.d, &env->fp_status);
1017 #endif
1018 return farg1.ll;
1021 /* fsub - fsub. */
1022 uint64_t helper_fsub (uint64_t arg1, uint64_t arg2)
1024 CPU_DoubleU farg1, farg2;
1026 farg1.ll = arg1;
1027 farg2.ll = arg2;
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);
1038 } else {
1039 farg1.d = float64_sub(farg1.d, farg2.d, &env->fp_status);
1042 #else
1043 farg1.d = float64_sub(farg1.d, farg2.d, &env->fp_status);
1044 #endif
1045 return farg1.ll;
1048 /* fmul - fmul. */
1049 uint64_t helper_fmul (uint64_t arg1, uint64_t arg2)
1051 CPU_DoubleU farg1, farg2;
1053 farg1.ll = arg1;
1054 farg2.ll = arg2;
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);
1064 } else {
1065 farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
1067 #else
1068 farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
1069 #endif
1070 return farg1.ll;
1073 /* fdiv - fdiv. */
1074 uint64_t helper_fdiv (uint64_t arg1, uint64_t arg2)
1076 CPU_DoubleU farg1, farg2;
1078 farg1.ll = arg1;
1079 farg2.ll = arg2;
1080 #if USE_PRECISE_EMULATION
1081 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1082 float64_is_signaling_nan(farg2.d))) {
1083 /* sNaN division */
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);
1091 } else {
1092 farg1.d = float64_div(farg1.d, farg2.d, &env->fp_status);
1094 #else
1095 farg1.d = float64_div(farg1.d, farg2.d, &env->fp_status);
1096 #endif
1097 return farg1.ll;
1100 /* fabs */
1101 uint64_t helper_fabs (uint64_t arg)
1103 CPU_DoubleU farg;
1105 farg.ll = arg;
1106 farg.d = float64_abs(farg.d);
1107 return farg.ll;
1110 /* fnabs */
1111 uint64_t helper_fnabs (uint64_t arg)
1113 CPU_DoubleU farg;
1115 farg.ll = arg;
1116 farg.d = float64_abs(farg.d);
1117 farg.d = float64_chs(farg.d);
1118 return farg.ll;
1121 /* fneg */
1122 uint64_t helper_fneg (uint64_t arg)
1124 CPU_DoubleU farg;
1126 farg.ll = arg;
1127 farg.d = float64_chs(farg.d);
1128 return farg.ll;
1131 /* fctiw - fctiw. */
1132 uint64_t helper_fctiw (uint64_t arg)
1134 CPU_DoubleU farg;
1135 farg.ll = 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);
1143 } else {
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;
1150 #endif
1152 return farg.ll;
1155 /* fctiwz - fctiwz. */
1156 uint64_t helper_fctiwz (uint64_t arg)
1158 CPU_DoubleU farg;
1159 farg.ll = 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);
1167 } else {
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;
1174 #endif
1176 return farg.ll;
1179 #if defined(TARGET_PPC64)
1180 /* fcfid - fcfid. */
1181 uint64_t helper_fcfid (uint64_t arg)
1183 CPU_DoubleU farg;
1184 farg.d = int64_to_float64(arg, &env->fp_status);
1185 return farg.ll;
1188 /* fctid - fctid. */
1189 uint64_t helper_fctid (uint64_t arg)
1191 CPU_DoubleU farg;
1192 farg.ll = 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);
1200 } else {
1201 farg.ll = float64_to_int64(farg.d, &env->fp_status);
1203 return farg.ll;
1206 /* fctidz - fctidz. */
1207 uint64_t helper_fctidz (uint64_t arg)
1209 CPU_DoubleU farg;
1210 farg.ll = 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);
1218 } else {
1219 farg.ll = float64_to_int64_round_to_zero(farg.d, &env->fp_status);
1221 return farg.ll;
1224 #endif
1226 static always_inline uint64_t do_fri (uint64_t arg, int rounding_mode)
1228 CPU_DoubleU farg;
1229 farg.ll = arg;
1231 if (unlikely(float64_is_signaling_nan(farg.d))) {
1232 /* sNaN round */
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);
1237 } else {
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();
1243 return farg.ll;
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;
1271 farg1.ll = arg1;
1272 farg2.ll = arg2;
1273 farg3.ll = arg3;
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);
1284 } else {
1285 #ifdef FLOAT128
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);
1296 } else {
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);
1301 #else
1302 /* This is OK on x86 hosts */
1303 farg1.d = (farg1.d * farg2.d) + farg3.d;
1304 #endif
1306 #else
1307 farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
1308 farg1.d = float64_add(farg1.d, farg3.d, &env->fp_status);
1309 #endif
1310 return farg1.ll;
1313 /* fmsub - fmsub. */
1314 uint64_t helper_fmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3)
1316 CPU_DoubleU farg1, farg2, farg3;
1318 farg1.ll = arg1;
1319 farg2.ll = arg2;
1320 farg3.ll = arg3;
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);
1331 } else {
1332 #ifdef FLOAT128
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);
1343 } else {
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);
1348 #else
1349 /* This is OK on x86 hosts */
1350 farg1.d = (farg1.d * farg2.d) - farg3.d;
1351 #endif
1353 #else
1354 farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
1355 farg1.d = float64_sub(farg1.d, farg3.d, &env->fp_status);
1356 #endif
1357 return farg1.ll;
1360 /* fnmadd - fnmadd. */
1361 uint64_t helper_fnmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3)
1363 CPU_DoubleU farg1, farg2, farg3;
1365 farg1.ll = arg1;
1366 farg2.ll = arg2;
1367 farg3.ll = arg3;
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);
1378 } else {
1379 #if USE_PRECISE_EMULATION
1380 #ifdef FLOAT128
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);
1391 } else {
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);
1396 #else
1397 /* This is OK on x86 hosts */
1398 farg1.d = (farg1.d * farg2.d) + farg3.d;
1399 #endif
1400 #else
1401 farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
1402 farg1.d = float64_add(farg1.d, farg3.d, &env->fp_status);
1403 #endif
1404 if (likely(!float64_is_nan(farg1.d)))
1405 farg1.d = float64_chs(farg1.d);
1407 return farg1.ll;
1410 /* fnmsub - fnmsub. */
1411 uint64_t helper_fnmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3)
1413 CPU_DoubleU farg1, farg2, farg3;
1415 farg1.ll = arg1;
1416 farg2.ll = arg2;
1417 farg3.ll = arg3;
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);
1428 } else {
1429 #if USE_PRECISE_EMULATION
1430 #ifdef FLOAT128
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);
1441 } else {
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);
1446 #else
1447 /* This is OK on x86 hosts */
1448 farg1.d = (farg1.d * farg2.d) - farg3.d;
1449 #endif
1450 #else
1451 farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
1452 farg1.d = float64_sub(farg1.d, farg3.d, &env->fp_status);
1453 #endif
1454 if (likely(!float64_is_nan(farg1.d)))
1455 farg1.d = float64_chs(farg1.d);
1457 return farg1.ll;
1460 /* frsp - frsp. */
1461 uint64_t helper_frsp (uint64_t arg)
1463 CPU_DoubleU farg;
1464 float32 f32;
1465 farg.ll = 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);
1471 } else {
1472 f32 = float64_to_float32(farg.d, &env->fp_status);
1473 farg.d = float32_to_float64(f32, &env->fp_status);
1475 #else
1476 f32 = float64_to_float32(farg.d, &env->fp_status);
1477 farg.d = float32_to_float64(f32, &env->fp_status);
1478 #endif
1479 return farg.ll;
1482 /* fsqrt - fsqrt. */
1483 uint64_t helper_fsqrt (uint64_t arg)
1485 CPU_DoubleU farg;
1486 farg.ll = 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);
1494 } else {
1495 farg.d = float64_sqrt(farg.d, &env->fp_status);
1497 return farg.ll;
1500 /* fre - fre. */
1501 uint64_t helper_fre (uint64_t arg)
1503 CPU_DoubleU fone, farg;
1504 fone.ll = 0x3FF0000000000000ULL; /* 1.0 */
1505 farg.ll = arg;
1507 if (unlikely(float64_is_signaling_nan(farg.d))) {
1508 /* sNaN reciprocal */
1509 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1510 } else {
1511 farg.d = float64_div(fone.d, farg.d, &env->fp_status);
1513 return farg.d;
1516 /* fres - fres. */
1517 uint64_t helper_fres (uint64_t arg)
1519 CPU_DoubleU fone, farg;
1520 float32 f32;
1521 fone.ll = 0x3FF0000000000000ULL; /* 1.0 */
1522 farg.ll = arg;
1524 if (unlikely(float64_is_signaling_nan(farg.d))) {
1525 /* sNaN reciprocal */
1526 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1527 } else {
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);
1532 return farg.ll;
1535 /* frsqrte - frsqrte. */
1536 uint64_t helper_frsqrte (uint64_t arg)
1538 CPU_DoubleU fone, farg;
1539 float32 f32;
1540 fone.ll = 0x3FF0000000000000ULL; /* 1.0 */
1541 farg.ll = arg;
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);
1549 } else {
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);
1555 return farg.ll;
1558 /* fsel - fsel. */
1559 uint64_t helper_fsel (uint64_t arg1, uint64_t arg2, uint64_t arg3)
1561 CPU_DoubleU farg1;
1563 farg1.ll = arg1;
1565 if ((!float64_is_neg(farg1.d) || float64_is_zero(farg1.d)) && !float64_is_nan(farg1.d))
1566 return arg2;
1567 else
1568 return arg3;
1571 void helper_fcmpu (uint64_t arg1, uint64_t arg2, uint32_t crfD)
1573 CPU_DoubleU farg1, farg2;
1574 uint32_t ret = 0;
1575 farg1.ll = arg1;
1576 farg2.ll = arg2;
1578 if (unlikely(float64_is_nan(farg1.d) ||
1579 float64_is_nan(farg2.d))) {
1580 ret = 0x01UL;
1581 } else if (float64_lt(farg1.d, farg2.d, &env->fp_status)) {
1582 ret = 0x08UL;
1583 } else if (!float64_le(farg1.d, farg2.d, &env->fp_status)) {
1584 ret = 0x04UL;
1585 } else {
1586 ret = 0x02UL;
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;
1603 uint32_t ret = 0;
1604 farg1.ll = arg1;
1605 farg2.ll = arg2;
1607 if (unlikely(float64_is_nan(farg1.d) ||
1608 float64_is_nan(farg2.d))) {
1609 ret = 0x01UL;
1610 } else if (float64_lt(farg1.d, farg2.d, &env->fp_status)) {
1611 ret = 0x08UL;
1612 } else if (!float64_le(farg1.d, farg2.d, &env->fp_status)) {
1613 ret = 0x04UL;
1614 } else {
1615 ret = 0x02UL;
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);
1627 } else {
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);
1638 if (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;
1651 } else {
1652 nip = (uint32_t)nip;
1653 msr = (uint32_t)(msr & msrm);
1654 if (keep_msrh)
1655 msr |= env->msr & ~((uint64_t)0xFFFFFFFF);
1657 #else
1658 nip = (uint32_t)nip;
1659 msr &= (uint32_t)msrm;
1660 #endif
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);
1666 #endif
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);
1691 #endif
1692 #endif
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);
1715 #endif
1717 /*****************************************************************************/
1718 /* PowerPC 601 specific instructions (POWER bridge) */
1720 target_ulong helper_clcs (uint32_t arg)
1722 switch (arg) {
1723 case 0x0CUL:
1724 /* Instruction cache line size */
1725 return env->icache_line_size;
1726 break;
1727 case 0x0DUL:
1728 /* Data cache line size */
1729 return env->dcache_line_size;
1730 break;
1731 case 0x0EUL:
1732 /* Minimum cache line size */
1733 return (env->icache_line_size < env->dcache_line_size) ?
1734 env->icache_line_size : env->dcache_line_size;
1735 break;
1736 case 0x0FUL:
1737 /* Maximum cache line size */
1738 return (env->icache_line_size > env->dcache_line_size) ?
1739 env->icache_line_size : env->dcache_line_size;
1740 break;
1741 default:
1742 /* Undefined */
1743 return 0;
1744 break;
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;
1755 return INT32_MIN;
1756 } else {
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;
1770 return INT32_MIN;
1771 } else {
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);
1776 } else {
1777 env->xer &= ~(1 << XER_OV);
1779 return tmp;
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;
1788 return INT32_MIN;
1789 } else {
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;
1801 return INT32_MIN;
1802 } else {
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)
1812 mmu_ctx_t ctx;
1813 int nb_BATs;
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;
1821 env->nb_BATs = 0;
1822 if (get_physical_address(env, &ctx, addr, 0, ACCESS_INT) == 0)
1823 ret = ctx.raddr;
1824 env->nb_BATs = nb_BATs;
1825 return ret;
1828 void helper_rfsvc (void)
1830 do_rfi(env->lr, env->ctr, 0x0000FFFF, 0);
1832 #endif
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:
1839 * -arg / 256
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];
1848 } else {
1849 return 0;
1852 #endif
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);
1875 return val;
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);
1919 #endif
1921 /* 440 specific */
1922 target_ulong helper_dlmzb (target_ulong high, target_ulong low, uint32_t update_Rc)
1924 target_ulong mask;
1925 int i;
1927 i = 1;
1928 for (mask = 0xFF000000; mask != 0; mask = mask >> 8) {
1929 if ((high & mask) == 0) {
1930 if (update_Rc) {
1931 env->crf[0] = 0x4;
1933 goto done;
1935 i++;
1937 for (mask = 0xFF000000; mask != 0; mask = mask >> 8) {
1938 if ((low & mask) == 0) {
1939 if (update_Rc) {
1940 env->crf[0] = 0x8;
1942 goto done;
1944 i++;
1946 if (update_Rc) {
1947 env->crf[0] = 0x2;
1949 done:
1950 env->xer = (env->xer & ~0x7F) | i;
1951 if (update_Rc) {
1952 env->crf[0] |= xer_so;
1954 return i;
1957 /*****************************************************************************/
1958 /* Altivec extension helpers */
1959 #if defined(WORDS_BIGENDIAN)
1960 #define HI_IDX 0
1961 #define LO_IDX 1
1962 #else
1963 #define HI_IDX 1
1964 #define LO_IDX 0
1965 #endif
1967 #if defined(WORDS_BIGENDIAN)
1968 #define VECTOR_FOR_INORDER_I(index, element) \
1969 for (index = 0; index < ARRAY_SIZE(r->element); index++)
1970 #else
1971 #define VECTOR_FOR_INORDER_I(index, element) \
1972 for (index = ARRAY_SIZE(r->element)-1; index >= 0; index--)
1973 #endif
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) \
1979 to_type r; \
1980 if (use_min && x < min) { \
1981 r = min; \
1982 *sat = 1; \
1983 } else if (use_max && x > max) { \
1984 r = max; \
1985 *sat = 1; \
1986 } else { \
1987 r = x; \
1989 return r; \
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)
2000 #undef SATCVT
2002 void helper_lvsl (ppc_avr_t *r, target_ulong sh)
2004 int i, j = (sh & 0xf);
2006 VECTOR_FOR_INORDER_I (i, u8) {
2007 r->u8[i] = j++;
2011 void helper_lvsr (ppc_avr_t *r, target_ulong sh)
2013 int i, j = 0x10 - (sh & 0xf);
2015 VECTOR_FOR_INORDER_I (i, u8) {
2016 r->u8[i] = j++;
2020 void helper_vaddcuw (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2022 int i;
2023 for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
2024 r->u32[i] = ~a->u32[i] < b->u32[i];
2028 #define VARITH_DO(name, op, element) \
2029 void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2031 int i; \
2032 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2033 r->element[i] = a->element[i] op b->element[i]; \
2036 #define VARITH(suffix, element) \
2037 VARITH_DO(add##suffix, +, element) \
2038 VARITH_DO(sub##suffix, -, element)
2039 VARITH(ubm, u8)
2040 VARITH(uhm, u16)
2041 VARITH(uwm, u32)
2042 #undef VARITH_DO
2043 #undef VARITH
2045 #define VAVG_DO(name, element, etype) \
2046 void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2048 int i; \
2049 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2050 etype x = (etype)a->element[i] + (etype)b->element[i] + 1; \
2051 r->element[i] = x >> 1; \
2055 #define VAVG(type, signed_element, signed_type, unsigned_element, unsigned_type) \
2056 VAVG_DO(avgs##type, signed_element, signed_type) \
2057 VAVG_DO(avgu##type, unsigned_element, unsigned_type)
2058 VAVG(b, s8, int16_t, u8, uint16_t)
2059 VAVG(h, s16, int32_t, u16, uint32_t)
2060 VAVG(w, s32, int64_t, u32, uint64_t)
2061 #undef VAVG_DO
2062 #undef VAVG
2064 void helper_vmhaddshs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2066 int sat = 0;
2067 int i;
2069 for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
2070 int32_t prod = a->s16[i] * b->s16[i];
2071 int32_t t = (int32_t)c->s16[i] + (prod >> 15);
2072 r->s16[i] = cvtswsh (t, &sat);
2075 if (sat) {
2076 env->vscr |= (1 << VSCR_SAT);
2080 void helper_vmhraddshs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2082 int sat = 0;
2083 int i;
2085 for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
2086 int32_t prod = a->s16[i] * b->s16[i] + 0x00004000;
2087 int32_t t = (int32_t)c->s16[i] + (prod >> 15);
2088 r->s16[i] = cvtswsh (t, &sat);
2091 if (sat) {
2092 env->vscr |= (1 << VSCR_SAT);
2096 #define VMINMAX_DO(name, compare, element) \
2097 void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2099 int i; \
2100 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2101 if (a->element[i] compare b->element[i]) { \
2102 r->element[i] = b->element[i]; \
2103 } else { \
2104 r->element[i] = a->element[i]; \
2108 #define VMINMAX(suffix, element) \
2109 VMINMAX_DO(min##suffix, >, element) \
2110 VMINMAX_DO(max##suffix, <, element)
2111 VMINMAX(sb, s8)
2112 VMINMAX(sh, s16)
2113 VMINMAX(sw, s32)
2114 VMINMAX(ub, u8)
2115 VMINMAX(uh, u16)
2116 VMINMAX(uw, u32)
2117 #undef VMINMAX_DO
2118 #undef VMINMAX
2120 #define VMRG_DO(name, element, highp) \
2121 void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2123 ppc_avr_t result; \
2124 int i; \
2125 size_t n_elems = ARRAY_SIZE(r->element); \
2126 for (i = 0; i < n_elems/2; i++) { \
2127 if (highp) { \
2128 result.element[i*2+HI_IDX] = a->element[i]; \
2129 result.element[i*2+LO_IDX] = b->element[i]; \
2130 } else { \
2131 result.element[n_elems - i*2 - (1+HI_IDX)] = b->element[n_elems - i - 1]; \
2132 result.element[n_elems - i*2 - (1+LO_IDX)] = a->element[n_elems - i - 1]; \
2135 *r = result; \
2137 #if defined(WORDS_BIGENDIAN)
2138 #define MRGHI 0
2139 #define MRGL0 1
2140 #else
2141 #define MRGHI 1
2142 #define MRGLO 0
2143 #endif
2144 #define VMRG(suffix, element) \
2145 VMRG_DO(mrgl##suffix, element, MRGHI) \
2146 VMRG_DO(mrgh##suffix, element, MRGLO)
2147 VMRG(b, u8)
2148 VMRG(h, u16)
2149 VMRG(w, u32)
2150 #undef VMRG_DO
2151 #undef VMRG
2152 #undef MRGHI
2153 #undef MRGLO
2155 void helper_vmsummbm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2157 int32_t prod[16];
2158 int i;
2160 for (i = 0; i < ARRAY_SIZE(r->s8); i++) {
2161 prod[i] = (int32_t)a->s8[i] * b->u8[i];
2164 VECTOR_FOR_INORDER_I(i, s32) {
2165 r->s32[i] = c->s32[i] + prod[4*i] + prod[4*i+1] + prod[4*i+2] + prod[4*i+3];
2169 void helper_vmsumshm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2171 int32_t prod[8];
2172 int i;
2174 for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
2175 prod[i] = a->s16[i] * b->s16[i];
2178 VECTOR_FOR_INORDER_I(i, s32) {
2179 r->s32[i] = c->s32[i] + prod[2*i] + prod[2*i+1];
2183 void helper_vmsumshs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2185 int32_t prod[8];
2186 int i;
2187 int sat = 0;
2189 for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
2190 prod[i] = (int32_t)a->s16[i] * b->s16[i];
2193 VECTOR_FOR_INORDER_I (i, s32) {
2194 int64_t t = (int64_t)c->s32[i] + prod[2*i] + prod[2*i+1];
2195 r->u32[i] = cvtsdsw(t, &sat);
2198 if (sat) {
2199 env->vscr |= (1 << VSCR_SAT);
2203 void helper_vmsumubm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2205 uint16_t prod[16];
2206 int i;
2208 for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
2209 prod[i] = a->u8[i] * b->u8[i];
2212 VECTOR_FOR_INORDER_I(i, u32) {
2213 r->u32[i] = c->u32[i] + prod[4*i] + prod[4*i+1] + prod[4*i+2] + prod[4*i+3];
2217 void helper_vmsumuhm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2219 uint32_t prod[8];
2220 int i;
2222 for (i = 0; i < ARRAY_SIZE(r->u16); i++) {
2223 prod[i] = a->u16[i] * b->u16[i];
2226 VECTOR_FOR_INORDER_I(i, u32) {
2227 r->u32[i] = c->u32[i] + prod[2*i] + prod[2*i+1];
2231 void helper_vmsumuhs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2233 uint32_t prod[8];
2234 int i;
2235 int sat = 0;
2237 for (i = 0; i < ARRAY_SIZE(r->u16); i++) {
2238 prod[i] = a->u16[i] * b->u16[i];
2241 VECTOR_FOR_INORDER_I (i, s32) {
2242 uint64_t t = (uint64_t)c->u32[i] + prod[2*i] + prod[2*i+1];
2243 r->u32[i] = cvtuduw(t, &sat);
2246 if (sat) {
2247 env->vscr |= (1 << VSCR_SAT);
2251 #define VMUL_DO(name, mul_element, prod_element, evenp) \
2252 void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2254 int i; \
2255 VECTOR_FOR_INORDER_I(i, prod_element) { \
2256 if (evenp) { \
2257 r->prod_element[i] = a->mul_element[i*2+HI_IDX] * b->mul_element[i*2+HI_IDX]; \
2258 } else { \
2259 r->prod_element[i] = a->mul_element[i*2+LO_IDX] * b->mul_element[i*2+LO_IDX]; \
2263 #define VMUL(suffix, mul_element, prod_element) \
2264 VMUL_DO(mule##suffix, mul_element, prod_element, 1) \
2265 VMUL_DO(mulo##suffix, mul_element, prod_element, 0)
2266 VMUL(sb, s8, s16)
2267 VMUL(sh, s16, s32)
2268 VMUL(ub, u8, u16)
2269 VMUL(uh, u16, u32)
2270 #undef VMUL_DO
2271 #undef VMUL
2273 void helper_vperm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2275 ppc_avr_t result;
2276 int i;
2277 VECTOR_FOR_INORDER_I (i, u8) {
2278 int s = c->u8[i] & 0x1f;
2279 #if defined(WORDS_BIGENDIAN)
2280 int index = s & 0xf;
2281 #else
2282 int index = 15 - (s & 0xf);
2283 #endif
2284 if (s & 0x10) {
2285 result.u8[i] = b->u8[index];
2286 } else {
2287 result.u8[i] = a->u8[index];
2290 *r = result;
2293 #if defined(WORDS_BIGENDIAN)
2294 #define PKBIG 1
2295 #else
2296 #define PKBIG 0
2297 #endif
2298 void helper_vpkpx (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2300 int i, j;
2301 ppc_avr_t result;
2302 #if defined(WORDS_BIGENDIAN)
2303 const ppc_avr_t *x[2] = { a, b };
2304 #else
2305 const ppc_avr_t *x[2] = { b, a };
2306 #endif
2308 VECTOR_FOR_INORDER_I (i, u64) {
2309 VECTOR_FOR_INORDER_I (j, u32){
2310 uint32_t e = x[i]->u32[j];
2311 result.u16[4*i+j] = (((e >> 9) & 0xfc00) |
2312 ((e >> 6) & 0x3e0) |
2313 ((e >> 3) & 0x1f));
2316 *r = result;
2319 #define VPK(suffix, from, to, cvt, dosat) \
2320 void helper_vpk##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2322 int i; \
2323 int sat = 0; \
2324 ppc_avr_t result; \
2325 ppc_avr_t *a0 = PKBIG ? a : b; \
2326 ppc_avr_t *a1 = PKBIG ? b : a; \
2327 VECTOR_FOR_INORDER_I (i, from) { \
2328 result.to[i] = cvt(a0->from[i], &sat); \
2329 result.to[i+ARRAY_SIZE(r->from)] = cvt(a1->from[i], &sat); \
2331 *r = result; \
2332 if (dosat && sat) { \
2333 env->vscr |= (1 << VSCR_SAT); \
2336 #define I(x, y) (x)
2337 VPK(shss, s16, s8, cvtshsb, 1)
2338 VPK(shus, s16, u8, cvtshub, 1)
2339 VPK(swss, s32, s16, cvtswsh, 1)
2340 VPK(swus, s32, u16, cvtswuh, 1)
2341 VPK(uhus, u16, u8, cvtuhub, 1)
2342 VPK(uwus, u32, u16, cvtuwuh, 1)
2343 VPK(uhum, u16, u8, I, 0)
2344 VPK(uwum, u32, u16, I, 0)
2345 #undef I
2346 #undef VPK
2347 #undef PKBIG
2349 #define VROTATE(suffix, element) \
2350 void helper_vrl##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2352 int i; \
2353 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2354 unsigned int mask = ((1 << (3 + (sizeof (a->element[0]) >> 1))) - 1); \
2355 unsigned int shift = b->element[i] & mask; \
2356 r->element[i] = (a->element[i] << shift) | (a->element[i] >> (sizeof(a->element[0]) * 8 - shift)); \
2359 VROTATE(b, u8)
2360 VROTATE(h, u16)
2361 VROTATE(w, u32)
2362 #undef VROTATE
2364 void helper_vsel (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2366 r->u64[0] = (a->u64[0] & ~c->u64[0]) | (b->u64[0] & c->u64[0]);
2367 r->u64[1] = (a->u64[1] & ~c->u64[1]) | (b->u64[1] & c->u64[1]);
2370 #define VSL(suffix, element) \
2371 void helper_vsl##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2373 int i; \
2374 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2375 unsigned int mask = ((1 << (3 + (sizeof (a->element[0]) >> 1))) - 1); \
2376 unsigned int shift = b->element[i] & mask; \
2377 r->element[i] = a->element[i] << shift; \
2380 VSL(b, u8)
2381 VSL(h, u16)
2382 VSL(w, u32)
2383 #undef VSL
2385 void helper_vsldoi (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t shift)
2387 int sh = shift & 0xf;
2388 int i;
2389 ppc_avr_t result;
2391 #if defined(WORDS_BIGENDIAN)
2392 for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
2393 int index = sh + i;
2394 if (index > 0xf) {
2395 result.u8[i] = b->u8[index-0x10];
2396 } else {
2397 result.u8[i] = a->u8[index];
2400 #else
2401 for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
2402 int index = (16 - sh) + i;
2403 if (index > 0xf) {
2404 result.u8[i] = a->u8[index-0x10];
2405 } else {
2406 result.u8[i] = b->u8[index];
2409 #endif
2410 *r = result;
2413 void helper_vslo (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2415 int sh = (b->u8[LO_IDX*0xf] >> 3) & 0xf;
2417 #if defined (WORDS_BIGENDIAN)
2418 memmove (&r->u8[0], &a->u8[sh], 16-sh);
2419 memset (&r->u8[16-sh], 0, sh);
2420 #else
2421 memmove (&r->u8[sh], &a->u8[0], 16-sh);
2422 memset (&r->u8[0], 0, sh);
2423 #endif
2426 /* Experimental testing shows that hardware masks the immediate. */
2427 #define _SPLAT_MASKED(element) (splat & (ARRAY_SIZE(r->element) - 1))
2428 #if defined(WORDS_BIGENDIAN)
2429 #define SPLAT_ELEMENT(element) _SPLAT_MASKED(element)
2430 #else
2431 #define SPLAT_ELEMENT(element) (ARRAY_SIZE(r->element)-1 - _SPLAT_MASKED(element))
2432 #endif
2433 #define VSPLT(suffix, element) \
2434 void helper_vsplt##suffix (ppc_avr_t *r, ppc_avr_t *b, uint32_t splat) \
2436 uint32_t s = b->element[SPLAT_ELEMENT(element)]; \
2437 int i; \
2438 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2439 r->element[i] = s; \
2442 VSPLT(b, u8)
2443 VSPLT(h, u16)
2444 VSPLT(w, u32)
2445 #undef VSPLT
2446 #undef SPLAT_ELEMENT
2447 #undef _SPLAT_MASKED
2449 #define VSR(suffix, element) \
2450 void helper_vsr##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2452 int i; \
2453 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2454 unsigned int mask = ((1 << (3 + (sizeof (a->element[0]) >> 1))) - 1); \
2455 unsigned int shift = b->element[i] & mask; \
2456 r->element[i] = a->element[i] >> shift; \
2459 VSR(ab, s8)
2460 VSR(ah, s16)
2461 VSR(aw, s32)
2462 VSR(b, u8)
2463 VSR(h, u16)
2464 VSR(w, u32)
2465 #undef VSR
2467 void helper_vsro (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2469 int sh = (b->u8[LO_IDX*0xf] >> 3) & 0xf;
2471 #if defined (WORDS_BIGENDIAN)
2472 memmove (&r->u8[sh], &a->u8[0], 16-sh);
2473 memset (&r->u8[0], 0, sh);
2474 #else
2475 memmove (&r->u8[0], &a->u8[sh], 16-sh);
2476 memset (&r->u8[16-sh], 0, sh);
2477 #endif
2480 void helper_vsubcuw (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2482 int i;
2483 for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
2484 r->u32[i] = a->u32[i] >= b->u32[i];
2488 #if defined(WORDS_BIGENDIAN)
2489 #define UPKHI 1
2490 #define UPKLO 0
2491 #else
2492 #define UPKHI 0
2493 #define UPKLO 1
2494 #endif
2495 #define VUPKPX(suffix, hi) \
2496 void helper_vupk##suffix (ppc_avr_t *r, ppc_avr_t *b) \
2498 int i; \
2499 ppc_avr_t result; \
2500 for (i = 0; i < ARRAY_SIZE(r->u32); i++) { \
2501 uint16_t e = b->u16[hi ? i : i+4]; \
2502 uint8_t a = (e >> 15) ? 0xff : 0; \
2503 uint8_t r = (e >> 10) & 0x1f; \
2504 uint8_t g = (e >> 5) & 0x1f; \
2505 uint8_t b = e & 0x1f; \
2506 result.u32[i] = (a << 24) | (r << 16) | (g << 8) | b; \
2508 *r = result; \
2510 VUPKPX(lpx, UPKLO)
2511 VUPKPX(hpx, UPKHI)
2512 #undef VUPKPX
2514 #define VUPK(suffix, unpacked, packee, hi) \
2515 void helper_vupk##suffix (ppc_avr_t *r, ppc_avr_t *b) \
2517 int i; \
2518 ppc_avr_t result; \
2519 if (hi) { \
2520 for (i = 0; i < ARRAY_SIZE(r->unpacked); i++) { \
2521 result.unpacked[i] = b->packee[i]; \
2523 } else { \
2524 for (i = ARRAY_SIZE(r->unpacked); i < ARRAY_SIZE(r->packee); i++) { \
2525 result.unpacked[i-ARRAY_SIZE(r->unpacked)] = b->packee[i]; \
2528 *r = result; \
2530 VUPK(hsb, s16, s8, UPKHI)
2531 VUPK(hsh, s32, s16, UPKHI)
2532 VUPK(lsb, s16, s8, UPKLO)
2533 VUPK(lsh, s32, s16, UPKLO)
2534 #undef VUPK
2535 #undef UPKHI
2536 #undef UPKLO
2538 #undef VECTOR_FOR_INORDER_I
2539 #undef HI_IDX
2540 #undef LO_IDX
2542 /*****************************************************************************/
2543 /* SPE extension helpers */
2544 /* Use a table to make this quicker */
2545 static uint8_t hbrev[16] = {
2546 0x0, 0x8, 0x4, 0xC, 0x2, 0xA, 0x6, 0xE,
2547 0x1, 0x9, 0x5, 0xD, 0x3, 0xB, 0x7, 0xF,
2550 static always_inline uint8_t byte_reverse (uint8_t val)
2552 return hbrev[val >> 4] | (hbrev[val & 0xF] << 4);
2555 static always_inline uint32_t word_reverse (uint32_t val)
2557 return byte_reverse(val >> 24) | (byte_reverse(val >> 16) << 8) |
2558 (byte_reverse(val >> 8) << 16) | (byte_reverse(val) << 24);
2561 #define MASKBITS 16 // Random value - to be fixed (implementation dependant)
2562 target_ulong helper_brinc (target_ulong arg1, target_ulong arg2)
2564 uint32_t a, b, d, mask;
2566 mask = UINT32_MAX >> (32 - MASKBITS);
2567 a = arg1 & mask;
2568 b = arg2 & mask;
2569 d = word_reverse(1 + word_reverse(a | ~b));
2570 return (arg1 & ~mask) | (d & b);
2573 uint32_t helper_cntlsw32 (uint32_t val)
2575 if (val & 0x80000000)
2576 return clz32(~val);
2577 else
2578 return clz32(val);
2581 uint32_t helper_cntlzw32 (uint32_t val)
2583 return clz32(val);
2586 /* Single-precision floating-point conversions */
2587 static always_inline uint32_t efscfsi (uint32_t val)
2589 CPU_FloatU u;
2591 u.f = int32_to_float32(val, &env->spe_status);
2593 return u.l;
2596 static always_inline uint32_t efscfui (uint32_t val)
2598 CPU_FloatU u;
2600 u.f = uint32_to_float32(val, &env->spe_status);
2602 return u.l;
2605 static always_inline int32_t efsctsi (uint32_t val)
2607 CPU_FloatU u;
2609 u.l = val;
2610 /* NaN are not treated the same way IEEE 754 does */
2611 if (unlikely(float32_is_nan(u.f)))
2612 return 0;
2614 return float32_to_int32(u.f, &env->spe_status);
2617 static always_inline uint32_t efsctui (uint32_t val)
2619 CPU_FloatU u;
2621 u.l = val;
2622 /* NaN are not treated the same way IEEE 754 does */
2623 if (unlikely(float32_is_nan(u.f)))
2624 return 0;
2626 return float32_to_uint32(u.f, &env->spe_status);
2629 static always_inline uint32_t efsctsiz (uint32_t val)
2631 CPU_FloatU u;
2633 u.l = val;
2634 /* NaN are not treated the same way IEEE 754 does */
2635 if (unlikely(float32_is_nan(u.f)))
2636 return 0;
2638 return float32_to_int32_round_to_zero(u.f, &env->spe_status);
2641 static always_inline uint32_t efsctuiz (uint32_t val)
2643 CPU_FloatU u;
2645 u.l = val;
2646 /* NaN are not treated the same way IEEE 754 does */
2647 if (unlikely(float32_is_nan(u.f)))
2648 return 0;
2650 return float32_to_uint32_round_to_zero(u.f, &env->spe_status);
2653 static always_inline uint32_t efscfsf (uint32_t val)
2655 CPU_FloatU u;
2656 float32 tmp;
2658 u.f = int32_to_float32(val, &env->spe_status);
2659 tmp = int64_to_float32(1ULL << 32, &env->spe_status);
2660 u.f = float32_div(u.f, tmp, &env->spe_status);
2662 return u.l;
2665 static always_inline uint32_t efscfuf (uint32_t val)
2667 CPU_FloatU u;
2668 float32 tmp;
2670 u.f = uint32_to_float32(val, &env->spe_status);
2671 tmp = uint64_to_float32(1ULL << 32, &env->spe_status);
2672 u.f = float32_div(u.f, tmp, &env->spe_status);
2674 return u.l;
2677 static always_inline uint32_t efsctsf (uint32_t val)
2679 CPU_FloatU u;
2680 float32 tmp;
2682 u.l = val;
2683 /* NaN are not treated the same way IEEE 754 does */
2684 if (unlikely(float32_is_nan(u.f)))
2685 return 0;
2686 tmp = uint64_to_float32(1ULL << 32, &env->spe_status);
2687 u.f = float32_mul(u.f, tmp, &env->spe_status);
2689 return float32_to_int32(u.f, &env->spe_status);
2692 static always_inline uint32_t efsctuf (uint32_t val)
2694 CPU_FloatU u;
2695 float32 tmp;
2697 u.l = val;
2698 /* NaN are not treated the same way IEEE 754 does */
2699 if (unlikely(float32_is_nan(u.f)))
2700 return 0;
2701 tmp = uint64_to_float32(1ULL << 32, &env->spe_status);
2702 u.f = float32_mul(u.f, tmp, &env->spe_status);
2704 return float32_to_uint32(u.f, &env->spe_status);
2707 #define HELPER_SPE_SINGLE_CONV(name) \
2708 uint32_t helper_e##name (uint32_t val) \
2710 return e##name(val); \
2712 /* efscfsi */
2713 HELPER_SPE_SINGLE_CONV(fscfsi);
2714 /* efscfui */
2715 HELPER_SPE_SINGLE_CONV(fscfui);
2716 /* efscfuf */
2717 HELPER_SPE_SINGLE_CONV(fscfuf);
2718 /* efscfsf */
2719 HELPER_SPE_SINGLE_CONV(fscfsf);
2720 /* efsctsi */
2721 HELPER_SPE_SINGLE_CONV(fsctsi);
2722 /* efsctui */
2723 HELPER_SPE_SINGLE_CONV(fsctui);
2724 /* efsctsiz */
2725 HELPER_SPE_SINGLE_CONV(fsctsiz);
2726 /* efsctuiz */
2727 HELPER_SPE_SINGLE_CONV(fsctuiz);
2728 /* efsctsf */
2729 HELPER_SPE_SINGLE_CONV(fsctsf);
2730 /* efsctuf */
2731 HELPER_SPE_SINGLE_CONV(fsctuf);
2733 #define HELPER_SPE_VECTOR_CONV(name) \
2734 uint64_t helper_ev##name (uint64_t val) \
2736 return ((uint64_t)e##name(val >> 32) << 32) | \
2737 (uint64_t)e##name(val); \
2739 /* evfscfsi */
2740 HELPER_SPE_VECTOR_CONV(fscfsi);
2741 /* evfscfui */
2742 HELPER_SPE_VECTOR_CONV(fscfui);
2743 /* evfscfuf */
2744 HELPER_SPE_VECTOR_CONV(fscfuf);
2745 /* evfscfsf */
2746 HELPER_SPE_VECTOR_CONV(fscfsf);
2747 /* evfsctsi */
2748 HELPER_SPE_VECTOR_CONV(fsctsi);
2749 /* evfsctui */
2750 HELPER_SPE_VECTOR_CONV(fsctui);
2751 /* evfsctsiz */
2752 HELPER_SPE_VECTOR_CONV(fsctsiz);
2753 /* evfsctuiz */
2754 HELPER_SPE_VECTOR_CONV(fsctuiz);
2755 /* evfsctsf */
2756 HELPER_SPE_VECTOR_CONV(fsctsf);
2757 /* evfsctuf */
2758 HELPER_SPE_VECTOR_CONV(fsctuf);
2760 /* Single-precision floating-point arithmetic */
2761 static always_inline uint32_t efsadd (uint32_t op1, uint32_t op2)
2763 CPU_FloatU u1, u2;
2764 u1.l = op1;
2765 u2.l = op2;
2766 u1.f = float32_add(u1.f, u2.f, &env->spe_status);
2767 return u1.l;
2770 static always_inline uint32_t efssub (uint32_t op1, uint32_t op2)
2772 CPU_FloatU u1, u2;
2773 u1.l = op1;
2774 u2.l = op2;
2775 u1.f = float32_sub(u1.f, u2.f, &env->spe_status);
2776 return u1.l;
2779 static always_inline uint32_t efsmul (uint32_t op1, uint32_t op2)
2781 CPU_FloatU u1, u2;
2782 u1.l = op1;
2783 u2.l = op2;
2784 u1.f = float32_mul(u1.f, u2.f, &env->spe_status);
2785 return u1.l;
2788 static always_inline uint32_t efsdiv (uint32_t op1, uint32_t op2)
2790 CPU_FloatU u1, u2;
2791 u1.l = op1;
2792 u2.l = op2;
2793 u1.f = float32_div(u1.f, u2.f, &env->spe_status);
2794 return u1.l;
2797 #define HELPER_SPE_SINGLE_ARITH(name) \
2798 uint32_t helper_e##name (uint32_t op1, uint32_t op2) \
2800 return e##name(op1, op2); \
2802 /* efsadd */
2803 HELPER_SPE_SINGLE_ARITH(fsadd);
2804 /* efssub */
2805 HELPER_SPE_SINGLE_ARITH(fssub);
2806 /* efsmul */
2807 HELPER_SPE_SINGLE_ARITH(fsmul);
2808 /* efsdiv */
2809 HELPER_SPE_SINGLE_ARITH(fsdiv);
2811 #define HELPER_SPE_VECTOR_ARITH(name) \
2812 uint64_t helper_ev##name (uint64_t op1, uint64_t op2) \
2814 return ((uint64_t)e##name(op1 >> 32, op2 >> 32) << 32) | \
2815 (uint64_t)e##name(op1, op2); \
2817 /* evfsadd */
2818 HELPER_SPE_VECTOR_ARITH(fsadd);
2819 /* evfssub */
2820 HELPER_SPE_VECTOR_ARITH(fssub);
2821 /* evfsmul */
2822 HELPER_SPE_VECTOR_ARITH(fsmul);
2823 /* evfsdiv */
2824 HELPER_SPE_VECTOR_ARITH(fsdiv);
2826 /* Single-precision floating-point comparisons */
2827 static always_inline uint32_t efststlt (uint32_t op1, uint32_t op2)
2829 CPU_FloatU u1, u2;
2830 u1.l = op1;
2831 u2.l = op2;
2832 return float32_lt(u1.f, u2.f, &env->spe_status) ? 4 : 0;
2835 static always_inline uint32_t efststgt (uint32_t op1, uint32_t op2)
2837 CPU_FloatU u1, u2;
2838 u1.l = op1;
2839 u2.l = op2;
2840 return float32_le(u1.f, u2.f, &env->spe_status) ? 0 : 4;
2843 static always_inline uint32_t efststeq (uint32_t op1, uint32_t op2)
2845 CPU_FloatU u1, u2;
2846 u1.l = op1;
2847 u2.l = op2;
2848 return float32_eq(u1.f, u2.f, &env->spe_status) ? 4 : 0;
2851 static always_inline uint32_t efscmplt (uint32_t op1, uint32_t op2)
2853 /* XXX: TODO: test special values (NaN, infinites, ...) */
2854 return efststlt(op1, op2);
2857 static always_inline uint32_t efscmpgt (uint32_t op1, uint32_t op2)
2859 /* XXX: TODO: test special values (NaN, infinites, ...) */
2860 return efststgt(op1, op2);
2863 static always_inline uint32_t efscmpeq (uint32_t op1, uint32_t op2)
2865 /* XXX: TODO: test special values (NaN, infinites, ...) */
2866 return efststeq(op1, op2);
2869 #define HELPER_SINGLE_SPE_CMP(name) \
2870 uint32_t helper_e##name (uint32_t op1, uint32_t op2) \
2872 return e##name(op1, op2) << 2; \
2874 /* efststlt */
2875 HELPER_SINGLE_SPE_CMP(fststlt);
2876 /* efststgt */
2877 HELPER_SINGLE_SPE_CMP(fststgt);
2878 /* efststeq */
2879 HELPER_SINGLE_SPE_CMP(fststeq);
2880 /* efscmplt */
2881 HELPER_SINGLE_SPE_CMP(fscmplt);
2882 /* efscmpgt */
2883 HELPER_SINGLE_SPE_CMP(fscmpgt);
2884 /* efscmpeq */
2885 HELPER_SINGLE_SPE_CMP(fscmpeq);
2887 static always_inline uint32_t evcmp_merge (int t0, int t1)
2889 return (t0 << 3) | (t1 << 2) | ((t0 | t1) << 1) | (t0 & t1);
2892 #define HELPER_VECTOR_SPE_CMP(name) \
2893 uint32_t helper_ev##name (uint64_t op1, uint64_t op2) \
2895 return evcmp_merge(e##name(op1 >> 32, op2 >> 32), e##name(op1, op2)); \
2897 /* evfststlt */
2898 HELPER_VECTOR_SPE_CMP(fststlt);
2899 /* evfststgt */
2900 HELPER_VECTOR_SPE_CMP(fststgt);
2901 /* evfststeq */
2902 HELPER_VECTOR_SPE_CMP(fststeq);
2903 /* evfscmplt */
2904 HELPER_VECTOR_SPE_CMP(fscmplt);
2905 /* evfscmpgt */
2906 HELPER_VECTOR_SPE_CMP(fscmpgt);
2907 /* evfscmpeq */
2908 HELPER_VECTOR_SPE_CMP(fscmpeq);
2910 /* Double-precision floating-point conversion */
2911 uint64_t helper_efdcfsi (uint32_t val)
2913 CPU_DoubleU u;
2915 u.d = int32_to_float64(val, &env->spe_status);
2917 return u.ll;
2920 uint64_t helper_efdcfsid (uint64_t val)
2922 CPU_DoubleU u;
2924 u.d = int64_to_float64(val, &env->spe_status);
2926 return u.ll;
2929 uint64_t helper_efdcfui (uint32_t val)
2931 CPU_DoubleU u;
2933 u.d = uint32_to_float64(val, &env->spe_status);
2935 return u.ll;
2938 uint64_t helper_efdcfuid (uint64_t val)
2940 CPU_DoubleU u;
2942 u.d = uint64_to_float64(val, &env->spe_status);
2944 return u.ll;
2947 uint32_t helper_efdctsi (uint64_t val)
2949 CPU_DoubleU u;
2951 u.ll = val;
2952 /* NaN are not treated the same way IEEE 754 does */
2953 if (unlikely(float64_is_nan(u.d)))
2954 return 0;
2956 return float64_to_int32(u.d, &env->spe_status);
2959 uint32_t helper_efdctui (uint64_t val)
2961 CPU_DoubleU u;
2963 u.ll = val;
2964 /* NaN are not treated the same way IEEE 754 does */
2965 if (unlikely(float64_is_nan(u.d)))
2966 return 0;
2968 return float64_to_uint32(u.d, &env->spe_status);
2971 uint32_t helper_efdctsiz (uint64_t val)
2973 CPU_DoubleU u;
2975 u.ll = val;
2976 /* NaN are not treated the same way IEEE 754 does */
2977 if (unlikely(float64_is_nan(u.d)))
2978 return 0;
2980 return float64_to_int32_round_to_zero(u.d, &env->spe_status);
2983 uint64_t helper_efdctsidz (uint64_t val)
2985 CPU_DoubleU u;
2987 u.ll = val;
2988 /* NaN are not treated the same way IEEE 754 does */
2989 if (unlikely(float64_is_nan(u.d)))
2990 return 0;
2992 return float64_to_int64_round_to_zero(u.d, &env->spe_status);
2995 uint32_t helper_efdctuiz (uint64_t val)
2997 CPU_DoubleU u;
2999 u.ll = val;
3000 /* NaN are not treated the same way IEEE 754 does */
3001 if (unlikely(float64_is_nan(u.d)))
3002 return 0;
3004 return float64_to_uint32_round_to_zero(u.d, &env->spe_status);
3007 uint64_t helper_efdctuidz (uint64_t val)
3009 CPU_DoubleU u;
3011 u.ll = val;
3012 /* NaN are not treated the same way IEEE 754 does */
3013 if (unlikely(float64_is_nan(u.d)))
3014 return 0;
3016 return float64_to_uint64_round_to_zero(u.d, &env->spe_status);
3019 uint64_t helper_efdcfsf (uint32_t val)
3021 CPU_DoubleU u;
3022 float64 tmp;
3024 u.d = int32_to_float64(val, &env->spe_status);
3025 tmp = int64_to_float64(1ULL << 32, &env->spe_status);
3026 u.d = float64_div(u.d, tmp, &env->spe_status);
3028 return u.ll;
3031 uint64_t helper_efdcfuf (uint32_t val)
3033 CPU_DoubleU u;
3034 float64 tmp;
3036 u.d = uint32_to_float64(val, &env->spe_status);
3037 tmp = int64_to_float64(1ULL << 32, &env->spe_status);
3038 u.d = float64_div(u.d, tmp, &env->spe_status);
3040 return u.ll;
3043 uint32_t helper_efdctsf (uint64_t val)
3045 CPU_DoubleU u;
3046 float64 tmp;
3048 u.ll = val;
3049 /* NaN are not treated the same way IEEE 754 does */
3050 if (unlikely(float64_is_nan(u.d)))
3051 return 0;
3052 tmp = uint64_to_float64(1ULL << 32, &env->spe_status);
3053 u.d = float64_mul(u.d, tmp, &env->spe_status);
3055 return float64_to_int32(u.d, &env->spe_status);
3058 uint32_t helper_efdctuf (uint64_t val)
3060 CPU_DoubleU u;
3061 float64 tmp;
3063 u.ll = val;
3064 /* NaN are not treated the same way IEEE 754 does */
3065 if (unlikely(float64_is_nan(u.d)))
3066 return 0;
3067 tmp = uint64_to_float64(1ULL << 32, &env->spe_status);
3068 u.d = float64_mul(u.d, tmp, &env->spe_status);
3070 return float64_to_uint32(u.d, &env->spe_status);
3073 uint32_t helper_efscfd (uint64_t val)
3075 CPU_DoubleU u1;
3076 CPU_FloatU u2;
3078 u1.ll = val;
3079 u2.f = float64_to_float32(u1.d, &env->spe_status);
3081 return u2.l;
3084 uint64_t helper_efdcfs (uint32_t val)
3086 CPU_DoubleU u2;
3087 CPU_FloatU u1;
3089 u1.l = val;
3090 u2.d = float32_to_float64(u1.f, &env->spe_status);
3092 return u2.ll;
3095 /* Double precision fixed-point arithmetic */
3096 uint64_t helper_efdadd (uint64_t op1, uint64_t op2)
3098 CPU_DoubleU u1, u2;
3099 u1.ll = op1;
3100 u2.ll = op2;
3101 u1.d = float64_add(u1.d, u2.d, &env->spe_status);
3102 return u1.ll;
3105 uint64_t helper_efdsub (uint64_t op1, uint64_t op2)
3107 CPU_DoubleU u1, u2;
3108 u1.ll = op1;
3109 u2.ll = op2;
3110 u1.d = float64_sub(u1.d, u2.d, &env->spe_status);
3111 return u1.ll;
3114 uint64_t helper_efdmul (uint64_t op1, uint64_t op2)
3116 CPU_DoubleU u1, u2;
3117 u1.ll = op1;
3118 u2.ll = op2;
3119 u1.d = float64_mul(u1.d, u2.d, &env->spe_status);
3120 return u1.ll;
3123 uint64_t helper_efddiv (uint64_t op1, uint64_t op2)
3125 CPU_DoubleU u1, u2;
3126 u1.ll = op1;
3127 u2.ll = op2;
3128 u1.d = float64_div(u1.d, u2.d, &env->spe_status);
3129 return u1.ll;
3132 /* Double precision floating point helpers */
3133 uint32_t helper_efdtstlt (uint64_t op1, uint64_t op2)
3135 CPU_DoubleU u1, u2;
3136 u1.ll = op1;
3137 u2.ll = op2;
3138 return float64_lt(u1.d, u2.d, &env->spe_status) ? 4 : 0;
3141 uint32_t helper_efdtstgt (uint64_t op1, uint64_t op2)
3143 CPU_DoubleU u1, u2;
3144 u1.ll = op1;
3145 u2.ll = op2;
3146 return float64_le(u1.d, u2.d, &env->spe_status) ? 0 : 4;
3149 uint32_t helper_efdtsteq (uint64_t op1, uint64_t op2)
3151 CPU_DoubleU u1, u2;
3152 u1.ll = op1;
3153 u2.ll = op2;
3154 return float64_eq(u1.d, u2.d, &env->spe_status) ? 4 : 0;
3157 uint32_t helper_efdcmplt (uint64_t op1, uint64_t op2)
3159 /* XXX: TODO: test special values (NaN, infinites, ...) */
3160 return helper_efdtstlt(op1, op2);
3163 uint32_t helper_efdcmpgt (uint64_t op1, uint64_t op2)
3165 /* XXX: TODO: test special values (NaN, infinites, ...) */
3166 return helper_efdtstgt(op1, op2);
3169 uint32_t helper_efdcmpeq (uint64_t op1, uint64_t op2)
3171 /* XXX: TODO: test special values (NaN, infinites, ...) */
3172 return helper_efdtsteq(op1, op2);
3175 /*****************************************************************************/
3176 /* Softmmu support */
3177 #if !defined (CONFIG_USER_ONLY)
3179 #define MMUSUFFIX _mmu
3181 #define SHIFT 0
3182 #include "softmmu_template.h"
3184 #define SHIFT 1
3185 #include "softmmu_template.h"
3187 #define SHIFT 2
3188 #include "softmmu_template.h"
3190 #define SHIFT 3
3191 #include "softmmu_template.h"
3193 /* try to fill the TLB and return an exception if error. If retaddr is
3194 NULL, it means that the function was called in C code (i.e. not
3195 from generated code or from helper.c) */
3196 /* XXX: fix it to restore all registers */
3197 void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
3199 TranslationBlock *tb;
3200 CPUState *saved_env;
3201 unsigned long pc;
3202 int ret;
3204 /* XXX: hack to restore env in all cases, even if not called from
3205 generated code */
3206 saved_env = env;
3207 env = cpu_single_env;
3208 ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
3209 if (unlikely(ret != 0)) {
3210 if (likely(retaddr)) {
3211 /* now we have a real cpu fault */
3212 pc = (unsigned long)retaddr;
3213 tb = tb_find_pc(pc);
3214 if (likely(tb)) {
3215 /* the PC is inside the translated code. It means that we have
3216 a virtual CPU fault */
3217 cpu_restore_state(tb, env, pc, NULL);
3220 helper_raise_exception_err(env->exception_index, env->error_code);
3222 env = saved_env;
3225 /* Segment registers load and store */
3226 target_ulong helper_load_sr (target_ulong sr_num)
3228 return env->sr[sr_num];
3231 void helper_store_sr (target_ulong sr_num, target_ulong val)
3233 ppc_store_sr(env, sr_num, val);
3236 /* SLB management */
3237 #if defined(TARGET_PPC64)
3238 target_ulong helper_load_slb (target_ulong slb_nr)
3240 return ppc_load_slb(env, slb_nr);
3243 void helper_store_slb (target_ulong slb_nr, target_ulong rs)
3245 ppc_store_slb(env, slb_nr, rs);
3248 void helper_slbia (void)
3250 ppc_slb_invalidate_all(env);
3253 void helper_slbie (target_ulong addr)
3255 ppc_slb_invalidate_one(env, addr);
3258 #endif /* defined(TARGET_PPC64) */
3260 /* TLB management */
3261 void helper_tlbia (void)
3263 ppc_tlb_invalidate_all(env);
3266 void helper_tlbie (target_ulong addr)
3268 ppc_tlb_invalidate_one(env, addr);
3271 /* Software driven TLBs management */
3272 /* PowerPC 602/603 software TLB load instructions helpers */
3273 static void do_6xx_tlb (target_ulong new_EPN, int is_code)
3275 target_ulong RPN, CMP, EPN;
3276 int way;
3278 RPN = env->spr[SPR_RPA];
3279 if (is_code) {
3280 CMP = env->spr[SPR_ICMP];
3281 EPN = env->spr[SPR_IMISS];
3282 } else {
3283 CMP = env->spr[SPR_DCMP];
3284 EPN = env->spr[SPR_DMISS];
3286 way = (env->spr[SPR_SRR1] >> 17) & 1;
3287 #if defined (DEBUG_SOFTWARE_TLB)
3288 if (loglevel != 0) {
3289 fprintf(logfile, "%s: EPN " ADDRX " " ADDRX " PTE0 " ADDRX
3290 " PTE1 " ADDRX " way %d\n",
3291 __func__, new_EPN, EPN, CMP, RPN, way);
3293 #endif
3294 /* Store this TLB */
3295 ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
3296 way, is_code, CMP, RPN);
3299 void helper_6xx_tlbd (target_ulong EPN)
3301 do_6xx_tlb(EPN, 0);
3304 void helper_6xx_tlbi (target_ulong EPN)
3306 do_6xx_tlb(EPN, 1);
3309 /* PowerPC 74xx software TLB load instructions helpers */
3310 static void do_74xx_tlb (target_ulong new_EPN, int is_code)
3312 target_ulong RPN, CMP, EPN;
3313 int way;
3315 RPN = env->spr[SPR_PTELO];
3316 CMP = env->spr[SPR_PTEHI];
3317 EPN = env->spr[SPR_TLBMISS] & ~0x3;
3318 way = env->spr[SPR_TLBMISS] & 0x3;
3319 #if defined (DEBUG_SOFTWARE_TLB)
3320 if (loglevel != 0) {
3321 fprintf(logfile, "%s: EPN " ADDRX " " ADDRX " PTE0 " ADDRX
3322 " PTE1 " ADDRX " way %d\n",
3323 __func__, new_EPN, EPN, CMP, RPN, way);
3325 #endif
3326 /* Store this TLB */
3327 ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
3328 way, is_code, CMP, RPN);
3331 void helper_74xx_tlbd (target_ulong EPN)
3333 do_74xx_tlb(EPN, 0);
3336 void helper_74xx_tlbi (target_ulong EPN)
3338 do_74xx_tlb(EPN, 1);
3341 static always_inline target_ulong booke_tlb_to_page_size (int size)
3343 return 1024 << (2 * size);
3346 static always_inline int booke_page_size_to_tlb (target_ulong page_size)
3348 int size;
3350 switch (page_size) {
3351 case 0x00000400UL:
3352 size = 0x0;
3353 break;
3354 case 0x00001000UL:
3355 size = 0x1;
3356 break;
3357 case 0x00004000UL:
3358 size = 0x2;
3359 break;
3360 case 0x00010000UL:
3361 size = 0x3;
3362 break;
3363 case 0x00040000UL:
3364 size = 0x4;
3365 break;
3366 case 0x00100000UL:
3367 size = 0x5;
3368 break;
3369 case 0x00400000UL:
3370 size = 0x6;
3371 break;
3372 case 0x01000000UL:
3373 size = 0x7;
3374 break;
3375 case 0x04000000UL:
3376 size = 0x8;
3377 break;
3378 case 0x10000000UL:
3379 size = 0x9;
3380 break;
3381 case 0x40000000UL:
3382 size = 0xA;
3383 break;
3384 #if defined (TARGET_PPC64)
3385 case 0x000100000000ULL:
3386 size = 0xB;
3387 break;
3388 case 0x000400000000ULL:
3389 size = 0xC;
3390 break;
3391 case 0x001000000000ULL:
3392 size = 0xD;
3393 break;
3394 case 0x004000000000ULL:
3395 size = 0xE;
3396 break;
3397 case 0x010000000000ULL:
3398 size = 0xF;
3399 break;
3400 #endif
3401 default:
3402 size = -1;
3403 break;
3406 return size;
3409 /* Helpers for 4xx TLB management */
3410 target_ulong helper_4xx_tlbre_lo (target_ulong entry)
3412 ppcemb_tlb_t *tlb;
3413 target_ulong ret;
3414 int size;
3416 entry &= 0x3F;
3417 tlb = &env->tlb[entry].tlbe;
3418 ret = tlb->EPN;
3419 if (tlb->prot & PAGE_VALID)
3420 ret |= 0x400;
3421 size = booke_page_size_to_tlb(tlb->size);
3422 if (size < 0 || size > 0x7)
3423 size = 1;
3424 ret |= size << 7;
3425 env->spr[SPR_40x_PID] = tlb->PID;
3426 return ret;
3429 target_ulong helper_4xx_tlbre_hi (target_ulong entry)
3431 ppcemb_tlb_t *tlb;
3432 target_ulong ret;
3434 entry &= 0x3F;
3435 tlb = &env->tlb[entry].tlbe;
3436 ret = tlb->RPN;
3437 if (tlb->prot & PAGE_EXEC)
3438 ret |= 0x200;
3439 if (tlb->prot & PAGE_WRITE)
3440 ret |= 0x100;
3441 return ret;
3444 void helper_4xx_tlbwe_hi (target_ulong entry, target_ulong val)
3446 ppcemb_tlb_t *tlb;
3447 target_ulong page, end;
3449 #if defined (DEBUG_SOFTWARE_TLB)
3450 if (loglevel != 0) {
3451 fprintf(logfile, "%s entry %d val " ADDRX "\n", __func__, (int)entry, val);
3453 #endif
3454 entry &= 0x3F;
3455 tlb = &env->tlb[entry].tlbe;
3456 /* Invalidate previous TLB (if it's valid) */
3457 if (tlb->prot & PAGE_VALID) {
3458 end = tlb->EPN + tlb->size;
3459 #if defined (DEBUG_SOFTWARE_TLB)
3460 if (loglevel != 0) {
3461 fprintf(logfile, "%s: invalidate old TLB %d start " ADDRX
3462 " end " ADDRX "\n", __func__, (int)entry, tlb->EPN, end);
3464 #endif
3465 for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE)
3466 tlb_flush_page(env, page);
3468 tlb->size = booke_tlb_to_page_size((val >> 7) & 0x7);
3469 /* We cannot handle TLB size < TARGET_PAGE_SIZE.
3470 * If this ever occurs, one should use the ppcemb target instead
3471 * of the ppc or ppc64 one
3473 if ((val & 0x40) && tlb->size < TARGET_PAGE_SIZE) {
3474 cpu_abort(env, "TLB size " TARGET_FMT_lu " < %u "
3475 "are not supported (%d)\n",
3476 tlb->size, TARGET_PAGE_SIZE, (int)((val >> 7) & 0x7));
3478 tlb->EPN = val & ~(tlb->size - 1);
3479 if (val & 0x40)
3480 tlb->prot |= PAGE_VALID;
3481 else
3482 tlb->prot &= ~PAGE_VALID;
3483 if (val & 0x20) {
3484 /* XXX: TO BE FIXED */
3485 cpu_abort(env, "Little-endian TLB entries are not supported by now\n");
3487 tlb->PID = env->spr[SPR_40x_PID]; /* PID */
3488 tlb->attr = val & 0xFF;
3489 #if defined (DEBUG_SOFTWARE_TLB)
3490 if (loglevel != 0) {
3491 fprintf(logfile, "%s: set up TLB %d RPN " PADDRX " EPN " ADDRX
3492 " size " ADDRX " prot %c%c%c%c PID %d\n", __func__,
3493 (int)entry, tlb->RPN, tlb->EPN, tlb->size,
3494 tlb->prot & PAGE_READ ? 'r' : '-',
3495 tlb->prot & PAGE_WRITE ? 'w' : '-',
3496 tlb->prot & PAGE_EXEC ? 'x' : '-',
3497 tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
3499 #endif
3500 /* Invalidate new TLB (if valid) */
3501 if (tlb->prot & PAGE_VALID) {
3502 end = tlb->EPN + tlb->size;
3503 #if defined (DEBUG_SOFTWARE_TLB)
3504 if (loglevel != 0) {
3505 fprintf(logfile, "%s: invalidate TLB %d start " ADDRX
3506 " end " ADDRX "\n", __func__, (int)entry, tlb->EPN, end);
3508 #endif
3509 for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE)
3510 tlb_flush_page(env, page);
3514 void helper_4xx_tlbwe_lo (target_ulong entry, target_ulong val)
3516 ppcemb_tlb_t *tlb;
3518 #if defined (DEBUG_SOFTWARE_TLB)
3519 if (loglevel != 0) {
3520 fprintf(logfile, "%s entry %i val " ADDRX "\n", __func__, (int)entry, val);
3522 #endif
3523 entry &= 0x3F;
3524 tlb = &env->tlb[entry].tlbe;
3525 tlb->RPN = val & 0xFFFFFC00;
3526 tlb->prot = PAGE_READ;
3527 if (val & 0x200)
3528 tlb->prot |= PAGE_EXEC;
3529 if (val & 0x100)
3530 tlb->prot |= PAGE_WRITE;
3531 #if defined (DEBUG_SOFTWARE_TLB)
3532 if (loglevel != 0) {
3533 fprintf(logfile, "%s: set up TLB %d RPN " PADDRX " EPN " ADDRX
3534 " size " ADDRX " prot %c%c%c%c PID %d\n", __func__,
3535 (int)entry, tlb->RPN, tlb->EPN, tlb->size,
3536 tlb->prot & PAGE_READ ? 'r' : '-',
3537 tlb->prot & PAGE_WRITE ? 'w' : '-',
3538 tlb->prot & PAGE_EXEC ? 'x' : '-',
3539 tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
3541 #endif
3544 target_ulong helper_4xx_tlbsx (target_ulong address)
3546 return ppcemb_tlb_search(env, address, env->spr[SPR_40x_PID]);
3549 /* PowerPC 440 TLB management */
3550 void helper_440_tlbwe (uint32_t word, target_ulong entry, target_ulong value)
3552 ppcemb_tlb_t *tlb;
3553 target_ulong EPN, RPN, size;
3554 int do_flush_tlbs;
3556 #if defined (DEBUG_SOFTWARE_TLB)
3557 if (loglevel != 0) {
3558 fprintf(logfile, "%s word %d entry %d value " ADDRX "\n",
3559 __func__, word, (int)entry, value);
3561 #endif
3562 do_flush_tlbs = 0;
3563 entry &= 0x3F;
3564 tlb = &env->tlb[entry].tlbe;
3565 switch (word) {
3566 default:
3567 /* Just here to please gcc */
3568 case 0:
3569 EPN = value & 0xFFFFFC00;
3570 if ((tlb->prot & PAGE_VALID) && EPN != tlb->EPN)
3571 do_flush_tlbs = 1;
3572 tlb->EPN = EPN;
3573 size = booke_tlb_to_page_size((value >> 4) & 0xF);
3574 if ((tlb->prot & PAGE_VALID) && tlb->size < size)
3575 do_flush_tlbs = 1;
3576 tlb->size = size;
3577 tlb->attr &= ~0x1;
3578 tlb->attr |= (value >> 8) & 1;
3579 if (value & 0x200) {
3580 tlb->prot |= PAGE_VALID;
3581 } else {
3582 if (tlb->prot & PAGE_VALID) {
3583 tlb->prot &= ~PAGE_VALID;
3584 do_flush_tlbs = 1;
3587 tlb->PID = env->spr[SPR_440_MMUCR] & 0x000000FF;
3588 if (do_flush_tlbs)
3589 tlb_flush(env, 1);
3590 break;
3591 case 1:
3592 RPN = value & 0xFFFFFC0F;
3593 if ((tlb->prot & PAGE_VALID) && tlb->RPN != RPN)
3594 tlb_flush(env, 1);
3595 tlb->RPN = RPN;
3596 break;
3597 case 2:
3598 tlb->attr = (tlb->attr & 0x1) | (value & 0x0000FF00);
3599 tlb->prot = tlb->prot & PAGE_VALID;
3600 if (value & 0x1)
3601 tlb->prot |= PAGE_READ << 4;
3602 if (value & 0x2)
3603 tlb->prot |= PAGE_WRITE << 4;
3604 if (value & 0x4)
3605 tlb->prot |= PAGE_EXEC << 4;
3606 if (value & 0x8)
3607 tlb->prot |= PAGE_READ;
3608 if (value & 0x10)
3609 tlb->prot |= PAGE_WRITE;
3610 if (value & 0x20)
3611 tlb->prot |= PAGE_EXEC;
3612 break;
3616 target_ulong helper_440_tlbre (uint32_t word, target_ulong entry)
3618 ppcemb_tlb_t *tlb;
3619 target_ulong ret;
3620 int size;
3622 entry &= 0x3F;
3623 tlb = &env->tlb[entry].tlbe;
3624 switch (word) {
3625 default:
3626 /* Just here to please gcc */
3627 case 0:
3628 ret = tlb->EPN;
3629 size = booke_page_size_to_tlb(tlb->size);
3630 if (size < 0 || size > 0xF)
3631 size = 1;
3632 ret |= size << 4;
3633 if (tlb->attr & 0x1)
3634 ret |= 0x100;
3635 if (tlb->prot & PAGE_VALID)
3636 ret |= 0x200;
3637 env->spr[SPR_440_MMUCR] &= ~0x000000FF;
3638 env->spr[SPR_440_MMUCR] |= tlb->PID;
3639 break;
3640 case 1:
3641 ret = tlb->RPN;
3642 break;
3643 case 2:
3644 ret = tlb->attr & ~0x1;
3645 if (tlb->prot & (PAGE_READ << 4))
3646 ret |= 0x1;
3647 if (tlb->prot & (PAGE_WRITE << 4))
3648 ret |= 0x2;
3649 if (tlb->prot & (PAGE_EXEC << 4))
3650 ret |= 0x4;
3651 if (tlb->prot & PAGE_READ)
3652 ret |= 0x8;
3653 if (tlb->prot & PAGE_WRITE)
3654 ret |= 0x10;
3655 if (tlb->prot & PAGE_EXEC)
3656 ret |= 0x20;
3657 break;
3659 return ret;
3662 target_ulong helper_440_tlbsx (target_ulong address)
3664 return ppcemb_tlb_search(env, address, env->spr[SPR_440_MMUCR] & 0xFF);
3667 #endif /* !CONFIG_USER_ONLY */