Add vrfi{m,n,p,z} instructions
[qemu/mini2440.git] / target-ppc / op_helper.c
blob1fca5d6a58e325149ad86822d42533cd42f3695a
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 #ifdef DEBUG_SOFTWARE_TLB
32 # define LOG_SWTLB(...) qemu_log(__VA_ARGS__)
33 #else
34 # define LOG_SWTLB(...) do { } while (0)
35 #endif
38 /*****************************************************************************/
39 /* Exceptions processing helpers */
41 void helper_raise_exception_err (uint32_t exception, uint32_t error_code)
43 #if 0
44 printf("Raise exception %3x code : %d\n", exception, error_code);
45 #endif
46 env->exception_index = exception;
47 env->error_code = error_code;
48 cpu_loop_exit();
51 void helper_raise_exception (uint32_t exception)
53 helper_raise_exception_err(exception, 0);
56 /*****************************************************************************/
57 /* Registers load and stores */
58 target_ulong helper_load_cr (void)
60 return (env->crf[0] << 28) |
61 (env->crf[1] << 24) |
62 (env->crf[2] << 20) |
63 (env->crf[3] << 16) |
64 (env->crf[4] << 12) |
65 (env->crf[5] << 8) |
66 (env->crf[6] << 4) |
67 (env->crf[7] << 0);
70 void helper_store_cr (target_ulong val, uint32_t mask)
72 int i, sh;
74 for (i = 0, sh = 7; i < 8; i++, sh--) {
75 if (mask & (1 << sh))
76 env->crf[i] = (val >> (sh * 4)) & 0xFUL;
80 /*****************************************************************************/
81 /* SPR accesses */
82 void helper_load_dump_spr (uint32_t sprn)
84 qemu_log("Read SPR %d %03x => " ADDRX "\n",
85 sprn, sprn, env->spr[sprn]);
88 void helper_store_dump_spr (uint32_t sprn)
90 qemu_log("Write SPR %d %03x <= " ADDRX "\n",
91 sprn, sprn, env->spr[sprn]);
94 target_ulong helper_load_tbl (void)
96 return cpu_ppc_load_tbl(env);
99 target_ulong helper_load_tbu (void)
101 return cpu_ppc_load_tbu(env);
104 target_ulong helper_load_atbl (void)
106 return cpu_ppc_load_atbl(env);
109 target_ulong helper_load_atbu (void)
111 return cpu_ppc_load_atbu(env);
114 target_ulong helper_load_601_rtcl (void)
116 return cpu_ppc601_load_rtcl(env);
119 target_ulong helper_load_601_rtcu (void)
121 return cpu_ppc601_load_rtcu(env);
124 #if !defined(CONFIG_USER_ONLY)
125 #if defined (TARGET_PPC64)
126 void helper_store_asr (target_ulong val)
128 ppc_store_asr(env, val);
130 #endif
132 void helper_store_sdr1 (target_ulong val)
134 ppc_store_sdr1(env, val);
137 void helper_store_tbl (target_ulong val)
139 cpu_ppc_store_tbl(env, val);
142 void helper_store_tbu (target_ulong val)
144 cpu_ppc_store_tbu(env, val);
147 void helper_store_atbl (target_ulong val)
149 cpu_ppc_store_atbl(env, val);
152 void helper_store_atbu (target_ulong val)
154 cpu_ppc_store_atbu(env, val);
157 void helper_store_601_rtcl (target_ulong val)
159 cpu_ppc601_store_rtcl(env, val);
162 void helper_store_601_rtcu (target_ulong val)
164 cpu_ppc601_store_rtcu(env, val);
167 target_ulong helper_load_decr (void)
169 return cpu_ppc_load_decr(env);
172 void helper_store_decr (target_ulong val)
174 cpu_ppc_store_decr(env, val);
177 void helper_store_hid0_601 (target_ulong val)
179 target_ulong hid0;
181 hid0 = env->spr[SPR_HID0];
182 if ((val ^ hid0) & 0x00000008) {
183 /* Change current endianness */
184 env->hflags &= ~(1 << MSR_LE);
185 env->hflags_nmsr &= ~(1 << MSR_LE);
186 env->hflags_nmsr |= (1 << MSR_LE) & (((val >> 3) & 1) << MSR_LE);
187 env->hflags |= env->hflags_nmsr;
188 qemu_log("%s: set endianness to %c => " ADDRX "\n",
189 __func__, val & 0x8 ? 'l' : 'b', env->hflags);
191 env->spr[SPR_HID0] = (uint32_t)val;
194 void helper_store_403_pbr (uint32_t num, target_ulong value)
196 if (likely(env->pb[num] != value)) {
197 env->pb[num] = value;
198 /* Should be optimized */
199 tlb_flush(env, 1);
203 target_ulong helper_load_40x_pit (void)
205 return load_40x_pit(env);
208 void helper_store_40x_pit (target_ulong val)
210 store_40x_pit(env, val);
213 void helper_store_40x_dbcr0 (target_ulong val)
215 store_40x_dbcr0(env, val);
218 void helper_store_40x_sler (target_ulong val)
220 store_40x_sler(env, val);
223 void helper_store_booke_tcr (target_ulong val)
225 store_booke_tcr(env, val);
228 void helper_store_booke_tsr (target_ulong val)
230 store_booke_tsr(env, val);
233 void helper_store_ibatu (uint32_t nr, target_ulong val)
235 ppc_store_ibatu(env, nr, val);
238 void helper_store_ibatl (uint32_t nr, target_ulong val)
240 ppc_store_ibatl(env, nr, val);
243 void helper_store_dbatu (uint32_t nr, target_ulong val)
245 ppc_store_dbatu(env, nr, val);
248 void helper_store_dbatl (uint32_t nr, target_ulong val)
250 ppc_store_dbatl(env, nr, val);
253 void helper_store_601_batl (uint32_t nr, target_ulong val)
255 ppc_store_ibatl_601(env, nr, val);
258 void helper_store_601_batu (uint32_t nr, target_ulong val)
260 ppc_store_ibatu_601(env, nr, val);
262 #endif
264 /*****************************************************************************/
265 /* Memory load and stores */
267 static always_inline target_ulong addr_add(target_ulong addr, target_long arg)
269 #if defined(TARGET_PPC64)
270 if (!msr_sf)
271 return (uint32_t)(addr + arg);
272 else
273 #endif
274 return addr + arg;
277 void helper_lmw (target_ulong addr, uint32_t reg)
279 for (; reg < 32; reg++) {
280 if (msr_le)
281 env->gpr[reg] = bswap32(ldl(addr));
282 else
283 env->gpr[reg] = ldl(addr);
284 addr = addr_add(addr, 4);
288 void helper_stmw (target_ulong addr, uint32_t reg)
290 for (; reg < 32; reg++) {
291 if (msr_le)
292 stl(addr, bswap32((uint32_t)env->gpr[reg]));
293 else
294 stl(addr, (uint32_t)env->gpr[reg]);
295 addr = addr_add(addr, 4);
299 void helper_lsw(target_ulong addr, uint32_t nb, uint32_t reg)
301 int sh;
302 for (; nb > 3; nb -= 4) {
303 env->gpr[reg] = ldl(addr);
304 reg = (reg + 1) % 32;
305 addr = addr_add(addr, 4);
307 if (unlikely(nb > 0)) {
308 env->gpr[reg] = 0;
309 for (sh = 24; nb > 0; nb--, sh -= 8) {
310 env->gpr[reg] |= ldub(addr) << sh;
311 addr = addr_add(addr, 1);
315 /* PPC32 specification says we must generate an exception if
316 * rA is in the range of registers to be loaded.
317 * In an other hand, IBM says this is valid, but rA won't be loaded.
318 * For now, I'll follow the spec...
320 void helper_lswx(target_ulong addr, uint32_t reg, uint32_t ra, uint32_t rb)
322 if (likely(xer_bc != 0)) {
323 if (unlikely((ra != 0 && reg < ra && (reg + xer_bc) > ra) ||
324 (reg < rb && (reg + xer_bc) > rb))) {
325 helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
326 POWERPC_EXCP_INVAL |
327 POWERPC_EXCP_INVAL_LSWX);
328 } else {
329 helper_lsw(addr, xer_bc, reg);
334 void helper_stsw(target_ulong addr, uint32_t nb, uint32_t reg)
336 int sh;
337 for (; nb > 3; nb -= 4) {
338 stl(addr, env->gpr[reg]);
339 reg = (reg + 1) % 32;
340 addr = addr_add(addr, 4);
342 if (unlikely(nb > 0)) {
343 for (sh = 24; nb > 0; nb--, sh -= 8) {
344 stb(addr, (env->gpr[reg] >> sh) & 0xFF);
345 addr = addr_add(addr, 1);
350 static void do_dcbz(target_ulong addr, int dcache_line_size)
352 addr &= ~(dcache_line_size - 1);
353 int i;
354 for (i = 0 ; i < dcache_line_size ; i += 4) {
355 stl(addr + i , 0);
357 if (env->reserve == addr)
358 env->reserve = (target_ulong)-1ULL;
361 void helper_dcbz(target_ulong addr)
363 do_dcbz(addr, env->dcache_line_size);
366 void helper_dcbz_970(target_ulong addr)
368 if (((env->spr[SPR_970_HID5] >> 7) & 0x3) == 1)
369 do_dcbz(addr, 32);
370 else
371 do_dcbz(addr, env->dcache_line_size);
374 void helper_icbi(target_ulong addr)
376 uint32_t tmp;
378 addr &= ~(env->dcache_line_size - 1);
379 /* Invalidate one cache line :
380 * PowerPC specification says this is to be treated like a load
381 * (not a fetch) by the MMU. To be sure it will be so,
382 * do the load "by hand".
384 tmp = ldl(addr);
385 tb_invalidate_page_range(addr, addr + env->icache_line_size);
388 // XXX: to be tested
389 target_ulong helper_lscbx (target_ulong addr, uint32_t reg, uint32_t ra, uint32_t rb)
391 int i, c, d;
392 d = 24;
393 for (i = 0; i < xer_bc; i++) {
394 c = ldub(addr);
395 addr = addr_add(addr, 1);
396 /* ra (if not 0) and rb are never modified */
397 if (likely(reg != rb && (ra == 0 || reg != ra))) {
398 env->gpr[reg] = (env->gpr[reg] & ~(0xFF << d)) | (c << d);
400 if (unlikely(c == xer_cmp))
401 break;
402 if (likely(d != 0)) {
403 d -= 8;
404 } else {
405 d = 24;
406 reg++;
407 reg = reg & 0x1F;
410 return i;
413 /*****************************************************************************/
414 /* Fixed point operations helpers */
415 #if defined(TARGET_PPC64)
417 /* multiply high word */
418 uint64_t helper_mulhd (uint64_t arg1, uint64_t arg2)
420 uint64_t tl, th;
422 muls64(&tl, &th, arg1, arg2);
423 return th;
426 /* multiply high word unsigned */
427 uint64_t helper_mulhdu (uint64_t arg1, uint64_t arg2)
429 uint64_t tl, th;
431 mulu64(&tl, &th, arg1, arg2);
432 return th;
435 uint64_t helper_mulldo (uint64_t arg1, uint64_t arg2)
437 int64_t th;
438 uint64_t tl;
440 muls64(&tl, (uint64_t *)&th, arg1, arg2);
441 /* If th != 0 && th != -1, then we had an overflow */
442 if (likely((uint64_t)(th + 1) <= 1)) {
443 env->xer &= ~(1 << XER_OV);
444 } else {
445 env->xer |= (1 << XER_OV) | (1 << XER_SO);
447 return (int64_t)tl;
449 #endif
451 target_ulong helper_cntlzw (target_ulong t)
453 return clz32(t);
456 #if defined(TARGET_PPC64)
457 target_ulong helper_cntlzd (target_ulong t)
459 return clz64(t);
461 #endif
463 /* shift right arithmetic helper */
464 target_ulong helper_sraw (target_ulong value, target_ulong shift)
466 int32_t ret;
468 if (likely(!(shift & 0x20))) {
469 if (likely((uint32_t)shift != 0)) {
470 shift &= 0x1f;
471 ret = (int32_t)value >> shift;
472 if (likely(ret >= 0 || (value & ((1 << shift) - 1)) == 0)) {
473 env->xer &= ~(1 << XER_CA);
474 } else {
475 env->xer |= (1 << XER_CA);
477 } else {
478 ret = (int32_t)value;
479 env->xer &= ~(1 << XER_CA);
481 } else {
482 ret = (int32_t)value >> 31;
483 if (ret) {
484 env->xer |= (1 << XER_CA);
485 } else {
486 env->xer &= ~(1 << XER_CA);
489 return (target_long)ret;
492 #if defined(TARGET_PPC64)
493 target_ulong helper_srad (target_ulong value, target_ulong shift)
495 int64_t ret;
497 if (likely(!(shift & 0x40))) {
498 if (likely((uint64_t)shift != 0)) {
499 shift &= 0x3f;
500 ret = (int64_t)value >> shift;
501 if (likely(ret >= 0 || (value & ((1 << shift) - 1)) == 0)) {
502 env->xer &= ~(1 << XER_CA);
503 } else {
504 env->xer |= (1 << XER_CA);
506 } else {
507 ret = (int64_t)value;
508 env->xer &= ~(1 << XER_CA);
510 } else {
511 ret = (int64_t)value >> 63;
512 if (ret) {
513 env->xer |= (1 << XER_CA);
514 } else {
515 env->xer &= ~(1 << XER_CA);
518 return ret;
520 #endif
522 target_ulong helper_popcntb (target_ulong val)
524 val = (val & 0x55555555) + ((val >> 1) & 0x55555555);
525 val = (val & 0x33333333) + ((val >> 2) & 0x33333333);
526 val = (val & 0x0f0f0f0f) + ((val >> 4) & 0x0f0f0f0f);
527 return val;
530 #if defined(TARGET_PPC64)
531 target_ulong helper_popcntb_64 (target_ulong val)
533 val = (val & 0x5555555555555555ULL) + ((val >> 1) & 0x5555555555555555ULL);
534 val = (val & 0x3333333333333333ULL) + ((val >> 2) & 0x3333333333333333ULL);
535 val = (val & 0x0f0f0f0f0f0f0f0fULL) + ((val >> 4) & 0x0f0f0f0f0f0f0f0fULL);
536 return val;
538 #endif
540 /*****************************************************************************/
541 /* Floating point operations helpers */
542 uint64_t helper_float32_to_float64(uint32_t arg)
544 CPU_FloatU f;
545 CPU_DoubleU d;
546 f.l = arg;
547 d.d = float32_to_float64(f.f, &env->fp_status);
548 return d.ll;
551 uint32_t helper_float64_to_float32(uint64_t arg)
553 CPU_FloatU f;
554 CPU_DoubleU d;
555 d.ll = arg;
556 f.f = float64_to_float32(d.d, &env->fp_status);
557 return f.l;
560 static always_inline int isden (float64 d)
562 CPU_DoubleU u;
564 u.d = d;
566 return ((u.ll >> 52) & 0x7FF) == 0;
569 uint32_t helper_compute_fprf (uint64_t arg, uint32_t set_fprf)
571 CPU_DoubleU farg;
572 int isneg;
573 int ret;
574 farg.ll = arg;
575 isneg = float64_is_neg(farg.d);
576 if (unlikely(float64_is_nan(farg.d))) {
577 if (float64_is_signaling_nan(farg.d)) {
578 /* Signaling NaN: flags are undefined */
579 ret = 0x00;
580 } else {
581 /* Quiet NaN */
582 ret = 0x11;
584 } else if (unlikely(float64_is_infinity(farg.d))) {
585 /* +/- infinity */
586 if (isneg)
587 ret = 0x09;
588 else
589 ret = 0x05;
590 } else {
591 if (float64_is_zero(farg.d)) {
592 /* +/- zero */
593 if (isneg)
594 ret = 0x12;
595 else
596 ret = 0x02;
597 } else {
598 if (isden(farg.d)) {
599 /* Denormalized numbers */
600 ret = 0x10;
601 } else {
602 /* Normalized numbers */
603 ret = 0x00;
605 if (isneg) {
606 ret |= 0x08;
607 } else {
608 ret |= 0x04;
612 if (set_fprf) {
613 /* We update FPSCR_FPRF */
614 env->fpscr &= ~(0x1F << FPSCR_FPRF);
615 env->fpscr |= ret << FPSCR_FPRF;
617 /* We just need fpcc to update Rc1 */
618 return ret & 0xF;
621 /* Floating-point invalid operations exception */
622 static always_inline uint64_t fload_invalid_op_excp (int op)
624 uint64_t ret = 0;
625 int ve;
627 ve = fpscr_ve;
628 switch (op) {
629 case POWERPC_EXCP_FP_VXSNAN:
630 env->fpscr |= 1 << FPSCR_VXSNAN;
631 break;
632 case POWERPC_EXCP_FP_VXSOFT:
633 env->fpscr |= 1 << FPSCR_VXSOFT;
634 break;
635 case POWERPC_EXCP_FP_VXISI:
636 /* Magnitude subtraction of infinities */
637 env->fpscr |= 1 << FPSCR_VXISI;
638 goto update_arith;
639 case POWERPC_EXCP_FP_VXIDI:
640 /* Division of infinity by infinity */
641 env->fpscr |= 1 << FPSCR_VXIDI;
642 goto update_arith;
643 case POWERPC_EXCP_FP_VXZDZ:
644 /* Division of zero by zero */
645 env->fpscr |= 1 << FPSCR_VXZDZ;
646 goto update_arith;
647 case POWERPC_EXCP_FP_VXIMZ:
648 /* Multiplication of zero by infinity */
649 env->fpscr |= 1 << FPSCR_VXIMZ;
650 goto update_arith;
651 case POWERPC_EXCP_FP_VXVC:
652 /* Ordered comparison of NaN */
653 env->fpscr |= 1 << FPSCR_VXVC;
654 env->fpscr &= ~(0xF << FPSCR_FPCC);
655 env->fpscr |= 0x11 << FPSCR_FPCC;
656 /* We must update the target FPR before raising the exception */
657 if (ve != 0) {
658 env->exception_index = POWERPC_EXCP_PROGRAM;
659 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_VXVC;
660 /* Update the floating-point enabled exception summary */
661 env->fpscr |= 1 << FPSCR_FEX;
662 /* Exception is differed */
663 ve = 0;
665 break;
666 case POWERPC_EXCP_FP_VXSQRT:
667 /* Square root of a negative number */
668 env->fpscr |= 1 << FPSCR_VXSQRT;
669 update_arith:
670 env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
671 if (ve == 0) {
672 /* Set the result to quiet NaN */
673 ret = 0xFFF8000000000000ULL;
674 env->fpscr &= ~(0xF << FPSCR_FPCC);
675 env->fpscr |= 0x11 << FPSCR_FPCC;
677 break;
678 case POWERPC_EXCP_FP_VXCVI:
679 /* Invalid conversion */
680 env->fpscr |= 1 << FPSCR_VXCVI;
681 env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
682 if (ve == 0) {
683 /* Set the result to quiet NaN */
684 ret = 0xFFF8000000000000ULL;
685 env->fpscr &= ~(0xF << FPSCR_FPCC);
686 env->fpscr |= 0x11 << FPSCR_FPCC;
688 break;
690 /* Update the floating-point invalid operation summary */
691 env->fpscr |= 1 << FPSCR_VX;
692 /* Update the floating-point exception summary */
693 env->fpscr |= 1 << FPSCR_FX;
694 if (ve != 0) {
695 /* Update the floating-point enabled exception summary */
696 env->fpscr |= 1 << FPSCR_FEX;
697 if (msr_fe0 != 0 || msr_fe1 != 0)
698 helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_FP | op);
700 return ret;
703 static always_inline void float_zero_divide_excp (void)
705 env->fpscr |= 1 << FPSCR_ZX;
706 env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
707 /* Update the floating-point exception summary */
708 env->fpscr |= 1 << FPSCR_FX;
709 if (fpscr_ze != 0) {
710 /* Update the floating-point enabled exception summary */
711 env->fpscr |= 1 << FPSCR_FEX;
712 if (msr_fe0 != 0 || msr_fe1 != 0) {
713 helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
714 POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX);
719 static always_inline void float_overflow_excp (void)
721 env->fpscr |= 1 << FPSCR_OX;
722 /* Update the floating-point exception summary */
723 env->fpscr |= 1 << FPSCR_FX;
724 if (fpscr_oe != 0) {
725 /* XXX: should adjust the result */
726 /* Update the floating-point enabled exception summary */
727 env->fpscr |= 1 << FPSCR_FEX;
728 /* We must update the target FPR before raising the exception */
729 env->exception_index = POWERPC_EXCP_PROGRAM;
730 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_OX;
731 } else {
732 env->fpscr |= 1 << FPSCR_XX;
733 env->fpscr |= 1 << FPSCR_FI;
737 static always_inline void float_underflow_excp (void)
739 env->fpscr |= 1 << FPSCR_UX;
740 /* Update the floating-point exception summary */
741 env->fpscr |= 1 << FPSCR_FX;
742 if (fpscr_ue != 0) {
743 /* XXX: should adjust the result */
744 /* Update the floating-point enabled exception summary */
745 env->fpscr |= 1 << FPSCR_FEX;
746 /* We must update the target FPR before raising the exception */
747 env->exception_index = POWERPC_EXCP_PROGRAM;
748 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_UX;
752 static always_inline void float_inexact_excp (void)
754 env->fpscr |= 1 << FPSCR_XX;
755 /* Update the floating-point exception summary */
756 env->fpscr |= 1 << FPSCR_FX;
757 if (fpscr_xe != 0) {
758 /* Update the floating-point enabled exception summary */
759 env->fpscr |= 1 << FPSCR_FEX;
760 /* We must update the target FPR before raising the exception */
761 env->exception_index = POWERPC_EXCP_PROGRAM;
762 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_XX;
766 static always_inline void fpscr_set_rounding_mode (void)
768 int rnd_type;
770 /* Set rounding mode */
771 switch (fpscr_rn) {
772 case 0:
773 /* Best approximation (round to nearest) */
774 rnd_type = float_round_nearest_even;
775 break;
776 case 1:
777 /* Smaller magnitude (round toward zero) */
778 rnd_type = float_round_to_zero;
779 break;
780 case 2:
781 /* Round toward +infinite */
782 rnd_type = float_round_up;
783 break;
784 default:
785 case 3:
786 /* Round toward -infinite */
787 rnd_type = float_round_down;
788 break;
790 set_float_rounding_mode(rnd_type, &env->fp_status);
793 void helper_fpscr_clrbit (uint32_t bit)
795 int prev;
797 prev = (env->fpscr >> bit) & 1;
798 env->fpscr &= ~(1 << bit);
799 if (prev == 1) {
800 switch (bit) {
801 case FPSCR_RN1:
802 case FPSCR_RN:
803 fpscr_set_rounding_mode();
804 break;
805 default:
806 break;
811 void helper_fpscr_setbit (uint32_t bit)
813 int prev;
815 prev = (env->fpscr >> bit) & 1;
816 env->fpscr |= 1 << bit;
817 if (prev == 0) {
818 switch (bit) {
819 case FPSCR_VX:
820 env->fpscr |= 1 << FPSCR_FX;
821 if (fpscr_ve)
822 goto raise_ve;
823 case FPSCR_OX:
824 env->fpscr |= 1 << FPSCR_FX;
825 if (fpscr_oe)
826 goto raise_oe;
827 break;
828 case FPSCR_UX:
829 env->fpscr |= 1 << FPSCR_FX;
830 if (fpscr_ue)
831 goto raise_ue;
832 break;
833 case FPSCR_ZX:
834 env->fpscr |= 1 << FPSCR_FX;
835 if (fpscr_ze)
836 goto raise_ze;
837 break;
838 case FPSCR_XX:
839 env->fpscr |= 1 << FPSCR_FX;
840 if (fpscr_xe)
841 goto raise_xe;
842 break;
843 case FPSCR_VXSNAN:
844 case FPSCR_VXISI:
845 case FPSCR_VXIDI:
846 case FPSCR_VXZDZ:
847 case FPSCR_VXIMZ:
848 case FPSCR_VXVC:
849 case FPSCR_VXSOFT:
850 case FPSCR_VXSQRT:
851 case FPSCR_VXCVI:
852 env->fpscr |= 1 << FPSCR_VX;
853 env->fpscr |= 1 << FPSCR_FX;
854 if (fpscr_ve != 0)
855 goto raise_ve;
856 break;
857 case FPSCR_VE:
858 if (fpscr_vx != 0) {
859 raise_ve:
860 env->error_code = POWERPC_EXCP_FP;
861 if (fpscr_vxsnan)
862 env->error_code |= POWERPC_EXCP_FP_VXSNAN;
863 if (fpscr_vxisi)
864 env->error_code |= POWERPC_EXCP_FP_VXISI;
865 if (fpscr_vxidi)
866 env->error_code |= POWERPC_EXCP_FP_VXIDI;
867 if (fpscr_vxzdz)
868 env->error_code |= POWERPC_EXCP_FP_VXZDZ;
869 if (fpscr_vximz)
870 env->error_code |= POWERPC_EXCP_FP_VXIMZ;
871 if (fpscr_vxvc)
872 env->error_code |= POWERPC_EXCP_FP_VXVC;
873 if (fpscr_vxsoft)
874 env->error_code |= POWERPC_EXCP_FP_VXSOFT;
875 if (fpscr_vxsqrt)
876 env->error_code |= POWERPC_EXCP_FP_VXSQRT;
877 if (fpscr_vxcvi)
878 env->error_code |= POWERPC_EXCP_FP_VXCVI;
879 goto raise_excp;
881 break;
882 case FPSCR_OE:
883 if (fpscr_ox != 0) {
884 raise_oe:
885 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_OX;
886 goto raise_excp;
888 break;
889 case FPSCR_UE:
890 if (fpscr_ux != 0) {
891 raise_ue:
892 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_UX;
893 goto raise_excp;
895 break;
896 case FPSCR_ZE:
897 if (fpscr_zx != 0) {
898 raise_ze:
899 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX;
900 goto raise_excp;
902 break;
903 case FPSCR_XE:
904 if (fpscr_xx != 0) {
905 raise_xe:
906 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_XX;
907 goto raise_excp;
909 break;
910 case FPSCR_RN1:
911 case FPSCR_RN:
912 fpscr_set_rounding_mode();
913 break;
914 default:
915 break;
916 raise_excp:
917 /* Update the floating-point enabled exception summary */
918 env->fpscr |= 1 << FPSCR_FEX;
919 /* We have to update Rc1 before raising the exception */
920 env->exception_index = POWERPC_EXCP_PROGRAM;
921 break;
926 void helper_store_fpscr (uint64_t arg, uint32_t mask)
929 * We use only the 32 LSB of the incoming fpr
931 uint32_t prev, new;
932 int i;
934 prev = env->fpscr;
935 new = (uint32_t)arg;
936 new &= ~0x60000000;
937 new |= prev & 0x60000000;
938 for (i = 0; i < 8; i++) {
939 if (mask & (1 << i)) {
940 env->fpscr &= ~(0xF << (4 * i));
941 env->fpscr |= new & (0xF << (4 * i));
944 /* Update VX and FEX */
945 if (fpscr_ix != 0)
946 env->fpscr |= 1 << FPSCR_VX;
947 else
948 env->fpscr &= ~(1 << FPSCR_VX);
949 if ((fpscr_ex & fpscr_eex) != 0) {
950 env->fpscr |= 1 << FPSCR_FEX;
951 env->exception_index = POWERPC_EXCP_PROGRAM;
952 /* XXX: we should compute it properly */
953 env->error_code = POWERPC_EXCP_FP;
955 else
956 env->fpscr &= ~(1 << FPSCR_FEX);
957 fpscr_set_rounding_mode();
960 void helper_float_check_status (void)
962 #ifdef CONFIG_SOFTFLOAT
963 if (env->exception_index == POWERPC_EXCP_PROGRAM &&
964 (env->error_code & POWERPC_EXCP_FP)) {
965 /* Differred floating-point exception after target FPR update */
966 if (msr_fe0 != 0 || msr_fe1 != 0)
967 helper_raise_exception_err(env->exception_index, env->error_code);
968 } else {
969 int status = get_float_exception_flags(&env->fp_status);
970 if (status & float_flag_divbyzero) {
971 float_zero_divide_excp();
972 } else if (status & float_flag_overflow) {
973 float_overflow_excp();
974 } else if (status & float_flag_underflow) {
975 float_underflow_excp();
976 } else if (status & float_flag_inexact) {
977 float_inexact_excp();
980 #else
981 if (env->exception_index == POWERPC_EXCP_PROGRAM &&
982 (env->error_code & POWERPC_EXCP_FP)) {
983 /* Differred floating-point exception after target FPR update */
984 if (msr_fe0 != 0 || msr_fe1 != 0)
985 helper_raise_exception_err(env->exception_index, env->error_code);
987 #endif
990 #ifdef CONFIG_SOFTFLOAT
991 void helper_reset_fpstatus (void)
993 set_float_exception_flags(0, &env->fp_status);
995 #endif
997 /* fadd - fadd. */
998 uint64_t helper_fadd (uint64_t arg1, uint64_t arg2)
1000 CPU_DoubleU farg1, farg2;
1002 farg1.ll = arg1;
1003 farg2.ll = arg2;
1004 #if USE_PRECISE_EMULATION
1005 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1006 float64_is_signaling_nan(farg2.d))) {
1007 /* sNaN addition */
1008 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1009 } else if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d) &&
1010 float64_is_neg(farg1.d) != float64_is_neg(farg2.d))) {
1011 /* Magnitude subtraction of infinities */
1012 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
1013 } else {
1014 farg1.d = float64_add(farg1.d, farg2.d, &env->fp_status);
1016 #else
1017 farg1.d = float64_add(farg1.d, farg2.d, &env->fp_status);
1018 #endif
1019 return farg1.ll;
1022 /* fsub - fsub. */
1023 uint64_t helper_fsub (uint64_t arg1, uint64_t arg2)
1025 CPU_DoubleU farg1, farg2;
1027 farg1.ll = arg1;
1028 farg2.ll = arg2;
1029 #if USE_PRECISE_EMULATION
1031 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1032 float64_is_signaling_nan(farg2.d))) {
1033 /* sNaN subtraction */
1034 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1035 } else if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d) &&
1036 float64_is_neg(farg1.d) == float64_is_neg(farg2.d))) {
1037 /* Magnitude subtraction of infinities */
1038 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
1039 } else {
1040 farg1.d = float64_sub(farg1.d, farg2.d, &env->fp_status);
1043 #else
1044 farg1.d = float64_sub(farg1.d, farg2.d, &env->fp_status);
1045 #endif
1046 return farg1.ll;
1049 /* fmul - fmul. */
1050 uint64_t helper_fmul (uint64_t arg1, uint64_t arg2)
1052 CPU_DoubleU farg1, farg2;
1054 farg1.ll = arg1;
1055 farg2.ll = arg2;
1056 #if USE_PRECISE_EMULATION
1057 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1058 float64_is_signaling_nan(farg2.d))) {
1059 /* sNaN multiplication */
1060 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1061 } else if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
1062 (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
1063 /* Multiplication of zero by infinity */
1064 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
1065 } else {
1066 farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
1068 #else
1069 farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
1070 #endif
1071 return farg1.ll;
1074 /* fdiv - fdiv. */
1075 uint64_t helper_fdiv (uint64_t arg1, uint64_t arg2)
1077 CPU_DoubleU farg1, farg2;
1079 farg1.ll = arg1;
1080 farg2.ll = arg2;
1081 #if USE_PRECISE_EMULATION
1082 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1083 float64_is_signaling_nan(farg2.d))) {
1084 /* sNaN division */
1085 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1086 } else if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d))) {
1087 /* Division of infinity by infinity */
1088 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIDI);
1089 } else if (unlikely(float64_is_zero(farg1.d) && float64_is_zero(farg2.d))) {
1090 /* Division of zero by zero */
1091 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXZDZ);
1092 } else {
1093 farg1.d = float64_div(farg1.d, farg2.d, &env->fp_status);
1095 #else
1096 farg1.d = float64_div(farg1.d, farg2.d, &env->fp_status);
1097 #endif
1098 return farg1.ll;
1101 /* fabs */
1102 uint64_t helper_fabs (uint64_t arg)
1104 CPU_DoubleU farg;
1106 farg.ll = arg;
1107 farg.d = float64_abs(farg.d);
1108 return farg.ll;
1111 /* fnabs */
1112 uint64_t helper_fnabs (uint64_t arg)
1114 CPU_DoubleU farg;
1116 farg.ll = arg;
1117 farg.d = float64_abs(farg.d);
1118 farg.d = float64_chs(farg.d);
1119 return farg.ll;
1122 /* fneg */
1123 uint64_t helper_fneg (uint64_t arg)
1125 CPU_DoubleU farg;
1127 farg.ll = arg;
1128 farg.d = float64_chs(farg.d);
1129 return farg.ll;
1132 /* fctiw - fctiw. */
1133 uint64_t helper_fctiw (uint64_t arg)
1135 CPU_DoubleU farg;
1136 farg.ll = arg;
1138 if (unlikely(float64_is_signaling_nan(farg.d))) {
1139 /* sNaN conversion */
1140 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
1141 } else if (unlikely(float64_is_nan(farg.d) || float64_is_infinity(farg.d))) {
1142 /* qNan / infinity conversion */
1143 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
1144 } else {
1145 farg.ll = float64_to_int32(farg.d, &env->fp_status);
1146 #if USE_PRECISE_EMULATION
1147 /* XXX: higher bits are not supposed to be significant.
1148 * to make tests easier, return the same as a real PowerPC 750
1150 farg.ll |= 0xFFF80000ULL << 32;
1151 #endif
1153 return farg.ll;
1156 /* fctiwz - fctiwz. */
1157 uint64_t helper_fctiwz (uint64_t arg)
1159 CPU_DoubleU farg;
1160 farg.ll = arg;
1162 if (unlikely(float64_is_signaling_nan(farg.d))) {
1163 /* sNaN conversion */
1164 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
1165 } else if (unlikely(float64_is_nan(farg.d) || float64_is_infinity(farg.d))) {
1166 /* qNan / infinity conversion */
1167 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
1168 } else {
1169 farg.ll = float64_to_int32_round_to_zero(farg.d, &env->fp_status);
1170 #if USE_PRECISE_EMULATION
1171 /* XXX: higher bits are not supposed to be significant.
1172 * to make tests easier, return the same as a real PowerPC 750
1174 farg.ll |= 0xFFF80000ULL << 32;
1175 #endif
1177 return farg.ll;
1180 #if defined(TARGET_PPC64)
1181 /* fcfid - fcfid. */
1182 uint64_t helper_fcfid (uint64_t arg)
1184 CPU_DoubleU farg;
1185 farg.d = int64_to_float64(arg, &env->fp_status);
1186 return farg.ll;
1189 /* fctid - fctid. */
1190 uint64_t helper_fctid (uint64_t arg)
1192 CPU_DoubleU farg;
1193 farg.ll = arg;
1195 if (unlikely(float64_is_signaling_nan(farg.d))) {
1196 /* sNaN conversion */
1197 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
1198 } else if (unlikely(float64_is_nan(farg.d) || float64_is_infinity(farg.d))) {
1199 /* qNan / infinity conversion */
1200 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
1201 } else {
1202 farg.ll = float64_to_int64(farg.d, &env->fp_status);
1204 return farg.ll;
1207 /* fctidz - fctidz. */
1208 uint64_t helper_fctidz (uint64_t arg)
1210 CPU_DoubleU farg;
1211 farg.ll = arg;
1213 if (unlikely(float64_is_signaling_nan(farg.d))) {
1214 /* sNaN conversion */
1215 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
1216 } else if (unlikely(float64_is_nan(farg.d) || float64_is_infinity(farg.d))) {
1217 /* qNan / infinity conversion */
1218 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
1219 } else {
1220 farg.ll = float64_to_int64_round_to_zero(farg.d, &env->fp_status);
1222 return farg.ll;
1225 #endif
1227 static always_inline uint64_t do_fri (uint64_t arg, int rounding_mode)
1229 CPU_DoubleU farg;
1230 farg.ll = arg;
1232 if (unlikely(float64_is_signaling_nan(farg.d))) {
1233 /* sNaN round */
1234 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
1235 } else if (unlikely(float64_is_nan(farg.d) || float64_is_infinity(farg.d))) {
1236 /* qNan / infinity round */
1237 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
1238 } else {
1239 set_float_rounding_mode(rounding_mode, &env->fp_status);
1240 farg.ll = float64_round_to_int(farg.d, &env->fp_status);
1241 /* Restore rounding mode from FPSCR */
1242 fpscr_set_rounding_mode();
1244 return farg.ll;
1247 uint64_t helper_frin (uint64_t arg)
1249 return do_fri(arg, float_round_nearest_even);
1252 uint64_t helper_friz (uint64_t arg)
1254 return do_fri(arg, float_round_to_zero);
1257 uint64_t helper_frip (uint64_t arg)
1259 return do_fri(arg, float_round_up);
1262 uint64_t helper_frim (uint64_t arg)
1264 return do_fri(arg, float_round_down);
1267 /* fmadd - fmadd. */
1268 uint64_t helper_fmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3)
1270 CPU_DoubleU farg1, farg2, farg3;
1272 farg1.ll = arg1;
1273 farg2.ll = arg2;
1274 farg3.ll = arg3;
1275 #if USE_PRECISE_EMULATION
1276 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1277 float64_is_signaling_nan(farg2.d) ||
1278 float64_is_signaling_nan(farg3.d))) {
1279 /* sNaN operation */
1280 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1281 } else if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
1282 (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
1283 /* Multiplication of zero by infinity */
1284 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
1285 } else {
1286 #ifdef FLOAT128
1287 /* This is the way the PowerPC specification defines it */
1288 float128 ft0_128, ft1_128;
1290 ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
1291 ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
1292 ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
1293 if (unlikely(float128_is_infinity(ft0_128) && float64_is_infinity(farg3.d) &&
1294 float128_is_neg(ft0_128) != float64_is_neg(farg3.d))) {
1295 /* Magnitude subtraction of infinities */
1296 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
1297 } else {
1298 ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
1299 ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
1300 farg1.d = float128_to_float64(ft0_128, &env->fp_status);
1302 #else
1303 /* This is OK on x86 hosts */
1304 farg1.d = (farg1.d * farg2.d) + farg3.d;
1305 #endif
1307 #else
1308 farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
1309 farg1.d = float64_add(farg1.d, farg3.d, &env->fp_status);
1310 #endif
1311 return farg1.ll;
1314 /* fmsub - fmsub. */
1315 uint64_t helper_fmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3)
1317 CPU_DoubleU farg1, farg2, farg3;
1319 farg1.ll = arg1;
1320 farg2.ll = arg2;
1321 farg3.ll = arg3;
1322 #if USE_PRECISE_EMULATION
1323 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1324 float64_is_signaling_nan(farg2.d) ||
1325 float64_is_signaling_nan(farg3.d))) {
1326 /* sNaN operation */
1327 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1328 } else if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
1329 (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
1330 /* Multiplication of zero by infinity */
1331 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
1332 } else {
1333 #ifdef FLOAT128
1334 /* This is the way the PowerPC specification defines it */
1335 float128 ft0_128, ft1_128;
1337 ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
1338 ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
1339 ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
1340 if (unlikely(float128_is_infinity(ft0_128) && float64_is_infinity(farg3.d) &&
1341 float128_is_neg(ft0_128) == float64_is_neg(farg3.d))) {
1342 /* Magnitude subtraction of infinities */
1343 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
1344 } else {
1345 ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
1346 ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
1347 farg1.d = float128_to_float64(ft0_128, &env->fp_status);
1349 #else
1350 /* This is OK on x86 hosts */
1351 farg1.d = (farg1.d * farg2.d) - farg3.d;
1352 #endif
1354 #else
1355 farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
1356 farg1.d = float64_sub(farg1.d, farg3.d, &env->fp_status);
1357 #endif
1358 return farg1.ll;
1361 /* fnmadd - fnmadd. */
1362 uint64_t helper_fnmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3)
1364 CPU_DoubleU farg1, farg2, farg3;
1366 farg1.ll = arg1;
1367 farg2.ll = arg2;
1368 farg3.ll = arg3;
1370 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1371 float64_is_signaling_nan(farg2.d) ||
1372 float64_is_signaling_nan(farg3.d))) {
1373 /* sNaN operation */
1374 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1375 } else if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
1376 (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
1377 /* Multiplication of zero by infinity */
1378 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
1379 } else {
1380 #if USE_PRECISE_EMULATION
1381 #ifdef FLOAT128
1382 /* This is the way the PowerPC specification defines it */
1383 float128 ft0_128, ft1_128;
1385 ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
1386 ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
1387 ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
1388 if (unlikely(float128_is_infinity(ft0_128) && float64_is_infinity(farg3.d) &&
1389 float128_is_neg(ft0_128) != float64_is_neg(farg3.d))) {
1390 /* Magnitude subtraction of infinities */
1391 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
1392 } else {
1393 ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
1394 ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
1395 farg1.d = float128_to_float64(ft0_128, &env->fp_status);
1397 #else
1398 /* This is OK on x86 hosts */
1399 farg1.d = (farg1.d * farg2.d) + farg3.d;
1400 #endif
1401 #else
1402 farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
1403 farg1.d = float64_add(farg1.d, farg3.d, &env->fp_status);
1404 #endif
1405 if (likely(!float64_is_nan(farg1.d)))
1406 farg1.d = float64_chs(farg1.d);
1408 return farg1.ll;
1411 /* fnmsub - fnmsub. */
1412 uint64_t helper_fnmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3)
1414 CPU_DoubleU farg1, farg2, farg3;
1416 farg1.ll = arg1;
1417 farg2.ll = arg2;
1418 farg3.ll = arg3;
1420 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1421 float64_is_signaling_nan(farg2.d) ||
1422 float64_is_signaling_nan(farg3.d))) {
1423 /* sNaN operation */
1424 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1425 } else if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
1426 (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
1427 /* Multiplication of zero by infinity */
1428 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
1429 } else {
1430 #if USE_PRECISE_EMULATION
1431 #ifdef FLOAT128
1432 /* This is the way the PowerPC specification defines it */
1433 float128 ft0_128, ft1_128;
1435 ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
1436 ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
1437 ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
1438 if (unlikely(float128_is_infinity(ft0_128) && float64_is_infinity(farg3.d) &&
1439 float128_is_neg(ft0_128) == float64_is_neg(farg3.d))) {
1440 /* Magnitude subtraction of infinities */
1441 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
1442 } else {
1443 ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
1444 ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
1445 farg1.d = float128_to_float64(ft0_128, &env->fp_status);
1447 #else
1448 /* This is OK on x86 hosts */
1449 farg1.d = (farg1.d * farg2.d) - farg3.d;
1450 #endif
1451 #else
1452 farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
1453 farg1.d = float64_sub(farg1.d, farg3.d, &env->fp_status);
1454 #endif
1455 if (likely(!float64_is_nan(farg1.d)))
1456 farg1.d = float64_chs(farg1.d);
1458 return farg1.ll;
1461 /* frsp - frsp. */
1462 uint64_t helper_frsp (uint64_t arg)
1464 CPU_DoubleU farg;
1465 float32 f32;
1466 farg.ll = arg;
1468 #if USE_PRECISE_EMULATION
1469 if (unlikely(float64_is_signaling_nan(farg.d))) {
1470 /* sNaN square root */
1471 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1472 } else {
1473 f32 = float64_to_float32(farg.d, &env->fp_status);
1474 farg.d = float32_to_float64(f32, &env->fp_status);
1476 #else
1477 f32 = float64_to_float32(farg.d, &env->fp_status);
1478 farg.d = float32_to_float64(f32, &env->fp_status);
1479 #endif
1480 return farg.ll;
1483 /* fsqrt - fsqrt. */
1484 uint64_t helper_fsqrt (uint64_t arg)
1486 CPU_DoubleU farg;
1487 farg.ll = arg;
1489 if (unlikely(float64_is_signaling_nan(farg.d))) {
1490 /* sNaN square root */
1491 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1492 } else if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) {
1493 /* Square root of a negative nonzero number */
1494 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSQRT);
1495 } else {
1496 farg.d = float64_sqrt(farg.d, &env->fp_status);
1498 return farg.ll;
1501 /* fre - fre. */
1502 uint64_t helper_fre (uint64_t arg)
1504 CPU_DoubleU fone, farg;
1505 fone.ll = 0x3FF0000000000000ULL; /* 1.0 */
1506 farg.ll = arg;
1508 if (unlikely(float64_is_signaling_nan(farg.d))) {
1509 /* sNaN reciprocal */
1510 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1511 } else {
1512 farg.d = float64_div(fone.d, farg.d, &env->fp_status);
1514 return farg.d;
1517 /* fres - fres. */
1518 uint64_t helper_fres (uint64_t arg)
1520 CPU_DoubleU fone, farg;
1521 float32 f32;
1522 fone.ll = 0x3FF0000000000000ULL; /* 1.0 */
1523 farg.ll = arg;
1525 if (unlikely(float64_is_signaling_nan(farg.d))) {
1526 /* sNaN reciprocal */
1527 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1528 } else {
1529 farg.d = float64_div(fone.d, farg.d, &env->fp_status);
1530 f32 = float64_to_float32(farg.d, &env->fp_status);
1531 farg.d = float32_to_float64(f32, &env->fp_status);
1533 return farg.ll;
1536 /* frsqrte - frsqrte. */
1537 uint64_t helper_frsqrte (uint64_t arg)
1539 CPU_DoubleU fone, farg;
1540 float32 f32;
1541 fone.ll = 0x3FF0000000000000ULL; /* 1.0 */
1542 farg.ll = arg;
1544 if (unlikely(float64_is_signaling_nan(farg.d))) {
1545 /* sNaN reciprocal square root */
1546 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1547 } else if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) {
1548 /* Reciprocal square root of a negative nonzero number */
1549 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSQRT);
1550 } else {
1551 farg.d = float64_sqrt(farg.d, &env->fp_status);
1552 farg.d = float64_div(fone.d, farg.d, &env->fp_status);
1553 f32 = float64_to_float32(farg.d, &env->fp_status);
1554 farg.d = float32_to_float64(f32, &env->fp_status);
1556 return farg.ll;
1559 /* fsel - fsel. */
1560 uint64_t helper_fsel (uint64_t arg1, uint64_t arg2, uint64_t arg3)
1562 CPU_DoubleU farg1;
1564 farg1.ll = arg1;
1566 if ((!float64_is_neg(farg1.d) || float64_is_zero(farg1.d)) && !float64_is_nan(farg1.d))
1567 return arg2;
1568 else
1569 return arg3;
1572 void helper_fcmpu (uint64_t arg1, uint64_t arg2, uint32_t crfD)
1574 CPU_DoubleU farg1, farg2;
1575 uint32_t ret = 0;
1576 farg1.ll = arg1;
1577 farg2.ll = arg2;
1579 if (unlikely(float64_is_nan(farg1.d) ||
1580 float64_is_nan(farg2.d))) {
1581 ret = 0x01UL;
1582 } else if (float64_lt(farg1.d, farg2.d, &env->fp_status)) {
1583 ret = 0x08UL;
1584 } else if (!float64_le(farg1.d, farg2.d, &env->fp_status)) {
1585 ret = 0x04UL;
1586 } else {
1587 ret = 0x02UL;
1590 env->fpscr &= ~(0x0F << FPSCR_FPRF);
1591 env->fpscr |= ret << FPSCR_FPRF;
1592 env->crf[crfD] = ret;
1593 if (unlikely(ret == 0x01UL
1594 && (float64_is_signaling_nan(farg1.d) ||
1595 float64_is_signaling_nan(farg2.d)))) {
1596 /* sNaN comparison */
1597 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1601 void helper_fcmpo (uint64_t arg1, uint64_t arg2, uint32_t crfD)
1603 CPU_DoubleU farg1, farg2;
1604 uint32_t ret = 0;
1605 farg1.ll = arg1;
1606 farg2.ll = arg2;
1608 if (unlikely(float64_is_nan(farg1.d) ||
1609 float64_is_nan(farg2.d))) {
1610 ret = 0x01UL;
1611 } else if (float64_lt(farg1.d, farg2.d, &env->fp_status)) {
1612 ret = 0x08UL;
1613 } else if (!float64_le(farg1.d, farg2.d, &env->fp_status)) {
1614 ret = 0x04UL;
1615 } else {
1616 ret = 0x02UL;
1619 env->fpscr &= ~(0x0F << FPSCR_FPRF);
1620 env->fpscr |= ret << FPSCR_FPRF;
1621 env->crf[crfD] = ret;
1622 if (unlikely (ret == 0x01UL)) {
1623 if (float64_is_signaling_nan(farg1.d) ||
1624 float64_is_signaling_nan(farg2.d)) {
1625 /* sNaN comparison */
1626 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN |
1627 POWERPC_EXCP_FP_VXVC);
1628 } else {
1629 /* qNaN comparison */
1630 fload_invalid_op_excp(POWERPC_EXCP_FP_VXVC);
1635 #if !defined (CONFIG_USER_ONLY)
1636 void helper_store_msr (target_ulong val)
1638 val = hreg_store_msr(env, val, 0);
1639 if (val != 0) {
1640 env->interrupt_request |= CPU_INTERRUPT_EXITTB;
1641 helper_raise_exception(val);
1645 static always_inline void do_rfi (target_ulong nip, target_ulong msr,
1646 target_ulong msrm, int keep_msrh)
1648 #if defined(TARGET_PPC64)
1649 if (msr & (1ULL << MSR_SF)) {
1650 nip = (uint64_t)nip;
1651 msr &= (uint64_t)msrm;
1652 } else {
1653 nip = (uint32_t)nip;
1654 msr = (uint32_t)(msr & msrm);
1655 if (keep_msrh)
1656 msr |= env->msr & ~((uint64_t)0xFFFFFFFF);
1658 #else
1659 nip = (uint32_t)nip;
1660 msr &= (uint32_t)msrm;
1661 #endif
1662 /* XXX: beware: this is false if VLE is supported */
1663 env->nip = nip & ~((target_ulong)0x00000003);
1664 hreg_store_msr(env, msr, 1);
1665 #if defined (DEBUG_OP)
1666 cpu_dump_rfi(env->nip, env->msr);
1667 #endif
1668 /* No need to raise an exception here,
1669 * as rfi is always the last insn of a TB
1671 env->interrupt_request |= CPU_INTERRUPT_EXITTB;
1674 void helper_rfi (void)
1676 do_rfi(env->spr[SPR_SRR0], env->spr[SPR_SRR1],
1677 ~((target_ulong)0xFFFF0000), 1);
1680 #if defined(TARGET_PPC64)
1681 void helper_rfid (void)
1683 do_rfi(env->spr[SPR_SRR0], env->spr[SPR_SRR1],
1684 ~((target_ulong)0xFFFF0000), 0);
1687 void helper_hrfid (void)
1689 do_rfi(env->spr[SPR_HSRR0], env->spr[SPR_HSRR1],
1690 ~((target_ulong)0xFFFF0000), 0);
1692 #endif
1693 #endif
1695 void helper_tw (target_ulong arg1, target_ulong arg2, uint32_t flags)
1697 if (!likely(!(((int32_t)arg1 < (int32_t)arg2 && (flags & 0x10)) ||
1698 ((int32_t)arg1 > (int32_t)arg2 && (flags & 0x08)) ||
1699 ((int32_t)arg1 == (int32_t)arg2 && (flags & 0x04)) ||
1700 ((uint32_t)arg1 < (uint32_t)arg2 && (flags & 0x02)) ||
1701 ((uint32_t)arg1 > (uint32_t)arg2 && (flags & 0x01))))) {
1702 helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_TRAP);
1706 #if defined(TARGET_PPC64)
1707 void helper_td (target_ulong arg1, target_ulong arg2, uint32_t flags)
1709 if (!likely(!(((int64_t)arg1 < (int64_t)arg2 && (flags & 0x10)) ||
1710 ((int64_t)arg1 > (int64_t)arg2 && (flags & 0x08)) ||
1711 ((int64_t)arg1 == (int64_t)arg2 && (flags & 0x04)) ||
1712 ((uint64_t)arg1 < (uint64_t)arg2 && (flags & 0x02)) ||
1713 ((uint64_t)arg1 > (uint64_t)arg2 && (flags & 0x01)))))
1714 helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_TRAP);
1716 #endif
1718 /*****************************************************************************/
1719 /* PowerPC 601 specific instructions (POWER bridge) */
1721 target_ulong helper_clcs (uint32_t arg)
1723 switch (arg) {
1724 case 0x0CUL:
1725 /* Instruction cache line size */
1726 return env->icache_line_size;
1727 break;
1728 case 0x0DUL:
1729 /* Data cache line size */
1730 return env->dcache_line_size;
1731 break;
1732 case 0x0EUL:
1733 /* Minimum cache line size */
1734 return (env->icache_line_size < env->dcache_line_size) ?
1735 env->icache_line_size : env->dcache_line_size;
1736 break;
1737 case 0x0FUL:
1738 /* Maximum cache line size */
1739 return (env->icache_line_size > env->dcache_line_size) ?
1740 env->icache_line_size : env->dcache_line_size;
1741 break;
1742 default:
1743 /* Undefined */
1744 return 0;
1745 break;
1749 target_ulong helper_div (target_ulong arg1, target_ulong arg2)
1751 uint64_t tmp = (uint64_t)arg1 << 32 | env->spr[SPR_MQ];
1753 if (((int32_t)tmp == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
1754 (int32_t)arg2 == 0) {
1755 env->spr[SPR_MQ] = 0;
1756 return INT32_MIN;
1757 } else {
1758 env->spr[SPR_MQ] = tmp % arg2;
1759 return tmp / (int32_t)arg2;
1763 target_ulong helper_divo (target_ulong arg1, target_ulong arg2)
1765 uint64_t tmp = (uint64_t)arg1 << 32 | env->spr[SPR_MQ];
1767 if (((int32_t)tmp == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
1768 (int32_t)arg2 == 0) {
1769 env->xer |= (1 << XER_OV) | (1 << XER_SO);
1770 env->spr[SPR_MQ] = 0;
1771 return INT32_MIN;
1772 } else {
1773 env->spr[SPR_MQ] = tmp % arg2;
1774 tmp /= (int32_t)arg2;
1775 if ((int32_t)tmp != tmp) {
1776 env->xer |= (1 << XER_OV) | (1 << XER_SO);
1777 } else {
1778 env->xer &= ~(1 << XER_OV);
1780 return tmp;
1784 target_ulong helper_divs (target_ulong arg1, target_ulong arg2)
1786 if (((int32_t)arg1 == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
1787 (int32_t)arg2 == 0) {
1788 env->spr[SPR_MQ] = 0;
1789 return INT32_MIN;
1790 } else {
1791 env->spr[SPR_MQ] = (int32_t)arg1 % (int32_t)arg2;
1792 return (int32_t)arg1 / (int32_t)arg2;
1796 target_ulong helper_divso (target_ulong arg1, target_ulong arg2)
1798 if (((int32_t)arg1 == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
1799 (int32_t)arg2 == 0) {
1800 env->xer |= (1 << XER_OV) | (1 << XER_SO);
1801 env->spr[SPR_MQ] = 0;
1802 return INT32_MIN;
1803 } else {
1804 env->xer &= ~(1 << XER_OV);
1805 env->spr[SPR_MQ] = (int32_t)arg1 % (int32_t)arg2;
1806 return (int32_t)arg1 / (int32_t)arg2;
1810 #if !defined (CONFIG_USER_ONLY)
1811 target_ulong helper_rac (target_ulong addr)
1813 mmu_ctx_t ctx;
1814 int nb_BATs;
1815 target_ulong ret = 0;
1817 /* We don't have to generate many instances of this instruction,
1818 * as rac is supervisor only.
1820 /* XXX: FIX THIS: Pretend we have no BAT */
1821 nb_BATs = env->nb_BATs;
1822 env->nb_BATs = 0;
1823 if (get_physical_address(env, &ctx, addr, 0, ACCESS_INT) == 0)
1824 ret = ctx.raddr;
1825 env->nb_BATs = nb_BATs;
1826 return ret;
1829 void helper_rfsvc (void)
1831 do_rfi(env->lr, env->ctr, 0x0000FFFF, 0);
1833 #endif
1835 /*****************************************************************************/
1836 /* 602 specific instructions */
1837 /* mfrom is the most crazy instruction ever seen, imho ! */
1838 /* Real implementation uses a ROM table. Do the same */
1839 /* Extremly decomposed:
1840 * -arg / 256
1841 * return 256 * log10(10 + 1.0) + 0.5
1843 #if !defined (CONFIG_USER_ONLY)
1844 target_ulong helper_602_mfrom (target_ulong arg)
1846 if (likely(arg < 602)) {
1847 #include "mfrom_table.c"
1848 return mfrom_ROM_table[arg];
1849 } else {
1850 return 0;
1853 #endif
1855 /*****************************************************************************/
1856 /* Embedded PowerPC specific helpers */
1858 /* XXX: to be improved to check access rights when in user-mode */
1859 target_ulong helper_load_dcr (target_ulong dcrn)
1861 target_ulong val = 0;
1863 if (unlikely(env->dcr_env == NULL)) {
1864 qemu_log("No DCR environment\n");
1865 helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
1866 POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL);
1867 } else if (unlikely(ppc_dcr_read(env->dcr_env, dcrn, &val) != 0)) {
1868 qemu_log("DCR read error %d %03x\n", (int)dcrn, (int)dcrn);
1869 helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
1870 POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG);
1872 return val;
1875 void helper_store_dcr (target_ulong dcrn, target_ulong val)
1877 if (unlikely(env->dcr_env == NULL)) {
1878 qemu_log("No DCR environment\n");
1879 helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
1880 POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL);
1881 } else if (unlikely(ppc_dcr_write(env->dcr_env, dcrn, val) != 0)) {
1882 qemu_log("DCR write error %d %03x\n", (int)dcrn, (int)dcrn);
1883 helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
1884 POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG);
1888 #if !defined(CONFIG_USER_ONLY)
1889 void helper_40x_rfci (void)
1891 do_rfi(env->spr[SPR_40x_SRR2], env->spr[SPR_40x_SRR3],
1892 ~((target_ulong)0xFFFF0000), 0);
1895 void helper_rfci (void)
1897 do_rfi(env->spr[SPR_BOOKE_CSRR0], SPR_BOOKE_CSRR1,
1898 ~((target_ulong)0x3FFF0000), 0);
1901 void helper_rfdi (void)
1903 do_rfi(env->spr[SPR_BOOKE_DSRR0], SPR_BOOKE_DSRR1,
1904 ~((target_ulong)0x3FFF0000), 0);
1907 void helper_rfmci (void)
1909 do_rfi(env->spr[SPR_BOOKE_MCSRR0], SPR_BOOKE_MCSRR1,
1910 ~((target_ulong)0x3FFF0000), 0);
1912 #endif
1914 /* 440 specific */
1915 target_ulong helper_dlmzb (target_ulong high, target_ulong low, uint32_t update_Rc)
1917 target_ulong mask;
1918 int i;
1920 i = 1;
1921 for (mask = 0xFF000000; mask != 0; mask = mask >> 8) {
1922 if ((high & mask) == 0) {
1923 if (update_Rc) {
1924 env->crf[0] = 0x4;
1926 goto done;
1928 i++;
1930 for (mask = 0xFF000000; mask != 0; mask = mask >> 8) {
1931 if ((low & mask) == 0) {
1932 if (update_Rc) {
1933 env->crf[0] = 0x8;
1935 goto done;
1937 i++;
1939 if (update_Rc) {
1940 env->crf[0] = 0x2;
1942 done:
1943 env->xer = (env->xer & ~0x7F) | i;
1944 if (update_Rc) {
1945 env->crf[0] |= xer_so;
1947 return i;
1950 /*****************************************************************************/
1951 /* Altivec extension helpers */
1952 #if defined(WORDS_BIGENDIAN)
1953 #define HI_IDX 0
1954 #define LO_IDX 1
1955 #else
1956 #define HI_IDX 1
1957 #define LO_IDX 0
1958 #endif
1960 #if defined(WORDS_BIGENDIAN)
1961 #define VECTOR_FOR_INORDER_I(index, element) \
1962 for (index = 0; index < ARRAY_SIZE(r->element); index++)
1963 #else
1964 #define VECTOR_FOR_INORDER_I(index, element) \
1965 for (index = ARRAY_SIZE(r->element)-1; index >= 0; index--)
1966 #endif
1968 /* If X is a NaN, store the corresponding QNaN into RESULT. Otherwise,
1969 * execute the following block. */
1970 #define DO_HANDLE_NAN(result, x) \
1971 if (float32_is_nan(x) || float32_is_signaling_nan(x)) { \
1972 CPU_FloatU __f; \
1973 __f.f = x; \
1974 __f.l = __f.l | (1 << 22); /* Set QNaN bit. */ \
1975 result = __f.f; \
1976 } else
1978 #define HANDLE_NAN1(result, x) \
1979 DO_HANDLE_NAN(result, x)
1980 #define HANDLE_NAN2(result, x, y) \
1981 DO_HANDLE_NAN(result, x) DO_HANDLE_NAN(result, y)
1982 #define HANDLE_NAN3(result, x, y, z) \
1983 DO_HANDLE_NAN(result, x) DO_HANDLE_NAN(result, y) DO_HANDLE_NAN(result, z)
1985 /* Saturating arithmetic helpers. */
1986 #define SATCVT(from, to, from_type, to_type, min, max, use_min, use_max) \
1987 static always_inline to_type cvt##from##to (from_type x, int *sat) \
1989 to_type r; \
1990 if (use_min && x < min) { \
1991 r = min; \
1992 *sat = 1; \
1993 } else if (use_max && x > max) { \
1994 r = max; \
1995 *sat = 1; \
1996 } else { \
1997 r = x; \
1999 return r; \
2001 SATCVT(sh, sb, int16_t, int8_t, INT8_MIN, INT8_MAX, 1, 1)
2002 SATCVT(sw, sh, int32_t, int16_t, INT16_MIN, INT16_MAX, 1, 1)
2003 SATCVT(sd, sw, int64_t, int32_t, INT32_MIN, INT32_MAX, 1, 1)
2004 SATCVT(uh, ub, uint16_t, uint8_t, 0, UINT8_MAX, 0, 1)
2005 SATCVT(uw, uh, uint32_t, uint16_t, 0, UINT16_MAX, 0, 1)
2006 SATCVT(ud, uw, uint64_t, uint32_t, 0, UINT32_MAX, 0, 1)
2007 SATCVT(sh, ub, int16_t, uint8_t, 0, UINT8_MAX, 1, 1)
2008 SATCVT(sw, uh, int32_t, uint16_t, 0, UINT16_MAX, 1, 1)
2009 SATCVT(sd, uw, int64_t, uint32_t, 0, UINT32_MAX, 1, 1)
2010 #undef SATCVT
2012 #define LVE(name, access, swap, element) \
2013 void helper_##name (ppc_avr_t *r, target_ulong addr) \
2015 size_t n_elems = ARRAY_SIZE(r->element); \
2016 int adjust = HI_IDX*(n_elems-1); \
2017 int sh = sizeof(r->element[0]) >> 1; \
2018 int index = (addr & 0xf) >> sh; \
2019 if(msr_le) { \
2020 r->element[LO_IDX ? index : (adjust - index)] = swap(access(addr)); \
2021 } else { \
2022 r->element[LO_IDX ? index : (adjust - index)] = access(addr); \
2025 #define I(x) (x)
2026 LVE(lvebx, ldub, I, u8)
2027 LVE(lvehx, lduw, bswap16, u16)
2028 LVE(lvewx, ldl, bswap32, u32)
2029 #undef I
2030 #undef LVE
2032 void helper_lvsl (ppc_avr_t *r, target_ulong sh)
2034 int i, j = (sh & 0xf);
2036 VECTOR_FOR_INORDER_I (i, u8) {
2037 r->u8[i] = j++;
2041 void helper_lvsr (ppc_avr_t *r, target_ulong sh)
2043 int i, j = 0x10 - (sh & 0xf);
2045 VECTOR_FOR_INORDER_I (i, u8) {
2046 r->u8[i] = j++;
2050 #define STVE(name, access, swap, element) \
2051 void helper_##name (ppc_avr_t *r, target_ulong addr) \
2053 size_t n_elems = ARRAY_SIZE(r->element); \
2054 int adjust = HI_IDX*(n_elems-1); \
2055 int sh = sizeof(r->element[0]) >> 1; \
2056 int index = (addr & 0xf) >> sh; \
2057 if(msr_le) { \
2058 access(addr, swap(r->element[LO_IDX ? index : (adjust - index)])); \
2059 } else { \
2060 access(addr, r->element[LO_IDX ? index : (adjust - index)]); \
2063 #define I(x) (x)
2064 STVE(stvebx, stb, I, u8)
2065 STVE(stvehx, stw, bswap16, u16)
2066 STVE(stvewx, stl, bswap32, u32)
2067 #undef I
2068 #undef LVE
2070 void helper_mtvscr (ppc_avr_t *r)
2072 #if defined(WORDS_BIGENDIAN)
2073 env->vscr = r->u32[3];
2074 #else
2075 env->vscr = r->u32[0];
2076 #endif
2077 set_flush_to_zero(vscr_nj, &env->vec_status);
2080 void helper_vaddcuw (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2082 int i;
2083 for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
2084 r->u32[i] = ~a->u32[i] < b->u32[i];
2088 #define VARITH_DO(name, op, element) \
2089 void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2091 int i; \
2092 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2093 r->element[i] = a->element[i] op b->element[i]; \
2096 #define VARITH(suffix, element) \
2097 VARITH_DO(add##suffix, +, element) \
2098 VARITH_DO(sub##suffix, -, element)
2099 VARITH(ubm, u8)
2100 VARITH(uhm, u16)
2101 VARITH(uwm, u32)
2102 #undef VARITH_DO
2103 #undef VARITH
2105 #define VARITHSAT_CASE(type, op, cvt, element) \
2107 type result = (type)a->element[i] op (type)b->element[i]; \
2108 r->element[i] = cvt(result, &sat); \
2111 #define VARITHSAT_DO(name, op, optype, cvt, element) \
2112 void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2114 int sat = 0; \
2115 int i; \
2116 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2117 switch (sizeof(r->element[0])) { \
2118 case 1: VARITHSAT_CASE(optype, op, cvt, element); break; \
2119 case 2: VARITHSAT_CASE(optype, op, cvt, element); break; \
2120 case 4: VARITHSAT_CASE(optype, op, cvt, element); break; \
2123 if (sat) { \
2124 env->vscr |= (1 << VSCR_SAT); \
2127 #define VARITHSAT_SIGNED(suffix, element, optype, cvt) \
2128 VARITHSAT_DO(adds##suffix##s, +, optype, cvt, element) \
2129 VARITHSAT_DO(subs##suffix##s, -, optype, cvt, element)
2130 #define VARITHSAT_UNSIGNED(suffix, element, optype, cvt) \
2131 VARITHSAT_DO(addu##suffix##s, +, optype, cvt, element) \
2132 VARITHSAT_DO(subu##suffix##s, -, optype, cvt, element)
2133 VARITHSAT_SIGNED(b, s8, int16_t, cvtshsb)
2134 VARITHSAT_SIGNED(h, s16, int32_t, cvtswsh)
2135 VARITHSAT_SIGNED(w, s32, int64_t, cvtsdsw)
2136 VARITHSAT_UNSIGNED(b, u8, uint16_t, cvtshub)
2137 VARITHSAT_UNSIGNED(h, u16, uint32_t, cvtswuh)
2138 VARITHSAT_UNSIGNED(w, u32, uint64_t, cvtsduw)
2139 #undef VARITHSAT_CASE
2140 #undef VARITHSAT_DO
2141 #undef VARITHSAT_SIGNED
2142 #undef VARITHSAT_UNSIGNED
2144 #define VAVG_DO(name, element, etype) \
2145 void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2147 int i; \
2148 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2149 etype x = (etype)a->element[i] + (etype)b->element[i] + 1; \
2150 r->element[i] = x >> 1; \
2154 #define VAVG(type, signed_element, signed_type, unsigned_element, unsigned_type) \
2155 VAVG_DO(avgs##type, signed_element, signed_type) \
2156 VAVG_DO(avgu##type, unsigned_element, unsigned_type)
2157 VAVG(b, s8, int16_t, u8, uint16_t)
2158 VAVG(h, s16, int32_t, u16, uint32_t)
2159 VAVG(w, s32, int64_t, u32, uint64_t)
2160 #undef VAVG_DO
2161 #undef VAVG
2163 #define VCMP_DO(suffix, compare, element, record) \
2164 void helper_vcmp##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2166 uint32_t ones = (uint32_t)-1; \
2167 uint32_t all = ones; \
2168 uint32_t none = 0; \
2169 int i; \
2170 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2171 uint32_t result = (a->element[i] compare b->element[i] ? ones : 0x0); \
2172 switch (sizeof (a->element[0])) { \
2173 case 4: r->u32[i] = result; break; \
2174 case 2: r->u16[i] = result; break; \
2175 case 1: r->u8[i] = result; break; \
2177 all &= result; \
2178 none |= result; \
2180 if (record) { \
2181 env->crf[6] = ((all != 0) << 3) | ((none == 0) << 1); \
2184 #define VCMP(suffix, compare, element) \
2185 VCMP_DO(suffix, compare, element, 0) \
2186 VCMP_DO(suffix##_dot, compare, element, 1)
2187 VCMP(equb, ==, u8)
2188 VCMP(equh, ==, u16)
2189 VCMP(equw, ==, u32)
2190 VCMP(gtub, >, u8)
2191 VCMP(gtuh, >, u16)
2192 VCMP(gtuw, >, u32)
2193 VCMP(gtsb, >, s8)
2194 VCMP(gtsh, >, s16)
2195 VCMP(gtsw, >, s32)
2196 #undef VCMP_DO
2197 #undef VCMP
2199 void helper_vmhaddshs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2201 int sat = 0;
2202 int i;
2204 for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
2205 int32_t prod = a->s16[i] * b->s16[i];
2206 int32_t t = (int32_t)c->s16[i] + (prod >> 15);
2207 r->s16[i] = cvtswsh (t, &sat);
2210 if (sat) {
2211 env->vscr |= (1 << VSCR_SAT);
2215 void helper_vmhraddshs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2217 int sat = 0;
2218 int i;
2220 for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
2221 int32_t prod = a->s16[i] * b->s16[i] + 0x00004000;
2222 int32_t t = (int32_t)c->s16[i] + (prod >> 15);
2223 r->s16[i] = cvtswsh (t, &sat);
2226 if (sat) {
2227 env->vscr |= (1 << VSCR_SAT);
2231 #define VMINMAX_DO(name, compare, element) \
2232 void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2234 int i; \
2235 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2236 if (a->element[i] compare b->element[i]) { \
2237 r->element[i] = b->element[i]; \
2238 } else { \
2239 r->element[i] = a->element[i]; \
2243 #define VMINMAX(suffix, element) \
2244 VMINMAX_DO(min##suffix, >, element) \
2245 VMINMAX_DO(max##suffix, <, element)
2246 VMINMAX(sb, s8)
2247 VMINMAX(sh, s16)
2248 VMINMAX(sw, s32)
2249 VMINMAX(ub, u8)
2250 VMINMAX(uh, u16)
2251 VMINMAX(uw, u32)
2252 #undef VMINMAX_DO
2253 #undef VMINMAX
2255 void helper_vmladduhm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2257 int i;
2258 for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
2259 int32_t prod = a->s16[i] * b->s16[i];
2260 r->s16[i] = (int16_t) (prod + c->s16[i]);
2264 #define VMRG_DO(name, element, highp) \
2265 void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2267 ppc_avr_t result; \
2268 int i; \
2269 size_t n_elems = ARRAY_SIZE(r->element); \
2270 for (i = 0; i < n_elems/2; i++) { \
2271 if (highp) { \
2272 result.element[i*2+HI_IDX] = a->element[i]; \
2273 result.element[i*2+LO_IDX] = b->element[i]; \
2274 } else { \
2275 result.element[n_elems - i*2 - (1+HI_IDX)] = b->element[n_elems - i - 1]; \
2276 result.element[n_elems - i*2 - (1+LO_IDX)] = a->element[n_elems - i - 1]; \
2279 *r = result; \
2281 #if defined(WORDS_BIGENDIAN)
2282 #define MRGHI 0
2283 #define MRGLO 1
2284 #else
2285 #define MRGHI 1
2286 #define MRGLO 0
2287 #endif
2288 #define VMRG(suffix, element) \
2289 VMRG_DO(mrgl##suffix, element, MRGHI) \
2290 VMRG_DO(mrgh##suffix, element, MRGLO)
2291 VMRG(b, u8)
2292 VMRG(h, u16)
2293 VMRG(w, u32)
2294 #undef VMRG_DO
2295 #undef VMRG
2296 #undef MRGHI
2297 #undef MRGLO
2299 void helper_vmsummbm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2301 int32_t prod[16];
2302 int i;
2304 for (i = 0; i < ARRAY_SIZE(r->s8); i++) {
2305 prod[i] = (int32_t)a->s8[i] * b->u8[i];
2308 VECTOR_FOR_INORDER_I(i, s32) {
2309 r->s32[i] = c->s32[i] + prod[4*i] + prod[4*i+1] + prod[4*i+2] + prod[4*i+3];
2313 void helper_vmsumshm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2315 int32_t prod[8];
2316 int i;
2318 for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
2319 prod[i] = a->s16[i] * b->s16[i];
2322 VECTOR_FOR_INORDER_I(i, s32) {
2323 r->s32[i] = c->s32[i] + prod[2*i] + prod[2*i+1];
2327 void helper_vmsumshs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2329 int32_t prod[8];
2330 int i;
2331 int sat = 0;
2333 for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
2334 prod[i] = (int32_t)a->s16[i] * b->s16[i];
2337 VECTOR_FOR_INORDER_I (i, s32) {
2338 int64_t t = (int64_t)c->s32[i] + prod[2*i] + prod[2*i+1];
2339 r->u32[i] = cvtsdsw(t, &sat);
2342 if (sat) {
2343 env->vscr |= (1 << VSCR_SAT);
2347 void helper_vmsumubm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2349 uint16_t prod[16];
2350 int i;
2352 for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
2353 prod[i] = a->u8[i] * b->u8[i];
2356 VECTOR_FOR_INORDER_I(i, u32) {
2357 r->u32[i] = c->u32[i] + prod[4*i] + prod[4*i+1] + prod[4*i+2] + prod[4*i+3];
2361 void helper_vmsumuhm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2363 uint32_t prod[8];
2364 int i;
2366 for (i = 0; i < ARRAY_SIZE(r->u16); i++) {
2367 prod[i] = a->u16[i] * b->u16[i];
2370 VECTOR_FOR_INORDER_I(i, u32) {
2371 r->u32[i] = c->u32[i] + prod[2*i] + prod[2*i+1];
2375 void helper_vmsumuhs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2377 uint32_t prod[8];
2378 int i;
2379 int sat = 0;
2381 for (i = 0; i < ARRAY_SIZE(r->u16); i++) {
2382 prod[i] = a->u16[i] * b->u16[i];
2385 VECTOR_FOR_INORDER_I (i, s32) {
2386 uint64_t t = (uint64_t)c->u32[i] + prod[2*i] + prod[2*i+1];
2387 r->u32[i] = cvtuduw(t, &sat);
2390 if (sat) {
2391 env->vscr |= (1 << VSCR_SAT);
2395 #define VMUL_DO(name, mul_element, prod_element, evenp) \
2396 void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2398 int i; \
2399 VECTOR_FOR_INORDER_I(i, prod_element) { \
2400 if (evenp) { \
2401 r->prod_element[i] = a->mul_element[i*2+HI_IDX] * b->mul_element[i*2+HI_IDX]; \
2402 } else { \
2403 r->prod_element[i] = a->mul_element[i*2+LO_IDX] * b->mul_element[i*2+LO_IDX]; \
2407 #define VMUL(suffix, mul_element, prod_element) \
2408 VMUL_DO(mule##suffix, mul_element, prod_element, 1) \
2409 VMUL_DO(mulo##suffix, mul_element, prod_element, 0)
2410 VMUL(sb, s8, s16)
2411 VMUL(sh, s16, s32)
2412 VMUL(ub, u8, u16)
2413 VMUL(uh, u16, u32)
2414 #undef VMUL_DO
2415 #undef VMUL
2417 void helper_vperm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2419 ppc_avr_t result;
2420 int i;
2421 VECTOR_FOR_INORDER_I (i, u8) {
2422 int s = c->u8[i] & 0x1f;
2423 #if defined(WORDS_BIGENDIAN)
2424 int index = s & 0xf;
2425 #else
2426 int index = 15 - (s & 0xf);
2427 #endif
2428 if (s & 0x10) {
2429 result.u8[i] = b->u8[index];
2430 } else {
2431 result.u8[i] = a->u8[index];
2434 *r = result;
2437 #if defined(WORDS_BIGENDIAN)
2438 #define PKBIG 1
2439 #else
2440 #define PKBIG 0
2441 #endif
2442 void helper_vpkpx (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2444 int i, j;
2445 ppc_avr_t result;
2446 #if defined(WORDS_BIGENDIAN)
2447 const ppc_avr_t *x[2] = { a, b };
2448 #else
2449 const ppc_avr_t *x[2] = { b, a };
2450 #endif
2452 VECTOR_FOR_INORDER_I (i, u64) {
2453 VECTOR_FOR_INORDER_I (j, u32){
2454 uint32_t e = x[i]->u32[j];
2455 result.u16[4*i+j] = (((e >> 9) & 0xfc00) |
2456 ((e >> 6) & 0x3e0) |
2457 ((e >> 3) & 0x1f));
2460 *r = result;
2463 #define VPK(suffix, from, to, cvt, dosat) \
2464 void helper_vpk##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2466 int i; \
2467 int sat = 0; \
2468 ppc_avr_t result; \
2469 ppc_avr_t *a0 = PKBIG ? a : b; \
2470 ppc_avr_t *a1 = PKBIG ? b : a; \
2471 VECTOR_FOR_INORDER_I (i, from) { \
2472 result.to[i] = cvt(a0->from[i], &sat); \
2473 result.to[i+ARRAY_SIZE(r->from)] = cvt(a1->from[i], &sat); \
2475 *r = result; \
2476 if (dosat && sat) { \
2477 env->vscr |= (1 << VSCR_SAT); \
2480 #define I(x, y) (x)
2481 VPK(shss, s16, s8, cvtshsb, 1)
2482 VPK(shus, s16, u8, cvtshub, 1)
2483 VPK(swss, s32, s16, cvtswsh, 1)
2484 VPK(swus, s32, u16, cvtswuh, 1)
2485 VPK(uhus, u16, u8, cvtuhub, 1)
2486 VPK(uwus, u32, u16, cvtuwuh, 1)
2487 VPK(uhum, u16, u8, I, 0)
2488 VPK(uwum, u32, u16, I, 0)
2489 #undef I
2490 #undef VPK
2491 #undef PKBIG
2493 #define VRFI(suffix, rounding) \
2494 void helper_vrfi##suffix (ppc_avr_t *r, ppc_avr_t *b) \
2496 int i; \
2497 float_status s = env->vec_status; \
2498 set_float_rounding_mode(rounding, &s); \
2499 for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
2500 HANDLE_NAN1(r->f[i], b->f[i]) { \
2501 r->f[i] = float32_round_to_int (b->f[i], &s); \
2505 VRFI(n, float_round_nearest_even)
2506 VRFI(m, float_round_down)
2507 VRFI(p, float_round_up)
2508 VRFI(z, float_round_to_zero)
2509 #undef VRFI
2511 #define VROTATE(suffix, element) \
2512 void helper_vrl##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2514 int i; \
2515 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2516 unsigned int mask = ((1 << (3 + (sizeof (a->element[0]) >> 1))) - 1); \
2517 unsigned int shift = b->element[i] & mask; \
2518 r->element[i] = (a->element[i] << shift) | (a->element[i] >> (sizeof(a->element[0]) * 8 - shift)); \
2521 VROTATE(b, u8)
2522 VROTATE(h, u16)
2523 VROTATE(w, u32)
2524 #undef VROTATE
2526 void helper_vsel (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2528 r->u64[0] = (a->u64[0] & ~c->u64[0]) | (b->u64[0] & c->u64[0]);
2529 r->u64[1] = (a->u64[1] & ~c->u64[1]) | (b->u64[1] & c->u64[1]);
2532 #if defined(WORDS_BIGENDIAN)
2533 #define LEFT 0
2534 #define RIGHT 1
2535 #else
2536 #define LEFT 1
2537 #define RIGHT 0
2538 #endif
2539 /* The specification says that the results are undefined if all of the
2540 * shift counts are not identical. We check to make sure that they are
2541 * to conform to what real hardware appears to do. */
2542 #define VSHIFT(suffix, leftp) \
2543 void helper_vs##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2545 int shift = b->u8[LO_IDX*0x15] & 0x7; \
2546 int doit = 1; \
2547 int i; \
2548 for (i = 0; i < ARRAY_SIZE(r->u8); i++) { \
2549 doit = doit && ((b->u8[i] & 0x7) == shift); \
2551 if (doit) { \
2552 if (shift == 0) { \
2553 *r = *a; \
2554 } else if (leftp) { \
2555 uint64_t carry = a->u64[LO_IDX] >> (64 - shift); \
2556 r->u64[HI_IDX] = (a->u64[HI_IDX] << shift) | carry; \
2557 r->u64[LO_IDX] = a->u64[LO_IDX] << shift; \
2558 } else { \
2559 uint64_t carry = a->u64[HI_IDX] << (64 - shift); \
2560 r->u64[LO_IDX] = (a->u64[LO_IDX] >> shift) | carry; \
2561 r->u64[HI_IDX] = a->u64[HI_IDX] >> shift; \
2565 VSHIFT(l, LEFT)
2566 VSHIFT(r, RIGHT)
2567 #undef VSHIFT
2568 #undef LEFT
2569 #undef RIGHT
2571 #define VSL(suffix, element) \
2572 void helper_vsl##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2574 int i; \
2575 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2576 unsigned int mask = ((1 << (3 + (sizeof (a->element[0]) >> 1))) - 1); \
2577 unsigned int shift = b->element[i] & mask; \
2578 r->element[i] = a->element[i] << shift; \
2581 VSL(b, u8)
2582 VSL(h, u16)
2583 VSL(w, u32)
2584 #undef VSL
2586 void helper_vsldoi (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t shift)
2588 int sh = shift & 0xf;
2589 int i;
2590 ppc_avr_t result;
2592 #if defined(WORDS_BIGENDIAN)
2593 for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
2594 int index = sh + i;
2595 if (index > 0xf) {
2596 result.u8[i] = b->u8[index-0x10];
2597 } else {
2598 result.u8[i] = a->u8[index];
2601 #else
2602 for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
2603 int index = (16 - sh) + i;
2604 if (index > 0xf) {
2605 result.u8[i] = a->u8[index-0x10];
2606 } else {
2607 result.u8[i] = b->u8[index];
2610 #endif
2611 *r = result;
2614 void helper_vslo (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2616 int sh = (b->u8[LO_IDX*0xf] >> 3) & 0xf;
2618 #if defined (WORDS_BIGENDIAN)
2619 memmove (&r->u8[0], &a->u8[sh], 16-sh);
2620 memset (&r->u8[16-sh], 0, sh);
2621 #else
2622 memmove (&r->u8[sh], &a->u8[0], 16-sh);
2623 memset (&r->u8[0], 0, sh);
2624 #endif
2627 /* Experimental testing shows that hardware masks the immediate. */
2628 #define _SPLAT_MASKED(element) (splat & (ARRAY_SIZE(r->element) - 1))
2629 #if defined(WORDS_BIGENDIAN)
2630 #define SPLAT_ELEMENT(element) _SPLAT_MASKED(element)
2631 #else
2632 #define SPLAT_ELEMENT(element) (ARRAY_SIZE(r->element)-1 - _SPLAT_MASKED(element))
2633 #endif
2634 #define VSPLT(suffix, element) \
2635 void helper_vsplt##suffix (ppc_avr_t *r, ppc_avr_t *b, uint32_t splat) \
2637 uint32_t s = b->element[SPLAT_ELEMENT(element)]; \
2638 int i; \
2639 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2640 r->element[i] = s; \
2643 VSPLT(b, u8)
2644 VSPLT(h, u16)
2645 VSPLT(w, u32)
2646 #undef VSPLT
2647 #undef SPLAT_ELEMENT
2648 #undef _SPLAT_MASKED
2650 #define VSPLTI(suffix, element, splat_type) \
2651 void helper_vspltis##suffix (ppc_avr_t *r, uint32_t splat) \
2653 splat_type x = (int8_t)(splat << 3) >> 3; \
2654 int i; \
2655 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2656 r->element[i] = x; \
2659 VSPLTI(b, s8, int8_t)
2660 VSPLTI(h, s16, int16_t)
2661 VSPLTI(w, s32, int32_t)
2662 #undef VSPLTI
2664 #define VSR(suffix, element) \
2665 void helper_vsr##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2667 int i; \
2668 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2669 unsigned int mask = ((1 << (3 + (sizeof (a->element[0]) >> 1))) - 1); \
2670 unsigned int shift = b->element[i] & mask; \
2671 r->element[i] = a->element[i] >> shift; \
2674 VSR(ab, s8)
2675 VSR(ah, s16)
2676 VSR(aw, s32)
2677 VSR(b, u8)
2678 VSR(h, u16)
2679 VSR(w, u32)
2680 #undef VSR
2682 void helper_vsro (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2684 int sh = (b->u8[LO_IDX*0xf] >> 3) & 0xf;
2686 #if defined (WORDS_BIGENDIAN)
2687 memmove (&r->u8[sh], &a->u8[0], 16-sh);
2688 memset (&r->u8[0], 0, sh);
2689 #else
2690 memmove (&r->u8[0], &a->u8[sh], 16-sh);
2691 memset (&r->u8[16-sh], 0, sh);
2692 #endif
2695 void helper_vsubcuw (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2697 int i;
2698 for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
2699 r->u32[i] = a->u32[i] >= b->u32[i];
2703 void helper_vsumsws (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2705 int64_t t;
2706 int i, upper;
2707 ppc_avr_t result;
2708 int sat = 0;
2710 #if defined(WORDS_BIGENDIAN)
2711 upper = ARRAY_SIZE(r->s32)-1;
2712 #else
2713 upper = 0;
2714 #endif
2715 t = (int64_t)b->s32[upper];
2716 for (i = 0; i < ARRAY_SIZE(r->s32); i++) {
2717 t += a->s32[i];
2718 result.s32[i] = 0;
2720 result.s32[upper] = cvtsdsw(t, &sat);
2721 *r = result;
2723 if (sat) {
2724 env->vscr |= (1 << VSCR_SAT);
2728 void helper_vsum2sws (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2730 int i, j, upper;
2731 ppc_avr_t result;
2732 int sat = 0;
2734 #if defined(WORDS_BIGENDIAN)
2735 upper = 1;
2736 #else
2737 upper = 0;
2738 #endif
2739 for (i = 0; i < ARRAY_SIZE(r->u64); i++) {
2740 int64_t t = (int64_t)b->s32[upper+i*2];
2741 result.u64[i] = 0;
2742 for (j = 0; j < ARRAY_SIZE(r->u64); j++) {
2743 t += a->s32[2*i+j];
2745 result.s32[upper+i*2] = cvtsdsw(t, &sat);
2748 *r = result;
2749 if (sat) {
2750 env->vscr |= (1 << VSCR_SAT);
2754 void helper_vsum4sbs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2756 int i, j;
2757 int sat = 0;
2759 for (i = 0; i < ARRAY_SIZE(r->s32); i++) {
2760 int64_t t = (int64_t)b->s32[i];
2761 for (j = 0; j < ARRAY_SIZE(r->s32); j++) {
2762 t += a->s8[4*i+j];
2764 r->s32[i] = cvtsdsw(t, &sat);
2767 if (sat) {
2768 env->vscr |= (1 << VSCR_SAT);
2772 void helper_vsum4shs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2774 int sat = 0;
2775 int i;
2777 for (i = 0; i < ARRAY_SIZE(r->s32); i++) {
2778 int64_t t = (int64_t)b->s32[i];
2779 t += a->s16[2*i] + a->s16[2*i+1];
2780 r->s32[i] = cvtsdsw(t, &sat);
2783 if (sat) {
2784 env->vscr |= (1 << VSCR_SAT);
2788 void helper_vsum4ubs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2790 int i, j;
2791 int sat = 0;
2793 for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
2794 uint64_t t = (uint64_t)b->u32[i];
2795 for (j = 0; j < ARRAY_SIZE(r->u32); j++) {
2796 t += a->u8[4*i+j];
2798 r->u32[i] = cvtuduw(t, &sat);
2801 if (sat) {
2802 env->vscr |= (1 << VSCR_SAT);
2806 #if defined(WORDS_BIGENDIAN)
2807 #define UPKHI 1
2808 #define UPKLO 0
2809 #else
2810 #define UPKHI 0
2811 #define UPKLO 1
2812 #endif
2813 #define VUPKPX(suffix, hi) \
2814 void helper_vupk##suffix (ppc_avr_t *r, ppc_avr_t *b) \
2816 int i; \
2817 ppc_avr_t result; \
2818 for (i = 0; i < ARRAY_SIZE(r->u32); i++) { \
2819 uint16_t e = b->u16[hi ? i : i+4]; \
2820 uint8_t a = (e >> 15) ? 0xff : 0; \
2821 uint8_t r = (e >> 10) & 0x1f; \
2822 uint8_t g = (e >> 5) & 0x1f; \
2823 uint8_t b = e & 0x1f; \
2824 result.u32[i] = (a << 24) | (r << 16) | (g << 8) | b; \
2826 *r = result; \
2828 VUPKPX(lpx, UPKLO)
2829 VUPKPX(hpx, UPKHI)
2830 #undef VUPKPX
2832 #define VUPK(suffix, unpacked, packee, hi) \
2833 void helper_vupk##suffix (ppc_avr_t *r, ppc_avr_t *b) \
2835 int i; \
2836 ppc_avr_t result; \
2837 if (hi) { \
2838 for (i = 0; i < ARRAY_SIZE(r->unpacked); i++) { \
2839 result.unpacked[i] = b->packee[i]; \
2841 } else { \
2842 for (i = ARRAY_SIZE(r->unpacked); i < ARRAY_SIZE(r->packee); i++) { \
2843 result.unpacked[i-ARRAY_SIZE(r->unpacked)] = b->packee[i]; \
2846 *r = result; \
2848 VUPK(hsb, s16, s8, UPKHI)
2849 VUPK(hsh, s32, s16, UPKHI)
2850 VUPK(lsb, s16, s8, UPKLO)
2851 VUPK(lsh, s32, s16, UPKLO)
2852 #undef VUPK
2853 #undef UPKHI
2854 #undef UPKLO
2856 #undef DO_HANDLE_NAN
2857 #undef HANDLE_NAN1
2858 #undef HANDLE_NAN2
2859 #undef HANDLE_NAN3
2860 #undef VECTOR_FOR_INORDER_I
2861 #undef HI_IDX
2862 #undef LO_IDX
2864 /*****************************************************************************/
2865 /* SPE extension helpers */
2866 /* Use a table to make this quicker */
2867 static uint8_t hbrev[16] = {
2868 0x0, 0x8, 0x4, 0xC, 0x2, 0xA, 0x6, 0xE,
2869 0x1, 0x9, 0x5, 0xD, 0x3, 0xB, 0x7, 0xF,
2872 static always_inline uint8_t byte_reverse (uint8_t val)
2874 return hbrev[val >> 4] | (hbrev[val & 0xF] << 4);
2877 static always_inline uint32_t word_reverse (uint32_t val)
2879 return byte_reverse(val >> 24) | (byte_reverse(val >> 16) << 8) |
2880 (byte_reverse(val >> 8) << 16) | (byte_reverse(val) << 24);
2883 #define MASKBITS 16 // Random value - to be fixed (implementation dependant)
2884 target_ulong helper_brinc (target_ulong arg1, target_ulong arg2)
2886 uint32_t a, b, d, mask;
2888 mask = UINT32_MAX >> (32 - MASKBITS);
2889 a = arg1 & mask;
2890 b = arg2 & mask;
2891 d = word_reverse(1 + word_reverse(a | ~b));
2892 return (arg1 & ~mask) | (d & b);
2895 uint32_t helper_cntlsw32 (uint32_t val)
2897 if (val & 0x80000000)
2898 return clz32(~val);
2899 else
2900 return clz32(val);
2903 uint32_t helper_cntlzw32 (uint32_t val)
2905 return clz32(val);
2908 /* Single-precision floating-point conversions */
2909 static always_inline uint32_t efscfsi (uint32_t val)
2911 CPU_FloatU u;
2913 u.f = int32_to_float32(val, &env->vec_status);
2915 return u.l;
2918 static always_inline uint32_t efscfui (uint32_t val)
2920 CPU_FloatU u;
2922 u.f = uint32_to_float32(val, &env->vec_status);
2924 return u.l;
2927 static always_inline int32_t efsctsi (uint32_t val)
2929 CPU_FloatU u;
2931 u.l = val;
2932 /* NaN are not treated the same way IEEE 754 does */
2933 if (unlikely(float32_is_nan(u.f)))
2934 return 0;
2936 return float32_to_int32(u.f, &env->vec_status);
2939 static always_inline uint32_t efsctui (uint32_t val)
2941 CPU_FloatU u;
2943 u.l = val;
2944 /* NaN are not treated the same way IEEE 754 does */
2945 if (unlikely(float32_is_nan(u.f)))
2946 return 0;
2948 return float32_to_uint32(u.f, &env->vec_status);
2951 static always_inline uint32_t efsctsiz (uint32_t val)
2953 CPU_FloatU u;
2955 u.l = val;
2956 /* NaN are not treated the same way IEEE 754 does */
2957 if (unlikely(float32_is_nan(u.f)))
2958 return 0;
2960 return float32_to_int32_round_to_zero(u.f, &env->vec_status);
2963 static always_inline uint32_t efsctuiz (uint32_t val)
2965 CPU_FloatU u;
2967 u.l = val;
2968 /* NaN are not treated the same way IEEE 754 does */
2969 if (unlikely(float32_is_nan(u.f)))
2970 return 0;
2972 return float32_to_uint32_round_to_zero(u.f, &env->vec_status);
2975 static always_inline uint32_t efscfsf (uint32_t val)
2977 CPU_FloatU u;
2978 float32 tmp;
2980 u.f = int32_to_float32(val, &env->vec_status);
2981 tmp = int64_to_float32(1ULL << 32, &env->vec_status);
2982 u.f = float32_div(u.f, tmp, &env->vec_status);
2984 return u.l;
2987 static always_inline uint32_t efscfuf (uint32_t val)
2989 CPU_FloatU u;
2990 float32 tmp;
2992 u.f = uint32_to_float32(val, &env->vec_status);
2993 tmp = uint64_to_float32(1ULL << 32, &env->vec_status);
2994 u.f = float32_div(u.f, tmp, &env->vec_status);
2996 return u.l;
2999 static always_inline uint32_t efsctsf (uint32_t val)
3001 CPU_FloatU u;
3002 float32 tmp;
3004 u.l = val;
3005 /* NaN are not treated the same way IEEE 754 does */
3006 if (unlikely(float32_is_nan(u.f)))
3007 return 0;
3008 tmp = uint64_to_float32(1ULL << 32, &env->vec_status);
3009 u.f = float32_mul(u.f, tmp, &env->vec_status);
3011 return float32_to_int32(u.f, &env->vec_status);
3014 static always_inline uint32_t efsctuf (uint32_t val)
3016 CPU_FloatU u;
3017 float32 tmp;
3019 u.l = val;
3020 /* NaN are not treated the same way IEEE 754 does */
3021 if (unlikely(float32_is_nan(u.f)))
3022 return 0;
3023 tmp = uint64_to_float32(1ULL << 32, &env->vec_status);
3024 u.f = float32_mul(u.f, tmp, &env->vec_status);
3026 return float32_to_uint32(u.f, &env->vec_status);
3029 #define HELPER_SPE_SINGLE_CONV(name) \
3030 uint32_t helper_e##name (uint32_t val) \
3032 return e##name(val); \
3034 /* efscfsi */
3035 HELPER_SPE_SINGLE_CONV(fscfsi);
3036 /* efscfui */
3037 HELPER_SPE_SINGLE_CONV(fscfui);
3038 /* efscfuf */
3039 HELPER_SPE_SINGLE_CONV(fscfuf);
3040 /* efscfsf */
3041 HELPER_SPE_SINGLE_CONV(fscfsf);
3042 /* efsctsi */
3043 HELPER_SPE_SINGLE_CONV(fsctsi);
3044 /* efsctui */
3045 HELPER_SPE_SINGLE_CONV(fsctui);
3046 /* efsctsiz */
3047 HELPER_SPE_SINGLE_CONV(fsctsiz);
3048 /* efsctuiz */
3049 HELPER_SPE_SINGLE_CONV(fsctuiz);
3050 /* efsctsf */
3051 HELPER_SPE_SINGLE_CONV(fsctsf);
3052 /* efsctuf */
3053 HELPER_SPE_SINGLE_CONV(fsctuf);
3055 #define HELPER_SPE_VECTOR_CONV(name) \
3056 uint64_t helper_ev##name (uint64_t val) \
3058 return ((uint64_t)e##name(val >> 32) << 32) | \
3059 (uint64_t)e##name(val); \
3061 /* evfscfsi */
3062 HELPER_SPE_VECTOR_CONV(fscfsi);
3063 /* evfscfui */
3064 HELPER_SPE_VECTOR_CONV(fscfui);
3065 /* evfscfuf */
3066 HELPER_SPE_VECTOR_CONV(fscfuf);
3067 /* evfscfsf */
3068 HELPER_SPE_VECTOR_CONV(fscfsf);
3069 /* evfsctsi */
3070 HELPER_SPE_VECTOR_CONV(fsctsi);
3071 /* evfsctui */
3072 HELPER_SPE_VECTOR_CONV(fsctui);
3073 /* evfsctsiz */
3074 HELPER_SPE_VECTOR_CONV(fsctsiz);
3075 /* evfsctuiz */
3076 HELPER_SPE_VECTOR_CONV(fsctuiz);
3077 /* evfsctsf */
3078 HELPER_SPE_VECTOR_CONV(fsctsf);
3079 /* evfsctuf */
3080 HELPER_SPE_VECTOR_CONV(fsctuf);
3082 /* Single-precision floating-point arithmetic */
3083 static always_inline uint32_t efsadd (uint32_t op1, uint32_t op2)
3085 CPU_FloatU u1, u2;
3086 u1.l = op1;
3087 u2.l = op2;
3088 u1.f = float32_add(u1.f, u2.f, &env->vec_status);
3089 return u1.l;
3092 static always_inline uint32_t efssub (uint32_t op1, uint32_t op2)
3094 CPU_FloatU u1, u2;
3095 u1.l = op1;
3096 u2.l = op2;
3097 u1.f = float32_sub(u1.f, u2.f, &env->vec_status);
3098 return u1.l;
3101 static always_inline uint32_t efsmul (uint32_t op1, uint32_t op2)
3103 CPU_FloatU u1, u2;
3104 u1.l = op1;
3105 u2.l = op2;
3106 u1.f = float32_mul(u1.f, u2.f, &env->vec_status);
3107 return u1.l;
3110 static always_inline uint32_t efsdiv (uint32_t op1, uint32_t op2)
3112 CPU_FloatU u1, u2;
3113 u1.l = op1;
3114 u2.l = op2;
3115 u1.f = float32_div(u1.f, u2.f, &env->vec_status);
3116 return u1.l;
3119 #define HELPER_SPE_SINGLE_ARITH(name) \
3120 uint32_t helper_e##name (uint32_t op1, uint32_t op2) \
3122 return e##name(op1, op2); \
3124 /* efsadd */
3125 HELPER_SPE_SINGLE_ARITH(fsadd);
3126 /* efssub */
3127 HELPER_SPE_SINGLE_ARITH(fssub);
3128 /* efsmul */
3129 HELPER_SPE_SINGLE_ARITH(fsmul);
3130 /* efsdiv */
3131 HELPER_SPE_SINGLE_ARITH(fsdiv);
3133 #define HELPER_SPE_VECTOR_ARITH(name) \
3134 uint64_t helper_ev##name (uint64_t op1, uint64_t op2) \
3136 return ((uint64_t)e##name(op1 >> 32, op2 >> 32) << 32) | \
3137 (uint64_t)e##name(op1, op2); \
3139 /* evfsadd */
3140 HELPER_SPE_VECTOR_ARITH(fsadd);
3141 /* evfssub */
3142 HELPER_SPE_VECTOR_ARITH(fssub);
3143 /* evfsmul */
3144 HELPER_SPE_VECTOR_ARITH(fsmul);
3145 /* evfsdiv */
3146 HELPER_SPE_VECTOR_ARITH(fsdiv);
3148 /* Single-precision floating-point comparisons */
3149 static always_inline uint32_t efststlt (uint32_t op1, uint32_t op2)
3151 CPU_FloatU u1, u2;
3152 u1.l = op1;
3153 u2.l = op2;
3154 return float32_lt(u1.f, u2.f, &env->vec_status) ? 4 : 0;
3157 static always_inline uint32_t efststgt (uint32_t op1, uint32_t op2)
3159 CPU_FloatU u1, u2;
3160 u1.l = op1;
3161 u2.l = op2;
3162 return float32_le(u1.f, u2.f, &env->vec_status) ? 0 : 4;
3165 static always_inline uint32_t efststeq (uint32_t op1, uint32_t op2)
3167 CPU_FloatU u1, u2;
3168 u1.l = op1;
3169 u2.l = op2;
3170 return float32_eq(u1.f, u2.f, &env->vec_status) ? 4 : 0;
3173 static always_inline uint32_t efscmplt (uint32_t op1, uint32_t op2)
3175 /* XXX: TODO: test special values (NaN, infinites, ...) */
3176 return efststlt(op1, op2);
3179 static always_inline uint32_t efscmpgt (uint32_t op1, uint32_t op2)
3181 /* XXX: TODO: test special values (NaN, infinites, ...) */
3182 return efststgt(op1, op2);
3185 static always_inline uint32_t efscmpeq (uint32_t op1, uint32_t op2)
3187 /* XXX: TODO: test special values (NaN, infinites, ...) */
3188 return efststeq(op1, op2);
3191 #define HELPER_SINGLE_SPE_CMP(name) \
3192 uint32_t helper_e##name (uint32_t op1, uint32_t op2) \
3194 return e##name(op1, op2) << 2; \
3196 /* efststlt */
3197 HELPER_SINGLE_SPE_CMP(fststlt);
3198 /* efststgt */
3199 HELPER_SINGLE_SPE_CMP(fststgt);
3200 /* efststeq */
3201 HELPER_SINGLE_SPE_CMP(fststeq);
3202 /* efscmplt */
3203 HELPER_SINGLE_SPE_CMP(fscmplt);
3204 /* efscmpgt */
3205 HELPER_SINGLE_SPE_CMP(fscmpgt);
3206 /* efscmpeq */
3207 HELPER_SINGLE_SPE_CMP(fscmpeq);
3209 static always_inline uint32_t evcmp_merge (int t0, int t1)
3211 return (t0 << 3) | (t1 << 2) | ((t0 | t1) << 1) | (t0 & t1);
3214 #define HELPER_VECTOR_SPE_CMP(name) \
3215 uint32_t helper_ev##name (uint64_t op1, uint64_t op2) \
3217 return evcmp_merge(e##name(op1 >> 32, op2 >> 32), e##name(op1, op2)); \
3219 /* evfststlt */
3220 HELPER_VECTOR_SPE_CMP(fststlt);
3221 /* evfststgt */
3222 HELPER_VECTOR_SPE_CMP(fststgt);
3223 /* evfststeq */
3224 HELPER_VECTOR_SPE_CMP(fststeq);
3225 /* evfscmplt */
3226 HELPER_VECTOR_SPE_CMP(fscmplt);
3227 /* evfscmpgt */
3228 HELPER_VECTOR_SPE_CMP(fscmpgt);
3229 /* evfscmpeq */
3230 HELPER_VECTOR_SPE_CMP(fscmpeq);
3232 /* Double-precision floating-point conversion */
3233 uint64_t helper_efdcfsi (uint32_t val)
3235 CPU_DoubleU u;
3237 u.d = int32_to_float64(val, &env->vec_status);
3239 return u.ll;
3242 uint64_t helper_efdcfsid (uint64_t val)
3244 CPU_DoubleU u;
3246 u.d = int64_to_float64(val, &env->vec_status);
3248 return u.ll;
3251 uint64_t helper_efdcfui (uint32_t val)
3253 CPU_DoubleU u;
3255 u.d = uint32_to_float64(val, &env->vec_status);
3257 return u.ll;
3260 uint64_t helper_efdcfuid (uint64_t val)
3262 CPU_DoubleU u;
3264 u.d = uint64_to_float64(val, &env->vec_status);
3266 return u.ll;
3269 uint32_t helper_efdctsi (uint64_t val)
3271 CPU_DoubleU u;
3273 u.ll = val;
3274 /* NaN are not treated the same way IEEE 754 does */
3275 if (unlikely(float64_is_nan(u.d)))
3276 return 0;
3278 return float64_to_int32(u.d, &env->vec_status);
3281 uint32_t helper_efdctui (uint64_t val)
3283 CPU_DoubleU u;
3285 u.ll = val;
3286 /* NaN are not treated the same way IEEE 754 does */
3287 if (unlikely(float64_is_nan(u.d)))
3288 return 0;
3290 return float64_to_uint32(u.d, &env->vec_status);
3293 uint32_t helper_efdctsiz (uint64_t val)
3295 CPU_DoubleU u;
3297 u.ll = val;
3298 /* NaN are not treated the same way IEEE 754 does */
3299 if (unlikely(float64_is_nan(u.d)))
3300 return 0;
3302 return float64_to_int32_round_to_zero(u.d, &env->vec_status);
3305 uint64_t helper_efdctsidz (uint64_t val)
3307 CPU_DoubleU u;
3309 u.ll = val;
3310 /* NaN are not treated the same way IEEE 754 does */
3311 if (unlikely(float64_is_nan(u.d)))
3312 return 0;
3314 return float64_to_int64_round_to_zero(u.d, &env->vec_status);
3317 uint32_t helper_efdctuiz (uint64_t val)
3319 CPU_DoubleU u;
3321 u.ll = val;
3322 /* NaN are not treated the same way IEEE 754 does */
3323 if (unlikely(float64_is_nan(u.d)))
3324 return 0;
3326 return float64_to_uint32_round_to_zero(u.d, &env->vec_status);
3329 uint64_t helper_efdctuidz (uint64_t val)
3331 CPU_DoubleU u;
3333 u.ll = val;
3334 /* NaN are not treated the same way IEEE 754 does */
3335 if (unlikely(float64_is_nan(u.d)))
3336 return 0;
3338 return float64_to_uint64_round_to_zero(u.d, &env->vec_status);
3341 uint64_t helper_efdcfsf (uint32_t val)
3343 CPU_DoubleU u;
3344 float64 tmp;
3346 u.d = int32_to_float64(val, &env->vec_status);
3347 tmp = int64_to_float64(1ULL << 32, &env->vec_status);
3348 u.d = float64_div(u.d, tmp, &env->vec_status);
3350 return u.ll;
3353 uint64_t helper_efdcfuf (uint32_t val)
3355 CPU_DoubleU u;
3356 float64 tmp;
3358 u.d = uint32_to_float64(val, &env->vec_status);
3359 tmp = int64_to_float64(1ULL << 32, &env->vec_status);
3360 u.d = float64_div(u.d, tmp, &env->vec_status);
3362 return u.ll;
3365 uint32_t helper_efdctsf (uint64_t val)
3367 CPU_DoubleU u;
3368 float64 tmp;
3370 u.ll = val;
3371 /* NaN are not treated the same way IEEE 754 does */
3372 if (unlikely(float64_is_nan(u.d)))
3373 return 0;
3374 tmp = uint64_to_float64(1ULL << 32, &env->vec_status);
3375 u.d = float64_mul(u.d, tmp, &env->vec_status);
3377 return float64_to_int32(u.d, &env->vec_status);
3380 uint32_t helper_efdctuf (uint64_t val)
3382 CPU_DoubleU u;
3383 float64 tmp;
3385 u.ll = val;
3386 /* NaN are not treated the same way IEEE 754 does */
3387 if (unlikely(float64_is_nan(u.d)))
3388 return 0;
3389 tmp = uint64_to_float64(1ULL << 32, &env->vec_status);
3390 u.d = float64_mul(u.d, tmp, &env->vec_status);
3392 return float64_to_uint32(u.d, &env->vec_status);
3395 uint32_t helper_efscfd (uint64_t val)
3397 CPU_DoubleU u1;
3398 CPU_FloatU u2;
3400 u1.ll = val;
3401 u2.f = float64_to_float32(u1.d, &env->vec_status);
3403 return u2.l;
3406 uint64_t helper_efdcfs (uint32_t val)
3408 CPU_DoubleU u2;
3409 CPU_FloatU u1;
3411 u1.l = val;
3412 u2.d = float32_to_float64(u1.f, &env->vec_status);
3414 return u2.ll;
3417 /* Double precision fixed-point arithmetic */
3418 uint64_t helper_efdadd (uint64_t op1, uint64_t op2)
3420 CPU_DoubleU u1, u2;
3421 u1.ll = op1;
3422 u2.ll = op2;
3423 u1.d = float64_add(u1.d, u2.d, &env->vec_status);
3424 return u1.ll;
3427 uint64_t helper_efdsub (uint64_t op1, uint64_t op2)
3429 CPU_DoubleU u1, u2;
3430 u1.ll = op1;
3431 u2.ll = op2;
3432 u1.d = float64_sub(u1.d, u2.d, &env->vec_status);
3433 return u1.ll;
3436 uint64_t helper_efdmul (uint64_t op1, uint64_t op2)
3438 CPU_DoubleU u1, u2;
3439 u1.ll = op1;
3440 u2.ll = op2;
3441 u1.d = float64_mul(u1.d, u2.d, &env->vec_status);
3442 return u1.ll;
3445 uint64_t helper_efddiv (uint64_t op1, uint64_t op2)
3447 CPU_DoubleU u1, u2;
3448 u1.ll = op1;
3449 u2.ll = op2;
3450 u1.d = float64_div(u1.d, u2.d, &env->vec_status);
3451 return u1.ll;
3454 /* Double precision floating point helpers */
3455 uint32_t helper_efdtstlt (uint64_t op1, uint64_t op2)
3457 CPU_DoubleU u1, u2;
3458 u1.ll = op1;
3459 u2.ll = op2;
3460 return float64_lt(u1.d, u2.d, &env->vec_status) ? 4 : 0;
3463 uint32_t helper_efdtstgt (uint64_t op1, uint64_t op2)
3465 CPU_DoubleU u1, u2;
3466 u1.ll = op1;
3467 u2.ll = op2;
3468 return float64_le(u1.d, u2.d, &env->vec_status) ? 0 : 4;
3471 uint32_t helper_efdtsteq (uint64_t op1, uint64_t op2)
3473 CPU_DoubleU u1, u2;
3474 u1.ll = op1;
3475 u2.ll = op2;
3476 return float64_eq(u1.d, u2.d, &env->vec_status) ? 4 : 0;
3479 uint32_t helper_efdcmplt (uint64_t op1, uint64_t op2)
3481 /* XXX: TODO: test special values (NaN, infinites, ...) */
3482 return helper_efdtstlt(op1, op2);
3485 uint32_t helper_efdcmpgt (uint64_t op1, uint64_t op2)
3487 /* XXX: TODO: test special values (NaN, infinites, ...) */
3488 return helper_efdtstgt(op1, op2);
3491 uint32_t helper_efdcmpeq (uint64_t op1, uint64_t op2)
3493 /* XXX: TODO: test special values (NaN, infinites, ...) */
3494 return helper_efdtsteq(op1, op2);
3497 /*****************************************************************************/
3498 /* Softmmu support */
3499 #if !defined (CONFIG_USER_ONLY)
3501 #define MMUSUFFIX _mmu
3503 #define SHIFT 0
3504 #include "softmmu_template.h"
3506 #define SHIFT 1
3507 #include "softmmu_template.h"
3509 #define SHIFT 2
3510 #include "softmmu_template.h"
3512 #define SHIFT 3
3513 #include "softmmu_template.h"
3515 /* try to fill the TLB and return an exception if error. If retaddr is
3516 NULL, it means that the function was called in C code (i.e. not
3517 from generated code or from helper.c) */
3518 /* XXX: fix it to restore all registers */
3519 void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
3521 TranslationBlock *tb;
3522 CPUState *saved_env;
3523 unsigned long pc;
3524 int ret;
3526 /* XXX: hack to restore env in all cases, even if not called from
3527 generated code */
3528 saved_env = env;
3529 env = cpu_single_env;
3530 ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
3531 if (unlikely(ret != 0)) {
3532 if (likely(retaddr)) {
3533 /* now we have a real cpu fault */
3534 pc = (unsigned long)retaddr;
3535 tb = tb_find_pc(pc);
3536 if (likely(tb)) {
3537 /* the PC is inside the translated code. It means that we have
3538 a virtual CPU fault */
3539 cpu_restore_state(tb, env, pc, NULL);
3542 helper_raise_exception_err(env->exception_index, env->error_code);
3544 env = saved_env;
3547 /* Segment registers load and store */
3548 target_ulong helper_load_sr (target_ulong sr_num)
3550 return env->sr[sr_num];
3553 void helper_store_sr (target_ulong sr_num, target_ulong val)
3555 ppc_store_sr(env, sr_num, val);
3558 /* SLB management */
3559 #if defined(TARGET_PPC64)
3560 target_ulong helper_load_slb (target_ulong slb_nr)
3562 return ppc_load_slb(env, slb_nr);
3565 void helper_store_slb (target_ulong slb_nr, target_ulong rs)
3567 ppc_store_slb(env, slb_nr, rs);
3570 void helper_slbia (void)
3572 ppc_slb_invalidate_all(env);
3575 void helper_slbie (target_ulong addr)
3577 ppc_slb_invalidate_one(env, addr);
3580 #endif /* defined(TARGET_PPC64) */
3582 /* TLB management */
3583 void helper_tlbia (void)
3585 ppc_tlb_invalidate_all(env);
3588 void helper_tlbie (target_ulong addr)
3590 ppc_tlb_invalidate_one(env, addr);
3593 /* Software driven TLBs management */
3594 /* PowerPC 602/603 software TLB load instructions helpers */
3595 static void do_6xx_tlb (target_ulong new_EPN, int is_code)
3597 target_ulong RPN, CMP, EPN;
3598 int way;
3600 RPN = env->spr[SPR_RPA];
3601 if (is_code) {
3602 CMP = env->spr[SPR_ICMP];
3603 EPN = env->spr[SPR_IMISS];
3604 } else {
3605 CMP = env->spr[SPR_DCMP];
3606 EPN = env->spr[SPR_DMISS];
3608 way = (env->spr[SPR_SRR1] >> 17) & 1;
3609 LOG_SWTLB("%s: EPN " ADDRX " " ADDRX " PTE0 " ADDRX
3610 " PTE1 " ADDRX " way %d\n",
3611 __func__, new_EPN, EPN, CMP, RPN, way);
3612 /* Store this TLB */
3613 ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
3614 way, is_code, CMP, RPN);
3617 void helper_6xx_tlbd (target_ulong EPN)
3619 do_6xx_tlb(EPN, 0);
3622 void helper_6xx_tlbi (target_ulong EPN)
3624 do_6xx_tlb(EPN, 1);
3627 /* PowerPC 74xx software TLB load instructions helpers */
3628 static void do_74xx_tlb (target_ulong new_EPN, int is_code)
3630 target_ulong RPN, CMP, EPN;
3631 int way;
3633 RPN = env->spr[SPR_PTELO];
3634 CMP = env->spr[SPR_PTEHI];
3635 EPN = env->spr[SPR_TLBMISS] & ~0x3;
3636 way = env->spr[SPR_TLBMISS] & 0x3;
3637 LOG_SWTLB("%s: EPN " ADDRX " " ADDRX " PTE0 " ADDRX
3638 " PTE1 " ADDRX " way %d\n",
3639 __func__, new_EPN, EPN, CMP, RPN, way);
3640 /* Store this TLB */
3641 ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
3642 way, is_code, CMP, RPN);
3645 void helper_74xx_tlbd (target_ulong EPN)
3647 do_74xx_tlb(EPN, 0);
3650 void helper_74xx_tlbi (target_ulong EPN)
3652 do_74xx_tlb(EPN, 1);
3655 static always_inline target_ulong booke_tlb_to_page_size (int size)
3657 return 1024 << (2 * size);
3660 static always_inline int booke_page_size_to_tlb (target_ulong page_size)
3662 int size;
3664 switch (page_size) {
3665 case 0x00000400UL:
3666 size = 0x0;
3667 break;
3668 case 0x00001000UL:
3669 size = 0x1;
3670 break;
3671 case 0x00004000UL:
3672 size = 0x2;
3673 break;
3674 case 0x00010000UL:
3675 size = 0x3;
3676 break;
3677 case 0x00040000UL:
3678 size = 0x4;
3679 break;
3680 case 0x00100000UL:
3681 size = 0x5;
3682 break;
3683 case 0x00400000UL:
3684 size = 0x6;
3685 break;
3686 case 0x01000000UL:
3687 size = 0x7;
3688 break;
3689 case 0x04000000UL:
3690 size = 0x8;
3691 break;
3692 case 0x10000000UL:
3693 size = 0x9;
3694 break;
3695 case 0x40000000UL:
3696 size = 0xA;
3697 break;
3698 #if defined (TARGET_PPC64)
3699 case 0x000100000000ULL:
3700 size = 0xB;
3701 break;
3702 case 0x000400000000ULL:
3703 size = 0xC;
3704 break;
3705 case 0x001000000000ULL:
3706 size = 0xD;
3707 break;
3708 case 0x004000000000ULL:
3709 size = 0xE;
3710 break;
3711 case 0x010000000000ULL:
3712 size = 0xF;
3713 break;
3714 #endif
3715 default:
3716 size = -1;
3717 break;
3720 return size;
3723 /* Helpers for 4xx TLB management */
3724 target_ulong helper_4xx_tlbre_lo (target_ulong entry)
3726 ppcemb_tlb_t *tlb;
3727 target_ulong ret;
3728 int size;
3730 entry &= 0x3F;
3731 tlb = &env->tlb[entry].tlbe;
3732 ret = tlb->EPN;
3733 if (tlb->prot & PAGE_VALID)
3734 ret |= 0x400;
3735 size = booke_page_size_to_tlb(tlb->size);
3736 if (size < 0 || size > 0x7)
3737 size = 1;
3738 ret |= size << 7;
3739 env->spr[SPR_40x_PID] = tlb->PID;
3740 return ret;
3743 target_ulong helper_4xx_tlbre_hi (target_ulong entry)
3745 ppcemb_tlb_t *tlb;
3746 target_ulong ret;
3748 entry &= 0x3F;
3749 tlb = &env->tlb[entry].tlbe;
3750 ret = tlb->RPN;
3751 if (tlb->prot & PAGE_EXEC)
3752 ret |= 0x200;
3753 if (tlb->prot & PAGE_WRITE)
3754 ret |= 0x100;
3755 return ret;
3758 void helper_4xx_tlbwe_hi (target_ulong entry, target_ulong val)
3760 ppcemb_tlb_t *tlb;
3761 target_ulong page, end;
3763 LOG_SWTLB("%s entry %d val " ADDRX "\n", __func__, (int)entry, val);
3764 entry &= 0x3F;
3765 tlb = &env->tlb[entry].tlbe;
3766 /* Invalidate previous TLB (if it's valid) */
3767 if (tlb->prot & PAGE_VALID) {
3768 end = tlb->EPN + tlb->size;
3769 LOG_SWTLB("%s: invalidate old TLB %d start " ADDRX
3770 " end " ADDRX "\n", __func__, (int)entry, tlb->EPN, end);
3771 for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE)
3772 tlb_flush_page(env, page);
3774 tlb->size = booke_tlb_to_page_size((val >> 7) & 0x7);
3775 /* We cannot handle TLB size < TARGET_PAGE_SIZE.
3776 * If this ever occurs, one should use the ppcemb target instead
3777 * of the ppc or ppc64 one
3779 if ((val & 0x40) && tlb->size < TARGET_PAGE_SIZE) {
3780 cpu_abort(env, "TLB size " TARGET_FMT_lu " < %u "
3781 "are not supported (%d)\n",
3782 tlb->size, TARGET_PAGE_SIZE, (int)((val >> 7) & 0x7));
3784 tlb->EPN = val & ~(tlb->size - 1);
3785 if (val & 0x40)
3786 tlb->prot |= PAGE_VALID;
3787 else
3788 tlb->prot &= ~PAGE_VALID;
3789 if (val & 0x20) {
3790 /* XXX: TO BE FIXED */
3791 cpu_abort(env, "Little-endian TLB entries are not supported by now\n");
3793 tlb->PID = env->spr[SPR_40x_PID]; /* PID */
3794 tlb->attr = val & 0xFF;
3795 LOG_SWTLB("%s: set up TLB %d RPN " PADDRX " EPN " ADDRX
3796 " size " ADDRX " prot %c%c%c%c PID %d\n", __func__,
3797 (int)entry, tlb->RPN, tlb->EPN, tlb->size,
3798 tlb->prot & PAGE_READ ? 'r' : '-',
3799 tlb->prot & PAGE_WRITE ? 'w' : '-',
3800 tlb->prot & PAGE_EXEC ? 'x' : '-',
3801 tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
3802 /* Invalidate new TLB (if valid) */
3803 if (tlb->prot & PAGE_VALID) {
3804 end = tlb->EPN + tlb->size;
3805 LOG_SWTLB("%s: invalidate TLB %d start " ADDRX
3806 " end " ADDRX "\n", __func__, (int)entry, tlb->EPN, end);
3807 for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE)
3808 tlb_flush_page(env, page);
3812 void helper_4xx_tlbwe_lo (target_ulong entry, target_ulong val)
3814 ppcemb_tlb_t *tlb;
3816 LOG_SWTLB("%s entry %i val " ADDRX "\n", __func__, (int)entry, val);
3817 entry &= 0x3F;
3818 tlb = &env->tlb[entry].tlbe;
3819 tlb->RPN = val & 0xFFFFFC00;
3820 tlb->prot = PAGE_READ;
3821 if (val & 0x200)
3822 tlb->prot |= PAGE_EXEC;
3823 if (val & 0x100)
3824 tlb->prot |= PAGE_WRITE;
3825 LOG_SWTLB("%s: set up TLB %d RPN " PADDRX " EPN " ADDRX
3826 " size " ADDRX " prot %c%c%c%c PID %d\n", __func__,
3827 (int)entry, tlb->RPN, tlb->EPN, tlb->size,
3828 tlb->prot & PAGE_READ ? 'r' : '-',
3829 tlb->prot & PAGE_WRITE ? 'w' : '-',
3830 tlb->prot & PAGE_EXEC ? 'x' : '-',
3831 tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
3834 target_ulong helper_4xx_tlbsx (target_ulong address)
3836 return ppcemb_tlb_search(env, address, env->spr[SPR_40x_PID]);
3839 /* PowerPC 440 TLB management */
3840 void helper_440_tlbwe (uint32_t word, target_ulong entry, target_ulong value)
3842 ppcemb_tlb_t *tlb;
3843 target_ulong EPN, RPN, size;
3844 int do_flush_tlbs;
3846 LOG_SWTLB("%s word %d entry %d value " ADDRX "\n",
3847 __func__, word, (int)entry, value);
3848 do_flush_tlbs = 0;
3849 entry &= 0x3F;
3850 tlb = &env->tlb[entry].tlbe;
3851 switch (word) {
3852 default:
3853 /* Just here to please gcc */
3854 case 0:
3855 EPN = value & 0xFFFFFC00;
3856 if ((tlb->prot & PAGE_VALID) && EPN != tlb->EPN)
3857 do_flush_tlbs = 1;
3858 tlb->EPN = EPN;
3859 size = booke_tlb_to_page_size((value >> 4) & 0xF);
3860 if ((tlb->prot & PAGE_VALID) && tlb->size < size)
3861 do_flush_tlbs = 1;
3862 tlb->size = size;
3863 tlb->attr &= ~0x1;
3864 tlb->attr |= (value >> 8) & 1;
3865 if (value & 0x200) {
3866 tlb->prot |= PAGE_VALID;
3867 } else {
3868 if (tlb->prot & PAGE_VALID) {
3869 tlb->prot &= ~PAGE_VALID;
3870 do_flush_tlbs = 1;
3873 tlb->PID = env->spr[SPR_440_MMUCR] & 0x000000FF;
3874 if (do_flush_tlbs)
3875 tlb_flush(env, 1);
3876 break;
3877 case 1:
3878 RPN = value & 0xFFFFFC0F;
3879 if ((tlb->prot & PAGE_VALID) && tlb->RPN != RPN)
3880 tlb_flush(env, 1);
3881 tlb->RPN = RPN;
3882 break;
3883 case 2:
3884 tlb->attr = (tlb->attr & 0x1) | (value & 0x0000FF00);
3885 tlb->prot = tlb->prot & PAGE_VALID;
3886 if (value & 0x1)
3887 tlb->prot |= PAGE_READ << 4;
3888 if (value & 0x2)
3889 tlb->prot |= PAGE_WRITE << 4;
3890 if (value & 0x4)
3891 tlb->prot |= PAGE_EXEC << 4;
3892 if (value & 0x8)
3893 tlb->prot |= PAGE_READ;
3894 if (value & 0x10)
3895 tlb->prot |= PAGE_WRITE;
3896 if (value & 0x20)
3897 tlb->prot |= PAGE_EXEC;
3898 break;
3902 target_ulong helper_440_tlbre (uint32_t word, target_ulong entry)
3904 ppcemb_tlb_t *tlb;
3905 target_ulong ret;
3906 int size;
3908 entry &= 0x3F;
3909 tlb = &env->tlb[entry].tlbe;
3910 switch (word) {
3911 default:
3912 /* Just here to please gcc */
3913 case 0:
3914 ret = tlb->EPN;
3915 size = booke_page_size_to_tlb(tlb->size);
3916 if (size < 0 || size > 0xF)
3917 size = 1;
3918 ret |= size << 4;
3919 if (tlb->attr & 0x1)
3920 ret |= 0x100;
3921 if (tlb->prot & PAGE_VALID)
3922 ret |= 0x200;
3923 env->spr[SPR_440_MMUCR] &= ~0x000000FF;
3924 env->spr[SPR_440_MMUCR] |= tlb->PID;
3925 break;
3926 case 1:
3927 ret = tlb->RPN;
3928 break;
3929 case 2:
3930 ret = tlb->attr & ~0x1;
3931 if (tlb->prot & (PAGE_READ << 4))
3932 ret |= 0x1;
3933 if (tlb->prot & (PAGE_WRITE << 4))
3934 ret |= 0x2;
3935 if (tlb->prot & (PAGE_EXEC << 4))
3936 ret |= 0x4;
3937 if (tlb->prot & PAGE_READ)
3938 ret |= 0x8;
3939 if (tlb->prot & PAGE_WRITE)
3940 ret |= 0x10;
3941 if (tlb->prot & PAGE_EXEC)
3942 ret |= 0x20;
3943 break;
3945 return ret;
3948 target_ulong helper_440_tlbsx (target_ulong address)
3950 return ppcemb_tlb_search(env, address, env->spr[SPR_440_MMUCR] & 0xFF);
3953 #endif /* !CONFIG_USER_ONLY */