* [Qemu-devel] [PULL 00/72] ppc patch queue 2012-06-24
@ 2012-06-23 23:06 Alexander Graf
2012-06-23 23:06 ` [Qemu-devel] [PATCH 01/72] ppc: Fix coding style in op_helper.c Alexander Graf
` (72 more replies)
0 siblings, 73 replies; 89+ messages in thread
From: Alexander Graf @ 2012-06-23 23:06 UTC (permalink / raw)
To: qemu-devel qemu-devel; +Cc: Blue Swirl, qemu-ppc Mailing List, Aurelien Jarno
Hi Blue / Aurelien,
This is my current patch queue for ppc. Please pull.
Alex
The following changes since commit affe5189907f397514cdd4ee7446595c1246a0e9:
Alexander Graf (1):
TCG: Fix compile breakage in tcg_dump_ops
are available in the git repository at:
git://repo.or.cz/qemu/agraf.git ppc-for-upstream
Alexander Graf (43):
PPC: mpc8544ds: Span initial TLB entry over as much RAM as we need
dt: allow add_subnode to create root subnodes
dt: add helpers for multi-cell adds
dt: add helper for phandle references
dt: temporarily disable subtree creation failure check
dt: add helper for phandle enumeration
dt: add helper for empty dt creation
dt: add helper for phandle allocation
dt: add helper for 64bit cell adds
PPC: e500: require libfdt
PPC: e500: dt: create memory node dynamically
PPC: e500: dt: create /cpus node dynamically
PPC: e500: dt: create /hypervisor node dynamically
PPC: e500: dt: create / node dynamically
PPC: e500: dt: create /chosen node dynamically
PPC: e500: dt: create /soc8544 node dynamically
PPC: e500: dt: create serial nodes dynamically
PPC: e500: dt: create mpic node dynamically
PPC: e500: dt: create global-utils node dynamically
PPC: e500: dt: create pci node dynamically
PPC: e500: dt: start with empty device tree
dt: Add -machine dumpdtb option to dump the current dtb
PPC: e500: dt: use 64bit cell helper
PPC: e500: dt: use target_phys_addr_t for ramsize
PPC: e500: enable manual loading of dtb blob
Revert "dt: temporarily disable subtree creation failure check"
PPC: e500: Use new MPIC dt format
PPC: e500: Use new SOC dt format
PPC: e500: Define addresses as always 64bit
PPC: e500: Extend address/size of / to 64bit
dt: Add global option to set phandle start offset
PPC: e500: Refactor serial dt generation
dt: make setprop argument static
PPC: e500: allow users to set the /compatible property via -machine
uImage: increase the gzip load size
PPC: Add some booke SPR defines
PPC: Add support for MSR_CM
PPC: BookE: Implement EPR SPR
PPC: BookE: Make ivpr selectable by CPU type
PPC: Add e5500 CPU target
PPC: Extract SPR dump generation into its own function
PPC: BookE: Support 32 and 64 bit wide MAS2
PPC: BookE206: Bump MAS2 to 64bit
Benjamin Herrenschmidt (4):
ppc64: Rudimentary Support for extra page sizes on server CPUs
pseries: Correctly create ibm,segment-page-sizes property
spapr_vscsi: Error handling fixes
spapr: Add "memop" hypercall
Blue Swirl (22):
ppc: Fix coding style in op_helper.c
ppc: Split exception helpers
ppc: Avoid AREG0 for exception helpers
ppc: Fix coding style in helper.c
ppc: Move exception helpers from helper.c to excp_helper.c
ppc: Split FPU and SPE ops
ppc: Avoid AREG0 for FPU and SPE helpers
ppc: Split integer and vector ops
ppc: Avoid AREG0 for integer and vector helpers
ppc: Split MMU etc. helpers from op_helper.c
ppc: Avoid AREG0 for MMU etc. helpers
ppc: Avoid a warning with the next patch
ppc: Move MMU helpers from helper.c to mmu_helper.c
ppc: Cleanup MMU merge
ppc: Split off timebase helpers
ppc: Avoid AREG0 for timebase helpers
ppc: Split off misc helpers
ppc: Avoid AREG0 for misc helpers
ppc: Move misc helpers from helper.c to misc_helper.c
ppc: Move load and store helpers, switch to AREG0 free mode
ppc: Add missing break
ppc: Make hbrev table const
Fabien Chouteau (2):
Avoid segfault in cpu_dump_state
booke_206_tlbwe: Discard invalid bits in MAS2
Kevin Wolf (1):
raw-posix: Fix build without is_allocated support
Makefile | 1 -
block/raw-posix.c | 9 +-
configure | 2 +-
cpu-all.h | 9 +
device_tree.c | 108 +-
device_tree.h | 22 +-
docs/specs/ppc-spapr-hcalls.txt | 78 +
hw/loader.c | 4 +-
hw/ppc/Makefile.objs | 2 +-
hw/ppce500_mpc8544ds.c | 283 ++-
hw/spapr.c | 46 +
hw/spapr.h | 3 +-
hw/spapr_hcall.c | 68 +
hw/spapr_vscsi.c | 4 +-
pc-bios/mpc8544ds.dtb | Bin 2028 -> 0 bytes
pc-bios/mpc8544ds.dts | 119 -
qemu-config.c | 12 +
qemu-log.h | 4 +-
target-ppc/Makefile.objs | 14 +-
target-ppc/cpu.h | 88 +-
target-ppc/excp_helper.c | 969 +++++++++
target-ppc/fpu_helper.c | 1740 +++++++++++++++
target-ppc/helper.c | 3168 +---------------------------
target-ppc/helper.h | 573 +++---
target-ppc/int_helper.c | 1564 ++++++++++++++
target-ppc/kvm.c | 208 ++
target-ppc/kvm_ppc.h | 5 +
target-ppc/mem_helper.c | 295 +++
target-ppc/misc_helper.c | 124 ++
target-ppc/mmu_helper.c | 3326 ++++++++++++++++++++++++++++
target-ppc/mpic_helper.c | 35 +
target-ppc/op_helper.c | 4568 ---------------------------------------
target-ppc/timebase_helper.c | 159 ++
target-ppc/translate.c | 462 +++--
target-ppc/translate_init.c | 249 ++-
35 files changed, 9858 insertions(+), 8463 deletions(-)
create mode 100644 docs/specs/ppc-spapr-hcalls.txt
delete mode 100644 pc-bios/mpc8544ds.dtb
delete mode 100644 pc-bios/mpc8544ds.dts
create mode 100644 target-ppc/excp_helper.c
create mode 100644 target-ppc/fpu_helper.c
create mode 100644 target-ppc/int_helper.c
create mode 100644 target-ppc/mem_helper.c
create mode 100644 target-ppc/misc_helper.c
create mode 100644 target-ppc/mmu_helper.c
create mode 100644 target-ppc/mpic_helper.c
delete mode 100644 target-ppc/op_helper.c
create mode 100644 target-ppc/timebase_helper.c
^ permalink raw reply [flat|nested] 89+ messages in thread
* [Qemu-devel] [PATCH 01/72] ppc: Fix coding style in op_helper.c
2012-06-23 23:06 [Qemu-devel] [PULL 00/72] ppc patch queue 2012-06-24 Alexander Graf
@ 2012-06-23 23:06 ` Alexander Graf
2012-06-23 23:06 ` [Qemu-devel] [PATCH 02/72] ppc: Split exception helpers Alexander Graf
` (71 subsequent siblings)
72 siblings, 0 replies; 89+ messages in thread
From: Alexander Graf @ 2012-06-23 23:06 UTC (permalink / raw)
To: qemu-devel qemu-devel
Cc: Blue Swirl, qemu-ppc Mailing List, Andreas Färber,
Aurelien Jarno
From: Blue Swirl <blauwirbel@gmail.com>
op_helper.c will be split by the next patches, fix
style issues before that.
Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Andreas Färber <afaerber@suse.de>
Signed-off-by: Alexander Graf <agraf@suse.de>
---
target-ppc/op_helper.c | 1245 ++++++++++++++++++++++++++++--------------------
1 files changed, 725 insertions(+), 520 deletions(-)
diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c
index 4ef2332..d9f7a8b 100644
--- a/target-ppc/op_helper.c
+++ b/target-ppc/op_helper.c
@@ -1,5 +1,5 @@
/*
- * PowerPC emulation helpers for qemu.
+ * PowerPC emulation helpers for QEMU.
*
* Copyright (c) 2003-2007 Jocelyn Mayer
*
@@ -42,7 +42,7 @@
/*****************************************************************************/
/* Exceptions processing helpers */
-void helper_raise_exception_err (uint32_t exception, uint32_t error_code)
+void helper_raise_exception_err(uint32_t exception, uint32_t error_code)
{
#if 0
printf("Raise exception %3x code : %d\n", exception, error_code);
@@ -52,116 +52,116 @@ void helper_raise_exception_err (uint32_t exception, uint32_t error_code)
cpu_loop_exit(env);
}
-void helper_raise_exception (uint32_t exception)
+void helper_raise_exception(uint32_t exception)
{
helper_raise_exception_err(exception, 0);
}
/*****************************************************************************/
/* SPR accesses */
-void helper_load_dump_spr (uint32_t sprn)
+void helper_load_dump_spr(uint32_t sprn)
{
qemu_log("Read SPR %d %03x => " TARGET_FMT_lx "\n", sprn, sprn,
env->spr[sprn]);
}
-void helper_store_dump_spr (uint32_t sprn)
+void helper_store_dump_spr(uint32_t sprn)
{
qemu_log("Write SPR %d %03x <= " TARGET_FMT_lx "\n", sprn, sprn,
env->spr[sprn]);
}
-target_ulong helper_load_tbl (void)
+target_ulong helper_load_tbl(void)
{
return (target_ulong)cpu_ppc_load_tbl(env);
}
-target_ulong helper_load_tbu (void)
+target_ulong helper_load_tbu(void)
{
return cpu_ppc_load_tbu(env);
}
-target_ulong helper_load_atbl (void)
+target_ulong helper_load_atbl(void)
{
return (target_ulong)cpu_ppc_load_atbl(env);
}
-target_ulong helper_load_atbu (void)
+target_ulong helper_load_atbu(void)
{
return cpu_ppc_load_atbu(env);
}
#if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY)
-target_ulong helper_load_purr (void)
+target_ulong helper_load_purr(void)
{
return (target_ulong)cpu_ppc_load_purr(env);
}
#endif
-target_ulong helper_load_601_rtcl (void)
+target_ulong helper_load_601_rtcl(void)
{
return cpu_ppc601_load_rtcl(env);
}
-target_ulong helper_load_601_rtcu (void)
+target_ulong helper_load_601_rtcu(void)
{
return cpu_ppc601_load_rtcu(env);
}
#if !defined(CONFIG_USER_ONLY)
-#if defined (TARGET_PPC64)
-void helper_store_asr (target_ulong val)
+#if defined(TARGET_PPC64)
+void helper_store_asr(target_ulong val)
{
ppc_store_asr(env, val);
}
#endif
-void helper_store_sdr1 (target_ulong val)
+void helper_store_sdr1(target_ulong val)
{
ppc_store_sdr1(env, val);
}
-void helper_store_tbl (target_ulong val)
+void helper_store_tbl(target_ulong val)
{
cpu_ppc_store_tbl(env, val);
}
-void helper_store_tbu (target_ulong val)
+void helper_store_tbu(target_ulong val)
{
cpu_ppc_store_tbu(env, val);
}
-void helper_store_atbl (target_ulong val)
+void helper_store_atbl(target_ulong val)
{
cpu_ppc_store_atbl(env, val);
}
-void helper_store_atbu (target_ulong val)
+void helper_store_atbu(target_ulong val)
{
cpu_ppc_store_atbu(env, val);
}
-void helper_store_601_rtcl (target_ulong val)
+void helper_store_601_rtcl(target_ulong val)
{
cpu_ppc601_store_rtcl(env, val);
}
-void helper_store_601_rtcu (target_ulong val)
+void helper_store_601_rtcu(target_ulong val)
{
cpu_ppc601_store_rtcu(env, val);
}
-target_ulong helper_load_decr (void)
+target_ulong helper_load_decr(void)
{
return cpu_ppc_load_decr(env);
}
-void helper_store_decr (target_ulong val)
+void helper_store_decr(target_ulong val)
{
cpu_ppc_store_decr(env, val);
}
-void helper_store_hid0_601 (target_ulong val)
+void helper_store_hid0_601(target_ulong val)
{
target_ulong hid0;
@@ -178,7 +178,7 @@ void helper_store_hid0_601 (target_ulong val)
env->spr[SPR_HID0] = (uint32_t)val;
}
-void helper_store_403_pbr (uint32_t num, target_ulong value)
+void helper_store_403_pbr(uint32_t num, target_ulong value)
{
if (likely(env->pb[num] != value)) {
env->pb[num] = value;
@@ -187,62 +187,62 @@ void helper_store_403_pbr (uint32_t num, target_ulong value)
}
}
-target_ulong helper_load_40x_pit (void)
+target_ulong helper_load_40x_pit(void)
{
return load_40x_pit(env);
}
-void helper_store_40x_pit (target_ulong val)
+void helper_store_40x_pit(target_ulong val)
{
store_40x_pit(env, val);
}
-void helper_store_40x_dbcr0 (target_ulong val)
+void helper_store_40x_dbcr0(target_ulong val)
{
store_40x_dbcr0(env, val);
}
-void helper_store_40x_sler (target_ulong val)
+void helper_store_40x_sler(target_ulong val)
{
store_40x_sler(env, val);
}
-void helper_store_booke_tcr (target_ulong val)
+void helper_store_booke_tcr(target_ulong val)
{
store_booke_tcr(env, val);
}
-void helper_store_booke_tsr (target_ulong val)
+void helper_store_booke_tsr(target_ulong val)
{
store_booke_tsr(env, val);
}
-void helper_store_ibatu (uint32_t nr, target_ulong val)
+void helper_store_ibatu(uint32_t nr, target_ulong val)
{
ppc_store_ibatu(env, nr, val);
}
-void helper_store_ibatl (uint32_t nr, target_ulong val)
+void helper_store_ibatl(uint32_t nr, target_ulong val)
{
ppc_store_ibatl(env, nr, val);
}
-void helper_store_dbatu (uint32_t nr, target_ulong val)
+void helper_store_dbatu(uint32_t nr, target_ulong val)
{
ppc_store_dbatu(env, nr, val);
}
-void helper_store_dbatl (uint32_t nr, target_ulong val)
+void helper_store_dbatl(uint32_t nr, target_ulong val)
{
ppc_store_dbatl(env, nr, val);
}
-void helper_store_601_batl (uint32_t nr, target_ulong val)
+void helper_store_601_batl(uint32_t nr, target_ulong val)
{
ppc_store_ibatl_601(env, nr, val);
}
-void helper_store_601_batu (uint32_t nr, target_ulong val)
+void helper_store_601_batu(uint32_t nr, target_ulong val)
{
ppc_store_ibatu_601(env, nr, val);
}
@@ -254,48 +254,53 @@ void helper_store_601_batu (uint32_t nr, target_ulong val)
static inline target_ulong addr_add(target_ulong addr, target_long arg)
{
#if defined(TARGET_PPC64)
- if (!msr_sf)
- return (uint32_t)(addr + arg);
- else
+ if (!msr_sf) {
+ return (uint32_t)(addr + arg);
+ } else
#endif
- return addr + arg;
+ {
+ return addr + arg;
+ }
}
-void helper_lmw (target_ulong addr, uint32_t reg)
+void helper_lmw(target_ulong addr, uint32_t reg)
{
for (; reg < 32; reg++) {
- if (msr_le)
+ if (msr_le) {
env->gpr[reg] = bswap32(ldl(addr));
- else
+ } else {
env->gpr[reg] = ldl(addr);
- addr = addr_add(addr, 4);
+ }
+ addr = addr_add(addr, 4);
}
}
-void helper_stmw (target_ulong addr, uint32_t reg)
+void helper_stmw(target_ulong addr, uint32_t reg)
{
for (; reg < 32; reg++) {
- if (msr_le)
+ if (msr_le) {
stl(addr, bswap32((uint32_t)env->gpr[reg]));
- else
+ } else {
stl(addr, (uint32_t)env->gpr[reg]);
- addr = addr_add(addr, 4);
+ }
+ addr = addr_add(addr, 4);
}
}
void helper_lsw(target_ulong addr, uint32_t nb, uint32_t reg)
{
int sh;
+
for (; nb > 3; nb -= 4) {
env->gpr[reg] = ldl(addr);
reg = (reg + 1) % 32;
- addr = addr_add(addr, 4);
+ addr = addr_add(addr, 4);
}
if (unlikely(nb > 0)) {
env->gpr[reg] = 0;
for (sh = 24; nb > 0; nb--, sh -= 8) {
env->gpr[reg] |= ldub(addr) << sh;
- addr = addr_add(addr, 1);
+ addr = addr_add(addr, 1);
}
}
}
@@ -321,10 +326,11 @@ void helper_lswx(target_ulong addr, uint32_t reg, uint32_t ra, uint32_t rb)
void helper_stsw(target_ulong addr, uint32_t nb, uint32_t reg)
{
int sh;
+
for (; nb > 3; nb -= 4) {
stl(addr, env->gpr[reg]);
reg = (reg + 1) % 32;
- addr = addr_add(addr, 4);
+ addr = addr_add(addr, 4);
}
if (unlikely(nb > 0)) {
for (sh = 24; nb > 0; nb--, sh -= 8) {
@@ -336,13 +342,15 @@ void helper_stsw(target_ulong addr, uint32_t nb, uint32_t reg)
static void do_dcbz(target_ulong addr, int dcache_line_size)
{
- addr &= ~(dcache_line_size - 1);
int i;
- for (i = 0 ; i < dcache_line_size ; i += 4) {
- stl(addr + i , 0);
+
+ addr &= ~(dcache_line_size - 1);
+ for (i = 0; i < dcache_line_size; i += 4) {
+ stl(addr + i, 0);
}
- if (env->reserve_addr == addr)
+ if (env->reserve_addr == addr) {
env->reserve_addr = (target_ulong)-1ULL;
+ }
}
void helper_dcbz(target_ulong addr)
@@ -352,10 +360,11 @@ void helper_dcbz(target_ulong addr)
void helper_dcbz_970(target_ulong addr)
{
- if (((env->spr[SPR_970_HID5] >> 7) & 0x3) == 1)
+ if (((env->spr[SPR_970_HID5] >> 7) & 0x3) == 1) {
do_dcbz(addr, 32);
- else
+ } else {
do_dcbz(addr, env->dcache_line_size);
+ }
}
void helper_icbi(target_ulong addr)
@@ -369,20 +378,23 @@ void helper_icbi(target_ulong addr)
ldl(addr);
}
-// XXX: to be tested
-target_ulong helper_lscbx (target_ulong addr, uint32_t reg, uint32_t ra, uint32_t rb)
+/* XXX: to be tested */
+target_ulong helper_lscbx(target_ulong addr, uint32_t reg, uint32_t ra,
+ uint32_t rb)
{
int i, c, d;
+
d = 24;
for (i = 0; i < xer_bc; i++) {
c = ldub(addr);
- addr = addr_add(addr, 1);
+ addr = addr_add(addr, 1);
/* ra (if not 0) and rb are never modified */
if (likely(reg != rb && (ra == 0 || reg != ra))) {
env->gpr[reg] = (env->gpr[reg] & ~(0xFF << d)) | (c << d);
}
- if (unlikely(c == xer_cmp))
+ if (unlikely(c == xer_cmp)) {
break;
+ }
if (likely(d != 0)) {
d -= 8;
} else {
@@ -399,7 +411,7 @@ target_ulong helper_lscbx (target_ulong addr, uint32_t reg, uint32_t ra, uint32_
#if defined(TARGET_PPC64)
/* multiply high word */
-uint64_t helper_mulhd (uint64_t arg1, uint64_t arg2)
+uint64_t helper_mulhd(uint64_t arg1, uint64_t arg2)
{
uint64_t tl, th;
@@ -408,7 +420,7 @@ uint64_t helper_mulhd (uint64_t arg1, uint64_t arg2)
}
/* multiply high word unsigned */
-uint64_t helper_mulhdu (uint64_t arg1, uint64_t arg2)
+uint64_t helper_mulhdu(uint64_t arg1, uint64_t arg2)
{
uint64_t tl, th;
@@ -416,7 +428,7 @@ uint64_t helper_mulhdu (uint64_t arg1, uint64_t arg2)
return th;
}
-uint64_t helper_mulldo (uint64_t arg1, uint64_t arg2)
+uint64_t helper_mulldo(uint64_t arg1, uint64_t arg2)
{
int64_t th;
uint64_t tl;
@@ -432,20 +444,20 @@ uint64_t helper_mulldo (uint64_t arg1, uint64_t arg2)
}
#endif
-target_ulong helper_cntlzw (target_ulong t)
+target_ulong helper_cntlzw(target_ulong t)
{
return clz32(t);
}
#if defined(TARGET_PPC64)
-target_ulong helper_cntlzd (target_ulong t)
+target_ulong helper_cntlzd(target_ulong t)
{
return clz64(t);
}
#endif
/* shift right arithmetic helper */
-target_ulong helper_sraw (target_ulong value, target_ulong shift)
+target_ulong helper_sraw(target_ulong value, target_ulong shift)
{
int32_t ret;
@@ -474,7 +486,7 @@ target_ulong helper_sraw (target_ulong value, target_ulong shift)
}
#if defined(TARGET_PPC64)
-target_ulong helper_srad (target_ulong value, target_ulong shift)
+target_ulong helper_srad(target_ulong value, target_ulong shift)
{
int64_t ret;
@@ -504,7 +516,7 @@ target_ulong helper_srad (target_ulong value, target_ulong shift)
#endif
#if defined(TARGET_PPC64)
-target_ulong helper_popcntb (target_ulong val)
+target_ulong helper_popcntb(target_ulong val)
{
val = (val & 0x5555555555555555ULL) + ((val >> 1) &
0x5555555555555555ULL);
@@ -515,7 +527,7 @@ target_ulong helper_popcntb (target_ulong val)
return val;
}
-target_ulong helper_popcntw (target_ulong val)
+target_ulong helper_popcntw(target_ulong val)
{
val = (val & 0x5555555555555555ULL) + ((val >> 1) &
0x5555555555555555ULL);
@@ -530,12 +542,12 @@ target_ulong helper_popcntw (target_ulong val)
return val;
}
-target_ulong helper_popcntd (target_ulong val)
+target_ulong helper_popcntd(target_ulong val)
{
return ctpop64(val);
}
#else
-target_ulong helper_popcntb (target_ulong val)
+target_ulong helper_popcntb(target_ulong val)
{
val = (val & 0x55555555) + ((val >> 1) & 0x55555555);
val = (val & 0x33333333) + ((val >> 2) & 0x33333333);
@@ -543,7 +555,7 @@ target_ulong helper_popcntb (target_ulong val)
return val;
}
-target_ulong helper_popcntw (target_ulong val)
+target_ulong helper_popcntw(target_ulong val)
{
val = (val & 0x55555555) + ((val >> 1) & 0x55555555);
val = (val & 0x33333333) + ((val >> 2) & 0x33333333);
@@ -560,6 +572,7 @@ uint64_t helper_float32_to_float64(uint32_t arg)
{
CPU_FloatU f;
CPU_DoubleU d;
+
f.l = arg;
d.d = float32_to_float64(f.f, &env->fp_status);
return d.ll;
@@ -569,6 +582,7 @@ uint32_t helper_float64_to_float32(uint64_t arg)
{
CPU_FloatU f;
CPU_DoubleU d;
+
d.ll = arg;
f.f = float64_to_float32(d.d, &env->fp_status);
return f.l;
@@ -583,11 +597,12 @@ static inline int isden(float64 d)
return ((u.ll >> 52) & 0x7FF) == 0;
}
-uint32_t helper_compute_fprf (uint64_t arg, uint32_t set_fprf)
+uint32_t helper_compute_fprf(uint64_t arg, uint32_t set_fprf)
{
CPU_DoubleU farg;
int isneg;
int ret;
+
farg.ll = arg;
isneg = float64_is_neg(farg.d);
if (unlikely(float64_is_any_nan(farg.d))) {
@@ -600,17 +615,19 @@ uint32_t helper_compute_fprf (uint64_t arg, uint32_t set_fprf)
}
} else if (unlikely(float64_is_infinity(farg.d))) {
/* +/- infinity */
- if (isneg)
+ if (isneg) {
ret = 0x09;
- else
+ } else {
ret = 0x05;
+ }
} else {
if (float64_is_zero(farg.d)) {
/* +/- zero */
- if (isneg)
+ if (isneg) {
ret = 0x12;
- else
+ } else {
ret = 0x02;
+ }
} else {
if (isden(farg.d)) {
/* Denormalized numbers */
@@ -645,10 +662,10 @@ static inline uint64_t fload_invalid_op_excp(int op)
switch (op) {
case POWERPC_EXCP_FP_VXSNAN:
env->fpscr |= 1 << FPSCR_VXSNAN;
- break;
+ break;
case POWERPC_EXCP_FP_VXSOFT:
env->fpscr |= 1 << FPSCR_VXSOFT;
- break;
+ break;
case POWERPC_EXCP_FP_VXISI:
/* Magnitude subtraction of infinities */
env->fpscr |= 1 << FPSCR_VXISI;
@@ -711,8 +728,10 @@ static inline uint64_t fload_invalid_op_excp(int op)
if (ve != 0) {
/* Update the floating-point enabled exception summary */
env->fpscr |= 1 << FPSCR_FEX;
- if (msr_fe0 != 0 || msr_fe1 != 0)
- helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_FP | op);
+ if (msr_fe0 != 0 || msr_fe1 != 0) {
+ helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
+ POWERPC_EXCP_FP | op);
+ }
}
return ret;
}
@@ -807,7 +826,7 @@ static inline void fpscr_set_rounding_mode(void)
set_float_rounding_mode(rnd_type, &env->fp_status);
}
-void helper_fpscr_clrbit (uint32_t bit)
+void helper_fpscr_clrbit(uint32_t bit)
{
int prev;
@@ -825,7 +844,7 @@ void helper_fpscr_clrbit (uint32_t bit)
}
}
-void helper_fpscr_setbit (uint32_t bit)
+void helper_fpscr_setbit(uint32_t bit)
{
int prev;
@@ -835,27 +854,32 @@ void helper_fpscr_setbit (uint32_t bit)
switch (bit) {
case FPSCR_VX:
env->fpscr |= 1 << FPSCR_FX;
- if (fpscr_ve)
+ if (fpscr_ve) {
goto raise_ve;
+ }
case FPSCR_OX:
env->fpscr |= 1 << FPSCR_FX;
- if (fpscr_oe)
+ if (fpscr_oe) {
goto raise_oe;
+ }
break;
case FPSCR_UX:
env->fpscr |= 1 << FPSCR_FX;
- if (fpscr_ue)
+ if (fpscr_ue) {
goto raise_ue;
+ }
break;
case FPSCR_ZX:
env->fpscr |= 1 << FPSCR_FX;
- if (fpscr_ze)
+ if (fpscr_ze) {
goto raise_ze;
+ }
break;
case FPSCR_XX:
env->fpscr |= 1 << FPSCR_FX;
- if (fpscr_xe)
+ if (fpscr_xe) {
goto raise_xe;
+ }
break;
case FPSCR_VXSNAN:
case FPSCR_VXISI:
@@ -868,31 +892,41 @@ void helper_fpscr_setbit (uint32_t bit)
case FPSCR_VXCVI:
env->fpscr |= 1 << FPSCR_VX;
env->fpscr |= 1 << FPSCR_FX;
- if (fpscr_ve != 0)
+ if (fpscr_ve != 0) {
goto raise_ve;
+ }
break;
case FPSCR_VE:
if (fpscr_vx != 0) {
raise_ve:
env->error_code = POWERPC_EXCP_FP;
- if (fpscr_vxsnan)
+ if (fpscr_vxsnan) {
env->error_code |= POWERPC_EXCP_FP_VXSNAN;
- if (fpscr_vxisi)
+ }
+ if (fpscr_vxisi) {
env->error_code |= POWERPC_EXCP_FP_VXISI;
- if (fpscr_vxidi)
+ }
+ if (fpscr_vxidi) {
env->error_code |= POWERPC_EXCP_FP_VXIDI;
- if (fpscr_vxzdz)
+ }
+ if (fpscr_vxzdz) {
env->error_code |= POWERPC_EXCP_FP_VXZDZ;
- if (fpscr_vximz)
+ }
+ if (fpscr_vximz) {
env->error_code |= POWERPC_EXCP_FP_VXIMZ;
- if (fpscr_vxvc)
+ }
+ if (fpscr_vxvc) {
env->error_code |= POWERPC_EXCP_FP_VXVC;
- if (fpscr_vxsoft)
+ }
+ if (fpscr_vxsoft) {
env->error_code |= POWERPC_EXCP_FP_VXSOFT;
- if (fpscr_vxsqrt)
+ }
+ if (fpscr_vxsqrt) {
env->error_code |= POWERPC_EXCP_FP_VXSQRT;
- if (fpscr_vxcvi)
+ }
+ if (fpscr_vxcvi) {
env->error_code |= POWERPC_EXCP_FP_VXCVI;
+ }
goto raise_excp;
}
break;
@@ -933,14 +967,14 @@ void helper_fpscr_setbit (uint32_t bit)
raise_excp:
/* Update the floating-point enabled exception summary */
env->fpscr |= 1 << FPSCR_FEX;
- /* We have to update Rc1 before raising the exception */
+ /* We have to update Rc1 before raising the exception */
env->exception_index = POWERPC_EXCP_PROGRAM;
break;
}
}
}
-void helper_store_fpscr (uint64_t arg, uint32_t mask)
+void helper_store_fpscr(uint64_t arg, uint32_t mask)
{
/*
* We use only the 32 LSB of the incoming fpr
@@ -959,28 +993,30 @@ void helper_store_fpscr (uint64_t arg, uint32_t mask)
}
}
/* Update VX and FEX */
- if (fpscr_ix != 0)
+ if (fpscr_ix != 0) {
env->fpscr |= 1 << FPSCR_VX;
- else
+ } else {
env->fpscr &= ~(1 << FPSCR_VX);
+ }
if ((fpscr_ex & fpscr_eex) != 0) {
env->fpscr |= 1 << FPSCR_FEX;
env->exception_index = POWERPC_EXCP_PROGRAM;
/* XXX: we should compute it properly */
env->error_code = POWERPC_EXCP_FP;
- }
- else
+ } else {
env->fpscr &= ~(1 << FPSCR_FEX);
+ }
fpscr_set_rounding_mode();
}
-void helper_float_check_status (void)
+void helper_float_check_status(void)
{
if (env->exception_index == POWERPC_EXCP_PROGRAM &&
(env->error_code & POWERPC_EXCP_FP)) {
/* Differred floating-point exception after target FPR update */
- if (msr_fe0 != 0 || msr_fe1 != 0)
+ if (msr_fe0 != 0 || msr_fe1 != 0) {
helper_raise_exception_err(env->exception_index, env->error_code);
+ }
} else {
int status = get_float_exception_flags(&env->fp_status);
if (status & float_flag_divbyzero) {
@@ -995,13 +1031,13 @@ void helper_float_check_status (void)
}
}
-void helper_reset_fpstatus (void)
+void helper_reset_fpstatus(void)
{
set_float_exception_flags(0, &env->fp_status);
}
/* fadd - fadd. */
-uint64_t helper_fadd (uint64_t arg1, uint64_t arg2)
+uint64_t helper_fadd(uint64_t arg1, uint64_t arg2)
{
CPU_DoubleU farg1, farg2;
@@ -1025,7 +1061,7 @@ uint64_t helper_fadd (uint64_t arg1, uint64_t arg2)
}
/* fsub - fsub. */
-uint64_t helper_fsub (uint64_t arg1, uint64_t arg2)
+uint64_t helper_fsub(uint64_t arg1, uint64_t arg2)
{
CPU_DoubleU farg1, farg2;
@@ -1049,7 +1085,7 @@ uint64_t helper_fsub (uint64_t arg1, uint64_t arg2)
}
/* fmul - fmul. */
-uint64_t helper_fmul (uint64_t arg1, uint64_t arg2)
+uint64_t helper_fmul(uint64_t arg1, uint64_t arg2)
{
CPU_DoubleU farg1, farg2;
@@ -1073,14 +1109,15 @@ uint64_t helper_fmul (uint64_t arg1, uint64_t arg2)
}
/* fdiv - fdiv. */
-uint64_t helper_fdiv (uint64_t arg1, uint64_t arg2)
+uint64_t helper_fdiv(uint64_t arg1, uint64_t arg2)
{
CPU_DoubleU farg1, farg2;
farg1.ll = arg1;
farg2.ll = arg2;
- if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d))) {
+ if (unlikely(float64_is_infinity(farg1.d) &&
+ float64_is_infinity(farg2.d))) {
/* Division of infinity by infinity */
farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIDI);
} else if (unlikely(float64_is_zero(farg1.d) && float64_is_zero(farg2.d))) {
@@ -1099,7 +1136,7 @@ uint64_t helper_fdiv (uint64_t arg1, uint64_t arg2)
}
/* fabs */
-uint64_t helper_fabs (uint64_t arg)
+uint64_t helper_fabs(uint64_t arg)
{
CPU_DoubleU farg;
@@ -1109,7 +1146,7 @@ uint64_t helper_fabs (uint64_t arg)
}
/* fnabs */
-uint64_t helper_fnabs (uint64_t arg)
+uint64_t helper_fnabs(uint64_t arg)
{
CPU_DoubleU farg;
@@ -1120,7 +1157,7 @@ uint64_t helper_fnabs (uint64_t arg)
}
/* fneg */
-uint64_t helper_fneg (uint64_t arg)
+uint64_t helper_fneg(uint64_t arg)
{
CPU_DoubleU farg;
@@ -1130,15 +1167,18 @@ uint64_t helper_fneg (uint64_t arg)
}
/* fctiw - fctiw. */
-uint64_t helper_fctiw (uint64_t arg)
+uint64_t helper_fctiw(uint64_t arg)
{
CPU_DoubleU farg;
+
farg.ll = arg;
if (unlikely(float64_is_signaling_nan(farg.d))) {
/* sNaN conversion */
- farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
- } else if (unlikely(float64_is_quiet_nan(farg.d) || float64_is_infinity(farg.d))) {
+ farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN |
+ POWERPC_EXCP_FP_VXCVI);
+ } else if (unlikely(float64_is_quiet_nan(farg.d) ||
+ float64_is_infinity(farg.d))) {
/* qNan / infinity conversion */
farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
} else {
@@ -1152,15 +1192,18 @@ uint64_t helper_fctiw (uint64_t arg)
}
/* fctiwz - fctiwz. */
-uint64_t helper_fctiwz (uint64_t arg)
+uint64_t helper_fctiwz(uint64_t arg)
{
CPU_DoubleU farg;
+
farg.ll = arg;
if (unlikely(float64_is_signaling_nan(farg.d))) {
/* sNaN conversion */
- farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
- } else if (unlikely(float64_is_quiet_nan(farg.d) || float64_is_infinity(farg.d))) {
+ farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN |
+ POWERPC_EXCP_FP_VXCVI);
+ } else if (unlikely(float64_is_quiet_nan(farg.d) ||
+ float64_is_infinity(farg.d))) {
/* qNan / infinity conversion */
farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
} else {
@@ -1175,23 +1218,27 @@ uint64_t helper_fctiwz (uint64_t arg)
#if defined(TARGET_PPC64)
/* fcfid - fcfid. */
-uint64_t helper_fcfid (uint64_t arg)
+uint64_t helper_fcfid(uint64_t arg)
{
CPU_DoubleU farg;
+
farg.d = int64_to_float64(arg, &env->fp_status);
return farg.ll;
}
/* fctid - fctid. */
-uint64_t helper_fctid (uint64_t arg)
+uint64_t helper_fctid(uint64_t arg)
{
CPU_DoubleU farg;
+
farg.ll = arg;
if (unlikely(float64_is_signaling_nan(farg.d))) {
/* sNaN conversion */
- farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
- } else if (unlikely(float64_is_quiet_nan(farg.d) || float64_is_infinity(farg.d))) {
+ farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN |
+ POWERPC_EXCP_FP_VXCVI);
+ } else if (unlikely(float64_is_quiet_nan(farg.d) ||
+ float64_is_infinity(farg.d))) {
/* qNan / infinity conversion */
farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
} else {
@@ -1201,15 +1248,18 @@ uint64_t helper_fctid (uint64_t arg)
}
/* fctidz - fctidz. */
-uint64_t helper_fctidz (uint64_t arg)
+uint64_t helper_fctidz(uint64_t arg)
{
CPU_DoubleU farg;
+
farg.ll = arg;
if (unlikely(float64_is_signaling_nan(farg.d))) {
/* sNaN conversion */
- farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
- } else if (unlikely(float64_is_quiet_nan(farg.d) || float64_is_infinity(farg.d))) {
+ farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN |
+ POWERPC_EXCP_FP_VXCVI);
+ } else if (unlikely(float64_is_quiet_nan(farg.d) ||
+ float64_is_infinity(farg.d))) {
/* qNan / infinity conversion */
farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
} else {
@@ -1223,12 +1273,15 @@ uint64_t helper_fctidz (uint64_t arg)
static inline uint64_t do_fri(uint64_t arg, int rounding_mode)
{
CPU_DoubleU farg;
+
farg.ll = arg;
if (unlikely(float64_is_signaling_nan(farg.d))) {
/* sNaN round */
- farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
- } else if (unlikely(float64_is_quiet_nan(farg.d) || float64_is_infinity(farg.d))) {
+ farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN |
+ POWERPC_EXCP_FP_VXCVI);
+ } else if (unlikely(float64_is_quiet_nan(farg.d) ||
+ float64_is_infinity(farg.d))) {
/* qNan / infinity round */
farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
} else {
@@ -1240,28 +1293,28 @@ static inline uint64_t do_fri(uint64_t arg, int rounding_mode)
return farg.ll;
}
-uint64_t helper_frin (uint64_t arg)
+uint64_t helper_frin(uint64_t arg)
{
return do_fri(arg, float_round_nearest_even);
}
-uint64_t helper_friz (uint64_t arg)
+uint64_t helper_friz(uint64_t arg)
{
return do_fri(arg, float_round_to_zero);
}
-uint64_t helper_frip (uint64_t arg)
+uint64_t helper_frip(uint64_t arg)
{
return do_fri(arg, float_round_up);
}
-uint64_t helper_frim (uint64_t arg)
+uint64_t helper_frim(uint64_t arg)
{
return do_fri(arg, float_round_down);
}
/* fmadd - fmadd. */
-uint64_t helper_fmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3)
+uint64_t helper_fmadd(uint64_t arg1, uint64_t arg2, uint64_t arg3)
{
CPU_DoubleU farg1, farg2, farg3;
@@ -1286,7 +1339,8 @@ uint64_t helper_fmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3)
ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
- if (unlikely(float128_is_infinity(ft0_128) && float64_is_infinity(farg3.d) &&
+ if (unlikely(float128_is_infinity(ft0_128) &&
+ float64_is_infinity(farg3.d) &&
float128_is_neg(ft0_128) != float64_is_neg(farg3.d))) {
/* Magnitude subtraction of infinities */
farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
@@ -1301,7 +1355,7 @@ uint64_t helper_fmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3)
}
/* fmsub - fmsub. */
-uint64_t helper_fmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3)
+uint64_t helper_fmsub(uint64_t arg1, uint64_t arg2, uint64_t arg3)
{
CPU_DoubleU farg1, farg2, farg3;
@@ -1310,7 +1364,8 @@ uint64_t helper_fmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3)
farg3.ll = arg3;
if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
- (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
+ (float64_is_zero(farg1.d) &&
+ float64_is_infinity(farg2.d)))) {
/* Multiplication of zero by infinity */
farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
} else {
@@ -1326,7 +1381,8 @@ uint64_t helper_fmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3)
ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
- if (unlikely(float128_is_infinity(ft0_128) && float64_is_infinity(farg3.d) &&
+ if (unlikely(float128_is_infinity(ft0_128) &&
+ float64_is_infinity(farg3.d) &&
float128_is_neg(ft0_128) == float64_is_neg(farg3.d))) {
/* Magnitude subtraction of infinities */
farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
@@ -1340,7 +1396,7 @@ uint64_t helper_fmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3)
}
/* fnmadd - fnmadd. */
-uint64_t helper_fnmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3)
+uint64_t helper_fnmadd(uint64_t arg1, uint64_t arg2, uint64_t arg3)
{
CPU_DoubleU farg1, farg2, farg3;
@@ -1365,7 +1421,8 @@ uint64_t helper_fnmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3)
ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
- if (unlikely(float128_is_infinity(ft0_128) && float64_is_infinity(farg3.d) &&
+ if (unlikely(float128_is_infinity(ft0_128) &&
+ float64_is_infinity(farg3.d) &&
float128_is_neg(ft0_128) != float64_is_neg(farg3.d))) {
/* Magnitude subtraction of infinities */
farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
@@ -1382,7 +1439,7 @@ uint64_t helper_fnmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3)
}
/* fnmsub - fnmsub. */
-uint64_t helper_fnmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3)
+uint64_t helper_fnmsub(uint64_t arg1, uint64_t arg2, uint64_t arg3)
{
CPU_DoubleU farg1, farg2, farg3;
@@ -1391,7 +1448,8 @@ uint64_t helper_fnmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3)
farg3.ll = arg3;
if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
- (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
+ (float64_is_zero(farg1.d) &&
+ float64_is_infinity(farg2.d)))) {
/* Multiplication of zero by infinity */
farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
} else {
@@ -1407,7 +1465,8 @@ uint64_t helper_fnmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3)
ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
- if (unlikely(float128_is_infinity(ft0_128) && float64_is_infinity(farg3.d) &&
+ if (unlikely(float128_is_infinity(ft0_128) &&
+ float64_is_infinity(farg3.d) &&
float128_is_neg(ft0_128) == float64_is_neg(farg3.d))) {
/* Magnitude subtraction of infinities */
farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
@@ -1424,15 +1483,16 @@ uint64_t helper_fnmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3)
}
/* frsp - frsp. */
-uint64_t helper_frsp (uint64_t arg)
+uint64_t helper_frsp(uint64_t arg)
{
CPU_DoubleU farg;
float32 f32;
+
farg.ll = arg;
if (unlikely(float64_is_signaling_nan(farg.d))) {
/* sNaN square root */
- fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
+ fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
}
f32 = float64_to_float32(farg.d, &env->fp_status);
farg.d = float32_to_float64(f32, &env->fp_status);
@@ -1441,9 +1501,10 @@ uint64_t helper_frsp (uint64_t arg)
}
/* fsqrt - fsqrt. */
-uint64_t helper_fsqrt (uint64_t arg)
+uint64_t helper_fsqrt(uint64_t arg)
{
CPU_DoubleU farg;
+
farg.ll = arg;
if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) {
@@ -1460,9 +1521,10 @@ uint64_t helper_fsqrt (uint64_t arg)
}
/* fre - fre. */
-uint64_t helper_fre (uint64_t arg)
+uint64_t helper_fre(uint64_t arg)
{
CPU_DoubleU farg;
+
farg.ll = arg;
if (unlikely(float64_is_signaling_nan(farg.d))) {
@@ -1474,10 +1536,11 @@ uint64_t helper_fre (uint64_t arg)
}
/* fres - fres. */
-uint64_t helper_fres (uint64_t arg)
+uint64_t helper_fres(uint64_t arg)
{
CPU_DoubleU farg;
float32 f32;
+
farg.ll = arg;
if (unlikely(float64_is_signaling_nan(farg.d))) {
@@ -1492,10 +1555,11 @@ uint64_t helper_fres (uint64_t arg)
}
/* frsqrte - frsqrte. */
-uint64_t helper_frsqrte (uint64_t arg)
+uint64_t helper_frsqrte(uint64_t arg)
{
CPU_DoubleU farg;
float32 f32;
+
farg.ll = arg;
if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) {
@@ -1515,23 +1579,25 @@ uint64_t helper_frsqrte (uint64_t arg)
}
/* fsel - fsel. */
-uint64_t helper_fsel (uint64_t arg1, uint64_t arg2, uint64_t arg3)
+uint64_t helper_fsel(uint64_t arg1, uint64_t arg2, uint64_t arg3)
{
CPU_DoubleU farg1;
farg1.ll = arg1;
- if ((!float64_is_neg(farg1.d) || float64_is_zero(farg1.d)) && !float64_is_any_nan(farg1.d)) {
+ if ((!float64_is_neg(farg1.d) || float64_is_zero(farg1.d)) &&
+ !float64_is_any_nan(farg1.d)) {
return arg2;
} else {
return arg3;
}
}
-void helper_fcmpu (uint64_t arg1, uint64_t arg2, uint32_t crfD)
+void helper_fcmpu(uint64_t arg1, uint64_t arg2, uint32_t crfD)
{
CPU_DoubleU farg1, farg2;
uint32_t ret = 0;
+
farg1.ll = arg1;
farg2.ll = arg2;
@@ -1557,10 +1623,11 @@ void helper_fcmpu (uint64_t arg1, uint64_t arg2, uint32_t crfD)
}
}
-void helper_fcmpo (uint64_t arg1, uint64_t arg2, uint32_t crfD)
+void helper_fcmpo(uint64_t arg1, uint64_t arg2, uint32_t crfD)
{
CPU_DoubleU farg1, farg2;
uint32_t ret = 0;
+
farg1.ll = arg1;
farg2.ll = arg2;
@@ -1578,7 +1645,7 @@ void helper_fcmpo (uint64_t arg1, uint64_t arg2, uint32_t crfD)
env->fpscr &= ~(0x0F << FPSCR_FPRF);
env->fpscr |= ret << FPSCR_FPRF;
env->crf[crfD] = ret;
- if (unlikely (ret == 0x01UL)) {
+ if (unlikely(ret == 0x01UL)) {
if (float64_is_signaling_nan(farg1.d) ||
float64_is_signaling_nan(farg2.d)) {
/* sNaN comparison */
@@ -1591,8 +1658,8 @@ void helper_fcmpo (uint64_t arg1, uint64_t arg2, uint32_t crfD)
}
}
-#if !defined (CONFIG_USER_ONLY)
-void helper_store_msr (target_ulong val)
+#if !defined(CONFIG_USER_ONLY)
+void helper_store_msr(target_ulong val)
{
val = hreg_store_msr(env, val, 0);
if (val != 0) {
@@ -1611,8 +1678,9 @@ static inline void do_rfi(target_ulong nip, target_ulong msr,
} else {
nip = (uint32_t)nip;
msr = (uint32_t)(msr & msrm);
- if (keep_msrh)
+ if (keep_msrh) {
msr |= env->msr & ~((uint64_t)0xFFFFFFFF);
+ }
}
#else
nip = (uint32_t)nip;
@@ -1621,7 +1689,7 @@ static inline void do_rfi(target_ulong nip, target_ulong msr,
/* XXX: beware: this is false if VLE is supported */
env->nip = nip & ~((target_ulong)0x00000003);
hreg_store_msr(env, msr, 1);
-#if defined (DEBUG_OP)
+#if defined(DEBUG_OP)
cpu_dump_rfi(env->nip, env->msr);
#endif
/* No need to raise an exception here,
@@ -1630,20 +1698,20 @@ static inline void do_rfi(target_ulong nip, target_ulong msr,
env->interrupt_request |= CPU_INTERRUPT_EXITTB;
}
-void helper_rfi (void)
+void helper_rfi(void)
{
do_rfi(env->spr[SPR_SRR0], env->spr[SPR_SRR1],
~((target_ulong)0x783F0000), 1);
}
#if defined(TARGET_PPC64)
-void helper_rfid (void)
+void helper_rfid(void)
{
do_rfi(env->spr[SPR_SRR0], env->spr[SPR_SRR1],
~((target_ulong)0x783F0000), 0);
}
-void helper_hrfid (void)
+void helper_hrfid(void)
{
do_rfi(env->spr[SPR_HSRR0], env->spr[SPR_HSRR1],
~((target_ulong)0x783F0000), 0);
@@ -1651,7 +1719,7 @@ void helper_hrfid (void)
#endif
#endif
-void helper_tw (target_ulong arg1, target_ulong arg2, uint32_t flags)
+void helper_tw(target_ulong arg1, target_ulong arg2, uint32_t flags)
{
if (!likely(!(((int32_t)arg1 < (int32_t)arg2 && (flags & 0x10)) ||
((int32_t)arg1 > (int32_t)arg2 && (flags & 0x08)) ||
@@ -1663,21 +1731,22 @@ void helper_tw (target_ulong arg1, target_ulong arg2, uint32_t flags)
}
#if defined(TARGET_PPC64)
-void helper_td (target_ulong arg1, target_ulong arg2, uint32_t flags)
+void helper_td(target_ulong arg1, target_ulong arg2, uint32_t flags)
{
if (!likely(!(((int64_t)arg1 < (int64_t)arg2 && (flags & 0x10)) ||
((int64_t)arg1 > (int64_t)arg2 && (flags & 0x08)) ||
((int64_t)arg1 == (int64_t)arg2 && (flags & 0x04)) ||
((uint64_t)arg1 < (uint64_t)arg2 && (flags & 0x02)) ||
- ((uint64_t)arg1 > (uint64_t)arg2 && (flags & 0x01)))))
+ ((uint64_t)arg1 > (uint64_t)arg2 && (flags & 0x01))))) {
helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_TRAP);
+ }
}
#endif
/*****************************************************************************/
/* PowerPC 601 specific instructions (POWER bridge) */
-target_ulong helper_clcs (uint32_t arg)
+target_ulong helper_clcs(uint32_t arg)
{
switch (arg) {
case 0x0CUL:
@@ -1691,12 +1760,12 @@ target_ulong helper_clcs (uint32_t arg)
case 0x0EUL:
/* Minimum cache line size */
return (env->icache_line_size < env->dcache_line_size) ?
- env->icache_line_size : env->dcache_line_size;
+ env->icache_line_size : env->dcache_line_size;
break;
case 0x0FUL:
/* Maximum cache line size */
return (env->icache_line_size > env->dcache_line_size) ?
- env->icache_line_size : env->dcache_line_size;
+ env->icache_line_size : env->dcache_line_size;
break;
default:
/* Undefined */
@@ -1705,7 +1774,7 @@ target_ulong helper_clcs (uint32_t arg)
}
}
-target_ulong helper_div (target_ulong arg1, target_ulong arg2)
+target_ulong helper_div(target_ulong arg1, target_ulong arg2)
{
uint64_t tmp = (uint64_t)arg1 << 32 | env->spr[SPR_MQ];
@@ -1719,7 +1788,7 @@ target_ulong helper_div (target_ulong arg1, target_ulong arg2)
}
}
-target_ulong helper_divo (target_ulong arg1, target_ulong arg2)
+target_ulong helper_divo(target_ulong arg1, target_ulong arg2)
{
uint64_t tmp = (uint64_t)arg1 << 32 | env->spr[SPR_MQ];
@@ -1731,7 +1800,7 @@ target_ulong helper_divo (target_ulong arg1, target_ulong arg2)
} else {
env->spr[SPR_MQ] = tmp % arg2;
tmp /= (int32_t)arg2;
- if ((int32_t)tmp != tmp) {
+ if ((int32_t)tmp != tmp) {
env->xer |= (1 << XER_OV) | (1 << XER_SO);
} else {
env->xer &= ~(1 << XER_OV);
@@ -1740,7 +1809,7 @@ target_ulong helper_divo (target_ulong arg1, target_ulong arg2)
}
}
-target_ulong helper_divs (target_ulong arg1, target_ulong arg2)
+target_ulong helper_divs(target_ulong arg1, target_ulong arg2)
{
if (((int32_t)arg1 == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
(int32_t)arg2 == 0) {
@@ -1752,7 +1821,7 @@ target_ulong helper_divs (target_ulong arg1, target_ulong arg2)
}
}
-target_ulong helper_divso (target_ulong arg1, target_ulong arg2)
+target_ulong helper_divso(target_ulong arg1, target_ulong arg2)
{
if (((int32_t)arg1 == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
(int32_t)arg2 == 0) {
@@ -1766,8 +1835,8 @@ target_ulong helper_divso (target_ulong arg1, target_ulong arg2)
}
}
-#if !defined (CONFIG_USER_ONLY)
-target_ulong helper_rac (target_ulong addr)
+#if !defined(CONFIG_USER_ONLY)
+target_ulong helper_rac(target_ulong addr)
{
mmu_ctx_t ctx;
int nb_BATs;
@@ -1779,13 +1848,14 @@ target_ulong helper_rac (target_ulong addr)
/* XXX: FIX THIS: Pretend we have no BAT */
nb_BATs = env->nb_BATs;
env->nb_BATs = 0;
- if (get_physical_address(env, &ctx, addr, 0, ACCESS_INT) == 0)
+ if (get_physical_address(env, &ctx, addr, 0, ACCESS_INT) == 0) {
ret = ctx.raddr;
+ }
env->nb_BATs = nb_BATs;
return ret;
}
-void helper_rfsvc (void)
+void helper_rfsvc(void)
{
do_rfi(env->lr, env->ctr, 0x0000FFFF, 0);
}
@@ -1799,8 +1869,8 @@ void helper_rfsvc (void)
* -arg / 256
* return 256 * log10(10 + 1.0) + 0.5
*/
-#if !defined (CONFIG_USER_ONLY)
-target_ulong helper_602_mfrom (target_ulong arg)
+#if !defined(CONFIG_USER_ONLY)
+target_ulong helper_602_mfrom(target_ulong arg)
{
if (likely(arg < 602)) {
#include "mfrom_table.c"
@@ -1815,15 +1885,17 @@ target_ulong helper_602_mfrom (target_ulong arg)
/* Embedded PowerPC specific helpers */
/* XXX: to be improved to check access rights when in user-mode */
-target_ulong helper_load_dcr (target_ulong dcrn)
+target_ulong helper_load_dcr(target_ulong dcrn)
{
uint32_t val = 0;
if (unlikely(env->dcr_env == NULL)) {
qemu_log("No DCR environment\n");
helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
- POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL);
- } else if (unlikely(ppc_dcr_read(env->dcr_env, (uint32_t)dcrn, &val) != 0)) {
+ POWERPC_EXCP_INVAL |
+ POWERPC_EXCP_INVAL_INVAL);
+ } else if (unlikely(ppc_dcr_read(env->dcr_env,
+ (uint32_t)dcrn, &val) != 0)) {
qemu_log("DCR read error %d %03x\n", (uint32_t)dcrn, (uint32_t)dcrn);
helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG);
@@ -1831,13 +1903,15 @@ target_ulong helper_load_dcr (target_ulong dcrn)
return val;
}
-void helper_store_dcr (target_ulong dcrn, target_ulong val)
+void helper_store_dcr(target_ulong dcrn, target_ulong val)
{
if (unlikely(env->dcr_env == NULL)) {
qemu_log("No DCR environment\n");
helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
- POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL);
- } else if (unlikely(ppc_dcr_write(env->dcr_env, (uint32_t)dcrn, (uint32_t)val) != 0)) {
+ POWERPC_EXCP_INVAL |
+ POWERPC_EXCP_INVAL_INVAL);
+ } else if (unlikely(ppc_dcr_write(env->dcr_env, (uint32_t)dcrn,
+ (uint32_t)val) != 0)) {
qemu_log("DCR write error %d %03x\n", (uint32_t)dcrn, (uint32_t)dcrn);
helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG);
@@ -1845,25 +1919,25 @@ void helper_store_dcr (target_ulong dcrn, target_ulong val)
}
#if !defined(CONFIG_USER_ONLY)
-void helper_40x_rfci (void)
+void helper_40x_rfci(void)
{
do_rfi(env->spr[SPR_40x_SRR2], env->spr[SPR_40x_SRR3],
~((target_ulong)0xFFFF0000), 0);
}
-void helper_rfci (void)
+void helper_rfci(void)
{
do_rfi(env->spr[SPR_BOOKE_CSRR0], SPR_BOOKE_CSRR1,
~((target_ulong)0x3FFF0000), 0);
}
-void helper_rfdi (void)
+void helper_rfdi(void)
{
do_rfi(env->spr[SPR_BOOKE_DSRR0], SPR_BOOKE_DSRR1,
~((target_ulong)0x3FFF0000), 0);
}
-void helper_rfmci (void)
+void helper_rfmci(void)
{
do_rfi(env->spr[SPR_BOOKE_MCSRR0], SPR_BOOKE_MCSRR1,
~((target_ulong)0x3FFF0000), 0);
@@ -1871,7 +1945,8 @@ void helper_rfmci (void)
#endif
/* 440 specific */
-target_ulong helper_dlmzb (target_ulong high, target_ulong low, uint32_t update_Rc)
+target_ulong helper_dlmzb(target_ulong high, target_ulong low,
+ uint32_t update_Rc)
{
target_ulong mask;
int i;
@@ -1917,57 +1992,59 @@ target_ulong helper_dlmzb (target_ulong high, target_ulong low, uint32_t update_
#endif
#if defined(HOST_WORDS_BIGENDIAN)
-#define VECTOR_FOR_INORDER_I(index, element) \
+#define VECTOR_FOR_INORDER_I(index, element) \
for (index = 0; index < ARRAY_SIZE(r->element); index++)
#else
-#define VECTOR_FOR_INORDER_I(index, element) \
- for (index = ARRAY_SIZE(r->element)-1; index >= 0; index--)
+#define VECTOR_FOR_INORDER_I(index, element) \
+ for (index = ARRAY_SIZE(r->element)-1; index >= 0; index--)
#endif
/* If X is a NaN, store the corresponding QNaN into RESULT. Otherwise,
* execute the following block. */
-#define DO_HANDLE_NAN(result, x) \
- if (float32_is_any_nan(x)) { \
- CPU_FloatU __f; \
- __f.f = x; \
- __f.l = __f.l | (1 << 22); /* Set QNaN bit. */ \
- result = __f.f; \
+#define DO_HANDLE_NAN(result, x) \
+ if (float32_is_any_nan(x)) { \
+ CPU_FloatU __f; \
+ __f.f = x; \
+ __f.l = __f.l | (1 << 22); /* Set QNaN bit. */ \
+ result = __f.f; \
} else
#define HANDLE_NAN1(result, x) \
DO_HANDLE_NAN(result, x)
-#define HANDLE_NAN2(result, x, y) \
+#define HANDLE_NAN2(result, x, y) \
DO_HANDLE_NAN(result, x) DO_HANDLE_NAN(result, y)
-#define HANDLE_NAN3(result, x, y, z) \
+#define HANDLE_NAN3(result, x, y, z) \
DO_HANDLE_NAN(result, x) DO_HANDLE_NAN(result, y) DO_HANDLE_NAN(result, z)
/* Saturating arithmetic helpers. */
-#define SATCVT(from, to, from_type, to_type, min, max) \
- static inline to_type cvt##from##to(from_type x, int *sat) \
- { \
- to_type r; \
- if (x < (from_type)min) { \
- r = min; \
- *sat = 1; \
- } else if (x > (from_type)max) { \
- r = max; \
- *sat = 1; \
- } else { \
- r = x; \
- } \
- return r; \
+#define SATCVT(from, to, from_type, to_type, min, max) \
+ static inline to_type cvt##from##to(from_type x, int *sat) \
+ { \
+ to_type r; \
+ \
+ if (x < (from_type)min) { \
+ r = min; \
+ *sat = 1; \
+ } else if (x > (from_type)max) { \
+ r = max; \
+ *sat = 1; \
+ } else { \
+ r = x; \
+ } \
+ return r; \
}
-#define SATCVTU(from, to, from_type, to_type, min, max) \
- static inline to_type cvt##from##to(from_type x, int *sat) \
- { \
- to_type r; \
- if (x > (from_type)max) { \
- r = max; \
- *sat = 1; \
- } else { \
- r = x; \
- } \
- return r; \
+#define SATCVTU(from, to, from_type, to_type, min, max) \
+ static inline to_type cvt##from##to(from_type x, int *sat) \
+ { \
+ to_type r; \
+ \
+ if (x > (from_type)max) { \
+ r = max; \
+ *sat = 1; \
+ } else { \
+ r = x; \
+ } \
+ return r; \
}
SATCVT(sh, sb, int16_t, int8_t, INT8_MIN, INT8_MAX)
SATCVT(sw, sh, int32_t, int16_t, INT16_MIN, INT16_MAX)
@@ -1983,17 +2060,20 @@ SATCVT(sd, uw, int64_t, uint32_t, 0, UINT32_MAX)
#undef SATCVTU
#define LVE(name, access, swap, element) \
- void helper_##name (ppc_avr_t *r, target_ulong addr) \
+ void helper_##name(ppc_avr_t *r, target_ulong addr) \
{ \
size_t n_elems = ARRAY_SIZE(r->element); \
- int adjust = HI_IDX*(n_elems-1); \
+ int adjust = HI_IDX*(n_elems - 1); \
int sh = sizeof(r->element[0]) >> 1; \
int index = (addr & 0xf) >> sh; \
- if(msr_le) { \
- r->element[LO_IDX ? index : (adjust - index)] = swap(access(addr)); \
- } else { \
- r->element[LO_IDX ? index : (adjust - index)] = access(addr); \
- } \
+ \
+ if (msr_le) { \
+ r->element[LO_IDX ? index : (adjust - index)] = \
+ swap(access(addr)); \
+ } else { \
+ r->element[LO_IDX ? index : (adjust - index)] = \
+ access(addr); \
+ } \
}
#define I(x) (x)
LVE(lvebx, ldub, I, u8)
@@ -2002,32 +2082,33 @@ LVE(lvewx, ldl, bswap32, u32)
#undef I
#undef LVE
-void helper_lvsl (ppc_avr_t *r, target_ulong sh)
+void helper_lvsl(ppc_avr_t *r, target_ulong sh)
{
int i, j = (sh & 0xf);
- VECTOR_FOR_INORDER_I (i, u8) {
+ VECTOR_FOR_INORDER_I(i, u8) {
r->u8[i] = j++;
}
}
-void helper_lvsr (ppc_avr_t *r, target_ulong sh)
+void helper_lvsr(ppc_avr_t *r, target_ulong sh)
{
int i, j = 0x10 - (sh & 0xf);
- VECTOR_FOR_INORDER_I (i, u8) {
+ VECTOR_FOR_INORDER_I(i, u8) {
r->u8[i] = j++;
}
}
-#define STVE(name, access, swap, element) \
- void helper_##name (ppc_avr_t *r, target_ulong addr) \
- { \
- size_t n_elems = ARRAY_SIZE(r->element); \
- int adjust = HI_IDX*(n_elems-1); \
- int sh = sizeof(r->element[0]) >> 1; \
- int index = (addr & 0xf) >> sh; \
- if(msr_le) { \
+#define STVE(name, access, swap, element) \
+ void helper_##name(ppc_avr_t *r, target_ulong addr) \
+ { \
+ size_t n_elems = ARRAY_SIZE(r->element); \
+ int adjust = HI_IDX * (n_elems - 1); \
+ int sh = sizeof(r->element[0]) >> 1; \
+ int index = (addr & 0xf) >> sh; \
+ \
+ if (msr_le) { \
access(addr, swap(r->element[LO_IDX ? index : (adjust - index)])); \
} else { \
access(addr, r->element[LO_IDX ? index : (adjust - index)]); \
@@ -2040,7 +2121,7 @@ STVE(stvewx, stl, bswap32, u32)
#undef I
#undef LVE
-void helper_mtvscr (ppc_avr_t *r)
+void helper_mtvscr(ppc_avr_t *r)
{
#if defined(HOST_WORDS_BIGENDIAN)
env->vscr = r->u32[3];
@@ -2050,25 +2131,27 @@ void helper_mtvscr (ppc_avr_t *r)
set_flush_to_zero(vscr_nj, &env->vec_status);
}
-void helper_vaddcuw (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
+void helper_vaddcuw(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
{
int i;
+
for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
r->u32[i] = ~a->u32[i] < b->u32[i];
}
}
-#define VARITH_DO(name, op, element) \
-void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
-{ \
- int i; \
- for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
- r->element[i] = a->element[i] op b->element[i]; \
- } \
-}
-#define VARITH(suffix, element) \
- VARITH_DO(add##suffix, +, element) \
- VARITH_DO(sub##suffix, -, element)
+#define VARITH_DO(name, op, element) \
+ void helper_v##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
+ { \
+ int i; \
+ \
+ for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
+ r->element[i] = a->element[i] op b->element[i]; \
+ } \
+ }
+#define VARITH(suffix, element) \
+ VARITH_DO(add##suffix, +, element) \
+ VARITH_DO(sub##suffix, -, element)
VARITH(ubm, u8)
VARITH(uhm, u16)
VARITH(uwm, u32)
@@ -2076,9 +2159,10 @@ VARITH(uwm, u32)
#undef VARITH
#define VARITHFP(suffix, func) \
- void helper_v##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
+ void helper_v##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
{ \
int i; \
+ \
for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
HANDLE_NAN2(r->f[i], a->f[i], b->f[i]) { \
r->f[i] = func(a->f[i], b->f[i], &env->vec_status); \
@@ -2096,26 +2180,33 @@ VARITHFP(subfp, float32_sub)
}
#define VARITHSAT_DO(name, op, optype, cvt, element) \
- void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
+ void helper_v##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
{ \
int sat = 0; \
int i; \
+ \
for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
switch (sizeof(r->element[0])) { \
- case 1: VARITHSAT_CASE(optype, op, cvt, element); break; \
- case 2: VARITHSAT_CASE(optype, op, cvt, element); break; \
- case 4: VARITHSAT_CASE(optype, op, cvt, element); break; \
+ case 1: \
+ VARITHSAT_CASE(optype, op, cvt, element); \
+ break; \
+ case 2: \
+ VARITHSAT_CASE(optype, op, cvt, element); \
+ break; \
+ case 4: \
+ VARITHSAT_CASE(optype, op, cvt, element); \
+ break; \
} \
} \
if (sat) { \
env->vscr |= (1 << VSCR_SAT); \
} \
}
-#define VARITHSAT_SIGNED(suffix, element, optype, cvt) \
- VARITHSAT_DO(adds##suffix##s, +, optype, cvt, element) \
+#define VARITHSAT_SIGNED(suffix, element, optype, cvt) \
+ VARITHSAT_DO(adds##suffix##s, +, optype, cvt, element) \
VARITHSAT_DO(subs##suffix##s, -, optype, cvt, element)
-#define VARITHSAT_UNSIGNED(suffix, element, optype, cvt) \
- VARITHSAT_DO(addu##suffix##s, +, optype, cvt, element) \
+#define VARITHSAT_UNSIGNED(suffix, element, optype, cvt) \
+ VARITHSAT_DO(addu##suffix##s, +, optype, cvt, element) \
VARITHSAT_DO(subu##suffix##s, -, optype, cvt, element)
VARITHSAT_SIGNED(b, s8, int16_t, cvtshsb)
VARITHSAT_SIGNED(h, s16, int32_t, cvtswsh)
@@ -2129,16 +2220,18 @@ VARITHSAT_UNSIGNED(w, u32, uint64_t, cvtsduw)
#undef VARITHSAT_UNSIGNED
#define VAVG_DO(name, element, etype) \
- void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
+ void helper_v##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
{ \
int i; \
+ \
for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
etype x = (etype)a->element[i] + (etype)b->element[i] + 1; \
r->element[i] = x >> 1; \
} \
}
-#define VAVG(type, signed_element, signed_type, unsigned_element, unsigned_type) \
+#define VAVG(type, signed_element, signed_type, unsigned_element, \
+ unsigned_type) \
VAVG_DO(avgs##type, signed_element, signed_type) \
VAVG_DO(avgu##type, unsigned_element, unsigned_type)
VAVG(b, s8, int16_t, u8, uint16_t)
@@ -2148,12 +2241,13 @@ VAVG(w, s32, int64_t, u32, uint64_t)
#undef VAVG
#define VCF(suffix, cvt, element) \
- void helper_vcf##suffix (ppc_avr_t *r, ppc_avr_t *b, uint32_t uim) \
+ void helper_vcf##suffix(ppc_avr_t *r, ppc_avr_t *b, uint32_t uim) \
{ \
int i; \
+ \
for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
float32 t = cvt(b->element[i], &env->vec_status); \
- r->f[i] = float32_scalbn (t, -uim, &env->vec_status); \
+ r->f[i] = float32_scalbn(t, -uim, &env->vec_status); \
} \
}
VCF(ux, uint32_to_float32, u32)
@@ -2161,18 +2255,26 @@ VCF(sx, int32_to_float32, s32)
#undef VCF
#define VCMP_DO(suffix, compare, element, record) \
- void helper_vcmp##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
+ void helper_vcmp##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
{ \
uint32_t ones = (uint32_t)-1; \
uint32_t all = ones; \
uint32_t none = 0; \
int i; \
+ \
for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
- uint32_t result = (a->element[i] compare b->element[i] ? ones : 0x0); \
- switch (sizeof (a->element[0])) { \
- case 4: r->u32[i] = result; break; \
- case 2: r->u16[i] = result; break; \
- case 1: r->u8[i] = result; break; \
+ uint32_t result = (a->element[i] compare b->element[i] ? \
+ ones : 0x0); \
+ switch (sizeof(a->element[0])) { \
+ case 4: \
+ r->u32[i] = result; \
+ break; \
+ case 2: \
+ r->u16[i] = result; \
+ break; \
+ case 1: \
+ r->u8[i] = result; \
+ break; \
} \
all &= result; \
none |= result; \
@@ -2197,15 +2299,17 @@ VCMP(gtsw, >, s32)
#undef VCMP
#define VCMPFP_DO(suffix, compare, order, record) \
- void helper_vcmp##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
+ void helper_vcmp##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
{ \
uint32_t ones = (uint32_t)-1; \
uint32_t all = ones; \
uint32_t none = 0; \
int i; \
+ \
for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
uint32_t result; \
- int rel = float32_compare_quiet(a->f[i], b->f[i], &env->vec_status); \
+ int rel = float32_compare_quiet(a->f[i], b->f[i], \
+ &env->vec_status); \
if (rel == float_relation_unordered) { \
result = 0; \
} else if (rel compare order) { \
@@ -2221,8 +2325,8 @@ VCMP(gtsw, >, s32)
env->crf[6] = ((all != 0) << 3) | ((none == 0) << 1); \
} \
}
-#define VCMPFP(suffix, compare, order) \
- VCMPFP_DO(suffix, compare, order, 0) \
+#define VCMPFP(suffix, compare, order) \
+ VCMPFP_DO(suffix, compare, order, 0) \
VCMPFP_DO(suffix##_dot, compare, order, 1)
VCMPFP(eqfp, ==, float_relation_equal)
VCMPFP(gefp, !=, float_relation_less)
@@ -2235,6 +2339,7 @@ static inline void vcmpbfp_internal(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b,
{
int i;
int all_in = 0;
+
for (i = 0; i < ARRAY_SIZE(r->f); i++) {
int le_rel = float32_compare_quiet(a->f[i], b->f[i], &env->vec_status);
if (le_rel == float_relation_unordered) {
@@ -2245,6 +2350,7 @@ static inline void vcmpbfp_internal(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b,
int ge_rel = float32_compare_quiet(a->f[i], bneg, &env->vec_status);
int le = le_rel != float_relation_greater;
int ge = ge_rel != float_relation_less;
+
r->u32[i] = ((!le) << 31) | ((!ge) << 30);
all_in |= (!le | !ge);
}
@@ -2254,22 +2360,23 @@ static inline void vcmpbfp_internal(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b,
}
}
-void helper_vcmpbfp (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
+void helper_vcmpbfp(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
{
vcmpbfp_internal(r, a, b, 0);
}
-void helper_vcmpbfp_dot (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
+void helper_vcmpbfp_dot(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
{
vcmpbfp_internal(r, a, b, 1);
}
#define VCT(suffix, satcvt, element) \
- void helper_vct##suffix (ppc_avr_t *r, ppc_avr_t *b, uint32_t uim) \
+ void helper_vct##suffix(ppc_avr_t *r, ppc_avr_t *b, uint32_t uim) \
{ \
int i; \
int sat = 0; \
float_status s = env->vec_status; \
+ \
set_float_rounding_mode(float_round_to_zero, &s); \
for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
if (float32_is_any_nan(b->f[i])) { \
@@ -2277,6 +2384,7 @@ void helper_vcmpbfp_dot (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
} else { \
float64 t = float32_to_float64(b->f[i], &s); \
int64_t j; \
+ \
t = float64_scalbn(t, uim, &s); \
j = float64_to_int64(t, &s); \
r->element[i] = satcvt(j, &sat); \
@@ -2290,14 +2398,16 @@ VCT(uxs, cvtsduw, u32)
VCT(sxs, cvtsdsw, s32)
#undef VCT
-void helper_vmaddfp (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
+void helper_vmaddfp(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
{
int i;
+
for (i = 0; i < ARRAY_SIZE(r->f); i++) {
HANDLE_NAN3(r->f[i], a->f[i], b->f[i], c->f[i]) {
/* Need to do the computation in higher precision and round
* once at the end. */
float64 af, bf, cf, t;
+
af = float32_to_float64(a->f[i], &env->vec_status);
bf = float32_to_float64(b->f[i], &env->vec_status);
cf = float32_to_float64(c->f[i], &env->vec_status);
@@ -2308,7 +2418,7 @@ void helper_vmaddfp (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
}
}
-void helper_vmhaddshs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
+void helper_vmhaddshs(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
{
int sat = 0;
int i;
@@ -2316,7 +2426,8 @@ void helper_vmhaddshs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
int32_t prod = a->s16[i] * b->s16[i];
int32_t t = (int32_t)c->s16[i] + (prod >> 15);
- r->s16[i] = cvtswsh (t, &sat);
+
+ r->s16[i] = cvtswsh(t, &sat);
}
if (sat) {
@@ -2324,7 +2435,7 @@ void helper_vmhaddshs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
}
}
-void helper_vmhraddshs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
+void helper_vmhraddshs(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
{
int sat = 0;
int i;
@@ -2332,7 +2443,7 @@ void helper_vmhraddshs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
int32_t prod = a->s16[i] * b->s16[i] + 0x00004000;
int32_t t = (int32_t)c->s16[i] + (prod >> 15);
- r->s16[i] = cvtswsh (t, &sat);
+ r->s16[i] = cvtswsh(t, &sat);
}
if (sat) {
@@ -2341,9 +2452,10 @@ void helper_vmhraddshs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
}
#define VMINMAX_DO(name, compare, element) \
- void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
+ void helper_v##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
{ \
int i; \
+ \
for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
if (a->element[i] compare b->element[i]) { \
r->element[i] = b->element[i]; \
@@ -2353,8 +2465,8 @@ void helper_vmhraddshs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
} \
}
#define VMINMAX(suffix, element) \
- VMINMAX_DO(min##suffix, >, element) \
- VMINMAX_DO(max##suffix, <, element)
+ VMINMAX_DO(min##suffix, >, element) \
+ VMINMAX_DO(max##suffix, <, element)
VMINMAX(sb, s8)
VMINMAX(sh, s16)
VMINMAX(sw, s32)
@@ -2365,12 +2477,14 @@ VMINMAX(uw, u32)
#undef VMINMAX
#define VMINMAXFP(suffix, rT, rF) \
- void helper_v##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
+ void helper_v##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
{ \
int i; \
+ \
for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
HANDLE_NAN2(r->f[i], a->f[i], b->f[i]) { \
- if (float32_lt_quiet(a->f[i], b->f[i], &env->vec_status)) { \
+ if (float32_lt_quiet(a->f[i], b->f[i], \
+ &env->vec_status)) { \
r->f[i] = rT->f[i]; \
} else { \
r->f[i] = rF->f[i]; \
@@ -2382,9 +2496,10 @@ VMINMAXFP(minfp, a, b)
VMINMAXFP(maxfp, b, a)
#undef VMINMAXFP
-void helper_vmladduhm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
+void helper_vmladduhm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
{
int i;
+
for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
int32_t prod = a->s16[i] * b->s16[i];
r->s16[i] = (int16_t) (prod + c->s16[i]);
@@ -2392,18 +2507,21 @@ void helper_vmladduhm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
}
#define VMRG_DO(name, element, highp) \
- void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
+ void helper_v##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
{ \
ppc_avr_t result; \
int i; \
size_t n_elems = ARRAY_SIZE(r->element); \
- for (i = 0; i < n_elems/2; i++) { \
+ \
+ for (i = 0; i < n_elems / 2; i++) { \
if (highp) { \
result.element[i*2+HI_IDX] = a->element[i]; \
result.element[i*2+LO_IDX] = b->element[i]; \
} else { \
- result.element[n_elems - i*2 - (1+HI_IDX)] = b->element[n_elems - i - 1]; \
- result.element[n_elems - i*2 - (1+LO_IDX)] = a->element[n_elems - i - 1]; \
+ result.element[n_elems - i * 2 - (1 + HI_IDX)] = \
+ b->element[n_elems - i - 1]; \
+ result.element[n_elems - i * 2 - (1 + LO_IDX)] = \
+ a->element[n_elems - i - 1]; \
} \
} \
*r = result; \
@@ -2416,8 +2534,8 @@ void helper_vmladduhm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
#define MRGLO 0
#endif
#define VMRG(suffix, element) \
- VMRG_DO(mrgl##suffix, element, MRGHI) \
- VMRG_DO(mrgh##suffix, element, MRGLO)
+ VMRG_DO(mrgl##suffix, element, MRGHI) \
+ VMRG_DO(mrgh##suffix, element, MRGLO)
VMRG(b, u8)
VMRG(h, u16)
VMRG(w, u32)
@@ -2426,7 +2544,7 @@ VMRG(w, u32)
#undef MRGHI
#undef MRGLO
-void helper_vmsummbm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
+void helper_vmsummbm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
{
int32_t prod[16];
int i;
@@ -2436,11 +2554,12 @@ void helper_vmsummbm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
}
VECTOR_FOR_INORDER_I(i, s32) {
- r->s32[i] = c->s32[i] + prod[4*i] + prod[4*i+1] + prod[4*i+2] + prod[4*i+3];
+ r->s32[i] = c->s32[i] + prod[4 * i] + prod[4 * i + 1] +
+ prod[4 * i + 2] + prod[4 * i + 3];
}
}
-void helper_vmsumshm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
+void helper_vmsumshm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
{
int32_t prod[8];
int i;
@@ -2450,11 +2569,11 @@ void helper_vmsumshm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
}
VECTOR_FOR_INORDER_I(i, s32) {
- r->s32[i] = c->s32[i] + prod[2*i] + prod[2*i+1];
+ r->s32[i] = c->s32[i] + prod[2 * i] + prod[2 * i + 1];
}
}
-void helper_vmsumshs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
+void helper_vmsumshs(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
{
int32_t prod[8];
int i;
@@ -2464,8 +2583,9 @@ void helper_vmsumshs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
prod[i] = (int32_t)a->s16[i] * b->s16[i];
}
- VECTOR_FOR_INORDER_I (i, s32) {
- int64_t t = (int64_t)c->s32[i] + prod[2*i] + prod[2*i+1];
+ VECTOR_FOR_INORDER_I(i, s32) {
+ int64_t t = (int64_t)c->s32[i] + prod[2 * i] + prod[2 * i + 1];
+
r->u32[i] = cvtsdsw(t, &sat);
}
@@ -2474,7 +2594,7 @@ void helper_vmsumshs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
}
}
-void helper_vmsumubm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
+void helper_vmsumubm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
{
uint16_t prod[16];
int i;
@@ -2484,11 +2604,12 @@ void helper_vmsumubm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
}
VECTOR_FOR_INORDER_I(i, u32) {
- r->u32[i] = c->u32[i] + prod[4*i] + prod[4*i+1] + prod[4*i+2] + prod[4*i+3];
+ r->u32[i] = c->u32[i] + prod[4 * i] + prod[4 * i + 1] +
+ prod[4 * i + 2] + prod[4 * i + 3];
}
}
-void helper_vmsumuhm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
+void helper_vmsumuhm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
{
uint32_t prod[8];
int i;
@@ -2498,11 +2619,11 @@ void helper_vmsumuhm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
}
VECTOR_FOR_INORDER_I(i, u32) {
- r->u32[i] = c->u32[i] + prod[2*i] + prod[2*i+1];
+ r->u32[i] = c->u32[i] + prod[2 * i] + prod[2 * i + 1];
}
}
-void helper_vmsumuhs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
+void helper_vmsumuhs(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
{
uint32_t prod[8];
int i;
@@ -2512,8 +2633,9 @@ void helper_vmsumuhs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
prod[i] = a->u16[i] * b->u16[i];
}
- VECTOR_FOR_INORDER_I (i, s32) {
- uint64_t t = (uint64_t)c->u32[i] + prod[2*i] + prod[2*i+1];
+ VECTOR_FOR_INORDER_I(i, s32) {
+ uint64_t t = (uint64_t)c->u32[i] + prod[2 * i] + prod[2 * i + 1];
+
r->u32[i] = cvtuduw(t, &sat);
}
@@ -2523,20 +2645,23 @@ void helper_vmsumuhs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
}
#define VMUL_DO(name, mul_element, prod_element, evenp) \
- void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
+ void helper_v##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
{ \
int i; \
+ \
VECTOR_FOR_INORDER_I(i, prod_element) { \
if (evenp) { \
- r->prod_element[i] = a->mul_element[i*2+HI_IDX] * b->mul_element[i*2+HI_IDX]; \
+ r->prod_element[i] = a->mul_element[i * 2 + HI_IDX] * \
+ b->mul_element[i * 2 + HI_IDX]; \
} else { \
- r->prod_element[i] = a->mul_element[i*2+LO_IDX] * b->mul_element[i*2+LO_IDX]; \
+ r->prod_element[i] = a->mul_element[i * 2 + LO_IDX] * \
+ b->mul_element[i * 2 + LO_IDX]; \
} \
} \
}
-#define VMUL(suffix, mul_element, prod_element) \
- VMUL_DO(mule##suffix, mul_element, prod_element, 1) \
- VMUL_DO(mulo##suffix, mul_element, prod_element, 0)
+#define VMUL(suffix, mul_element, prod_element) \
+ VMUL_DO(mule##suffix, mul_element, prod_element, 1) \
+ VMUL_DO(mulo##suffix, mul_element, prod_element, 0)
VMUL(sb, s8, s16)
VMUL(sh, s16, s32)
VMUL(ub, u8, u16)
@@ -2544,14 +2669,16 @@ VMUL(uh, u16, u32)
#undef VMUL_DO
#undef VMUL
-void helper_vnmsubfp (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
+void helper_vnmsubfp(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
{
int i;
+
for (i = 0; i < ARRAY_SIZE(r->f); i++) {
HANDLE_NAN3(r->f[i], a->f[i], b->f[i], c->f[i]) {
/* Need to do the computation is higher precision and round
* once at the end. */
float64 af, bf, cf, t;
+
af = float32_to_float64(a->f[i], &env->vec_status);
bf = float32_to_float64(b->f[i], &env->vec_status);
cf = float32_to_float64(c->f[i], &env->vec_status);
@@ -2563,17 +2690,19 @@ void helper_vnmsubfp (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
}
}
-void helper_vperm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
+void helper_vperm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
{
ppc_avr_t result;
int i;
- VECTOR_FOR_INORDER_I (i, u8) {
+
+ VECTOR_FOR_INORDER_I(i, u8) {
int s = c->u8[i] & 0x1f;
#if defined(HOST_WORDS_BIGENDIAN)
int index = s & 0xf;
#else
int index = 15 - (s & 0xf);
#endif
+
if (s & 0x10) {
result.u8[i] = b->u8[index];
} else {
@@ -2588,7 +2717,7 @@ void helper_vperm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
#else
#define PKBIG 0
#endif
-void helper_vpkpx (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
+void helper_vpkpx(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
{
int i, j;
ppc_avr_t result;
@@ -2598,9 +2727,10 @@ void helper_vpkpx (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
const ppc_avr_t *x[2] = { b, a };
#endif
- VECTOR_FOR_INORDER_I (i, u64) {
- VECTOR_FOR_INORDER_I (j, u32){
+ VECTOR_FOR_INORDER_I(i, u64) {
+ VECTOR_FOR_INORDER_I(j, u32) {
uint32_t e = x[i]->u32[j];
+
result.u16[4*i+j] = (((e >> 9) & 0xfc00) |
((e >> 6) & 0x3e0) |
((e >> 3) & 0x1f));
@@ -2609,15 +2739,16 @@ void helper_vpkpx (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
*r = result;
}
-#define VPK(suffix, from, to, cvt, dosat) \
- void helper_vpk##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
+#define VPK(suffix, from, to, cvt, dosat) \
+ void helper_vpk##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
{ \
int i; \
int sat = 0; \
ppc_avr_t result; \
ppc_avr_t *a0 = PKBIG ? a : b; \
ppc_avr_t *a1 = PKBIG ? b : a; \
- VECTOR_FOR_INORDER_I (i, from) { \
+ \
+ VECTOR_FOR_INORDER_I(i, from) { \
result.to[i] = cvt(a0->from[i], &sat); \
result.to[i+ARRAY_SIZE(r->from)] = cvt(a1->from[i], &sat); \
} \
@@ -2639,9 +2770,10 @@ VPK(uwum, u32, u16, I, 0)
#undef VPK
#undef PKBIG
-void helper_vrefp (ppc_avr_t *r, ppc_avr_t *b)
+void helper_vrefp(ppc_avr_t *r, ppc_avr_t *b)
{
int i;
+
for (i = 0; i < ARRAY_SIZE(r->f); i++) {
HANDLE_NAN1(r->f[i], b->f[i]) {
r->f[i] = float32_div(float32_one, b->f[i], &env->vec_status);
@@ -2649,17 +2781,18 @@ void helper_vrefp (ppc_avr_t *r, ppc_avr_t *b)
}
}
-#define VRFI(suffix, rounding) \
- void helper_vrfi##suffix (ppc_avr_t *r, ppc_avr_t *b) \
- { \
- int i; \
- float_status s = env->vec_status; \
- set_float_rounding_mode(rounding, &s); \
- for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
- HANDLE_NAN1(r->f[i], b->f[i]) { \
- r->f[i] = float32_round_to_int (b->f[i], &s); \
- } \
- } \
+#define VRFI(suffix, rounding) \
+ void helper_vrfi##suffix(ppc_avr_t *r, ppc_avr_t *b) \
+ { \
+ int i; \
+ float_status s = env->vec_status; \
+ \
+ set_float_rounding_mode(rounding, &s); \
+ for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
+ HANDLE_NAN1(r->f[i], b->f[i]) { \
+ r->f[i] = float32_round_to_int (b->f[i], &s); \
+ } \
+ } \
}
VRFI(n, float_round_nearest_even)
VRFI(m, float_round_down)
@@ -2668,13 +2801,17 @@ VRFI(z, float_round_to_zero)
#undef VRFI
#define VROTATE(suffix, element) \
- void helper_vrl##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
+ void helper_vrl##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
{ \
int i; \
+ \
for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
- unsigned int mask = ((1 << (3 + (sizeof (a->element[0]) >> 1))) - 1); \
+ unsigned int mask = ((1 << \
+ (3 + (sizeof(a->element[0]) >> 1))) \
+ - 1); \
unsigned int shift = b->element[i] & mask; \
- r->element[i] = (a->element[i] << shift) | (a->element[i] >> (sizeof(a->element[0]) * 8 - shift)); \
+ r->element[i] = (a->element[i] << shift) | \
+ (a->element[i] >> (sizeof(a->element[0]) * 8 - shift)); \
} \
}
VROTATE(b, u8)
@@ -2682,26 +2819,29 @@ VROTATE(h, u16)
VROTATE(w, u32)
#undef VROTATE
-void helper_vrsqrtefp (ppc_avr_t *r, ppc_avr_t *b)
+void helper_vrsqrtefp(ppc_avr_t *r, ppc_avr_t *b)
{
int i;
+
for (i = 0; i < ARRAY_SIZE(r->f); i++) {
HANDLE_NAN1(r->f[i], b->f[i]) {
float32 t = float32_sqrt(b->f[i], &env->vec_status);
+
r->f[i] = float32_div(float32_one, t, &env->vec_status);
}
}
}
-void helper_vsel (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
+void helper_vsel(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
{
r->u64[0] = (a->u64[0] & ~c->u64[0]) | (b->u64[0] & c->u64[0]);
r->u64[1] = (a->u64[1] & ~c->u64[1]) | (b->u64[1] & c->u64[1]);
}
-void helper_vexptefp (ppc_avr_t *r, ppc_avr_t *b)
+void helper_vexptefp(ppc_avr_t *r, ppc_avr_t *b)
{
int i;
+
for (i = 0; i < ARRAY_SIZE(r->f); i++) {
HANDLE_NAN1(r->f[i], b->f[i]) {
r->f[i] = float32_exp2(b->f[i], &env->vec_status);
@@ -2709,9 +2849,10 @@ void helper_vexptefp (ppc_avr_t *r, ppc_avr_t *b)
}
}
-void helper_vlogefp (ppc_avr_t *r, ppc_avr_t *b)
+void helper_vlogefp(ppc_avr_t *r, ppc_avr_t *b)
{
int i;
+
for (i = 0; i < ARRAY_SIZE(r->f); i++) {
HANDLE_NAN1(r->f[i], b->f[i]) {
r->f[i] = float32_log2(b->f[i], &env->vec_status);
@@ -2730,11 +2871,12 @@ void helper_vlogefp (ppc_avr_t *r, ppc_avr_t *b)
* shift counts are not identical. We check to make sure that they are
* to conform to what real hardware appears to do. */
#define VSHIFT(suffix, leftp) \
- void helper_vs##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
+ void helper_vs##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
{ \
int shift = b->u8[LO_IDX*15] & 0x7; \
int doit = 1; \
int i; \
+ \
for (i = 0; i < ARRAY_SIZE(r->u8); i++) { \
doit = doit && ((b->u8[i] & 0x7) == shift); \
} \
@@ -2743,10 +2885,12 @@ void helper_vlogefp (ppc_avr_t *r, ppc_avr_t *b)
*r = *a; \
} else if (leftp) { \
uint64_t carry = a->u64[LO_IDX] >> (64 - shift); \
+ \
r->u64[HI_IDX] = (a->u64[HI_IDX] << shift) | carry; \
r->u64[LO_IDX] = a->u64[LO_IDX] << shift; \
} else { \
uint64_t carry = a->u64[HI_IDX] << (64 - shift); \
+ \
r->u64[LO_IDX] = (a->u64[LO_IDX] >> shift) | carry; \
r->u64[HI_IDX] = a->u64[HI_IDX] >> shift; \
} \
@@ -2759,12 +2903,16 @@ VSHIFT(r, RIGHT)
#undef RIGHT
#define VSL(suffix, element) \
- void helper_vsl##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
+ void helper_vsl##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
{ \
int i; \
+ \
for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
- unsigned int mask = ((1 << (3 + (sizeof (a->element[0]) >> 1))) - 1); \
+ unsigned int mask = ((1 << \
+ (3 + (sizeof(a->element[0]) >> 1))) \
+ - 1); \
unsigned int shift = b->element[i] & mask; \
+ \
r->element[i] = a->element[i] << shift; \
} \
}
@@ -2773,7 +2921,7 @@ VSL(h, u16)
VSL(w, u32)
#undef VSL
-void helper_vsldoi (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t shift)
+void helper_vsldoi(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t shift)
{
int sh = shift & 0xf;
int i;
@@ -2783,7 +2931,7 @@ void helper_vsldoi (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t shift)
for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
int index = sh + i;
if (index > 0xf) {
- result.u8[i] = b->u8[index-0x10];
+ result.u8[i] = b->u8[index - 0x10];
} else {
result.u8[i] = a->u8[index];
}
@@ -2792,7 +2940,7 @@ void helper_vsldoi (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t shift)
for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
int index = (16 - sh) + i;
if (index > 0xf) {
- result.u8[i] = a->u8[index-0x10];
+ result.u8[i] = a->u8[index - 0x10];
} else {
result.u8[i] = b->u8[index];
}
@@ -2801,16 +2949,16 @@ void helper_vsldoi (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t shift)
*r = result;
}
-void helper_vslo (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
+void helper_vslo(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
{
- int sh = (b->u8[LO_IDX*0xf] >> 3) & 0xf;
+ int sh = (b->u8[LO_IDX*0xf] >> 3) & 0xf;
-#if defined (HOST_WORDS_BIGENDIAN)
- memmove (&r->u8[0], &a->u8[sh], 16-sh);
- memset (&r->u8[16-sh], 0, sh);
+#if defined(HOST_WORDS_BIGENDIAN)
+ memmove(&r->u8[0], &a->u8[sh], 16 - sh);
+ memset(&r->u8[16-sh], 0, sh);
#else
- memmove (&r->u8[sh], &a->u8[0], 16-sh);
- memset (&r->u8[0], 0, sh);
+ memmove(&r->u8[sh], &a->u8[0], 16 - sh);
+ memset(&r->u8[0], 0, sh);
#endif
}
@@ -2819,13 +2967,15 @@ void helper_vslo (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
#if defined(HOST_WORDS_BIGENDIAN)
#define SPLAT_ELEMENT(element) _SPLAT_MASKED(element)
#else
-#define SPLAT_ELEMENT(element) (ARRAY_SIZE(r->element)-1 - _SPLAT_MASKED(element))
+#define SPLAT_ELEMENT(element) \
+ (ARRAY_SIZE(r->element) - 1 - _SPLAT_MASKED(element))
#endif
#define VSPLT(suffix, element) \
- void helper_vsplt##suffix (ppc_avr_t *r, ppc_avr_t *b, uint32_t splat) \
+ void helper_vsplt##suffix(ppc_avr_t *r, ppc_avr_t *b, uint32_t splat) \
{ \
uint32_t s = b->element[SPLAT_ELEMENT(element)]; \
int i; \
+ \
for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
r->element[i] = s; \
} \
@@ -2838,10 +2988,11 @@ VSPLT(w, u32)
#undef _SPLAT_MASKED
#define VSPLTI(suffix, element, splat_type) \
- void helper_vspltis##suffix (ppc_avr_t *r, uint32_t splat) \
+ void helper_vspltis##suffix(ppc_avr_t *r, uint32_t splat) \
{ \
splat_type x = (int8_t)(splat << 3) >> 3; \
int i; \
+ \
for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
r->element[i] = x; \
} \
@@ -2852,12 +3003,16 @@ VSPLTI(w, s32, int32_t)
#undef VSPLTI
#define VSR(suffix, element) \
- void helper_vsr##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
+ void helper_vsr##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
{ \
int i; \
+ \
for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
- unsigned int mask = ((1 << (3 + (sizeof (a->element[0]) >> 1))) - 1); \
+ unsigned int mask = ((1 << \
+ (3 + (sizeof(a->element[0]) >> 1))) \
+ - 1); \
unsigned int shift = b->element[i] & mask; \
+ \
r->element[i] = a->element[i] >> shift; \
} \
}
@@ -2869,28 +3024,29 @@ VSR(h, u16)
VSR(w, u32)
#undef VSR
-void helper_vsro (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
+void helper_vsro(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
{
- int sh = (b->u8[LO_IDX*0xf] >> 3) & 0xf;
+ int sh = (b->u8[LO_IDX * 0xf] >> 3) & 0xf;
-#if defined (HOST_WORDS_BIGENDIAN)
- memmove (&r->u8[sh], &a->u8[0], 16-sh);
- memset (&r->u8[0], 0, sh);
+#if defined(HOST_WORDS_BIGENDIAN)
+ memmove(&r->u8[sh], &a->u8[0], 16 - sh);
+ memset(&r->u8[0], 0, sh);
#else
- memmove (&r->u8[0], &a->u8[sh], 16-sh);
- memset (&r->u8[16-sh], 0, sh);
+ memmove(&r->u8[0], &a->u8[sh], 16 - sh);
+ memset(&r->u8[16 - sh], 0, sh);
#endif
}
-void helper_vsubcuw (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
+void helper_vsubcuw(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
{
int i;
+
for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
r->u32[i] = a->u32[i] >= b->u32[i];
}
}
-void helper_vsumsws (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
+void helper_vsumsws(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
{
int64_t t;
int i, upper;
@@ -2915,7 +3071,7 @@ void helper_vsumsws (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
}
}
-void helper_vsum2sws (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
+void helper_vsum2sws(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
{
int i, j, upper;
ppc_avr_t result;
@@ -2927,12 +3083,13 @@ void helper_vsum2sws (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
upper = 0;
#endif
for (i = 0; i < ARRAY_SIZE(r->u64); i++) {
- int64_t t = (int64_t)b->s32[upper+i*2];
+ int64_t t = (int64_t)b->s32[upper + i * 2];
+
result.u64[i] = 0;
for (j = 0; j < ARRAY_SIZE(r->u64); j++) {
- t += a->s32[2*i+j];
+ t += a->s32[2 * i + j];
}
- result.s32[upper+i*2] = cvtsdsw(t, &sat);
+ result.s32[upper + i * 2] = cvtsdsw(t, &sat);
}
*r = result;
@@ -2941,15 +3098,16 @@ void helper_vsum2sws (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
}
}
-void helper_vsum4sbs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
+void helper_vsum4sbs(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
{
int i, j;
int sat = 0;
for (i = 0; i < ARRAY_SIZE(r->s32); i++) {
int64_t t = (int64_t)b->s32[i];
+
for (j = 0; j < ARRAY_SIZE(r->s32); j++) {
- t += a->s8[4*i+j];
+ t += a->s8[4 * i + j];
}
r->s32[i] = cvtsdsw(t, &sat);
}
@@ -2959,14 +3117,15 @@ void helper_vsum4sbs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
}
}
-void helper_vsum4shs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
+void helper_vsum4shs(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
{
int sat = 0;
int i;
for (i = 0; i < ARRAY_SIZE(r->s32); i++) {
int64_t t = (int64_t)b->s32[i];
- t += a->s16[2*i] + a->s16[2*i+1];
+
+ t += a->s16[2 * i] + a->s16[2 * i + 1];
r->s32[i] = cvtsdsw(t, &sat);
}
@@ -2975,15 +3134,16 @@ void helper_vsum4shs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
}
}
-void helper_vsum4ubs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
+void helper_vsum4ubs(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
{
int i, j;
int sat = 0;
for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
uint64_t t = (uint64_t)b->u32[i];
+
for (j = 0; j < ARRAY_SIZE(r->u32); j++) {
- t += a->u8[4*i+j];
+ t += a->u8[4 * i + j];
}
r->u32[i] = cvtuduw(t, &sat);
}
@@ -3000,17 +3160,19 @@ void helper_vsum4ubs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
#define UPKHI 0
#define UPKLO 1
#endif
-#define VUPKPX(suffix, hi) \
- void helper_vupk##suffix (ppc_avr_t *r, ppc_avr_t *b) \
- { \
- int i; \
- ppc_avr_t result; \
- for (i = 0; i < ARRAY_SIZE(r->u32); i++) { \
- uint16_t e = b->u16[hi ? i : i+4]; \
- uint8_t a = (e >> 15) ? 0xff : 0; \
- uint8_t r = (e >> 10) & 0x1f; \
- uint8_t g = (e >> 5) & 0x1f; \
- uint8_t b = e & 0x1f; \
+#define VUPKPX(suffix, hi) \
+ void helper_vupk##suffix(ppc_avr_t *r, ppc_avr_t *b) \
+ { \
+ int i; \
+ ppc_avr_t result; \
+ \
+ for (i = 0; i < ARRAY_SIZE(r->u32); i++) { \
+ uint16_t e = b->u16[hi ? i : i+4]; \
+ uint8_t a = (e >> 15) ? 0xff : 0; \
+ uint8_t r = (e >> 10) & 0x1f; \
+ uint8_t g = (e >> 5) & 0x1f; \
+ uint8_t b = e & 0x1f; \
+ \
result.u32[i] = (a << 24) | (r << 16) | (g << 8) | b; \
} \
*r = result; \
@@ -3020,17 +3182,19 @@ VUPKPX(hpx, UPKHI)
#undef VUPKPX
#define VUPK(suffix, unpacked, packee, hi) \
- void helper_vupk##suffix (ppc_avr_t *r, ppc_avr_t *b) \
+ void helper_vupk##suffix(ppc_avr_t *r, ppc_avr_t *b) \
{ \
int i; \
ppc_avr_t result; \
+ \
if (hi) { \
for (i = 0; i < ARRAY_SIZE(r->unpacked); i++) { \
result.unpacked[i] = b->packee[i]; \
} \
} else { \
- for (i = ARRAY_SIZE(r->unpacked); i < ARRAY_SIZE(r->packee); i++) { \
- result.unpacked[i-ARRAY_SIZE(r->unpacked)] = b->packee[i]; \
+ for (i = ARRAY_SIZE(r->unpacked); i < ARRAY_SIZE(r->packee); \
+ i++) { \
+ result.unpacked[i - ARRAY_SIZE(r->unpacked)] = b->packee[i]; \
} \
} \
*r = result; \
@@ -3070,8 +3234,8 @@ static inline uint32_t word_reverse(uint32_t val)
(byte_reverse(val >> 8) << 16) | (byte_reverse(val) << 24);
}
-#define MASKBITS 16 // Random value - to be fixed (implementation dependent)
-target_ulong helper_brinc (target_ulong arg1, target_ulong arg2)
+#define MASKBITS 16 /* Random value - to be fixed (implementation dependent) */
+target_ulong helper_brinc(target_ulong arg1, target_ulong arg2)
{
uint32_t a, b, d, mask;
@@ -3082,15 +3246,16 @@ target_ulong helper_brinc (target_ulong arg1, target_ulong arg2)
return (arg1 & ~mask) | (d & b);
}
-uint32_t helper_cntlsw32 (uint32_t val)
+uint32_t helper_cntlsw32(uint32_t val)
{
- if (val & 0x80000000)
+ if (val & 0x80000000) {
return clz32(~val);
- else
+ } else {
return clz32(val);
+ }
}
-uint32_t helper_cntlzw32 (uint32_t val)
+uint32_t helper_cntlzw32(uint32_t val)
{
return clz32(val);
}
@@ -3120,8 +3285,9 @@ static inline int32_t efsctsi(uint32_t val)
u.l = val;
/* NaN are not treated the same way IEEE 754 does */
- if (unlikely(float32_is_quiet_nan(u.f)))
+ if (unlikely(float32_is_quiet_nan(u.f))) {
return 0;
+ }
return float32_to_int32(u.f, &env->vec_status);
}
@@ -3132,8 +3298,9 @@ static inline uint32_t efsctui(uint32_t val)
u.l = val;
/* NaN are not treated the same way IEEE 754 does */
- if (unlikely(float32_is_quiet_nan(u.f)))
+ if (unlikely(float32_is_quiet_nan(u.f))) {
return 0;
+ }
return float32_to_uint32(u.f, &env->vec_status);
}
@@ -3144,8 +3311,9 @@ static inline uint32_t efsctsiz(uint32_t val)
u.l = val;
/* NaN are not treated the same way IEEE 754 does */
- if (unlikely(float32_is_quiet_nan(u.f)))
+ if (unlikely(float32_is_quiet_nan(u.f))) {
return 0;
+ }
return float32_to_int32_round_to_zero(u.f, &env->vec_status);
}
@@ -3156,8 +3324,9 @@ static inline uint32_t efsctuiz(uint32_t val)
u.l = val;
/* NaN are not treated the same way IEEE 754 does */
- if (unlikely(float32_is_quiet_nan(u.f)))
+ if (unlikely(float32_is_quiet_nan(u.f))) {
return 0;
+ }
return float32_to_uint32_round_to_zero(u.f, &env->vec_status);
}
@@ -3193,8 +3362,9 @@ static inline uint32_t efsctsf(uint32_t val)
u.l = val;
/* NaN are not treated the same way IEEE 754 does */
- if (unlikely(float32_is_quiet_nan(u.f)))
+ if (unlikely(float32_is_quiet_nan(u.f))) {
return 0;
+ }
tmp = uint64_to_float32(1ULL << 32, &env->vec_status);
u.f = float32_mul(u.f, tmp, &env->vec_status);
@@ -3208,19 +3378,20 @@ static inline uint32_t efsctuf(uint32_t val)
u.l = val;
/* NaN are not treated the same way IEEE 754 does */
- if (unlikely(float32_is_quiet_nan(u.f)))
+ if (unlikely(float32_is_quiet_nan(u.f))) {
return 0;
+ }
tmp = uint64_to_float32(1ULL << 32, &env->vec_status);
u.f = float32_mul(u.f, tmp, &env->vec_status);
return float32_to_uint32(u.f, &env->vec_status);
}
-#define HELPER_SPE_SINGLE_CONV(name) \
-uint32_t helper_e##name (uint32_t val) \
-{ \
- return e##name(val); \
-}
+#define HELPER_SPE_SINGLE_CONV(name) \
+ uint32_t helper_e##name(uint32_t val) \
+ { \
+ return e##name(val); \
+ }
/* efscfsi */
HELPER_SPE_SINGLE_CONV(fscfsi);
/* efscfui */
@@ -3242,12 +3413,12 @@ HELPER_SPE_SINGLE_CONV(fsctsf);
/* efsctuf */
HELPER_SPE_SINGLE_CONV(fsctuf);
-#define HELPER_SPE_VECTOR_CONV(name) \
-uint64_t helper_ev##name (uint64_t val) \
-{ \
- return ((uint64_t)e##name(val >> 32) << 32) | \
- (uint64_t)e##name(val); \
-}
+#define HELPER_SPE_VECTOR_CONV(name) \
+ uint64_t helper_ev##name(uint64_t val) \
+ { \
+ return ((uint64_t)e##name(val >> 32) << 32) | \
+ (uint64_t)e##name(val); \
+ }
/* evfscfsi */
HELPER_SPE_VECTOR_CONV(fscfsi);
/* evfscfui */
@@ -3273,6 +3444,7 @@ HELPER_SPE_VECTOR_CONV(fsctuf);
static inline uint32_t efsadd(uint32_t op1, uint32_t op2)
{
CPU_FloatU u1, u2;
+
u1.l = op1;
u2.l = op2;
u1.f = float32_add(u1.f, u2.f, &env->vec_status);
@@ -3282,6 +3454,7 @@ static inline uint32_t efsadd(uint32_t op1, uint32_t op2)
static inline uint32_t efssub(uint32_t op1, uint32_t op2)
{
CPU_FloatU u1, u2;
+
u1.l = op1;
u2.l = op2;
u1.f = float32_sub(u1.f, u2.f, &env->vec_status);
@@ -3291,6 +3464,7 @@ static inline uint32_t efssub(uint32_t op1, uint32_t op2)
static inline uint32_t efsmul(uint32_t op1, uint32_t op2)
{
CPU_FloatU u1, u2;
+
u1.l = op1;
u2.l = op2;
u1.f = float32_mul(u1.f, u2.f, &env->vec_status);
@@ -3300,17 +3474,18 @@ static inline uint32_t efsmul(uint32_t op1, uint32_t op2)
static inline uint32_t efsdiv(uint32_t op1, uint32_t op2)
{
CPU_FloatU u1, u2;
+
u1.l = op1;
u2.l = op2;
u1.f = float32_div(u1.f, u2.f, &env->vec_status);
return u1.l;
}
-#define HELPER_SPE_SINGLE_ARITH(name) \
-uint32_t helper_e##name (uint32_t op1, uint32_t op2) \
-{ \
- return e##name(op1, op2); \
-}
+#define HELPER_SPE_SINGLE_ARITH(name) \
+ uint32_t helper_e##name(uint32_t op1, uint32_t op2) \
+ { \
+ return e##name(op1, op2); \
+ }
/* efsadd */
HELPER_SPE_SINGLE_ARITH(fsadd);
/* efssub */
@@ -3320,12 +3495,12 @@ HELPER_SPE_SINGLE_ARITH(fsmul);
/* efsdiv */
HELPER_SPE_SINGLE_ARITH(fsdiv);
-#define HELPER_SPE_VECTOR_ARITH(name) \
-uint64_t helper_ev##name (uint64_t op1, uint64_t op2) \
-{ \
- return ((uint64_t)e##name(op1 >> 32, op2 >> 32) << 32) | \
- (uint64_t)e##name(op1, op2); \
-}
+#define HELPER_SPE_VECTOR_ARITH(name) \
+ uint64_t helper_ev##name(uint64_t op1, uint64_t op2) \
+ { \
+ return ((uint64_t)e##name(op1 >> 32, op2 >> 32) << 32) | \
+ (uint64_t)e##name(op1, op2); \
+ }
/* evfsadd */
HELPER_SPE_VECTOR_ARITH(fsadd);
/* evfssub */
@@ -3339,6 +3514,7 @@ HELPER_SPE_VECTOR_ARITH(fsdiv);
static inline uint32_t efscmplt(uint32_t op1, uint32_t op2)
{
CPU_FloatU u1, u2;
+
u1.l = op1;
u2.l = op2;
return float32_lt(u1.f, u2.f, &env->vec_status) ? 4 : 0;
@@ -3347,6 +3523,7 @@ static inline uint32_t efscmplt(uint32_t op1, uint32_t op2)
static inline uint32_t efscmpgt(uint32_t op1, uint32_t op2)
{
CPU_FloatU u1, u2;
+
u1.l = op1;
u2.l = op2;
return float32_le(u1.f, u2.f, &env->vec_status) ? 0 : 4;
@@ -3355,6 +3532,7 @@ static inline uint32_t efscmpgt(uint32_t op1, uint32_t op2)
static inline uint32_t efscmpeq(uint32_t op1, uint32_t op2)
{
CPU_FloatU u1, u2;
+
u1.l = op1;
u2.l = op2;
return float32_eq(u1.f, u2.f, &env->vec_status) ? 4 : 0;
@@ -3378,11 +3556,11 @@ static inline uint32_t efststeq(uint32_t op1, uint32_t op2)
return efscmpeq(op1, op2);
}
-#define HELPER_SINGLE_SPE_CMP(name) \
-uint32_t helper_e##name (uint32_t op1, uint32_t op2) \
-{ \
- return e##name(op1, op2) << 2; \
-}
+#define HELPER_SINGLE_SPE_CMP(name) \
+ uint32_t helper_e##name(uint32_t op1, uint32_t op2) \
+ { \
+ return e##name(op1, op2) << 2; \
+ }
/* efststlt */
HELPER_SINGLE_SPE_CMP(fststlt);
/* efststgt */
@@ -3401,11 +3579,11 @@ static inline uint32_t evcmp_merge(int t0, int t1)
return (t0 << 3) | (t1 << 2) | ((t0 | t1) << 1) | (t0 & t1);
}
-#define HELPER_VECTOR_SPE_CMP(name) \
-uint32_t helper_ev##name (uint64_t op1, uint64_t op2) \
-{ \
- return evcmp_merge(e##name(op1 >> 32, op2 >> 32), e##name(op1, op2)); \
-}
+#define HELPER_VECTOR_SPE_CMP(name) \
+ uint32_t helper_ev##name(uint64_t op1, uint64_t op2) \
+ { \
+ return evcmp_merge(e##name(op1 >> 32, op2 >> 32), e##name(op1, op2)); \
+ }
/* evfststlt */
HELPER_VECTOR_SPE_CMP(fststlt);
/* evfststgt */
@@ -3420,7 +3598,7 @@ HELPER_VECTOR_SPE_CMP(fscmpgt);
HELPER_VECTOR_SPE_CMP(fscmpeq);
/* Double-precision floating-point conversion */
-uint64_t helper_efdcfsi (uint32_t val)
+uint64_t helper_efdcfsi(uint32_t val)
{
CPU_DoubleU u;
@@ -3429,7 +3607,7 @@ uint64_t helper_efdcfsi (uint32_t val)
return u.ll;
}
-uint64_t helper_efdcfsid (uint64_t val)
+uint64_t helper_efdcfsid(uint64_t val)
{
CPU_DoubleU u;
@@ -3438,7 +3616,7 @@ uint64_t helper_efdcfsid (uint64_t val)
return u.ll;
}
-uint64_t helper_efdcfui (uint32_t val)
+uint64_t helper_efdcfui(uint32_t val)
{
CPU_DoubleU u;
@@ -3447,7 +3625,7 @@ uint64_t helper_efdcfui (uint32_t val)
return u.ll;
}
-uint64_t helper_efdcfuid (uint64_t val)
+uint64_t helper_efdcfuid(uint64_t val)
{
CPU_DoubleU u;
@@ -3456,7 +3634,7 @@ uint64_t helper_efdcfuid (uint64_t val)
return u.ll;
}
-uint32_t helper_efdctsi (uint64_t val)
+uint32_t helper_efdctsi(uint64_t val)
{
CPU_DoubleU u;
@@ -3469,7 +3647,7 @@ uint32_t helper_efdctsi (uint64_t val)
return float64_to_int32(u.d, &env->vec_status);
}
-uint32_t helper_efdctui (uint64_t val)
+uint32_t helper_efdctui(uint64_t val)
{
CPU_DoubleU u;
@@ -3482,7 +3660,7 @@ uint32_t helper_efdctui (uint64_t val)
return float64_to_uint32(u.d, &env->vec_status);
}
-uint32_t helper_efdctsiz (uint64_t val)
+uint32_t helper_efdctsiz(uint64_t val)
{
CPU_DoubleU u;
@@ -3495,7 +3673,7 @@ uint32_t helper_efdctsiz (uint64_t val)
return float64_to_int32_round_to_zero(u.d, &env->vec_status);
}
-uint64_t helper_efdctsidz (uint64_t val)
+uint64_t helper_efdctsidz(uint64_t val)
{
CPU_DoubleU u;
@@ -3508,7 +3686,7 @@ uint64_t helper_efdctsidz (uint64_t val)
return float64_to_int64_round_to_zero(u.d, &env->vec_status);
}
-uint32_t helper_efdctuiz (uint64_t val)
+uint32_t helper_efdctuiz(uint64_t val)
{
CPU_DoubleU u;
@@ -3521,7 +3699,7 @@ uint32_t helper_efdctuiz (uint64_t val)
return float64_to_uint32_round_to_zero(u.d, &env->vec_status);
}
-uint64_t helper_efdctuidz (uint64_t val)
+uint64_t helper_efdctuidz(uint64_t val)
{
CPU_DoubleU u;
@@ -3534,7 +3712,7 @@ uint64_t helper_efdctuidz (uint64_t val)
return float64_to_uint64_round_to_zero(u.d, &env->vec_status);
}
-uint64_t helper_efdcfsf (uint32_t val)
+uint64_t helper_efdcfsf(uint32_t val)
{
CPU_DoubleU u;
float64 tmp;
@@ -3546,7 +3724,7 @@ uint64_t helper_efdcfsf (uint32_t val)
return u.ll;
}
-uint64_t helper_efdcfuf (uint32_t val)
+uint64_t helper_efdcfuf(uint32_t val)
{
CPU_DoubleU u;
float64 tmp;
@@ -3558,7 +3736,7 @@ uint64_t helper_efdcfuf (uint32_t val)
return u.ll;
}
-uint32_t helper_efdctsf (uint64_t val)
+uint32_t helper_efdctsf(uint64_t val)
{
CPU_DoubleU u;
float64 tmp;
@@ -3574,7 +3752,7 @@ uint32_t helper_efdctsf (uint64_t val)
return float64_to_int32(u.d, &env->vec_status);
}
-uint32_t helper_efdctuf (uint64_t val)
+uint32_t helper_efdctuf(uint64_t val)
{
CPU_DoubleU u;
float64 tmp;
@@ -3590,7 +3768,7 @@ uint32_t helper_efdctuf (uint64_t val)
return float64_to_uint32(u.d, &env->vec_status);
}
-uint32_t helper_efscfd (uint64_t val)
+uint32_t helper_efscfd(uint64_t val)
{
CPU_DoubleU u1;
CPU_FloatU u2;
@@ -3601,7 +3779,7 @@ uint32_t helper_efscfd (uint64_t val)
return u2.l;
}
-uint64_t helper_efdcfs (uint32_t val)
+uint64_t helper_efdcfs(uint32_t val)
{
CPU_DoubleU u2;
CPU_FloatU u1;
@@ -3613,36 +3791,40 @@ uint64_t helper_efdcfs (uint32_t val)
}
/* Double precision fixed-point arithmetic */
-uint64_t helper_efdadd (uint64_t op1, uint64_t op2)
+uint64_t helper_efdadd(uint64_t op1, uint64_t op2)
{
CPU_DoubleU u1, u2;
+
u1.ll = op1;
u2.ll = op2;
u1.d = float64_add(u1.d, u2.d, &env->vec_status);
return u1.ll;
}
-uint64_t helper_efdsub (uint64_t op1, uint64_t op2)
+uint64_t helper_efdsub(uint64_t op1, uint64_t op2)
{
CPU_DoubleU u1, u2;
+
u1.ll = op1;
u2.ll = op2;
u1.d = float64_sub(u1.d, u2.d, &env->vec_status);
return u1.ll;
}
-uint64_t helper_efdmul (uint64_t op1, uint64_t op2)
+uint64_t helper_efdmul(uint64_t op1, uint64_t op2)
{
CPU_DoubleU u1, u2;
+
u1.ll = op1;
u2.ll = op2;
u1.d = float64_mul(u1.d, u2.d, &env->vec_status);
return u1.ll;
}
-uint64_t helper_efddiv (uint64_t op1, uint64_t op2)
+uint64_t helper_efddiv(uint64_t op1, uint64_t op2)
{
CPU_DoubleU u1, u2;
+
u1.ll = op1;
u2.ll = op2;
u1.d = float64_div(u1.d, u2.d, &env->vec_status);
@@ -3650,43 +3832,46 @@ uint64_t helper_efddiv (uint64_t op1, uint64_t op2)
}
/* Double precision floating point helpers */
-uint32_t helper_efdtstlt (uint64_t op1, uint64_t op2)
+uint32_t helper_efdtstlt(uint64_t op1, uint64_t op2)
{
CPU_DoubleU u1, u2;
+
u1.ll = op1;
u2.ll = op2;
return float64_lt(u1.d, u2.d, &env->vec_status) ? 4 : 0;
}
-uint32_t helper_efdtstgt (uint64_t op1, uint64_t op2)
+uint32_t helper_efdtstgt(uint64_t op1, uint64_t op2)
{
CPU_DoubleU u1, u2;
+
u1.ll = op1;
u2.ll = op2;
return float64_le(u1.d, u2.d, &env->vec_status) ? 0 : 4;
}
-uint32_t helper_efdtsteq (uint64_t op1, uint64_t op2)
+uint32_t helper_efdtsteq(uint64_t op1, uint64_t op2)
{
CPU_DoubleU u1, u2;
+
u1.ll = op1;
u2.ll = op2;
return float64_eq_quiet(u1.d, u2.d, &env->vec_status) ? 4 : 0;
}
-uint32_t helper_efdcmplt (uint64_t op1, uint64_t op2)
+uint32_t helper_efdcmplt(uint64_t op1, uint64_t op2)
{
/* XXX: TODO: test special values (NaN, infinites, ...) */
return helper_efdtstlt(op1, op2);
}
-uint32_t helper_efdcmpgt (uint64_t op1, uint64_t op2)
+uint32_t helper_efdcmpgt(uint64_t op1, uint64_t op2)
{
/* XXX: TODO: test special values (NaN, infinites, ...) */
return helper_efdtstgt(op1, op2);
}
-uint32_t helper_efdcmpeq (uint64_t op1, uint64_t op2)
+uint32_t helper_efdcmpeq(uint64_t op1, uint64_t op2)
{
/* XXX: TODO: test special values (NaN, infinites, ...) */
return helper_efdtsteq(op1, op2);
@@ -3694,7 +3879,7 @@ uint32_t helper_efdcmpeq (uint64_t op1, uint64_t op2)
/*****************************************************************************/
/* Softmmu support */
-#if !defined (CONFIG_USER_ONLY)
+#if !defined(CONFIG_USER_ONLY)
#define MMUSUFFIX _mmu
@@ -3740,30 +3925,31 @@ void tlb_fill(CPUPPCState *env1, target_ulong addr, int is_write, int mmu_idx,
}
/* Segment registers load and store */
-target_ulong helper_load_sr (target_ulong sr_num)
+target_ulong helper_load_sr(target_ulong sr_num)
{
#if defined(TARGET_PPC64)
- if (env->mmu_model & POWERPC_MMU_64)
+ if (env->mmu_model & POWERPC_MMU_64) {
return ppc_load_sr(env, sr_num);
+ }
#endif
return env->sr[sr_num];
}
-void helper_store_sr (target_ulong sr_num, target_ulong val)
+void helper_store_sr(target_ulong sr_num, target_ulong val)
{
ppc_store_sr(env, sr_num, val);
}
/* SLB management */
#if defined(TARGET_PPC64)
-void helper_store_slb (target_ulong rb, target_ulong rs)
+void helper_store_slb(target_ulong rb, target_ulong rs)
{
if (ppc_store_slb(env, rb, rs) < 0) {
helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_INVAL);
}
}
-target_ulong helper_load_slb_esid (target_ulong rb)
+target_ulong helper_load_slb_esid(target_ulong rb)
{
target_ulong rt;
@@ -3773,7 +3959,7 @@ target_ulong helper_load_slb_esid (target_ulong rb)
return rt;
}
-target_ulong helper_load_slb_vsid (target_ulong rb)
+target_ulong helper_load_slb_vsid(target_ulong rb)
{
target_ulong rt;
@@ -3783,12 +3969,12 @@ target_ulong helper_load_slb_vsid (target_ulong rb)
return rt;
}
-void helper_slbia (void)
+void helper_slbia(void)
{
ppc_slb_invalidate_all(env);
}
-void helper_slbie (target_ulong addr)
+void helper_slbie(target_ulong addr)
{
ppc_slb_invalidate_one(env, addr);
}
@@ -3796,19 +3982,19 @@ void helper_slbie (target_ulong addr)
#endif /* defined(TARGET_PPC64) */
/* TLB management */
-void helper_tlbia (void)
+void helper_tlbia(void)
{
ppc_tlb_invalidate_all(env);
}
-void helper_tlbie (target_ulong addr)
+void helper_tlbie(target_ulong addr)
{
ppc_tlb_invalidate_one(env, addr);
}
/* Software driven TLBs management */
/* PowerPC 602/603 software TLB load instructions helpers */
-static void do_6xx_tlb (target_ulong new_EPN, int is_code)
+static void do_6xx_tlb(target_ulong new_EPN, int is_code)
{
target_ulong RPN, CMP, EPN;
int way;
@@ -3831,18 +4017,18 @@ static void do_6xx_tlb (target_ulong new_EPN, int is_code)
way, is_code, CMP, RPN);
}
-void helper_6xx_tlbd (target_ulong EPN)
+void helper_6xx_tlbd(target_ulong EPN)
{
do_6xx_tlb(EPN, 0);
}
-void helper_6xx_tlbi (target_ulong EPN)
+void helper_6xx_tlbi(target_ulong EPN)
{
do_6xx_tlb(EPN, 1);
}
/* PowerPC 74xx software TLB load instructions helpers */
-static void do_74xx_tlb (target_ulong new_EPN, int is_code)
+static void do_74xx_tlb(target_ulong new_EPN, int is_code)
{
target_ulong RPN, CMP, EPN;
int way;
@@ -3860,12 +4046,12 @@ static void do_74xx_tlb (target_ulong new_EPN, int is_code)
way, is_code, CMP, RPN);
}
-void helper_74xx_tlbd (target_ulong EPN)
+void helper_74xx_tlbd(target_ulong EPN)
{
do_74xx_tlb(EPN, 0);
}
-void helper_74xx_tlbi (target_ulong EPN)
+void helper_74xx_tlbi(target_ulong EPN)
{
do_74xx_tlb(EPN, 1);
}
@@ -3913,7 +4099,7 @@ static inline int booke_page_size_to_tlb(target_ulong page_size)
case 0x40000000UL:
size = 0xA;
break;
-#if defined (TARGET_PPC64)
+#if defined(TARGET_PPC64)
case 0x000100000000ULL:
size = 0xB;
break;
@@ -3954,7 +4140,7 @@ static inline int booke_page_size_to_tlb(target_ulong page_size)
#define PPC4XX_TLBLO_ATTR_MASK 0x000000FF
#define PPC4XX_TLBLO_RPN_MASK 0xFFFFFC00
-target_ulong helper_4xx_tlbre_hi (target_ulong entry)
+target_ulong helper_4xx_tlbre_hi(target_ulong entry)
{
ppcemb_tlb_t *tlb;
target_ulong ret;
@@ -3975,7 +4161,7 @@ target_ulong helper_4xx_tlbre_hi (target_ulong entry)
return ret;
}
-target_ulong helper_4xx_tlbre_lo (target_ulong entry)
+target_ulong helper_4xx_tlbre_lo(target_ulong entry)
{
ppcemb_tlb_t *tlb;
target_ulong ret;
@@ -3992,7 +4178,7 @@ target_ulong helper_4xx_tlbre_lo (target_ulong entry)
return ret;
}
-void helper_4xx_tlbwe_hi (target_ulong entry, target_ulong val)
+void helper_4xx_tlbwe_hi(target_ulong entry, target_ulong val)
{
ppcemb_tlb_t *tlb;
target_ulong page, end;
@@ -4051,7 +4237,7 @@ void helper_4xx_tlbwe_hi (target_ulong entry, target_ulong val)
}
}
-void helper_4xx_tlbwe_lo (target_ulong entry, target_ulong val)
+void helper_4xx_tlbwe_lo(target_ulong entry, target_ulong val)
{
ppcemb_tlb_t *tlb;
@@ -4077,13 +4263,13 @@ void helper_4xx_tlbwe_lo (target_ulong entry, target_ulong val)
tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
}
-target_ulong helper_4xx_tlbsx (target_ulong address)
+target_ulong helper_4xx_tlbsx(target_ulong address)
{
return ppcemb_tlb_search(env, address, env->spr[SPR_40x_PID]);
}
/* PowerPC 440 TLB management */
-void helper_440_tlbwe (uint32_t word, target_ulong entry, target_ulong value)
+void helper_440_tlbwe(uint32_t word, target_ulong entry, target_ulong value)
{
ppcemb_tlb_t *tlb;
target_ulong EPN, RPN, size;
@@ -4099,12 +4285,14 @@ void helper_440_tlbwe (uint32_t word, target_ulong entry, target_ulong value)
/* Just here to please gcc */
case 0:
EPN = value & 0xFFFFFC00;
- if ((tlb->prot & PAGE_VALID) && EPN != tlb->EPN)
+ if ((tlb->prot & PAGE_VALID) && EPN != tlb->EPN) {
do_flush_tlbs = 1;
+ }
tlb->EPN = EPN;
size = booke_tlb_to_page_size((value >> 4) & 0xF);
- if ((tlb->prot & PAGE_VALID) && tlb->size < size)
+ if ((tlb->prot & PAGE_VALID) && tlb->size < size) {
do_flush_tlbs = 1;
+ }
tlb->size = size;
tlb->attr &= ~0x1;
tlb->attr |= (value >> 8) & 1;
@@ -4117,35 +4305,43 @@ void helper_440_tlbwe (uint32_t word, target_ulong entry, target_ulong value)
}
}
tlb->PID = env->spr[SPR_440_MMUCR] & 0x000000FF;
- if (do_flush_tlbs)
+ if (do_flush_tlbs) {
tlb_flush(env, 1);
+ }
break;
case 1:
RPN = value & 0xFFFFFC0F;
- if ((tlb->prot & PAGE_VALID) && tlb->RPN != RPN)
+ if ((tlb->prot & PAGE_VALID) && tlb->RPN != RPN) {
tlb_flush(env, 1);
+ }
tlb->RPN = RPN;
break;
case 2:
tlb->attr = (tlb->attr & 0x1) | (value & 0x0000FF00);
tlb->prot = tlb->prot & PAGE_VALID;
- if (value & 0x1)
+ if (value & 0x1) {
tlb->prot |= PAGE_READ << 4;
- if (value & 0x2)
+ }
+ if (value & 0x2) {
tlb->prot |= PAGE_WRITE << 4;
- if (value & 0x4)
+ }
+ if (value & 0x4) {
tlb->prot |= PAGE_EXEC << 4;
- if (value & 0x8)
+ }
+ if (value & 0x8) {
tlb->prot |= PAGE_READ;
- if (value & 0x10)
+ }
+ if (value & 0x10) {
tlb->prot |= PAGE_WRITE;
- if (value & 0x20)
+ }
+ if (value & 0x20) {
tlb->prot |= PAGE_EXEC;
+ }
break;
}
}
-target_ulong helper_440_tlbre (uint32_t word, target_ulong entry)
+target_ulong helper_440_tlbre(uint32_t word, target_ulong entry)
{
ppcemb_tlb_t *tlb;
target_ulong ret;
@@ -4159,13 +4355,16 @@ target_ulong helper_440_tlbre (uint32_t word, target_ulong entry)
case 0:
ret = tlb->EPN;
size = booke_page_size_to_tlb(tlb->size);
- if (size < 0 || size > 0xF)
+ if (size < 0 || size > 0xF) {
size = 1;
+ }
ret |= size << 4;
- if (tlb->attr & 0x1)
+ if (tlb->attr & 0x1) {
ret |= 0x100;
- if (tlb->prot & PAGE_VALID)
+ }
+ if (tlb->prot & PAGE_VALID) {
ret |= 0x200;
+ }
env->spr[SPR_440_MMUCR] &= ~0x000000FF;
env->spr[SPR_440_MMUCR] |= tlb->PID;
break;
@@ -4174,24 +4373,30 @@ target_ulong helper_440_tlbre (uint32_t word, target_ulong entry)
break;
case 2:
ret = tlb->attr & ~0x1;
- if (tlb->prot & (PAGE_READ << 4))
+ if (tlb->prot & (PAGE_READ << 4)) {
ret |= 0x1;
- if (tlb->prot & (PAGE_WRITE << 4))
+ }
+ if (tlb->prot & (PAGE_WRITE << 4)) {
ret |= 0x2;
- if (tlb->prot & (PAGE_EXEC << 4))
+ }
+ if (tlb->prot & (PAGE_EXEC << 4)) {
ret |= 0x4;
- if (tlb->prot & PAGE_READ)
+ }
+ if (tlb->prot & PAGE_READ) {
ret |= 0x8;
- if (tlb->prot & PAGE_WRITE)
+ }
+ if (tlb->prot & PAGE_WRITE) {
ret |= 0x10;
- if (tlb->prot & PAGE_EXEC)
+ }
+ if (tlb->prot & PAGE_EXEC) {
ret |= 0x20;
+ }
break;
}
return ret;
}
-target_ulong helper_440_tlbsx (target_ulong address)
+target_ulong helper_440_tlbsx(target_ulong address)
{
return ppcemb_tlb_search(env, address, env->spr[SPR_440_MMUCR] & 0xFF);
}
@@ -4247,7 +4452,7 @@ void helper_booke206_tlbwe(void)
}
if (((env->spr[SPR_BOOKE_MAS0] & MAS0_ATSEL) == MAS0_ATSEL_LRAT) &&
- !msr_gs) {
+ !msr_gs) {
/* XXX we don't support direct LRAT setting yet */
fprintf(stderr, "cpu: don't support LRAT setting yet\n");
return;
@@ -4278,7 +4483,7 @@ void helper_booke206_tlbwe(void)
cpu_abort(env, "missing HV implementation\n");
}
tlb->mas7_3 = ((uint64_t)env->spr[SPR_BOOKE_MAS7] << 32) |
- env->spr[SPR_BOOKE_MAS3];
+ env->spr[SPR_BOOKE_MAS3];
tlb->mas1 = env->spr[SPR_BOOKE_MAS1];
/* MAV 1.0 only */
@@ -4376,7 +4581,7 @@ void helper_booke206_tlbsx(target_ulong address)
}
env->spr[SPR_BOOKE_MAS1] |= (env->spr[SPR_BOOKE_MAS6] >> 16)
- << MAS1_TID_SHIFT;
+ << MAS1_TID_SHIFT;
/* next victim logic */
env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_ESEL_SHIFT;
--
1.6.0.2
^ permalink raw reply related [flat|nested] 89+ messages in thread
* [Qemu-devel] [PATCH 02/72] ppc: Split exception helpers
2012-06-23 23:06 [Qemu-devel] [PULL 00/72] ppc patch queue 2012-06-24 Alexander Graf
2012-06-23 23:06 ` [Qemu-devel] [PATCH 01/72] ppc: Fix coding style in op_helper.c Alexander Graf
@ 2012-06-23 23:06 ` Alexander Graf
2012-06-23 23:06 ` [Qemu-devel] [PATCH 03/72] ppc: Avoid AREG0 for " Alexander Graf
` (70 subsequent siblings)
72 siblings, 0 replies; 89+ messages in thread
From: Alexander Graf @ 2012-06-23 23:06 UTC (permalink / raw)
To: qemu-devel qemu-devel
Cc: Blue Swirl, qemu-ppc Mailing List, Andreas Färber,
Aurelien Jarno
From: Blue Swirl <blauwirbel@gmail.com>
Move exception helpers from op_helper.c to excp_helper.c.
Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Andreas Färber <afaerber@suse.de>
Signed-off-by: Alexander Graf <agraf@suse.de>
---
target-ppc/Makefile.objs | 2 +
target-ppc/excp_helper.c | 218 ++++++++++++++++++++++++++++++++++++++++++++++
target-ppc/op_helper.c | 190 ----------------------------------------
3 files changed, 220 insertions(+), 190 deletions(-)
create mode 100644 target-ppc/excp_helper.c
diff --git a/target-ppc/Makefile.objs b/target-ppc/Makefile.objs
index f781610..c0f7e76 100644
--- a/target-ppc/Makefile.objs
+++ b/target-ppc/Makefile.objs
@@ -2,5 +2,7 @@ obj-y += translate.o op_helper.o helper.o
obj-$(CONFIG_SOFTMMU) += machine.o
obj-$(CONFIG_KVM) += kvm.o kvm_ppc.o
obj-y += op_helper.o helper.o
+obj-y += excp_helper.o
+$(obj)/excp_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
$(obj)/op_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
diff --git a/target-ppc/excp_helper.c b/target-ppc/excp_helper.c
new file mode 100644
index 0000000..f03f738
--- /dev/null
+++ b/target-ppc/excp_helper.c
@@ -0,0 +1,218 @@
+/*
+ * PowerPC exception emulation helpers for QEMU.
+ *
+ * Copyright (c) 2003-2007 Jocelyn Mayer
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "cpu.h"
+#include "dyngen-exec.h"
+#include "helper.h"
+
+#include "helper_regs.h"
+
+//#define DEBUG_OP
+//#define DEBUG_EXCEPTIONS
+
+/*****************************************************************************/
+/* Exceptions processing helpers */
+
+void helper_raise_exception_err(uint32_t exception, uint32_t error_code)
+{
+#if 0
+ printf("Raise exception %3x code : %d\n", exception, error_code);
+#endif
+ env->exception_index = exception;
+ env->error_code = error_code;
+ cpu_loop_exit(env);
+}
+
+void helper_raise_exception(uint32_t exception)
+{
+ helper_raise_exception_err(exception, 0);
+}
+
+#if !defined(CONFIG_USER_ONLY)
+void helper_store_msr(target_ulong val)
+{
+ val = hreg_store_msr(env, val, 0);
+ if (val != 0) {
+ env->interrupt_request |= CPU_INTERRUPT_EXITTB;
+ helper_raise_exception(val);
+ }
+}
+
+static inline void do_rfi(target_ulong nip, target_ulong msr,
+ target_ulong msrm, int keep_msrh)
+{
+#if defined(TARGET_PPC64)
+ if (msr & (1ULL << MSR_SF)) {
+ nip = (uint64_t)nip;
+ msr &= (uint64_t)msrm;
+ } else {
+ nip = (uint32_t)nip;
+ msr = (uint32_t)(msr & msrm);
+ if (keep_msrh) {
+ msr |= env->msr & ~((uint64_t)0xFFFFFFFF);
+ }
+ }
+#else
+ nip = (uint32_t)nip;
+ msr &= (uint32_t)msrm;
+#endif
+ /* XXX: beware: this is false if VLE is supported */
+ env->nip = nip & ~((target_ulong)0x00000003);
+ hreg_store_msr(env, msr, 1);
+#if defined(DEBUG_OP)
+ cpu_dump_rfi(env->nip, env->msr);
+#endif
+ /* No need to raise an exception here,
+ * as rfi is always the last insn of a TB
+ */
+ env->interrupt_request |= CPU_INTERRUPT_EXITTB;
+}
+
+void helper_rfi(void)
+{
+ do_rfi(env->spr[SPR_SRR0], env->spr[SPR_SRR1],
+ ~((target_ulong)0x783F0000), 1);
+}
+
+#if defined(TARGET_PPC64)
+void helper_rfid(void)
+{
+ do_rfi(env->spr[SPR_SRR0], env->spr[SPR_SRR1],
+ ~((target_ulong)0x783F0000), 0);
+}
+
+void helper_hrfid(void)
+{
+ do_rfi(env->spr[SPR_HSRR0], env->spr[SPR_HSRR1],
+ ~((target_ulong)0x783F0000), 0);
+}
+#endif
+
+/*****************************************************************************/
+/* Embedded PowerPC specific helpers */
+void helper_40x_rfci(void)
+{
+ do_rfi(env->spr[SPR_40x_SRR2], env->spr[SPR_40x_SRR3],
+ ~((target_ulong)0xFFFF0000), 0);
+}
+
+void helper_rfci(void)
+{
+ do_rfi(env->spr[SPR_BOOKE_CSRR0], SPR_BOOKE_CSRR1,
+ ~((target_ulong)0x3FFF0000), 0);
+}
+
+void helper_rfdi(void)
+{
+ do_rfi(env->spr[SPR_BOOKE_DSRR0], SPR_BOOKE_DSRR1,
+ ~((target_ulong)0x3FFF0000), 0);
+}
+
+void helper_rfmci(void)
+{
+ do_rfi(env->spr[SPR_BOOKE_MCSRR0], SPR_BOOKE_MCSRR1,
+ ~((target_ulong)0x3FFF0000), 0);
+}
+#endif
+
+void helper_tw(target_ulong arg1, target_ulong arg2, uint32_t flags)
+{
+ if (!likely(!(((int32_t)arg1 < (int32_t)arg2 && (flags & 0x10)) ||
+ ((int32_t)arg1 > (int32_t)arg2 && (flags & 0x08)) ||
+ ((int32_t)arg1 == (int32_t)arg2 && (flags & 0x04)) ||
+ ((uint32_t)arg1 < (uint32_t)arg2 && (flags & 0x02)) ||
+ ((uint32_t)arg1 > (uint32_t)arg2 && (flags & 0x01))))) {
+ helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_TRAP);
+ }
+}
+
+#if defined(TARGET_PPC64)
+void helper_td(target_ulong arg1, target_ulong arg2, uint32_t flags)
+{
+ if (!likely(!(((int64_t)arg1 < (int64_t)arg2 && (flags & 0x10)) ||
+ ((int64_t)arg1 > (int64_t)arg2 && (flags & 0x08)) ||
+ ((int64_t)arg1 == (int64_t)arg2 && (flags & 0x04)) ||
+ ((uint64_t)arg1 < (uint64_t)arg2 && (flags & 0x02)) ||
+ ((uint64_t)arg1 > (uint64_t)arg2 && (flags & 0x01))))) {
+ helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_TRAP);
+ }
+}
+#endif
+
+#if !defined(CONFIG_USER_ONLY)
+/*****************************************************************************/
+/* PowerPC 601 specific instructions (POWER bridge) */
+
+void helper_rfsvc(void)
+{
+ do_rfi(env->lr, env->ctr, 0x0000FFFF, 0);
+}
+
+/* Embedded.Processor Control */
+static int dbell2irq(target_ulong rb)
+{
+ int msg = rb & DBELL_TYPE_MASK;
+ int irq = -1;
+
+ switch (msg) {
+ case DBELL_TYPE_DBELL:
+ irq = PPC_INTERRUPT_DOORBELL;
+ break;
+ case DBELL_TYPE_DBELL_CRIT:
+ irq = PPC_INTERRUPT_CDOORBELL;
+ break;
+ case DBELL_TYPE_G_DBELL:
+ case DBELL_TYPE_G_DBELL_CRIT:
+ case DBELL_TYPE_G_DBELL_MC:
+ /* XXX implement */
+ default:
+ break;
+ }
+
+ return irq;
+}
+
+void helper_msgclr(target_ulong rb)
+{
+ int irq = dbell2irq(rb);
+
+ if (irq < 0) {
+ return;
+ }
+
+ env->pending_interrupts &= ~(1 << irq);
+}
+
+void helper_msgsnd(target_ulong rb)
+{
+ int irq = dbell2irq(rb);
+ int pir = rb & DBELL_PIRTAG_MASK;
+ CPUPPCState *cenv;
+
+ if (irq < 0) {
+ return;
+ }
+
+ for (cenv = first_cpu; cenv != NULL; cenv = cenv->next_cpu) {
+ if ((rb & DBELL_BRDCAST) || (cenv->spr[SPR_BOOKE_PIR] == pir)) {
+ cenv->pending_interrupts |= 1 << irq;
+ cpu_interrupt(cenv, CPU_INTERRUPT_HARD);
+ }
+ }
+}
+#endif
diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c
index d9f7a8b..2e87860 100644
--- a/target-ppc/op_helper.c
+++ b/target-ppc/op_helper.c
@@ -29,7 +29,6 @@
#endif /* !defined(CONFIG_USER_ONLY) */
//#define DEBUG_OP
-//#define DEBUG_EXCEPTIONS
//#define DEBUG_SOFTWARE_TLB
#ifdef DEBUG_SOFTWARE_TLB
@@ -38,25 +37,6 @@
# define LOG_SWTLB(...) do { } while (0)
#endif
-
-/*****************************************************************************/
-/* Exceptions processing helpers */
-
-void helper_raise_exception_err(uint32_t exception, uint32_t error_code)
-{
-#if 0
- printf("Raise exception %3x code : %d\n", exception, error_code);
-#endif
- env->exception_index = exception;
- env->error_code = error_code;
- cpu_loop_exit(env);
-}
-
-void helper_raise_exception(uint32_t exception)
-{
- helper_raise_exception_err(exception, 0);
-}
-
/*****************************************************************************/
/* SPR accesses */
void helper_load_dump_spr(uint32_t sprn)
@@ -1658,91 +1638,6 @@ void helper_fcmpo(uint64_t arg1, uint64_t arg2, uint32_t crfD)
}
}
-#if !defined(CONFIG_USER_ONLY)
-void helper_store_msr(target_ulong val)
-{
- val = hreg_store_msr(env, val, 0);
- if (val != 0) {
- env->interrupt_request |= CPU_INTERRUPT_EXITTB;
- helper_raise_exception(val);
- }
-}
-
-static inline void do_rfi(target_ulong nip, target_ulong msr,
- target_ulong msrm, int keep_msrh)
-{
-#if defined(TARGET_PPC64)
- if (msr & (1ULL << MSR_SF)) {
- nip = (uint64_t)nip;
- msr &= (uint64_t)msrm;
- } else {
- nip = (uint32_t)nip;
- msr = (uint32_t)(msr & msrm);
- if (keep_msrh) {
- msr |= env->msr & ~((uint64_t)0xFFFFFFFF);
- }
- }
-#else
- nip = (uint32_t)nip;
- msr &= (uint32_t)msrm;
-#endif
- /* XXX: beware: this is false if VLE is supported */
- env->nip = nip & ~((target_ulong)0x00000003);
- hreg_store_msr(env, msr, 1);
-#if defined(DEBUG_OP)
- cpu_dump_rfi(env->nip, env->msr);
-#endif
- /* No need to raise an exception here,
- * as rfi is always the last insn of a TB
- */
- env->interrupt_request |= CPU_INTERRUPT_EXITTB;
-}
-
-void helper_rfi(void)
-{
- do_rfi(env->spr[SPR_SRR0], env->spr[SPR_SRR1],
- ~((target_ulong)0x783F0000), 1);
-}
-
-#if defined(TARGET_PPC64)
-void helper_rfid(void)
-{
- do_rfi(env->spr[SPR_SRR0], env->spr[SPR_SRR1],
- ~((target_ulong)0x783F0000), 0);
-}
-
-void helper_hrfid(void)
-{
- do_rfi(env->spr[SPR_HSRR0], env->spr[SPR_HSRR1],
- ~((target_ulong)0x783F0000), 0);
-}
-#endif
-#endif
-
-void helper_tw(target_ulong arg1, target_ulong arg2, uint32_t flags)
-{
- if (!likely(!(((int32_t)arg1 < (int32_t)arg2 && (flags & 0x10)) ||
- ((int32_t)arg1 > (int32_t)arg2 && (flags & 0x08)) ||
- ((int32_t)arg1 == (int32_t)arg2 && (flags & 0x04)) ||
- ((uint32_t)arg1 < (uint32_t)arg2 && (flags & 0x02)) ||
- ((uint32_t)arg1 > (uint32_t)arg2 && (flags & 0x01))))) {
- helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_TRAP);
- }
-}
-
-#if defined(TARGET_PPC64)
-void helper_td(target_ulong arg1, target_ulong arg2, uint32_t flags)
-{
- if (!likely(!(((int64_t)arg1 < (int64_t)arg2 && (flags & 0x10)) ||
- ((int64_t)arg1 > (int64_t)arg2 && (flags & 0x08)) ||
- ((int64_t)arg1 == (int64_t)arg2 && (flags & 0x04)) ||
- ((uint64_t)arg1 < (uint64_t)arg2 && (flags & 0x02)) ||
- ((uint64_t)arg1 > (uint64_t)arg2 && (flags & 0x01))))) {
- helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_TRAP);
- }
-}
-#endif
-
/*****************************************************************************/
/* PowerPC 601 specific instructions (POWER bridge) */
@@ -1854,11 +1749,6 @@ target_ulong helper_rac(target_ulong addr)
env->nb_BATs = nb_BATs;
return ret;
}
-
-void helper_rfsvc(void)
-{
- do_rfi(env->lr, env->ctr, 0x0000FFFF, 0);
-}
#endif
/*****************************************************************************/
@@ -1918,32 +1808,6 @@ void helper_store_dcr(target_ulong dcrn, target_ulong val)
}
}
-#if !defined(CONFIG_USER_ONLY)
-void helper_40x_rfci(void)
-{
- do_rfi(env->spr[SPR_40x_SRR2], env->spr[SPR_40x_SRR3],
- ~((target_ulong)0xFFFF0000), 0);
-}
-
-void helper_rfci(void)
-{
- do_rfi(env->spr[SPR_BOOKE_CSRR0], SPR_BOOKE_CSRR1,
- ~((target_ulong)0x3FFF0000), 0);
-}
-
-void helper_rfdi(void)
-{
- do_rfi(env->spr[SPR_BOOKE_DSRR0], SPR_BOOKE_DSRR1,
- ~((target_ulong)0x3FFF0000), 0);
-}
-
-void helper_rfmci(void)
-{
- do_rfi(env->spr[SPR_BOOKE_MCSRR0], SPR_BOOKE_MCSRR1,
- ~((target_ulong)0x3FFF0000), 0);
-}
-#endif
-
/* 440 specific */
target_ulong helper_dlmzb(target_ulong high, target_ulong low,
uint32_t update_Rc)
@@ -4716,58 +4580,4 @@ void helper_booke206_tlbflush(uint32_t type)
booke206_flush_tlb(env, flags, 1);
}
-
-/* Embedded.Processor Control */
-static int dbell2irq(target_ulong rb)
-{
- int msg = rb & DBELL_TYPE_MASK;
- int irq = -1;
-
- switch (msg) {
- case DBELL_TYPE_DBELL:
- irq = PPC_INTERRUPT_DOORBELL;
- break;
- case DBELL_TYPE_DBELL_CRIT:
- irq = PPC_INTERRUPT_CDOORBELL;
- break;
- case DBELL_TYPE_G_DBELL:
- case DBELL_TYPE_G_DBELL_CRIT:
- case DBELL_TYPE_G_DBELL_MC:
- /* XXX implement */
- default:
- break;
- }
-
- return irq;
-}
-
-void helper_msgclr(target_ulong rb)
-{
- int irq = dbell2irq(rb);
-
- if (irq < 0) {
- return;
- }
-
- env->pending_interrupts &= ~(1 << irq);
-}
-
-void helper_msgsnd(target_ulong rb)
-{
- int irq = dbell2irq(rb);
- int pir = rb & DBELL_PIRTAG_MASK;
- CPUPPCState *cenv;
-
- if (irq < 0) {
- return;
- }
-
- for (cenv = first_cpu; cenv != NULL; cenv = cenv->next_cpu) {
- if ((rb & DBELL_BRDCAST) || (cenv->spr[SPR_BOOKE_PIR] == pir)) {
- cenv->pending_interrupts |= 1 << irq;
- cpu_interrupt(cenv, CPU_INTERRUPT_HARD);
- }
- }
-}
-
#endif /* !CONFIG_USER_ONLY */
--
1.6.0.2
^ permalink raw reply related [flat|nested] 89+ messages in thread
* [Qemu-devel] [PATCH 03/72] ppc: Avoid AREG0 for exception helpers
2012-06-23 23:06 [Qemu-devel] [PULL 00/72] ppc patch queue 2012-06-24 Alexander Graf
2012-06-23 23:06 ` [Qemu-devel] [PATCH 01/72] ppc: Fix coding style in op_helper.c Alexander Graf
2012-06-23 23:06 ` [Qemu-devel] [PATCH 02/72] ppc: Split exception helpers Alexander Graf
@ 2012-06-23 23:06 ` Alexander Graf
2012-06-23 23:06 ` [Qemu-devel] [PATCH 04/72] ppc: Fix coding style in helper.c Alexander Graf
` (69 subsequent siblings)
72 siblings, 0 replies; 89+ messages in thread
From: Alexander Graf @ 2012-06-23 23:06 UTC (permalink / raw)
To: qemu-devel qemu-devel
Cc: Blue Swirl, qemu-ppc Mailing List, Andreas Färber,
Aurelien Jarno
From: Blue Swirl <blauwirbel@gmail.com>
Add an explicit CPUPPCState parameter instead of relying on AREG0.
Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Andreas Färber <afaerber@suse.de>
Signed-off-by: Alexander Graf <agraf@suse.de>
---
target-ppc/Makefile.objs | 1 -
target-ppc/excp_helper.c | 60 ++++++++++++++++++++++++---------------------
target-ppc/helper.h | 28 ++++++++++----------
target-ppc/op_helper.c | 32 +++++++++++++----------
target-ppc/translate.c | 40 ++++++++++++++++--------------
5 files changed, 85 insertions(+), 76 deletions(-)
diff --git a/target-ppc/Makefile.objs b/target-ppc/Makefile.objs
index c0f7e76..a02b7bc 100644
--- a/target-ppc/Makefile.objs
+++ b/target-ppc/Makefile.objs
@@ -4,5 +4,4 @@ obj-$(CONFIG_KVM) += kvm.o kvm_ppc.o
obj-y += op_helper.o helper.o
obj-y += excp_helper.o
-$(obj)/excp_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
$(obj)/op_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
diff --git a/target-ppc/excp_helper.c b/target-ppc/excp_helper.c
index f03f738..c153f4a 100644
--- a/target-ppc/excp_helper.c
+++ b/target-ppc/excp_helper.c
@@ -17,7 +17,6 @@
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include "cpu.h"
-#include "dyngen-exec.h"
#include "helper.h"
#include "helper_regs.h"
@@ -28,7 +27,8 @@
/*****************************************************************************/
/* Exceptions processing helpers */
-void helper_raise_exception_err(uint32_t exception, uint32_t error_code)
+void helper_raise_exception_err(CPUPPCState *env, uint32_t exception,
+ uint32_t error_code)
{
#if 0
printf("Raise exception %3x code : %d\n", exception, error_code);
@@ -38,22 +38,22 @@ void helper_raise_exception_err(uint32_t exception, uint32_t error_code)
cpu_loop_exit(env);
}
-void helper_raise_exception(uint32_t exception)
+void helper_raise_exception(CPUPPCState *env, uint32_t exception)
{
- helper_raise_exception_err(exception, 0);
+ helper_raise_exception_err(env, exception, 0);
}
#if !defined(CONFIG_USER_ONLY)
-void helper_store_msr(target_ulong val)
+void helper_store_msr(CPUPPCState *env, target_ulong val)
{
val = hreg_store_msr(env, val, 0);
if (val != 0) {
env->interrupt_request |= CPU_INTERRUPT_EXITTB;
- helper_raise_exception(val);
+ helper_raise_exception(env, val);
}
}
-static inline void do_rfi(target_ulong nip, target_ulong msr,
+static inline void do_rfi(CPUPPCState *env, target_ulong nip, target_ulong msr,
target_ulong msrm, int keep_msrh)
{
#if defined(TARGET_PPC64)
@@ -83,73 +83,77 @@ static inline void do_rfi(target_ulong nip, target_ulong msr,
env->interrupt_request |= CPU_INTERRUPT_EXITTB;
}
-void helper_rfi(void)
+void helper_rfi(CPUPPCState *env)
{
- do_rfi(env->spr[SPR_SRR0], env->spr[SPR_SRR1],
+ do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1],
~((target_ulong)0x783F0000), 1);
}
#if defined(TARGET_PPC64)
-void helper_rfid(void)
+void helper_rfid(CPUPPCState *env)
{
- do_rfi(env->spr[SPR_SRR0], env->spr[SPR_SRR1],
+ do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1],
~((target_ulong)0x783F0000), 0);
}
-void helper_hrfid(void)
+void helper_hrfid(CPUPPCState *env)
{
- do_rfi(env->spr[SPR_HSRR0], env->spr[SPR_HSRR1],
+ do_rfi(env, env->spr[SPR_HSRR0], env->spr[SPR_HSRR1],
~((target_ulong)0x783F0000), 0);
}
#endif
/*****************************************************************************/
/* Embedded PowerPC specific helpers */
-void helper_40x_rfci(void)
+void helper_40x_rfci(CPUPPCState *env)
{
- do_rfi(env->spr[SPR_40x_SRR2], env->spr[SPR_40x_SRR3],
+ do_rfi(env, env->spr[SPR_40x_SRR2], env->spr[SPR_40x_SRR3],
~((target_ulong)0xFFFF0000), 0);
}
-void helper_rfci(void)
+void helper_rfci(CPUPPCState *env)
{
- do_rfi(env->spr[SPR_BOOKE_CSRR0], SPR_BOOKE_CSRR1,
+ do_rfi(env, env->spr[SPR_BOOKE_CSRR0], SPR_BOOKE_CSRR1,
~((target_ulong)0x3FFF0000), 0);
}
-void helper_rfdi(void)
+void helper_rfdi(CPUPPCState *env)
{
- do_rfi(env->spr[SPR_BOOKE_DSRR0], SPR_BOOKE_DSRR1,
+ do_rfi(env, env->spr[SPR_BOOKE_DSRR0], SPR_BOOKE_DSRR1,
~((target_ulong)0x3FFF0000), 0);
}
-void helper_rfmci(void)
+void helper_rfmci(CPUPPCState *env)
{
- do_rfi(env->spr[SPR_BOOKE_MCSRR0], SPR_BOOKE_MCSRR1,
+ do_rfi(env, env->spr[SPR_BOOKE_MCSRR0], SPR_BOOKE_MCSRR1,
~((target_ulong)0x3FFF0000), 0);
}
#endif
-void helper_tw(target_ulong arg1, target_ulong arg2, uint32_t flags)
+void helper_tw(CPUPPCState *env, target_ulong arg1, target_ulong arg2,
+ uint32_t flags)
{
if (!likely(!(((int32_t)arg1 < (int32_t)arg2 && (flags & 0x10)) ||
((int32_t)arg1 > (int32_t)arg2 && (flags & 0x08)) ||
((int32_t)arg1 == (int32_t)arg2 && (flags & 0x04)) ||
((uint32_t)arg1 < (uint32_t)arg2 && (flags & 0x02)) ||
((uint32_t)arg1 > (uint32_t)arg2 && (flags & 0x01))))) {
- helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_TRAP);
+ helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
+ POWERPC_EXCP_TRAP);
}
}
#if defined(TARGET_PPC64)
-void helper_td(target_ulong arg1, target_ulong arg2, uint32_t flags)
+void helper_td(CPUPPCState *env, target_ulong arg1, target_ulong arg2,
+ uint32_t flags)
{
if (!likely(!(((int64_t)arg1 < (int64_t)arg2 && (flags & 0x10)) ||
((int64_t)arg1 > (int64_t)arg2 && (flags & 0x08)) ||
((int64_t)arg1 == (int64_t)arg2 && (flags & 0x04)) ||
((uint64_t)arg1 < (uint64_t)arg2 && (flags & 0x02)) ||
((uint64_t)arg1 > (uint64_t)arg2 && (flags & 0x01))))) {
- helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_TRAP);
+ helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
+ POWERPC_EXCP_TRAP);
}
}
#endif
@@ -158,9 +162,9 @@ void helper_td(target_ulong arg1, target_ulong arg2, uint32_t flags)
/*****************************************************************************/
/* PowerPC 601 specific instructions (POWER bridge) */
-void helper_rfsvc(void)
+void helper_rfsvc(CPUPPCState *env)
{
- do_rfi(env->lr, env->ctr, 0x0000FFFF, 0);
+ do_rfi(env, env->lr, env->ctr, 0x0000FFFF, 0);
}
/* Embedded.Processor Control */
@@ -187,7 +191,7 @@ static int dbell2irq(target_ulong rb)
return irq;
}
-void helper_msgclr(target_ulong rb)
+void helper_msgclr(CPUPPCState *env, target_ulong rb)
{
int irq = dbell2irq(rb);
diff --git a/target-ppc/helper.h b/target-ppc/helper.h
index 148543a..a4562ae 100644
--- a/target-ppc/helper.h
+++ b/target-ppc/helper.h
@@ -1,22 +1,22 @@
#include "def-helper.h"
-DEF_HELPER_2(raise_exception_err, void, i32, i32)
-DEF_HELPER_1(raise_exception, void, i32)
-DEF_HELPER_3(tw, void, tl, tl, i32)
+DEF_HELPER_3(raise_exception_err, void, env, i32, i32)
+DEF_HELPER_2(raise_exception, void, env, i32)
+DEF_HELPER_4(tw, void, env, tl, tl, i32)
#if defined(TARGET_PPC64)
-DEF_HELPER_3(td, void, tl, tl, i32)
+DEF_HELPER_4(td, void, env, tl, tl, i32)
#endif
#if !defined(CONFIG_USER_ONLY)
-DEF_HELPER_1(store_msr, void, tl)
-DEF_HELPER_0(rfi, void)
-DEF_HELPER_0(rfsvc, void)
-DEF_HELPER_0(40x_rfci, void)
-DEF_HELPER_0(rfci, void)
-DEF_HELPER_0(rfdi, void)
-DEF_HELPER_0(rfmci, void)
+DEF_HELPER_2(store_msr, void, env, tl)
+DEF_HELPER_1(rfi, void, env)
+DEF_HELPER_1(rfsvc, void, env)
+DEF_HELPER_1(40x_rfci, void, env)
+DEF_HELPER_1(rfci, void, env)
+DEF_HELPER_1(rfdi, void, env)
+DEF_HELPER_1(rfmci, void, env)
#if defined(TARGET_PPC64)
-DEF_HELPER_0(rfid, void)
-DEF_HELPER_0(hrfid, void)
+DEF_HELPER_1(rfid, void, env)
+DEF_HELPER_1(hrfid, void, env)
#endif
#endif
@@ -359,7 +359,7 @@ DEF_HELPER_FLAGS_2(store_sr, TCG_CALL_CONST, void, tl, tl)
DEF_HELPER_FLAGS_1(602_mfrom, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl)
DEF_HELPER_1(msgsnd, void, tl)
-DEF_HELPER_1(msgclr, void, tl)
+DEF_HELPER_2(msgclr, void, env, tl)
#endif
DEF_HELPER_3(dlmzb, tl, tl, tl, i32)
diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c
index 2e87860..eedbb42 100644
--- a/target-ppc/op_helper.c
+++ b/target-ppc/op_helper.c
@@ -294,7 +294,7 @@ void helper_lswx(target_ulong addr, uint32_t reg, uint32_t ra, uint32_t rb)
if (likely(xer_bc != 0)) {
if (unlikely((ra != 0 && reg < ra && (reg + xer_bc) > ra) ||
(reg < rb && (reg + xer_bc) > rb))) {
- helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
+ helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
POWERPC_EXCP_INVAL |
POWERPC_EXCP_INVAL_LSWX);
} else {
@@ -709,7 +709,7 @@ static inline uint64_t fload_invalid_op_excp(int op)
/* Update the floating-point enabled exception summary */
env->fpscr |= 1 << FPSCR_FEX;
if (msr_fe0 != 0 || msr_fe1 != 0) {
- helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
+ helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
POWERPC_EXCP_FP | op);
}
}
@@ -726,7 +726,7 @@ static inline void float_zero_divide_excp(void)
/* Update the floating-point enabled exception summary */
env->fpscr |= 1 << FPSCR_FEX;
if (msr_fe0 != 0 || msr_fe1 != 0) {
- helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
+ helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX);
}
}
@@ -995,7 +995,8 @@ void helper_float_check_status(void)
(env->error_code & POWERPC_EXCP_FP)) {
/* Differred floating-point exception after target FPR update */
if (msr_fe0 != 0 || msr_fe1 != 0) {
- helper_raise_exception_err(env->exception_index, env->error_code);
+ helper_raise_exception_err(env, env->exception_index,
+ env->error_code);
}
} else {
int status = get_float_exception_flags(&env->fp_status);
@@ -1781,13 +1782,13 @@ target_ulong helper_load_dcr(target_ulong dcrn)
if (unlikely(env->dcr_env == NULL)) {
qemu_log("No DCR environment\n");
- helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
+ helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
POWERPC_EXCP_INVAL |
POWERPC_EXCP_INVAL_INVAL);
} else if (unlikely(ppc_dcr_read(env->dcr_env,
(uint32_t)dcrn, &val) != 0)) {
qemu_log("DCR read error %d %03x\n", (uint32_t)dcrn, (uint32_t)dcrn);
- helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
+ helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG);
}
return val;
@@ -1797,13 +1798,13 @@ void helper_store_dcr(target_ulong dcrn, target_ulong val)
{
if (unlikely(env->dcr_env == NULL)) {
qemu_log("No DCR environment\n");
- helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
+ helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
POWERPC_EXCP_INVAL |
POWERPC_EXCP_INVAL_INVAL);
} else if (unlikely(ppc_dcr_write(env->dcr_env, (uint32_t)dcrn,
(uint32_t)val) != 0)) {
qemu_log("DCR write error %d %03x\n", (uint32_t)dcrn, (uint32_t)dcrn);
- helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
+ helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG);
}
}
@@ -3783,7 +3784,7 @@ void tlb_fill(CPUPPCState *env1, target_ulong addr, int is_write, int mmu_idx,
cpu_restore_state(tb, env, retaddr);
}
}
- helper_raise_exception_err(env->exception_index, env->error_code);
+ helper_raise_exception_err(env, env->exception_index, env->error_code);
}
env = saved_env;
}
@@ -3809,7 +3810,8 @@ void helper_store_sr(target_ulong sr_num, target_ulong val)
void helper_store_slb(target_ulong rb, target_ulong rs)
{
if (ppc_store_slb(env, rb, rs) < 0) {
- helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_INVAL);
+ helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
+ POWERPC_EXCP_INVAL);
}
}
@@ -3818,7 +3820,8 @@ target_ulong helper_load_slb_esid(target_ulong rb)
target_ulong rt;
if (ppc_load_slb_esid(env, rb, &rt) < 0) {
- helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_INVAL);
+ helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
+ POWERPC_EXCP_INVAL);
}
return rt;
}
@@ -3828,7 +3831,8 @@ target_ulong helper_load_slb_vsid(target_ulong rb)
target_ulong rt;
if (ppc_load_slb_vsid(env, rb, &rt) < 0) {
- helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_INVAL);
+ helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
+ POWERPC_EXCP_INVAL);
}
return rt;
}
@@ -4328,7 +4332,7 @@ void helper_booke206_tlbwe(void)
tlb = booke206_cur_tlb(env);
if (!tlb) {
- helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
+ helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
POWERPC_EXCP_INVAL |
POWERPC_EXCP_INVAL_INVAL);
}
@@ -4338,7 +4342,7 @@ void helper_booke206_tlbwe(void)
size_ps = booke206_tlbnps(env, tlbn);
if ((env->spr[SPR_BOOKE_MAS1] & MAS1_VALID) && (tlbncfg & TLBnCFG_AVAIL) &&
!(size_ps & (1 << size_tlb))) {
- helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
+ helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
POWERPC_EXCP_INVAL |
POWERPC_EXCP_INVAL_INVAL);
}
diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index cf59765..02626ae 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -270,7 +270,7 @@ static inline void gen_exception_err(DisasContext *ctx, uint32_t excp, uint32_t
}
t0 = tcg_const_i32(excp);
t1 = tcg_const_i32(error);
- gen_helper_raise_exception_err(t0, t1);
+ gen_helper_raise_exception_err(cpu_env, t0, t1);
tcg_temp_free_i32(t0);
tcg_temp_free_i32(t1);
ctx->exception = (excp);
@@ -283,7 +283,7 @@ static inline void gen_exception(DisasContext *ctx, uint32_t excp)
gen_update_nip(ctx, ctx->nip);
}
t0 = tcg_const_i32(excp);
- gen_helper_raise_exception(t0);
+ gen_helper_raise_exception(cpu_env, t0);
tcg_temp_free_i32(t0);
ctx->exception = (excp);
}
@@ -297,7 +297,7 @@ static inline void gen_debug_exception(DisasContext *ctx)
gen_update_nip(ctx, ctx->nip);
}
t0 = tcg_const_i32(EXCP_DEBUG);
- gen_helper_raise_exception(t0);
+ gen_helper_raise_exception(cpu_env, t0);
tcg_temp_free_i32(t0);
}
@@ -2495,7 +2495,7 @@ static inline void gen_check_align(DisasContext *ctx, TCGv EA, int mask)
tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 0, l1);
t1 = tcg_const_i32(POWERPC_EXCP_ALIGN);
t2 = tcg_const_i32(0);
- gen_helper_raise_exception_err(t1, t2);
+ gen_helper_raise_exception_err(cpu_env, t1, t2);
tcg_temp_free_i32(t1);
tcg_temp_free_i32(t2);
gen_set_label(l1);
@@ -3662,7 +3662,7 @@ static void gen_rfi(DisasContext *ctx)
return;
}
gen_update_cfar(ctx, ctx->nip);
- gen_helper_rfi();
+ gen_helper_rfi(cpu_env);
gen_sync_exception(ctx);
#endif
}
@@ -3679,7 +3679,7 @@ static void gen_rfid(DisasContext *ctx)
return;
}
gen_update_cfar(ctx, ctx->nip);
- gen_helper_rfid();
+ gen_helper_rfid(cpu_env);
gen_sync_exception(ctx);
#endif
}
@@ -3694,7 +3694,7 @@ static void gen_hrfid(DisasContext *ctx)
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
return;
}
- gen_helper_hrfid();
+ gen_helper_hrfid(cpu_env);
gen_sync_exception(ctx);
#endif
}
@@ -3722,7 +3722,8 @@ static void gen_tw(DisasContext *ctx)
TCGv_i32 t0 = tcg_const_i32(TO(ctx->opcode));
/* Update the nip since this might generate a trap exception */
gen_update_nip(ctx, ctx->nip);
- gen_helper_tw(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)], t0);
+ gen_helper_tw(cpu_env, cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)],
+ t0);
tcg_temp_free_i32(t0);
}
@@ -3733,7 +3734,7 @@ static void gen_twi(DisasContext *ctx)
TCGv_i32 t1 = tcg_const_i32(TO(ctx->opcode));
/* Update the nip since this might generate a trap exception */
gen_update_nip(ctx, ctx->nip);
- gen_helper_tw(cpu_gpr[rA(ctx->opcode)], t0, t1);
+ gen_helper_tw(cpu_env, cpu_gpr[rA(ctx->opcode)], t0, t1);
tcg_temp_free(t0);
tcg_temp_free_i32(t1);
}
@@ -3745,7 +3746,8 @@ static void gen_td(DisasContext *ctx)
TCGv_i32 t0 = tcg_const_i32(TO(ctx->opcode));
/* Update the nip since this might generate a trap exception */
gen_update_nip(ctx, ctx->nip);
- gen_helper_td(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)], t0);
+ gen_helper_td(cpu_env, cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)],
+ t0);
tcg_temp_free_i32(t0);
}
@@ -3756,7 +3758,7 @@ static void gen_tdi(DisasContext *ctx)
TCGv_i32 t1 = tcg_const_i32(TO(ctx->opcode));
/* Update the nip since this might generate a trap exception */
gen_update_nip(ctx, ctx->nip);
- gen_helper_td(cpu_gpr[rA(ctx->opcode)], t0, t1);
+ gen_helper_td(cpu_env, cpu_gpr[rA(ctx->opcode)], t0, t1);
tcg_temp_free(t0);
tcg_temp_free_i32(t1);
}
@@ -3934,7 +3936,7 @@ static void gen_mtmsrd(DisasContext *ctx)
* directly from ppc_store_msr
*/
gen_update_nip(ctx, ctx->nip);
- gen_helper_store_msr(cpu_gpr[rS(ctx->opcode)]);
+ gen_helper_store_msr(cpu_env, cpu_gpr[rS(ctx->opcode)]);
/* Must stop the translation as machine state (may have) changed */
/* Note that mtmsr is not always defined as context-synchronizing */
gen_stop_exception(ctx);
@@ -3972,7 +3974,7 @@ static void gen_mtmsr(DisasContext *ctx)
#else
tcg_gen_mov_tl(msr, cpu_gpr[rS(ctx->opcode)]);
#endif
- gen_helper_store_msr(msr);
+ gen_helper_store_msr(cpu_env, msr);
/* Must stop the translation as machine state (may have) changed */
/* Note that mtmsr is not always defined as context-synchronizing */
gen_stop_exception(ctx);
@@ -5290,7 +5292,7 @@ static void gen_rfsvc(DisasContext *ctx)
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
return;
}
- gen_helper_rfsvc();
+ gen_helper_rfsvc(cpu_env);
gen_sync_exception(ctx);
#endif
}
@@ -5849,7 +5851,7 @@ static void gen_rfci_40x(DisasContext *ctx)
return;
}
/* Restore CPU state */
- gen_helper_40x_rfci();
+ gen_helper_40x_rfci(cpu_env);
gen_sync_exception(ctx);
#endif
}
@@ -5864,7 +5866,7 @@ static void gen_rfci(DisasContext *ctx)
return;
}
/* Restore CPU state */
- gen_helper_rfci();
+ gen_helper_rfci(cpu_env);
gen_sync_exception(ctx);
#endif
}
@@ -5882,7 +5884,7 @@ static void gen_rfdi(DisasContext *ctx)
return;
}
/* Restore CPU state */
- gen_helper_rfdi();
+ gen_helper_rfdi(cpu_env);
gen_sync_exception(ctx);
#endif
}
@@ -5898,7 +5900,7 @@ static void gen_rfmci(DisasContext *ctx)
return;
}
/* Restore CPU state */
- gen_helper_rfmci();
+ gen_helper_rfmci(cpu_env);
gen_sync_exception(ctx);
#endif
}
@@ -6258,7 +6260,7 @@ static void gen_msgclr(DisasContext *ctx)
return;
}
- gen_helper_msgclr(cpu_gpr[rB(ctx->opcode)]);
+ gen_helper_msgclr(cpu_env, cpu_gpr[rB(ctx->opcode)]);
#endif
}
--
1.6.0.2
^ permalink raw reply related [flat|nested] 89+ messages in thread
* [Qemu-devel] [PATCH 04/72] ppc: Fix coding style in helper.c
2012-06-23 23:06 [Qemu-devel] [PULL 00/72] ppc patch queue 2012-06-24 Alexander Graf
` (2 preceding siblings ...)
2012-06-23 23:06 ` [Qemu-devel] [PATCH 03/72] ppc: Avoid AREG0 for " Alexander Graf
@ 2012-06-23 23:06 ` Alexander Graf
2012-06-23 23:06 ` [Qemu-devel] [PATCH 05/72] ppc: Move exception helpers from helper.c to excp_helper.c Alexander Graf
` (68 subsequent siblings)
72 siblings, 0 replies; 89+ messages in thread
From: Alexander Graf @ 2012-06-23 23:06 UTC (permalink / raw)
To: qemu-devel qemu-devel
Cc: Blue Swirl, qemu-ppc Mailing List, Andreas Färber,
Aurelien Jarno
From: Blue Swirl <blauwirbel@gmail.com>
helper.c will be spilt by the next patches, fix
style issues before that.
Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Andreas Färber <afaerber@suse.de>
Signed-off-by: Alexander Graf <agraf@suse.de>
---
target-ppc/helper.c | 394 ++++++++++++++++++++++++++++++---------------------
1 files changed, 230 insertions(+), 164 deletions(-)
diff --git a/target-ppc/helper.c b/target-ppc/helper.c
index 3f7d8a4..44f1cdd 100644
--- a/target-ppc/helper.c
+++ b/target-ppc/helper.c
@@ -1,5 +1,5 @@
/*
- * PowerPC emulation helpers for qemu.
+ * PowerPC emulation helpers for QEMU.
*
* Copyright (c) 2003-2007 Jocelyn Mayer
*
@@ -73,8 +73,8 @@ void (*cpu_ppc_hypercall)(CPUPPCState *);
/* PowerPC MMU emulation */
#if defined(CONFIG_USER_ONLY)
-int cpu_ppc_handle_mmu_fault (CPUPPCState *env, target_ulong address, int rw,
- int mmu_idx)
+int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw,
+ int mmu_idx)
{
int exception, error_code;
@@ -84,8 +84,9 @@ int cpu_ppc_handle_mmu_fault (CPUPPCState *env, target_ulong address, int rw,
} else {
exception = POWERPC_EXCP_DSI;
error_code = 0x40000000;
- if (rw)
+ if (rw) {
error_code |= 0x02000000;
+ }
env->spr[SPR_DAR] = address;
env->spr[SPR_DSISR] = error_code;
}
@@ -160,8 +161,9 @@ static inline int pp_check(int key, int pp, int nx)
break;
}
}
- if (nx == 0)
+ if (nx == 0) {
access |= PAGE_EXEC;
+ }
return access;
}
@@ -171,27 +173,30 @@ static inline int check_prot(int prot, int rw, int access_type)
int ret;
if (access_type == ACCESS_CODE) {
- if (prot & PAGE_EXEC)
+ if (prot & PAGE_EXEC) {
ret = 0;
- else
+ } else {
ret = -2;
+ }
} else if (rw) {
- if (prot & PAGE_WRITE)
+ if (prot & PAGE_WRITE) {
ret = 0;
- else
+ } else {
ret = -2;
+ }
} else {
- if (prot & PAGE_READ)
+ if (prot & PAGE_READ) {
ret = 0;
- else
+ } else {
ret = -2;
+ }
}
return ret;
}
-static inline int _pte_check(mmu_ctx_t *ctx, int is_64b, target_ulong pte0,
- target_ulong pte1, int h, int rw, int type)
+static inline int pte_check(mmu_ctx_t *ctx, int is_64b, target_ulong pte0,
+ target_ulong pte1, int h, int rw, int type)
{
target_ulong ptem, mmask;
int access, ret, pteh, ptev, pp;
@@ -254,14 +259,14 @@ static inline int _pte_check(mmu_ctx_t *ctx, int is_64b, target_ulong pte0,
static inline int pte32_check(mmu_ctx_t *ctx, target_ulong pte0,
target_ulong pte1, int h, int rw, int type)
{
- return _pte_check(ctx, 0, pte0, pte1, h, rw, type);
+ return pte_check(ctx, 0, pte0, pte1, h, rw, type);
}
#if defined(TARGET_PPC64)
static inline int pte64_check(mmu_ctx_t *ctx, target_ulong pte0,
target_ulong pte1, int h, int rw, int type)
{
- return _pte_check(ctx, 1, pte0, pte1, h, rw, type);
+ return pte_check(ctx, 1, pte0, pte1, h, rw, type);
}
#endif
@@ -291,8 +296,8 @@ static inline int pte_update_flags(mmu_ctx_t *ctx, target_ulong *pte1p,
}
/* Software driven TLB helpers */
-static inline int ppc6xx_tlb_getnum(CPUPPCState *env, target_ulong eaddr, int way,
- int is_code)
+static inline int ppc6xx_tlb_getnum(CPUPPCState *env, target_ulong eaddr,
+ int way, int is_code)
{
int nr;
@@ -301,8 +306,9 @@ static inline int ppc6xx_tlb_getnum(CPUPPCState *env, target_ulong eaddr, int wa
/* Select TLB way */
nr += env->tlb_per_way * way;
/* 6xx have separate TLBs for instructions and data */
- if (is_code && env->id_tlbs == 1)
+ if (is_code && env->id_tlbs == 1) {
nr += env->nb_tlb;
+ }
return nr;
}
@@ -312,11 +318,12 @@ static inline void ppc6xx_tlb_invalidate_all(CPUPPCState *env)
ppc6xx_tlb_t *tlb;
int nr, max;
- //LOG_SWTLB("Invalidate all TLBs\n");
+ /* LOG_SWTLB("Invalidate all TLBs\n"); */
/* Invalidate all defined software TLB */
max = env->nb_tlb;
- if (env->id_tlbs == 1)
+ if (env->id_tlbs == 1) {
max *= 2;
+ }
for (nr = 0; nr < max; nr++) {
tlb = &env->tlb.tlb6[nr];
pte_invalidate(&tlb->pte0);
@@ -324,9 +331,9 @@ static inline void ppc6xx_tlb_invalidate_all(CPUPPCState *env)
tlb_flush(env, 1);
}
-static inline void __ppc6xx_tlb_invalidate_virt(CPUPPCState *env,
- target_ulong eaddr,
- int is_code, int match_epn)
+static inline void ppc6xx_tlb_invalidate_virt2(CPUPPCState *env,
+ target_ulong eaddr,
+ int is_code, int match_epn)
{
#if !defined(FLUSH_ALL_TLBS)
ppc6xx_tlb_t *tlb;
@@ -352,11 +359,11 @@ static inline void __ppc6xx_tlb_invalidate_virt(CPUPPCState *env,
static inline void ppc6xx_tlb_invalidate_virt(CPUPPCState *env,
target_ulong eaddr, int is_code)
{
- __ppc6xx_tlb_invalidate_virt(env, eaddr, is_code, 0);
+ ppc6xx_tlb_invalidate_virt2(env, eaddr, is_code, 0);
}
-void ppc6xx_tlb_store (CPUPPCState *env, target_ulong EPN, int way, int is_code,
- target_ulong pte0, target_ulong pte1)
+void ppc6xx_tlb_store(CPUPPCState *env, target_ulong EPN, int way, int is_code,
+ target_ulong pte0, target_ulong pte1)
{
ppc6xx_tlb_t *tlb;
int nr;
@@ -366,7 +373,7 @@ void ppc6xx_tlb_store (CPUPPCState *env, target_ulong EPN, int way, int is_code,
LOG_SWTLB("Set TLB %d/%d EPN " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
" PTE1 " TARGET_FMT_lx "\n", nr, env->nb_tlb, EPN, pte0, pte1);
/* Invalidate any pending reference in QEMU for this virtual address */
- __ppc6xx_tlb_invalidate_virt(env, EPN, is_code, 1);
+ ppc6xx_tlb_invalidate_virt2(env, EPN, is_code, 1);
tlb->pte0 = pte0;
tlb->pte1 = pte1;
tlb->EPN = EPN;
@@ -436,8 +443,8 @@ static inline int ppc6xx_tlb_check(CPUPPCState *env, mmu_ctx_t *ctx,
}
/* Perform BAT hit & translation */
-static inline void bat_size_prot(CPUPPCState *env, target_ulong *blp, int *validp,
- int *protp, target_ulong *BATu,
+static inline void bat_size_prot(CPUPPCState *env, target_ulong *blp,
+ int *validp, int *protp, target_ulong *BATu,
target_ulong *BATl)
{
target_ulong bl;
@@ -452,8 +459,9 @@ static inline void bat_size_prot(CPUPPCState *env, target_ulong *blp, int *valid
pp = *BATl & 0x00000003;
if (pp != 0) {
prot = PAGE_READ | PAGE_EXEC;
- if (pp == 0x2)
+ if (pp == 0x2) {
prot |= PAGE_WRITE;
+ }
}
}
*blp = bl;
@@ -475,10 +483,11 @@ static inline void bat_601_size_prot(CPUPPCState *env, target_ulong *blp,
valid = (*BATl >> 6) & 1;
if (valid) {
pp = *BATu & 0x00000003;
- if (msr_pr == 0)
+ if (msr_pr == 0) {
key = (*BATu >> 3) & 1;
- else
+ } else {
key = (*BATu >> 2) & 1;
+ }
prot = pp_check(key, pp, 0);
}
*blp = bl;
@@ -486,8 +495,8 @@ static inline void bat_601_size_prot(CPUPPCState *env, target_ulong *blp,
*protp = prot;
}
-static inline int get_bat(CPUPPCState *env, mmu_ctx_t *ctx, target_ulong virtual,
- int rw, int type)
+static inline int get_bat(CPUPPCState *env, mmu_ctx_t *ctx,
+ target_ulong virtual, int rw, int type)
{
target_ulong *BATlt, *BATut, *BATu, *BATl;
target_ulong BEPIl, BEPIu, bl;
@@ -530,10 +539,11 @@ static inline int get_bat(CPUPPCState *env, mmu_ctx_t *ctx, target_ulong virtual
/* Compute access rights */
ctx->prot = prot;
ret = check_prot(ctx->prot, rw, type);
- if (ret == 0)
+ if (ret == 0) {
LOG_BATS("BAT %d match: r " TARGET_FMT_plx " prot=%c%c\n",
i, ctx->raddr, ctx->prot & PAGE_READ ? 'R' : '-',
ctx->prot & PAGE_WRITE ? 'W' : '-');
+ }
break;
}
}
@@ -569,7 +579,7 @@ static inline target_phys_addr_t get_pteg_offset(CPUPPCState *env,
}
/* PTE table lookup */
-static inline int _find_pte(CPUPPCState *env, mmu_ctx_t *ctx, int is_64b, int h,
+static inline int find_pte2(CPUPPCState *env, mmu_ctx_t *ctx, int is_64b, int h,
int rw, int type, int target_page_bits)
{
target_phys_addr_t pteg_off;
@@ -679,11 +689,12 @@ static inline int find_pte(CPUPPCState *env, mmu_ctx_t *ctx, int h, int rw,
int type, int target_page_bits)
{
#if defined(TARGET_PPC64)
- if (env->mmu_model & POWERPC_MMU_64)
- return _find_pte(env, ctx, 1, h, rw, type, target_page_bits);
+ if (env->mmu_model & POWERPC_MMU_64) {
+ return find_pte2(env, ctx, 1, h, rw, type, target_page_bits);
+ }
#endif
- return _find_pte(env, ctx, 0, h, rw, type, target_page_bits);
+ return find_pte2(env, ctx, 0, h, rw, type, target_page_bits);
}
#if defined(TARGET_PPC64)
@@ -716,7 +727,7 @@ static inline ppc_slb_t *slb_lookup(CPUPPCState *env, target_ulong eaddr)
return NULL;
}
-void ppc_slb_invalidate_all (CPUPPCState *env)
+void ppc_slb_invalidate_all(CPUPPCState *env)
{
int n, do_invalidate;
@@ -734,11 +745,12 @@ void ppc_slb_invalidate_all (CPUPPCState *env)
do_invalidate = 1;
}
}
- if (do_invalidate)
+ if (do_invalidate) {
tlb_flush(env, 1);
+ }
}
-void ppc_slb_invalidate_one (CPUPPCState *env, uint64_t T0)
+void ppc_slb_invalidate_one(CPUPPCState *env, uint64_t T0)
{
ppc_slb_t *slb;
@@ -758,7 +770,7 @@ void ppc_slb_invalidate_one (CPUPPCState *env, uint64_t T0)
}
}
-int ppc_store_slb (CPUPPCState *env, target_ulong rb, target_ulong rs)
+int ppc_store_slb(CPUPPCState *env, target_ulong rb, target_ulong rs)
{
int slot = rb & 0xfff;
ppc_slb_t *slb = &env->slb[slot];
@@ -784,7 +796,7 @@ int ppc_store_slb (CPUPPCState *env, target_ulong rb, target_ulong rs)
return 0;
}
-int ppc_load_slb_esid (CPUPPCState *env, target_ulong rb, target_ulong *rt)
+int ppc_load_slb_esid(CPUPPCState *env, target_ulong rb, target_ulong *rt)
{
int slot = rb & 0xfff;
ppc_slb_t *slb = &env->slb[slot];
@@ -797,7 +809,7 @@ int ppc_load_slb_esid (CPUPPCState *env, target_ulong rb, target_ulong *rt)
return 0;
}
-int ppc_load_slb_vsid (CPUPPCState *env, target_ulong rb, target_ulong *rt)
+int ppc_load_slb_vsid(CPUPPCState *env, target_ulong rb, target_ulong *rt)
{
int slot = rb & 0xfff;
ppc_slb_t *slb = &env->slb[slot];
@@ -909,21 +921,24 @@ static inline int get_segment(CPUPPCState *env, mmu_ctx_t *ctx,
ret = find_pte(env, ctx, 0, rw, type, target_page_bits);
if (ret < 0) {
/* Secondary table lookup */
- if (eaddr != 0xEFFFFFFF)
+ if (eaddr != 0xEFFFFFFF) {
LOG_MMU("1 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
" vsid=" TARGET_FMT_lx " api=" TARGET_FMT_lx
" hash=" TARGET_FMT_plx "\n", env->htab_base,
env->htab_mask, vsid, ctx->ptem, ctx->hash[1]);
+ }
ret2 = find_pte(env, ctx, 1, rw, type,
target_page_bits);
- if (ret2 != -1)
+ if (ret2 != -1) {
ret = ret2;
+ }
}
}
-#if defined (DUMP_PAGE_TABLES)
+#if defined(DUMP_PAGE_TABLES)
if (qemu_log_enabled()) {
target_phys_addr_t curaddr;
uint32_t a0, a1, a2, a3;
+
qemu_log("Page table: " TARGET_FMT_plx " len " TARGET_FMT_plx
"\n", sdr, mask + 0x80);
for (curaddr = sdr; curaddr < (sdr + mask + 0x80);
@@ -945,6 +960,7 @@ static inline int get_segment(CPUPPCState *env, mmu_ctx_t *ctx,
}
} else {
target_ulong sr;
+
LOG_MMU("direct store...\n");
/* Direct-store segment : absolutely *BUGGY* for now */
@@ -1018,11 +1034,13 @@ int ppcemb_tlb_check(CPUPPCState *env, ppcemb_tlb_t *tlb,
" " TARGET_FMT_lx " %u %x\n", __func__, i, address, pid, tlb->EPN,
mask, (uint32_t)tlb->PID, tlb->prot);
/* Check PID */
- if (tlb->PID != 0 && tlb->PID != pid)
+ if (tlb->PID != 0 && tlb->PID != pid) {
return -1;
+ }
/* Check effective address */
- if ((address & mask) != tlb->EPN)
+ if ((address & mask) != tlb->EPN) {
return -1;
+ }
*raddrp = (tlb->RPN & mask) | (address & ~mask);
#if (TARGET_PHYS_ADDR_BITS >= 36)
if (ext) {
@@ -1035,7 +1053,7 @@ int ppcemb_tlb_check(CPUPPCState *env, ppcemb_tlb_t *tlb,
}
/* Generic TLB search function for PowerPC embedded implementations */
-int ppcemb_tlb_search (CPUPPCState *env, target_ulong address, uint32_t pid)
+int ppcemb_tlb_search(CPUPPCState *env, target_ulong address, uint32_t pid)
{
ppcemb_tlb_t *tlb;
target_phys_addr_t raddr;
@@ -1080,8 +1098,9 @@ static inline void ppc4xx_tlb_invalidate_virt(CPUPPCState *env,
tlb = &env->tlb.tlbe[i];
if (ppcemb_tlb_check(env, tlb, &raddr, eaddr, pid, 0, i) == 0) {
end = tlb->EPN + tlb->size;
- for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE)
+ for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) {
tlb_flush_page(env, page);
+ }
tlb->prot &= ~PAGE_VALID;
break;
}
@@ -1091,8 +1110,9 @@ static inline void ppc4xx_tlb_invalidate_virt(CPUPPCState *env,
#endif
}
-static int mmu40x_get_physical_address (CPUPPCState *env, mmu_ctx_t *ctx,
- target_ulong address, int rw, int access_type)
+static int mmu40x_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
+ target_ulong address, int rw,
+ int access_type)
{
ppcemb_tlb_t *tlb;
target_phys_addr_t raddr;
@@ -1104,8 +1124,9 @@ static int mmu40x_get_physical_address (CPUPPCState *env, mmu_ctx_t *ctx,
for (i = 0; i < env->nb_tlb; i++) {
tlb = &env->tlb.tlbe[i];
if (ppcemb_tlb_check(env, tlb, &raddr, address,
- env->spr[SPR_40x_PID], 0, i) < 0)
+ env->spr[SPR_40x_PID], 0, i) < 0) {
continue;
+ }
zsel = (tlb->attr >> 4) & 0xF;
zpr = (env->spr[SPR_40x_ZPR] >> (30 - (2 * zsel))) & 0x3;
LOG_SWTLB("%s: TLB %d zsel %d zpr %d rw %d attr %08x\n",
@@ -1113,8 +1134,9 @@ static int mmu40x_get_physical_address (CPUPPCState *env, mmu_ctx_t *ctx,
/* Check execute enable bit */
switch (zpr) {
case 0x2:
- if (pr != 0)
+ if (pr != 0) {
goto check_perms;
+ }
/* No break here */
case 0x3:
/* All accesses granted */
@@ -1135,8 +1157,9 @@ static int mmu40x_get_physical_address (CPUPPCState *env, mmu_ctx_t *ctx,
/* Check from TLB entry */
ctx->prot = tlb->prot;
ret = check_prot(ctx->prot, rw, access_type);
- if (ret == -2)
+ if (ret == -2) {
env->spr[SPR_40x_ESR] = 0;
+ }
break;
}
if (ret >= 0) {
@@ -1153,7 +1176,7 @@ static int mmu40x_get_physical_address (CPUPPCState *env, mmu_ctx_t *ctx,
return ret;
}
-void store_40x_sler (CPUPPCState *env, uint32_t val)
+void store_40x_sler(CPUPPCState *env, uint32_t val)
{
/* XXX: TO BE FIXED */
if (val != 0x00000000) {
@@ -1162,12 +1185,12 @@ void store_40x_sler (CPUPPCState *env, uint32_t val)
env->spr[SPR_405_SLER] = val;
}
-static inline int mmubooke_check_tlb (CPUPPCState *env, ppcemb_tlb_t *tlb,
- target_phys_addr_t *raddr, int *prot,
- target_ulong address, int rw,
- int access_type, int i)
+static inline int mmubooke_check_tlb(CPUPPCState *env, ppcemb_tlb_t *tlb,
+ target_phys_addr_t *raddr, int *prot,
+ target_ulong address, int rw,
+ int access_type, int i)
{
- int ret, _prot;
+ int ret, prot2;
if (ppcemb_tlb_check(env, tlb, raddr, address,
env->spr[SPR_BOOKE_PID],
@@ -1193,9 +1216,9 @@ static inline int mmubooke_check_tlb (CPUPPCState *env, ppcemb_tlb_t *tlb,
found_tlb:
if (msr_pr != 0) {
- _prot = tlb->prot & 0xF;
+ prot2 = tlb->prot & 0xF;
} else {
- _prot = (tlb->prot >> 4) & 0xF;
+ prot2 = (tlb->prot >> 4) & 0xF;
}
/* Check the address space */
@@ -1205,13 +1228,13 @@ found_tlb:
return -1;
}
- *prot = _prot;
- if (_prot & PAGE_EXEC) {
+ *prot = prot2;
+ if (prot2 & PAGE_EXEC) {
LOG_SWTLB("%s: good TLB!\n", __func__);
return 0;
}
- LOG_SWTLB("%s: no PAGE_EXEC: %x\n", __func__, _prot);
+ LOG_SWTLB("%s: no PAGE_EXEC: %x\n", __func__, prot2);
ret = -3;
} else {
if (msr_dr != (tlb->attr & 1)) {
@@ -1219,22 +1242,22 @@ found_tlb:
return -1;
}
- *prot = _prot;
- if ((!rw && _prot & PAGE_READ) || (rw && (_prot & PAGE_WRITE))) {
+ *prot = prot2;
+ if ((!rw && prot2 & PAGE_READ) || (rw && (prot2 & PAGE_WRITE))) {
LOG_SWTLB("%s: found TLB!\n", __func__);
return 0;
}
- LOG_SWTLB("%s: PAGE_READ/WRITE doesn't match: %x\n", __func__, _prot);
+ LOG_SWTLB("%s: PAGE_READ/WRITE doesn't match: %x\n", __func__, prot2);
ret = -2;
}
return ret;
}
-static int mmubooke_get_physical_address (CPUPPCState *env, mmu_ctx_t *ctx,
- target_ulong address, int rw,
- int access_type)
+static int mmubooke_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
+ target_ulong address, int rw,
+ int access_type)
{
ppcemb_tlb_t *tlb;
target_phys_addr_t raddr;
@@ -1285,7 +1308,8 @@ void booke206_flush_tlb(CPUPPCState *env, int flags, const int check_iprot)
tlb_flush(env, 1);
}
-target_phys_addr_t booke206_tlb_to_page_size(CPUPPCState *env, ppcmas_tlb_t *tlb)
+target_phys_addr_t booke206_tlb_to_page_size(CPUPPCState *env,
+ ppcmas_tlb_t *tlb)
{
int tlbm_size;
@@ -1337,7 +1361,7 @@ static int mmubooke206_check_tlb(CPUPPCState *env, ppcmas_tlb_t *tlb,
int access_type)
{
int ret;
- int _prot = 0;
+ int prot2 = 0;
if (ppcmas_tlb_check(env, tlb, raddr, address,
env->spr[SPR_BOOKE_PID]) >= 0) {
@@ -1363,23 +1387,23 @@ found_tlb:
if (msr_pr != 0) {
if (tlb->mas7_3 & MAS3_UR) {
- _prot |= PAGE_READ;
+ prot2 |= PAGE_READ;
}
if (tlb->mas7_3 & MAS3_UW) {
- _prot |= PAGE_WRITE;
+ prot2 |= PAGE_WRITE;
}
if (tlb->mas7_3 & MAS3_UX) {
- _prot |= PAGE_EXEC;
+ prot2 |= PAGE_EXEC;
}
} else {
if (tlb->mas7_3 & MAS3_SR) {
- _prot |= PAGE_READ;
+ prot2 |= PAGE_READ;
}
if (tlb->mas7_3 & MAS3_SW) {
- _prot |= PAGE_WRITE;
+ prot2 |= PAGE_WRITE;
}
if (tlb->mas7_3 & MAS3_SX) {
- _prot |= PAGE_EXEC;
+ prot2 |= PAGE_EXEC;
}
}
@@ -1390,13 +1414,13 @@ found_tlb:
return -1;
}
- *prot = _prot;
- if (_prot & PAGE_EXEC) {
+ *prot = prot2;
+ if (prot2 & PAGE_EXEC) {
LOG_SWTLB("%s: good TLB!\n", __func__);
return 0;
}
- LOG_SWTLB("%s: no PAGE_EXEC: %x\n", __func__, _prot);
+ LOG_SWTLB("%s: no PAGE_EXEC: %x\n", __func__, prot2);
ret = -3;
} else {
if (msr_dr != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) {
@@ -1404,13 +1428,13 @@ found_tlb:
return -1;
}
- *prot = _prot;
- if ((!rw && _prot & PAGE_READ) || (rw && (_prot & PAGE_WRITE))) {
+ *prot = prot2;
+ if ((!rw && prot2 & PAGE_READ) || (rw && (prot2 & PAGE_WRITE))) {
LOG_SWTLB("%s: found TLB!\n", __func__);
return 0;
}
- LOG_SWTLB("%s: PAGE_READ/WRITE doesn't match: %x\n", __func__, _prot);
+ LOG_SWTLB("%s: PAGE_READ/WRITE doesn't match: %x\n", __func__, prot2);
ret = -2;
}
@@ -1521,7 +1545,8 @@ static void mmubooke206_dump_one_tlb(FILE *f, fprintf_function cpu_fprintf,
int i;
cpu_fprintf(f, "\nTLB%d:\n", tlbn);
- cpu_fprintf(f, "Effective Physical Size TID TS SRWX URWX WIMGE U0123\n");
+ cpu_fprintf(f, "Effective Physical Size TID TS SRWX"
+ " URWX WIMGE U0123\n");
entry = &env->tlb.tlbm[offset];
for (i = 0; i < tlbsize; i++, entry++) {
@@ -1537,7 +1562,8 @@ static void mmubooke206_dump_one_tlb(FILE *f, fprintf_function cpu_fprintf,
ea = entry->mas2 & ~(size - 1);
pa = entry->mas7_3 & ~(size - 1);
- cpu_fprintf(f, "0x%016" PRIx64 " 0x%016" PRIx64 " %4s %-5u %1u S%c%c%c U%c%c%c %c%c%c%c%c U%c%c%c%c\n",
+ cpu_fprintf(f, "0x%016" PRIx64 " 0x%016" PRIx64 " %4s %-5u %1u S%c%c%c"
+ "U%c%c%c %c%c%c%c%c U%c%c%c%c\n",
(uint64_t)ea, (uint64_t)pa,
book3e_tsize_to_str[tsize],
(entry->mas1 & MAS1_TID_MASK) >> MAS1_TID_SHIFT,
@@ -1691,8 +1717,8 @@ static inline int check_physical(CPUPPCState *env, mmu_ctx_t *ctx,
return ret;
}
-int get_physical_address (CPUPPCState *env, mmu_ctx_t *ctx, target_ulong eaddr,
- int rw, int access_type)
+int get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx, target_ulong eaddr,
+ int rw, int access_type)
{
int ret;
@@ -1721,8 +1747,9 @@ int get_physical_address (CPUPPCState *env, mmu_ctx_t *ctx, target_ulong eaddr,
case POWERPC_MMU_SOFT_6xx:
case POWERPC_MMU_SOFT_74xx:
/* Try to find a BAT */
- if (env->nb_BATs != 0)
+ if (env->nb_BATs != 0) {
ret = get_bat(env, ctx, eaddr, rw, access_type);
+ }
#if defined(TARGET_PPC64)
case POWERPC_MMU_620:
case POWERPC_MMU_64B:
@@ -1766,12 +1793,13 @@ int get_physical_address (CPUPPCState *env, mmu_ctx_t *ctx, target_ulong eaddr,
return ret;
}
-target_phys_addr_t cpu_get_phys_page_debug (CPUPPCState *env, target_ulong addr)
+target_phys_addr_t cpu_get_phys_page_debug(CPUPPCState *env, target_ulong addr)
{
mmu_ctx_t ctx;
- if (unlikely(get_physical_address(env, &ctx, addr, 0, ACCESS_INT) != 0))
+ if (unlikely(get_physical_address(env, &ctx, addr, 0, ACCESS_INT) != 0)) {
return -1;
+ }
return ctx.raddr & TARGET_PAGE_MASK;
}
@@ -1817,8 +1845,8 @@ static void booke206_update_mas_tlb_miss(CPUPPCState *env, target_ulong address,
}
/* Perform address translation */
-int cpu_ppc_handle_mmu_fault (CPUPPCState *env, target_ulong address, int rw,
- int mmu_idx)
+int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw,
+ int mmu_idx)
{
mmu_ctx_t ctx;
int access_type;
@@ -1966,10 +1994,11 @@ int cpu_ppc_handle_mmu_fault (CPUPPCState *env, target_ulong address, int rw,
env->exception_index = POWERPC_EXCP_DTLB;
env->error_code = 0;
env->spr[SPR_40x_DEAR] = address;
- if (rw)
+ if (rw) {
env->spr[SPR_40x_ESR] = 0x00800000;
- else
+ } else {
env->spr[SPR_40x_ESR] = 0x00000000;
+ }
break;
case POWERPC_MMU_32B:
case POWERPC_MMU_601:
@@ -1981,10 +2010,11 @@ int cpu_ppc_handle_mmu_fault (CPUPPCState *env, target_ulong address, int rw,
env->exception_index = POWERPC_EXCP_DSI;
env->error_code = 0;
env->spr[SPR_DAR] = address;
- if (rw == 1)
+ if (rw == 1) {
env->spr[SPR_DSISR] = 0x42000000;
- else
+ } else {
env->spr[SPR_DSISR] = 0x40000000;
+ }
break;
case POWERPC_MMU_MPC8xx:
/* XXX: TODO */
@@ -2045,20 +2075,22 @@ int cpu_ppc_handle_mmu_fault (CPUPPCState *env, target_ulong address, int rw,
env->exception_index = POWERPC_EXCP_DSI;
env->error_code = 0;
env->spr[SPR_DAR] = address;
- if (rw == 1)
+ if (rw == 1) {
env->spr[SPR_DSISR] = 0x06000000;
- else
+ } else {
env->spr[SPR_DSISR] = 0x04000000;
+ }
break;
case ACCESS_EXT:
/* eciwx or ecowx */
env->exception_index = POWERPC_EXCP_DSI;
env->error_code = 0;
env->spr[SPR_DAR] = address;
- if (rw == 1)
+ if (rw == 1) {
env->spr[SPR_DSISR] = 0x06100000;
- else
+ } else {
env->spr[SPR_DSISR] = 0x04100000;
+ }
break;
default:
printf("DSI: invalid exception (%d)\n", ret);
@@ -2077,10 +2109,11 @@ int cpu_ppc_handle_mmu_fault (CPUPPCState *env, target_ulong address, int rw,
env->error_code = 0;
env->spr[SPR_DAR] = address;
/* XXX: this might be incorrect */
- if (rw == 1)
+ if (rw == 1) {
env->spr[SPR_DSISR] = 0x42000000;
- else
+ } else {
env->spr[SPR_DSISR] = 0x40000000;
+ }
} else {
env->exception_index = POWERPC_EXCP_DSEG;
env->error_code = 0;
@@ -2112,8 +2145,9 @@ static inline void do_invalidate_BAT(CPUPPCState *env, target_ulong BATu,
end = base + mask + 0x00020000;
LOG_BATS("Flush BAT from " TARGET_FMT_lx " to " TARGET_FMT_lx " ("
TARGET_FMT_lx ")\n", base, end, mask);
- for (page = base; page != end; page += TARGET_PAGE_SIZE)
+ for (page = base; page != end; page += TARGET_PAGE_SIZE) {
tlb_flush_page(env, page);
+ }
LOG_BATS("Flush done\n");
}
#endif
@@ -2125,7 +2159,7 @@ static inline void dump_store_bat(CPUPPCState *env, char ID, int ul, int nr,
nr, ul == 0 ? 'u' : 'l', value, env->nip);
}
-void ppc_store_ibatu (CPUPPCState *env, int nr, target_ulong value)
+void ppc_store_ibatu(CPUPPCState *env, int nr, target_ulong value)
{
target_ulong mask;
@@ -2151,13 +2185,13 @@ void ppc_store_ibatu (CPUPPCState *env, int nr, target_ulong value)
}
}
-void ppc_store_ibatl (CPUPPCState *env, int nr, target_ulong value)
+void ppc_store_ibatl(CPUPPCState *env, int nr, target_ulong value)
{
dump_store_bat(env, 'I', 1, nr, value);
env->IBAT[1][nr] = value;
}
-void ppc_store_dbatu (CPUPPCState *env, int nr, target_ulong value)
+void ppc_store_dbatu(CPUPPCState *env, int nr, target_ulong value)
{
target_ulong mask;
@@ -2183,13 +2217,13 @@ void ppc_store_dbatu (CPUPPCState *env, int nr, target_ulong value)
}
}
-void ppc_store_dbatl (CPUPPCState *env, int nr, target_ulong value)
+void ppc_store_dbatl(CPUPPCState *env, int nr, target_ulong value)
{
dump_store_bat(env, 'D', 1, nr, value);
env->DBAT[1][nr] = value;
}
-void ppc_store_ibatu_601 (CPUPPCState *env, int nr, target_ulong value)
+void ppc_store_ibatu_601(CPUPPCState *env, int nr, target_ulong value)
{
target_ulong mask;
#if defined(FLUSH_ALL_TLBS)
@@ -2224,13 +2258,14 @@ void ppc_store_ibatu_601 (CPUPPCState *env, int nr, target_ulong value)
#endif
}
#if defined(FLUSH_ALL_TLBS)
- if (do_inval)
+ if (do_inval) {
tlb_flush(env, 1);
+ }
#endif
}
}
-void ppc_store_ibatl_601 (CPUPPCState *env, int nr, target_ulong value)
+void ppc_store_ibatl_601(CPUPPCState *env, int nr, target_ulong value)
{
target_ulong mask;
#if defined(FLUSH_ALL_TLBS)
@@ -2261,15 +2296,16 @@ void ppc_store_ibatl_601 (CPUPPCState *env, int nr, target_ulong value)
env->IBAT[1][nr] = value;
env->DBAT[1][nr] = value;
#if defined(FLUSH_ALL_TLBS)
- if (do_inval)
+ if (do_inval) {
tlb_flush(env, 1);
+ }
#endif
}
}
/*****************************************************************************/
/* TLB management */
-void ppc_tlb_invalidate_all (CPUPPCState *env)
+void ppc_tlb_invalidate_all(CPUPPCState *env)
{
switch (env->mmu_model) {
case POWERPC_MMU_SOFT_6xx:
@@ -2309,7 +2345,7 @@ void ppc_tlb_invalidate_all (CPUPPCState *env)
}
}
-void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr)
+void ppc_tlb_invalidate_one(CPUPPCState *env, target_ulong addr)
{
#if !defined(FLUSH_ALL_TLBS)
addr &= TARGET_PAGE_MASK;
@@ -2317,8 +2353,9 @@ void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr)
case POWERPC_MMU_SOFT_6xx:
case POWERPC_MMU_SOFT_74xx:
ppc6xx_tlb_invalidate_virt(env, addr, 0);
- if (env->id_tlbs == 1)
+ if (env->id_tlbs == 1) {
ppc6xx_tlb_invalidate_virt(env, addr, 1);
+ }
break;
case POWERPC_MMU_SOFT_4xx:
case POWERPC_MMU_SOFT_4xx_Z:
@@ -2388,7 +2425,7 @@ void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr)
/*****************************************************************************/
/* Special registers manipulation */
#if defined(TARGET_PPC64)
-void ppc_store_asr (CPUPPCState *env, target_ulong value)
+void ppc_store_asr(CPUPPCState *env, target_ulong value)
{
if (env->asr != value) {
env->asr = value;
@@ -2397,7 +2434,7 @@ void ppc_store_asr (CPUPPCState *env, target_ulong value)
}
#endif
-void ppc_store_sdr1 (CPUPPCState *env, target_ulong value)
+void ppc_store_sdr1(CPUPPCState *env, target_ulong value)
{
LOG_MMU("%s: " TARGET_FMT_lx "\n", __func__, value);
if (env->spr[SPR_SDR1] != value) {
@@ -2425,14 +2462,14 @@ void ppc_store_sdr1 (CPUPPCState *env, target_ulong value)
}
#if defined(TARGET_PPC64)
-target_ulong ppc_load_sr (CPUPPCState *env, int slb_nr)
+target_ulong ppc_load_sr(CPUPPCState *env, int slb_nr)
{
- // XXX
+ /* XXX */
return 0;
}
#endif
-void ppc_store_sr (CPUPPCState *env, int srnum, target_ulong value)
+void ppc_store_sr(CPUPPCState *env, int srnum, target_ulong value)
{
LOG_MMU("%s: reg=%d " TARGET_FMT_lx " " TARGET_FMT_lx "\n", __func__,
srnum, value, env->sr[srnum]);
@@ -2465,37 +2502,38 @@ void ppc_store_sr (CPUPPCState *env, int srnum, target_ulong value)
/* Invalidate 256 MB of virtual memory */
page = (16 << 20) * srnum;
end = page + (16 << 20);
- for (; page != end; page += TARGET_PAGE_SIZE)
+ for (; page != end; page += TARGET_PAGE_SIZE) {
tlb_flush_page(env, page);
+ }
}
#else
tlb_flush(env, 1);
#endif
}
}
-#endif /* !defined (CONFIG_USER_ONLY) */
+#endif /* !defined(CONFIG_USER_ONLY) */
/* GDBstub can read and write MSR... */
-void ppc_store_msr (CPUPPCState *env, target_ulong value)
+void ppc_store_msr(CPUPPCState *env, target_ulong value)
{
hreg_store_msr(env, value, 0);
}
/*****************************************************************************/
/* Exception processing */
-#if defined (CONFIG_USER_ONLY)
-void do_interrupt (CPUPPCState *env)
+#if defined(CONFIG_USER_ONLY)
+void do_interrupt(CPUPPCState *env)
{
env->exception_index = POWERPC_EXCP_NONE;
env->error_code = 0;
}
-void ppc_hw_interrupt (CPUPPCState *env)
+void ppc_hw_interrupt(CPUPPCState *env)
{
env->exception_index = POWERPC_EXCP_NONE;
env->error_code = 0;
}
-#else /* defined (CONFIG_USER_ONLY) */
+#else /* defined(CONFIG_USER_ONLY) */
static inline void dump_syscall(CPUPPCState *env)
{
qemu_log_mask(CPU_LOG_INT, "syscall r0=%016" PRIx64 " r3=%016" PRIx64
@@ -2602,23 +2640,27 @@ static inline void powerpc_excp(CPUPPCState *env, int excp_model, int excp)
case POWERPC_EXCP_DSI: /* Data storage exception */
LOG_EXCP("DSI exception: DSISR=" TARGET_FMT_lx" DAR=" TARGET_FMT_lx
"\n", env->spr[SPR_DSISR], env->spr[SPR_DAR]);
- if (lpes1 == 0)
+ if (lpes1 == 0) {
new_msr |= (target_ulong)MSR_HVB;
+ }
goto store_next;
case POWERPC_EXCP_ISI: /* Instruction storage exception */
LOG_EXCP("ISI exception: msr=" TARGET_FMT_lx ", nip=" TARGET_FMT_lx
"\n", msr, env->nip);
- if (lpes1 == 0)
+ if (lpes1 == 0) {
new_msr |= (target_ulong)MSR_HVB;
+ }
msr |= env->error_code;
goto store_next;
case POWERPC_EXCP_EXTERNAL: /* External input */
- if (lpes0 == 1)
+ if (lpes0 == 1) {
new_msr |= (target_ulong)MSR_HVB;
+ }
goto store_next;
case POWERPC_EXCP_ALIGN: /* Alignment exception */
- if (lpes1 == 0)
+ if (lpes1 == 0) {
new_msr |= (target_ulong)MSR_HVB;
+ }
/* XXX: this is false */
/* Get rS/rD and rA from faulting opcode */
env->spr[SPR_DSISR] |= (ldl_code((env->nip - 4)) & 0x03FF0000) >> 16;
@@ -2632,29 +2674,34 @@ static inline void powerpc_excp(CPUPPCState *env, int excp_model, int excp)
env->error_code = 0;
return;
}
- if (lpes1 == 0)
+ if (lpes1 == 0) {
new_msr |= (target_ulong)MSR_HVB;
+ }
msr |= 0x00100000;
- if (msr_fe0 == msr_fe1)
+ if (msr_fe0 == msr_fe1) {
goto store_next;
+ }
msr |= 0x00010000;
break;
case POWERPC_EXCP_INVAL:
LOG_EXCP("Invalid instruction at " TARGET_FMT_lx "\n", env->nip);
- if (lpes1 == 0)
+ if (lpes1 == 0) {
new_msr |= (target_ulong)MSR_HVB;
+ }
msr |= 0x00080000;
env->spr[SPR_BOOKE_ESR] = ESR_PIL;
break;
case POWERPC_EXCP_PRIV:
- if (lpes1 == 0)
+ if (lpes1 == 0) {
new_msr |= (target_ulong)MSR_HVB;
+ }
msr |= 0x00040000;
env->spr[SPR_BOOKE_ESR] = ESR_PPR;
break;
case POWERPC_EXCP_TRAP:
- if (lpes1 == 0)
+ if (lpes1 == 0) {
new_msr |= (target_ulong)MSR_HVB;
+ }
msr |= 0x00020000;
env->spr[SPR_BOOKE_ESR] = ESR_PTR;
break;
@@ -2666,8 +2713,9 @@ static inline void powerpc_excp(CPUPPCState *env, int excp_model, int excp)
}
goto store_current;
case POWERPC_EXCP_FPU: /* Floating-point unavailable exception */
- if (lpes1 == 0)
+ if (lpes1 == 0) {
new_msr |= (target_ulong)MSR_HVB;
+ }
goto store_current;
case POWERPC_EXCP_SYSCALL: /* System call exception */
dump_syscall(env);
@@ -2676,14 +2724,16 @@ static inline void powerpc_excp(CPUPPCState *env, int excp_model, int excp)
cpu_ppc_hypercall(env);
return;
}
- if (lev == 1 || (lpes0 == 0 && lpes1 == 0))
+ if (lev == 1 || (lpes0 == 0 && lpes1 == 0)) {
new_msr |= (target_ulong)MSR_HVB;
+ }
goto store_next;
case POWERPC_EXCP_APU: /* Auxiliary processor unavailable */
goto store_current;
case POWERPC_EXCP_DECR: /* Decrementer exception */
- if (lpes1 == 0)
+ if (lpes1 == 0) {
new_msr |= (target_ulong)MSR_HVB;
+ }
goto store_next;
case POWERPC_EXCP_FIT: /* Fixed-interval timer interrupt */
/* FIT on 4xx */
@@ -2758,12 +2808,14 @@ static inline void powerpc_excp(CPUPPCState *env, int excp_model, int excp)
}
goto store_next;
case POWERPC_EXCP_DSEG: /* Data segment exception */
- if (lpes1 == 0)
+ if (lpes1 == 0) {
new_msr |= (target_ulong)MSR_HVB;
+ }
goto store_next;
case POWERPC_EXCP_ISEG: /* Instruction segment exception */
- if (lpes1 == 0)
+ if (lpes1 == 0) {
new_msr |= (target_ulong)MSR_HVB;
+ }
goto store_next;
case POWERPC_EXCP_HDECR: /* Hypervisor decrementer exception */
srr0 = SPR_HSRR0;
@@ -2772,8 +2824,9 @@ static inline void powerpc_excp(CPUPPCState *env, int excp_model, int excp)
new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
goto store_next;
case POWERPC_EXCP_TRACE: /* Trace exception */
- if (lpes1 == 0)
+ if (lpes1 == 0) {
new_msr |= (target_ulong)MSR_HVB;
+ }
goto store_next;
case POWERPC_EXCP_HDSI: /* Hypervisor data storage exception */
srr0 = SPR_HSRR0;
@@ -2800,8 +2853,9 @@ static inline void powerpc_excp(CPUPPCState *env, int excp_model, int excp)
new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
goto store_next;
case POWERPC_EXCP_VPU: /* Vector unavailable exception */
- if (lpes1 == 0)
+ if (lpes1 == 0) {
new_msr |= (target_ulong)MSR_HVB;
+ }
goto store_current;
case POWERPC_EXCP_PIT: /* Programmable interval timer interrupt */
LOG_EXCP("PIT exception\n");
@@ -2820,8 +2874,9 @@ static inline void powerpc_excp(CPUPPCState *env, int excp_model, int excp)
"is not implemented yet !\n");
goto store_next;
case POWERPC_EXCP_IFTLB: /* Instruction fetch TLB error */
- if (lpes1 == 0) /* XXX: check this */
+ if (lpes1 == 0) { /* XXX: check this */
new_msr |= (target_ulong)MSR_HVB;
+ }
switch (excp_model) {
case POWERPC_EXCP_602:
case POWERPC_EXCP_603:
@@ -2838,8 +2893,9 @@ static inline void powerpc_excp(CPUPPCState *env, int excp_model, int excp)
}
break;
case POWERPC_EXCP_DLTLB: /* Data load TLB miss */
- if (lpes1 == 0) /* XXX: check this */
+ if (lpes1 == 0) { /* XXX: check this */
new_msr |= (target_ulong)MSR_HVB;
+ }
switch (excp_model) {
case POWERPC_EXCP_602:
case POWERPC_EXCP_603:
@@ -2856,8 +2912,9 @@ static inline void powerpc_excp(CPUPPCState *env, int excp_model, int excp)
}
break;
case POWERPC_EXCP_DSTLB: /* Data store TLB miss */
- if (lpes1 == 0) /* XXX: check this */
+ if (lpes1 == 0) { /* XXX: check this */
new_msr |= (target_ulong)MSR_HVB;
+ }
switch (excp_model) {
case POWERPC_EXCP_602:
case POWERPC_EXCP_603:
@@ -2872,21 +2929,23 @@ static inline void powerpc_excp(CPUPPCState *env, int excp_model, int excp)
goto tlb_miss;
case POWERPC_EXCP_7x5:
tlb_miss:
-#if defined (DEBUG_SOFTWARE_TLB)
+#if defined(DEBUG_SOFTWARE_TLB)
if (qemu_log_enabled()) {
const char *es;
target_ulong *miss, *cmp;
int en;
+
if (excp == POWERPC_EXCP_IFTLB) {
es = "I";
en = 'I';
miss = &env->spr[SPR_IMISS];
cmp = &env->spr[SPR_ICMP];
} else {
- if (excp == POWERPC_EXCP_DLTLB)
+ if (excp == POWERPC_EXCP_DLTLB) {
es = "DL";
- else
+ } else {
es = "DS";
+ }
en = 'D';
miss = &env->spr[SPR_DMISS];
cmp = &env->spr[SPR_DCMP];
@@ -2905,21 +2964,23 @@ static inline void powerpc_excp(CPUPPCState *env, int excp_model, int excp)
break;
case POWERPC_EXCP_74xx:
tlb_miss_74xx:
-#if defined (DEBUG_SOFTWARE_TLB)
+#if defined(DEBUG_SOFTWARE_TLB)
if (qemu_log_enabled()) {
const char *es;
target_ulong *miss, *cmp;
int en;
+
if (excp == POWERPC_EXCP_IFTLB) {
es = "I";
en = 'I';
miss = &env->spr[SPR_TLBMISS];
cmp = &env->spr[SPR_PTEHI];
} else {
- if (excp == POWERPC_EXCP_DLTLB)
+ if (excp == POWERPC_EXCP_DLTLB) {
es = "DL";
- else
+ } else {
es = "DS";
+ }
en = 'D';
miss = &env->spr[SPR_TLBMISS];
cmp = &env->spr[SPR_PTEHI];
@@ -2959,8 +3020,9 @@ static inline void powerpc_excp(CPUPPCState *env, int excp_model, int excp)
"is not implemented yet !\n");
goto store_next;
case POWERPC_EXCP_PERFM: /* Embedded performance monitor interrupt */
- if (lpes1 == 0)
+ if (lpes1 == 0) {
new_msr |= (target_ulong)MSR_HVB;
+ }
/* XXX: TODO */
cpu_abort(env,
"Performance counter exception is not implemented yet !\n");
@@ -3005,13 +3067,16 @@ static inline void powerpc_excp(CPUPPCState *env, int excp_model, int excp)
/* Save MSR */
env->spr[srr1] = msr;
/* If any alternate SRR register are defined, duplicate saved values */
- if (asrr0 != -1)
+ if (asrr0 != -1) {
env->spr[asrr0] = env->spr[srr0];
- if (asrr1 != -1)
+ }
+ if (asrr1 != -1) {
env->spr[asrr1] = env->spr[srr1];
+ }
/* If we disactivated any translation, flush TLBs */
- if (msr & ((1 << MSR_IR) | (1 << MSR_DR)))
+ if (msr & ((1 << MSR_IR) | (1 << MSR_DR))) {
tlb_flush(env, 1);
+ }
if (msr_ile) {
new_msr |= (target_ulong)1 << MSR_LE;
@@ -3058,12 +3123,12 @@ static inline void powerpc_excp(CPUPPCState *env, int excp_model, int excp)
}
}
-void do_interrupt (CPUPPCState *env)
+void do_interrupt(CPUPPCState *env)
{
powerpc_excp(env, env->excp_model, env->exception_index);
}
-void ppc_hw_interrupt (CPUPPCState *env)
+void ppc_hw_interrupt(CPUPPCState *env)
{
int hdice;
@@ -3180,7 +3245,7 @@ void ppc_hw_interrupt (CPUPPCState *env)
}
#endif /* !CONFIG_USER_ONLY */
-void cpu_dump_rfi (target_ulong RA, target_ulong msr)
+void cpu_dump_rfi(target_ulong RA, target_ulong msr)
{
qemu_log("Return from exception at " TARGET_FMT_lx " with flags "
TARGET_FMT_lx "\n", RA, msr);
@@ -3193,8 +3258,9 @@ PowerPCCPU *cpu_ppc_init(const char *cpu_model)
const ppc_def_t *def;
def = cpu_ppc_find_by_name(cpu_model);
- if (!def)
+ if (!def) {
return NULL;
+ }
cpu = POWERPC_CPU(object_new(TYPE_POWERPC_CPU));
env = &cpu->env;
--
1.6.0.2
^ permalink raw reply related [flat|nested] 89+ messages in thread
* [Qemu-devel] [PATCH 05/72] ppc: Move exception helpers from helper.c to excp_helper.c
2012-06-23 23:06 [Qemu-devel] [PULL 00/72] ppc patch queue 2012-06-24 Alexander Graf
` (3 preceding siblings ...)
2012-06-23 23:06 ` [Qemu-devel] [PATCH 04/72] ppc: Fix coding style in helper.c Alexander Graf
@ 2012-06-23 23:06 ` Alexander Graf
2012-06-23 23:06 ` [Qemu-devel] [PATCH 06/72] ppc: Split FPU and SPE ops Alexander Graf
` (67 subsequent siblings)
72 siblings, 0 replies; 89+ messages in thread
From: Alexander Graf @ 2012-06-23 23:06 UTC (permalink / raw)
To: qemu-devel qemu-devel
Cc: Blue Swirl, qemu-ppc Mailing List, Andreas Färber,
Aurelien Jarno
From: Blue Swirl <blauwirbel@gmail.com>
Move exception helpers from helper.c to excp_helper.c and
make cpu_dump_rfi() static.
Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Andreas Färber <afaerber@suse.de>
Signed-off-by: Alexander Graf <agraf@suse.de>
---
target-ppc/cpu.h | 2 -
target-ppc/excp_helper.c | 745 ++++++++++++++++++++++++++++++++++++++++++++++
target-ppc/helper.c | 744 ---------------------------------------------
3 files changed, 745 insertions(+), 746 deletions(-)
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index 77a2858..32cfcef 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -1117,8 +1117,6 @@ int get_physical_address (CPUPPCState *env, mmu_ctx_t *ctx, target_ulong vaddr,
void do_interrupt (CPUPPCState *env);
void ppc_hw_interrupt (CPUPPCState *env);
-void cpu_dump_rfi (target_ulong RA, target_ulong msr);
-
#if !defined(CONFIG_USER_ONLY)
void ppc6xx_tlb_store (CPUPPCState *env, target_ulong EPN, int way, int is_code,
target_ulong pte0, target_ulong pte1);
diff --git a/target-ppc/excp_helper.c b/target-ppc/excp_helper.c
index c153f4a..7fa7a59 100644
--- a/target-ppc/excp_helper.c
+++ b/target-ppc/excp_helper.c
@@ -24,6 +24,751 @@
//#define DEBUG_OP
//#define DEBUG_EXCEPTIONS
+#ifdef DEBUG_EXCEPTIONS
+# define LOG_EXCP(...) qemu_log(__VA_ARGS__)
+#else
+# define LOG_EXCP(...) do { } while (0)
+#endif
+
+/*****************************************************************************/
+/* PowerPC Hypercall emulation */
+
+void (*cpu_ppc_hypercall)(CPUPPCState *);
+
+/*****************************************************************************/
+/* Exception processing */
+#if defined(CONFIG_USER_ONLY)
+void do_interrupt(CPUPPCState *env)
+{
+ env->exception_index = POWERPC_EXCP_NONE;
+ env->error_code = 0;
+}
+
+void ppc_hw_interrupt(CPUPPCState *env)
+{
+ env->exception_index = POWERPC_EXCP_NONE;
+ env->error_code = 0;
+}
+#else /* defined(CONFIG_USER_ONLY) */
+static inline void dump_syscall(CPUPPCState *env)
+{
+ qemu_log_mask(CPU_LOG_INT, "syscall r0=%016" PRIx64 " r3=%016" PRIx64
+ " r4=%016" PRIx64 " r5=%016" PRIx64 " r6=%016" PRIx64
+ " nip=" TARGET_FMT_lx "\n",
+ ppc_dump_gpr(env, 0), ppc_dump_gpr(env, 3),
+ ppc_dump_gpr(env, 4), ppc_dump_gpr(env, 5),
+ ppc_dump_gpr(env, 6), env->nip);
+}
+
+/* Note that this function should be greatly optimized
+ * when called with a constant excp, from ppc_hw_interrupt
+ */
+static inline void powerpc_excp(CPUPPCState *env, int excp_model, int excp)
+{
+ target_ulong msr, new_msr, vector;
+ int srr0, srr1, asrr0, asrr1;
+ int lpes0, lpes1, lev;
+
+ if (0) {
+ /* XXX: find a suitable condition to enable the hypervisor mode */
+ lpes0 = (env->spr[SPR_LPCR] >> 1) & 1;
+ lpes1 = (env->spr[SPR_LPCR] >> 2) & 1;
+ } else {
+ /* Those values ensure we won't enter the hypervisor mode */
+ lpes0 = 0;
+ lpes1 = 1;
+ }
+
+ qemu_log_mask(CPU_LOG_INT, "Raise exception at " TARGET_FMT_lx
+ " => %08x (%02x)\n", env->nip, excp, env->error_code);
+
+ /* new srr1 value excluding must-be-zero bits */
+ msr = env->msr & ~0x783f0000ULL;
+
+ /* new interrupt handler msr */
+ new_msr = env->msr & ((target_ulong)1 << MSR_ME);
+
+ /* target registers */
+ srr0 = SPR_SRR0;
+ srr1 = SPR_SRR1;
+ asrr0 = -1;
+ asrr1 = -1;
+
+ switch (excp) {
+ case POWERPC_EXCP_NONE:
+ /* Should never happen */
+ return;
+ case POWERPC_EXCP_CRITICAL: /* Critical input */
+ switch (excp_model) {
+ case POWERPC_EXCP_40x:
+ srr0 = SPR_40x_SRR2;
+ srr1 = SPR_40x_SRR3;
+ break;
+ case POWERPC_EXCP_BOOKE:
+ srr0 = SPR_BOOKE_CSRR0;
+ srr1 = SPR_BOOKE_CSRR1;
+ break;
+ case POWERPC_EXCP_G2:
+ break;
+ default:
+ goto excp_invalid;
+ }
+ goto store_next;
+ case POWERPC_EXCP_MCHECK: /* Machine check exception */
+ if (msr_me == 0) {
+ /* Machine check exception is not enabled.
+ * Enter checkstop state.
+ */
+ if (qemu_log_enabled()) {
+ qemu_log("Machine check while not allowed. "
+ "Entering checkstop state\n");
+ } else {
+ fprintf(stderr, "Machine check while not allowed. "
+ "Entering checkstop state\n");
+ }
+ env->halted = 1;
+ env->interrupt_request |= CPU_INTERRUPT_EXITTB;
+ }
+ if (0) {
+ /* XXX: find a suitable condition to enable the hypervisor mode */
+ new_msr |= (target_ulong)MSR_HVB;
+ }
+
+ /* machine check exceptions don't have ME set */
+ new_msr &= ~((target_ulong)1 << MSR_ME);
+
+ /* XXX: should also have something loaded in DAR / DSISR */
+ switch (excp_model) {
+ case POWERPC_EXCP_40x:
+ srr0 = SPR_40x_SRR2;
+ srr1 = SPR_40x_SRR3;
+ break;
+ case POWERPC_EXCP_BOOKE:
+ srr0 = SPR_BOOKE_MCSRR0;
+ srr1 = SPR_BOOKE_MCSRR1;
+ asrr0 = SPR_BOOKE_CSRR0;
+ asrr1 = SPR_BOOKE_CSRR1;
+ break;
+ default:
+ break;
+ }
+ goto store_next;
+ case POWERPC_EXCP_DSI: /* Data storage exception */
+ LOG_EXCP("DSI exception: DSISR=" TARGET_FMT_lx" DAR=" TARGET_FMT_lx
+ "\n", env->spr[SPR_DSISR], env->spr[SPR_DAR]);
+ if (lpes1 == 0) {
+ new_msr |= (target_ulong)MSR_HVB;
+ }
+ goto store_next;
+ case POWERPC_EXCP_ISI: /* Instruction storage exception */
+ LOG_EXCP("ISI exception: msr=" TARGET_FMT_lx ", nip=" TARGET_FMT_lx
+ "\n", msr, env->nip);
+ if (lpes1 == 0) {
+ new_msr |= (target_ulong)MSR_HVB;
+ }
+ msr |= env->error_code;
+ goto store_next;
+ case POWERPC_EXCP_EXTERNAL: /* External input */
+ if (lpes0 == 1) {
+ new_msr |= (target_ulong)MSR_HVB;
+ }
+ goto store_next;
+ case POWERPC_EXCP_ALIGN: /* Alignment exception */
+ if (lpes1 == 0) {
+ new_msr |= (target_ulong)MSR_HVB;
+ }
+ /* XXX: this is false */
+ /* Get rS/rD and rA from faulting opcode */
+ env->spr[SPR_DSISR] |= (ldl_code((env->nip - 4)) & 0x03FF0000) >> 16;
+ goto store_current;
+ case POWERPC_EXCP_PROGRAM: /* Program exception */
+ switch (env->error_code & ~0xF) {
+ case POWERPC_EXCP_FP:
+ if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) {
+ LOG_EXCP("Ignore floating point exception\n");
+ env->exception_index = POWERPC_EXCP_NONE;
+ env->error_code = 0;
+ return;
+ }
+ if (lpes1 == 0) {
+ new_msr |= (target_ulong)MSR_HVB;
+ }
+ msr |= 0x00100000;
+ if (msr_fe0 == msr_fe1) {
+ goto store_next;
+ }
+ msr |= 0x00010000;
+ break;
+ case POWERPC_EXCP_INVAL:
+ LOG_EXCP("Invalid instruction at " TARGET_FMT_lx "\n", env->nip);
+ if (lpes1 == 0) {
+ new_msr |= (target_ulong)MSR_HVB;
+ }
+ msr |= 0x00080000;
+ env->spr[SPR_BOOKE_ESR] = ESR_PIL;
+ break;
+ case POWERPC_EXCP_PRIV:
+ if (lpes1 == 0) {
+ new_msr |= (target_ulong)MSR_HVB;
+ }
+ msr |= 0x00040000;
+ env->spr[SPR_BOOKE_ESR] = ESR_PPR;
+ break;
+ case POWERPC_EXCP_TRAP:
+ if (lpes1 == 0) {
+ new_msr |= (target_ulong)MSR_HVB;
+ }
+ msr |= 0x00020000;
+ env->spr[SPR_BOOKE_ESR] = ESR_PTR;
+ break;
+ default:
+ /* Should never occur */
+ cpu_abort(env, "Invalid program exception %d. Aborting\n",
+ env->error_code);
+ break;
+ }
+ goto store_current;
+ case POWERPC_EXCP_FPU: /* Floating-point unavailable exception */
+ if (lpes1 == 0) {
+ new_msr |= (target_ulong)MSR_HVB;
+ }
+ goto store_current;
+ case POWERPC_EXCP_SYSCALL: /* System call exception */
+ dump_syscall(env);
+ lev = env->error_code;
+ if ((lev == 1) && cpu_ppc_hypercall) {
+ cpu_ppc_hypercall(env);
+ return;
+ }
+ if (lev == 1 || (lpes0 == 0 && lpes1 == 0)) {
+ new_msr |= (target_ulong)MSR_HVB;
+ }
+ goto store_next;
+ case POWERPC_EXCP_APU: /* Auxiliary processor unavailable */
+ goto store_current;
+ case POWERPC_EXCP_DECR: /* Decrementer exception */
+ if (lpes1 == 0) {
+ new_msr |= (target_ulong)MSR_HVB;
+ }
+ goto store_next;
+ case POWERPC_EXCP_FIT: /* Fixed-interval timer interrupt */
+ /* FIT on 4xx */
+ LOG_EXCP("FIT exception\n");
+ goto store_next;
+ case POWERPC_EXCP_WDT: /* Watchdog timer interrupt */
+ LOG_EXCP("WDT exception\n");
+ switch (excp_model) {
+ case POWERPC_EXCP_BOOKE:
+ srr0 = SPR_BOOKE_CSRR0;
+ srr1 = SPR_BOOKE_CSRR1;
+ break;
+ default:
+ break;
+ }
+ goto store_next;
+ case POWERPC_EXCP_DTLB: /* Data TLB error */
+ goto store_next;
+ case POWERPC_EXCP_ITLB: /* Instruction TLB error */
+ goto store_next;
+ case POWERPC_EXCP_DEBUG: /* Debug interrupt */
+ switch (excp_model) {
+ case POWERPC_EXCP_BOOKE:
+ srr0 = SPR_BOOKE_DSRR0;
+ srr1 = SPR_BOOKE_DSRR1;
+ asrr0 = SPR_BOOKE_CSRR0;
+ asrr1 = SPR_BOOKE_CSRR1;
+ break;
+ default:
+ break;
+ }
+ /* XXX: TODO */
+ cpu_abort(env, "Debug exception is not implemented yet !\n");
+ goto store_next;
+ case POWERPC_EXCP_SPEU: /* SPE/embedded floating-point unavailable */
+ env->spr[SPR_BOOKE_ESR] = ESR_SPV;
+ goto store_current;
+ case POWERPC_EXCP_EFPDI: /* Embedded floating-point data interrupt */
+ /* XXX: TODO */
+ cpu_abort(env, "Embedded floating point data exception "
+ "is not implemented yet !\n");
+ env->spr[SPR_BOOKE_ESR] = ESR_SPV;
+ goto store_next;
+ case POWERPC_EXCP_EFPRI: /* Embedded floating-point round interrupt */
+ /* XXX: TODO */
+ cpu_abort(env, "Embedded floating point round exception "
+ "is not implemented yet !\n");
+ env->spr[SPR_BOOKE_ESR] = ESR_SPV;
+ goto store_next;
+ case POWERPC_EXCP_EPERFM: /* Embedded performance monitor interrupt */
+ /* XXX: TODO */
+ cpu_abort(env,
+ "Performance counter exception is not implemented yet !\n");
+ goto store_next;
+ case POWERPC_EXCP_DOORI: /* Embedded doorbell interrupt */
+ goto store_next;
+ case POWERPC_EXCP_DOORCI: /* Embedded doorbell critical interrupt */
+ srr0 = SPR_BOOKE_CSRR0;
+ srr1 = SPR_BOOKE_CSRR1;
+ goto store_next;
+ case POWERPC_EXCP_RESET: /* System reset exception */
+ if (msr_pow) {
+ /* indicate that we resumed from power save mode */
+ msr |= 0x10000;
+ } else {
+ new_msr &= ~((target_ulong)1 << MSR_ME);
+ }
+
+ if (0) {
+ /* XXX: find a suitable condition to enable the hypervisor mode */
+ new_msr |= (target_ulong)MSR_HVB;
+ }
+ goto store_next;
+ case POWERPC_EXCP_DSEG: /* Data segment exception */
+ if (lpes1 == 0) {
+ new_msr |= (target_ulong)MSR_HVB;
+ }
+ goto store_next;
+ case POWERPC_EXCP_ISEG: /* Instruction segment exception */
+ if (lpes1 == 0) {
+ new_msr |= (target_ulong)MSR_HVB;
+ }
+ goto store_next;
+ case POWERPC_EXCP_HDECR: /* Hypervisor decrementer exception */
+ srr0 = SPR_HSRR0;
+ srr1 = SPR_HSRR1;
+ new_msr |= (target_ulong)MSR_HVB;
+ new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
+ goto store_next;
+ case POWERPC_EXCP_TRACE: /* Trace exception */
+ if (lpes1 == 0) {
+ new_msr |= (target_ulong)MSR_HVB;
+ }
+ goto store_next;
+ case POWERPC_EXCP_HDSI: /* Hypervisor data storage exception */
+ srr0 = SPR_HSRR0;
+ srr1 = SPR_HSRR1;
+ new_msr |= (target_ulong)MSR_HVB;
+ new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
+ goto store_next;
+ case POWERPC_EXCP_HISI: /* Hypervisor instruction storage exception */
+ srr0 = SPR_HSRR0;
+ srr1 = SPR_HSRR1;
+ new_msr |= (target_ulong)MSR_HVB;
+ new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
+ goto store_next;
+ case POWERPC_EXCP_HDSEG: /* Hypervisor data segment exception */
+ srr0 = SPR_HSRR0;
+ srr1 = SPR_HSRR1;
+ new_msr |= (target_ulong)MSR_HVB;
+ new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
+ goto store_next;
+ case POWERPC_EXCP_HISEG: /* Hypervisor instruction segment exception */
+ srr0 = SPR_HSRR0;
+ srr1 = SPR_HSRR1;
+ new_msr |= (target_ulong)MSR_HVB;
+ new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
+ goto store_next;
+ case POWERPC_EXCP_VPU: /* Vector unavailable exception */
+ if (lpes1 == 0) {
+ new_msr |= (target_ulong)MSR_HVB;
+ }
+ goto store_current;
+ case POWERPC_EXCP_PIT: /* Programmable interval timer interrupt */
+ LOG_EXCP("PIT exception\n");
+ goto store_next;
+ case POWERPC_EXCP_IO: /* IO error exception */
+ /* XXX: TODO */
+ cpu_abort(env, "601 IO error exception is not implemented yet !\n");
+ goto store_next;
+ case POWERPC_EXCP_RUNM: /* Run mode exception */
+ /* XXX: TODO */
+ cpu_abort(env, "601 run mode exception is not implemented yet !\n");
+ goto store_next;
+ case POWERPC_EXCP_EMUL: /* Emulation trap exception */
+ /* XXX: TODO */
+ cpu_abort(env, "602 emulation trap exception "
+ "is not implemented yet !\n");
+ goto store_next;
+ case POWERPC_EXCP_IFTLB: /* Instruction fetch TLB error */
+ if (lpes1 == 0) { /* XXX: check this */
+ new_msr |= (target_ulong)MSR_HVB;
+ }
+ switch (excp_model) {
+ case POWERPC_EXCP_602:
+ case POWERPC_EXCP_603:
+ case POWERPC_EXCP_603E:
+ case POWERPC_EXCP_G2:
+ goto tlb_miss_tgpr;
+ case POWERPC_EXCP_7x5:
+ goto tlb_miss;
+ case POWERPC_EXCP_74xx:
+ goto tlb_miss_74xx;
+ default:
+ cpu_abort(env, "Invalid instruction TLB miss exception\n");
+ break;
+ }
+ break;
+ case POWERPC_EXCP_DLTLB: /* Data load TLB miss */
+ if (lpes1 == 0) { /* XXX: check this */
+ new_msr |= (target_ulong)MSR_HVB;
+ }
+ switch (excp_model) {
+ case POWERPC_EXCP_602:
+ case POWERPC_EXCP_603:
+ case POWERPC_EXCP_603E:
+ case POWERPC_EXCP_G2:
+ goto tlb_miss_tgpr;
+ case POWERPC_EXCP_7x5:
+ goto tlb_miss;
+ case POWERPC_EXCP_74xx:
+ goto tlb_miss_74xx;
+ default:
+ cpu_abort(env, "Invalid data load TLB miss exception\n");
+ break;
+ }
+ break;
+ case POWERPC_EXCP_DSTLB: /* Data store TLB miss */
+ if (lpes1 == 0) { /* XXX: check this */
+ new_msr |= (target_ulong)MSR_HVB;
+ }
+ switch (excp_model) {
+ case POWERPC_EXCP_602:
+ case POWERPC_EXCP_603:
+ case POWERPC_EXCP_603E:
+ case POWERPC_EXCP_G2:
+ tlb_miss_tgpr:
+ /* Swap temporary saved registers with GPRs */
+ if (!(new_msr & ((target_ulong)1 << MSR_TGPR))) {
+ new_msr |= (target_ulong)1 << MSR_TGPR;
+ hreg_swap_gpr_tgpr(env);
+ }
+ goto tlb_miss;
+ case POWERPC_EXCP_7x5:
+ tlb_miss:
+#if defined(DEBUG_SOFTWARE_TLB)
+ if (qemu_log_enabled()) {
+ const char *es;
+ target_ulong *miss, *cmp;
+ int en;
+
+ if (excp == POWERPC_EXCP_IFTLB) {
+ es = "I";
+ en = 'I';
+ miss = &env->spr[SPR_IMISS];
+ cmp = &env->spr[SPR_ICMP];
+ } else {
+ if (excp == POWERPC_EXCP_DLTLB) {
+ es = "DL";
+ } else {
+ es = "DS";
+ }
+ en = 'D';
+ miss = &env->spr[SPR_DMISS];
+ cmp = &env->spr[SPR_DCMP];
+ }
+ qemu_log("6xx %sTLB miss: %cM " TARGET_FMT_lx " %cC "
+ TARGET_FMT_lx " H1 " TARGET_FMT_lx " H2 "
+ TARGET_FMT_lx " %08x\n", es, en, *miss, en, *cmp,
+ env->spr[SPR_HASH1], env->spr[SPR_HASH2],
+ env->error_code);
+ }
+#endif
+ msr |= env->crf[0] << 28;
+ msr |= env->error_code; /* key, D/I, S/L bits */
+ /* Set way using a LRU mechanism */
+ msr |= ((env->last_way + 1) & (env->nb_ways - 1)) << 17;
+ break;
+ case POWERPC_EXCP_74xx:
+ tlb_miss_74xx:
+#if defined(DEBUG_SOFTWARE_TLB)
+ if (qemu_log_enabled()) {
+ const char *es;
+ target_ulong *miss, *cmp;
+ int en;
+
+ if (excp == POWERPC_EXCP_IFTLB) {
+ es = "I";
+ en = 'I';
+ miss = &env->spr[SPR_TLBMISS];
+ cmp = &env->spr[SPR_PTEHI];
+ } else {
+ if (excp == POWERPC_EXCP_DLTLB) {
+ es = "DL";
+ } else {
+ es = "DS";
+ }
+ en = 'D';
+ miss = &env->spr[SPR_TLBMISS];
+ cmp = &env->spr[SPR_PTEHI];
+ }
+ qemu_log("74xx %sTLB miss: %cM " TARGET_FMT_lx " %cC "
+ TARGET_FMT_lx " %08x\n", es, en, *miss, en, *cmp,
+ env->error_code);
+ }
+#endif
+ msr |= env->error_code; /* key bit */
+ break;
+ default:
+ cpu_abort(env, "Invalid data store TLB miss exception\n");
+ break;
+ }
+ goto store_next;
+ case POWERPC_EXCP_FPA: /* Floating-point assist exception */
+ /* XXX: TODO */
+ cpu_abort(env, "Floating point assist exception "
+ "is not implemented yet !\n");
+ goto store_next;
+ case POWERPC_EXCP_DABR: /* Data address breakpoint */
+ /* XXX: TODO */
+ cpu_abort(env, "DABR exception is not implemented yet !\n");
+ goto store_next;
+ case POWERPC_EXCP_IABR: /* Instruction address breakpoint */
+ /* XXX: TODO */
+ cpu_abort(env, "IABR exception is not implemented yet !\n");
+ goto store_next;
+ case POWERPC_EXCP_SMI: /* System management interrupt */
+ /* XXX: TODO */
+ cpu_abort(env, "SMI exception is not implemented yet !\n");
+ goto store_next;
+ case POWERPC_EXCP_THERM: /* Thermal interrupt */
+ /* XXX: TODO */
+ cpu_abort(env, "Thermal management exception "
+ "is not implemented yet !\n");
+ goto store_next;
+ case POWERPC_EXCP_PERFM: /* Embedded performance monitor interrupt */
+ if (lpes1 == 0) {
+ new_msr |= (target_ulong)MSR_HVB;
+ }
+ /* XXX: TODO */
+ cpu_abort(env,
+ "Performance counter exception is not implemented yet !\n");
+ goto store_next;
+ case POWERPC_EXCP_VPUA: /* Vector assist exception */
+ /* XXX: TODO */
+ cpu_abort(env, "VPU assist exception is not implemented yet !\n");
+ goto store_next;
+ case POWERPC_EXCP_SOFTP: /* Soft patch exception */
+ /* XXX: TODO */
+ cpu_abort(env,
+ "970 soft-patch exception is not implemented yet !\n");
+ goto store_next;
+ case POWERPC_EXCP_MAINT: /* Maintenance exception */
+ /* XXX: TODO */
+ cpu_abort(env,
+ "970 maintenance exception is not implemented yet !\n");
+ goto store_next;
+ case POWERPC_EXCP_MEXTBR: /* Maskable external breakpoint */
+ /* XXX: TODO */
+ cpu_abort(env, "Maskable external exception "
+ "is not implemented yet !\n");
+ goto store_next;
+ case POWERPC_EXCP_NMEXTBR: /* Non maskable external breakpoint */
+ /* XXX: TODO */
+ cpu_abort(env, "Non maskable external exception "
+ "is not implemented yet !\n");
+ goto store_next;
+ default:
+ excp_invalid:
+ cpu_abort(env, "Invalid PowerPC exception %d. Aborting\n", excp);
+ break;
+ store_current:
+ /* save current instruction location */
+ env->spr[srr0] = env->nip - 4;
+ break;
+ store_next:
+ /* save next instruction location */
+ env->spr[srr0] = env->nip;
+ break;
+ }
+ /* Save MSR */
+ env->spr[srr1] = msr;
+ /* If any alternate SRR register are defined, duplicate saved values */
+ if (asrr0 != -1) {
+ env->spr[asrr0] = env->spr[srr0];
+ }
+ if (asrr1 != -1) {
+ env->spr[asrr1] = env->spr[srr1];
+ }
+ /* If we disactivated any translation, flush TLBs */
+ if (msr & ((1 << MSR_IR) | (1 << MSR_DR))) {
+ tlb_flush(env, 1);
+ }
+
+ if (msr_ile) {
+ new_msr |= (target_ulong)1 << MSR_LE;
+ }
+
+ /* Jump to handler */
+ vector = env->excp_vectors[excp];
+ if (vector == (target_ulong)-1ULL) {
+ cpu_abort(env, "Raised an exception without defined vector %d\n",
+ excp);
+ }
+ vector |= env->excp_prefix;
+#if defined(TARGET_PPC64)
+ if (excp_model == POWERPC_EXCP_BOOKE) {
+ if (!msr_icm) {
+ vector = (uint32_t)vector;
+ } else {
+ new_msr |= (target_ulong)1 << MSR_CM;
+ }
+ } else {
+ if (!msr_isf && !(env->mmu_model & POWERPC_MMU_64)) {
+ vector = (uint32_t)vector;
+ } else {
+ new_msr |= (target_ulong)1 << MSR_SF;
+ }
+ }
+#endif
+ /* XXX: we don't use hreg_store_msr here as already have treated
+ * any special case that could occur. Just store MSR and update hflags
+ */
+ env->msr = new_msr & env->msr_mask;
+ hreg_compute_hflags(env);
+ env->nip = vector;
+ /* Reset exception state */
+ env->exception_index = POWERPC_EXCP_NONE;
+ env->error_code = 0;
+
+ if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
+ (env->mmu_model == POWERPC_MMU_BOOKE206)) {
+ /* XXX: The BookE changes address space when switching modes,
+ we should probably implement that as different MMU indexes,
+ but for the moment we do it the slow way and flush all. */
+ tlb_flush(env, 1);
+ }
+}
+
+void do_interrupt(CPUPPCState *env)
+{
+ powerpc_excp(env, env->excp_model, env->exception_index);
+}
+
+void ppc_hw_interrupt(CPUPPCState *env)
+{
+ int hdice;
+
+#if 0
+ qemu_log_mask(CPU_LOG_INT, "%s: %p pending %08x req %08x me %d ee %d\n",
+ __func__, env, env->pending_interrupts,
+ env->interrupt_request, (int)msr_me, (int)msr_ee);
+#endif
+ /* External reset */
+ if (env->pending_interrupts & (1 << PPC_INTERRUPT_RESET)) {
+ env->pending_interrupts &= ~(1 << PPC_INTERRUPT_RESET);
+ powerpc_excp(env, env->excp_model, POWERPC_EXCP_RESET);
+ return;
+ }
+ /* Machine check exception */
+ if (env->pending_interrupts & (1 << PPC_INTERRUPT_MCK)) {
+ env->pending_interrupts &= ~(1 << PPC_INTERRUPT_MCK);
+ powerpc_excp(env, env->excp_model, POWERPC_EXCP_MCHECK);
+ return;
+ }
+#if 0 /* TODO */
+ /* External debug exception */
+ if (env->pending_interrupts & (1 << PPC_INTERRUPT_DEBUG)) {
+ env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DEBUG);
+ powerpc_excp(env, env->excp_model, POWERPC_EXCP_DEBUG);
+ return;
+ }
+#endif
+ if (0) {
+ /* XXX: find a suitable condition to enable the hypervisor mode */
+ hdice = env->spr[SPR_LPCR] & 1;
+ } else {
+ hdice = 0;
+ }
+ if ((msr_ee != 0 || msr_hv == 0 || msr_pr != 0) && hdice != 0) {
+ /* Hypervisor decrementer exception */
+ if (env->pending_interrupts & (1 << PPC_INTERRUPT_HDECR)) {
+ env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDECR);
+ powerpc_excp(env, env->excp_model, POWERPC_EXCP_HDECR);
+ return;
+ }
+ }
+ if (msr_ce != 0) {
+ /* External critical interrupt */
+ if (env->pending_interrupts & (1 << PPC_INTERRUPT_CEXT)) {
+ /* Taking a critical external interrupt does not clear the external
+ * critical interrupt status
+ */
+#if 0
+ env->pending_interrupts &= ~(1 << PPC_INTERRUPT_CEXT);
+#endif
+ powerpc_excp(env, env->excp_model, POWERPC_EXCP_CRITICAL);
+ return;
+ }
+ }
+ if (msr_ee != 0) {
+ /* Watchdog timer on embedded PowerPC */
+ if (env->pending_interrupts & (1 << PPC_INTERRUPT_WDT)) {
+ env->pending_interrupts &= ~(1 << PPC_INTERRUPT_WDT);
+ powerpc_excp(env, env->excp_model, POWERPC_EXCP_WDT);
+ return;
+ }
+ if (env->pending_interrupts & (1 << PPC_INTERRUPT_CDOORBELL)) {
+ env->pending_interrupts &= ~(1 << PPC_INTERRUPT_CDOORBELL);
+ powerpc_excp(env, env->excp_model, POWERPC_EXCP_DOORCI);
+ return;
+ }
+ /* Fixed interval timer on embedded PowerPC */
+ if (env->pending_interrupts & (1 << PPC_INTERRUPT_FIT)) {
+ env->pending_interrupts &= ~(1 << PPC_INTERRUPT_FIT);
+ powerpc_excp(env, env->excp_model, POWERPC_EXCP_FIT);
+ return;
+ }
+ /* Programmable interval timer on embedded PowerPC */
+ if (env->pending_interrupts & (1 << PPC_INTERRUPT_PIT)) {
+ env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PIT);
+ powerpc_excp(env, env->excp_model, POWERPC_EXCP_PIT);
+ return;
+ }
+ /* Decrementer exception */
+ if (env->pending_interrupts & (1 << PPC_INTERRUPT_DECR)) {
+ env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DECR);
+ powerpc_excp(env, env->excp_model, POWERPC_EXCP_DECR);
+ return;
+ }
+ /* External interrupt */
+ if (env->pending_interrupts & (1 << PPC_INTERRUPT_EXT)) {
+ /* Taking an external interrupt does not clear the external
+ * interrupt status
+ */
+#if 0
+ env->pending_interrupts &= ~(1 << PPC_INTERRUPT_EXT);
+#endif
+ powerpc_excp(env, env->excp_model, POWERPC_EXCP_EXTERNAL);
+ return;
+ }
+ if (env->pending_interrupts & (1 << PPC_INTERRUPT_DOORBELL)) {
+ env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DOORBELL);
+ powerpc_excp(env, env->excp_model, POWERPC_EXCP_DOORI);
+ return;
+ }
+ if (env->pending_interrupts & (1 << PPC_INTERRUPT_PERFM)) {
+ env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PERFM);
+ powerpc_excp(env, env->excp_model, POWERPC_EXCP_PERFM);
+ return;
+ }
+ /* Thermal interrupt */
+ if (env->pending_interrupts & (1 << PPC_INTERRUPT_THERM)) {
+ env->pending_interrupts &= ~(1 << PPC_INTERRUPT_THERM);
+ powerpc_excp(env, env->excp_model, POWERPC_EXCP_THERM);
+ return;
+ }
+ }
+}
+#endif /* !CONFIG_USER_ONLY */
+
+#if defined(DEBUG_OP)
+static void cpu_dump_rfi(target_ulong RA, target_ulong msr)
+{
+ qemu_log("Return from exception at " TARGET_FMT_lx " with flags "
+ TARGET_FMT_lx "\n", RA, msr);
+}
+#endif
+
/*****************************************************************************/
/* Exceptions processing helpers */
diff --git a/target-ppc/helper.c b/target-ppc/helper.c
index 44f1cdd..17e72a9 100644
--- a/target-ppc/helper.c
+++ b/target-ppc/helper.c
@@ -28,7 +28,6 @@
//#define DEBUG_SLB
//#define DEBUG_SOFTWARE_TLB
//#define DUMP_PAGE_TABLES
-//#define DEBUG_EXCEPTIONS
//#define FLUSH_ALL_TLBS
#ifdef DEBUG_MMU
@@ -58,17 +57,6 @@
# define LOG_SLB(...) do { } while (0)
#endif
-#ifdef DEBUG_EXCEPTIONS
-# define LOG_EXCP(...) qemu_log(__VA_ARGS__)
-#else
-# define LOG_EXCP(...) do { } while (0)
-#endif
-
-/*****************************************************************************/
-/* PowerPC Hypercall emulation */
-
-void (*cpu_ppc_hypercall)(CPUPPCState *);
-
/*****************************************************************************/
/* PowerPC MMU emulation */
@@ -2519,738 +2507,6 @@ void ppc_store_msr(CPUPPCState *env, target_ulong value)
hreg_store_msr(env, value, 0);
}
-/*****************************************************************************/
-/* Exception processing */
-#if defined(CONFIG_USER_ONLY)
-void do_interrupt(CPUPPCState *env)
-{
- env->exception_index = POWERPC_EXCP_NONE;
- env->error_code = 0;
-}
-
-void ppc_hw_interrupt(CPUPPCState *env)
-{
- env->exception_index = POWERPC_EXCP_NONE;
- env->error_code = 0;
-}
-#else /* defined(CONFIG_USER_ONLY) */
-static inline void dump_syscall(CPUPPCState *env)
-{
- qemu_log_mask(CPU_LOG_INT, "syscall r0=%016" PRIx64 " r3=%016" PRIx64
- " r4=%016" PRIx64 " r5=%016" PRIx64 " r6=%016" PRIx64
- " nip=" TARGET_FMT_lx "\n",
- ppc_dump_gpr(env, 0), ppc_dump_gpr(env, 3),
- ppc_dump_gpr(env, 4), ppc_dump_gpr(env, 5),
- ppc_dump_gpr(env, 6), env->nip);
-}
-
-/* Note that this function should be greatly optimized
- * when called with a constant excp, from ppc_hw_interrupt
- */
-static inline void powerpc_excp(CPUPPCState *env, int excp_model, int excp)
-{
- target_ulong msr, new_msr, vector;
- int srr0, srr1, asrr0, asrr1;
- int lpes0, lpes1, lev;
-
- if (0) {
- /* XXX: find a suitable condition to enable the hypervisor mode */
- lpes0 = (env->spr[SPR_LPCR] >> 1) & 1;
- lpes1 = (env->spr[SPR_LPCR] >> 2) & 1;
- } else {
- /* Those values ensure we won't enter the hypervisor mode */
- lpes0 = 0;
- lpes1 = 1;
- }
-
- qemu_log_mask(CPU_LOG_INT, "Raise exception at " TARGET_FMT_lx
- " => %08x (%02x)\n", env->nip, excp, env->error_code);
-
- /* new srr1 value excluding must-be-zero bits */
- msr = env->msr & ~0x783f0000ULL;
-
- /* new interrupt handler msr */
- new_msr = env->msr & ((target_ulong)1 << MSR_ME);
-
- /* target registers */
- srr0 = SPR_SRR0;
- srr1 = SPR_SRR1;
- asrr0 = -1;
- asrr1 = -1;
-
- switch (excp) {
- case POWERPC_EXCP_NONE:
- /* Should never happen */
- return;
- case POWERPC_EXCP_CRITICAL: /* Critical input */
- switch (excp_model) {
- case POWERPC_EXCP_40x:
- srr0 = SPR_40x_SRR2;
- srr1 = SPR_40x_SRR3;
- break;
- case POWERPC_EXCP_BOOKE:
- srr0 = SPR_BOOKE_CSRR0;
- srr1 = SPR_BOOKE_CSRR1;
- break;
- case POWERPC_EXCP_G2:
- break;
- default:
- goto excp_invalid;
- }
- goto store_next;
- case POWERPC_EXCP_MCHECK: /* Machine check exception */
- if (msr_me == 0) {
- /* Machine check exception is not enabled.
- * Enter checkstop state.
- */
- if (qemu_log_enabled()) {
- qemu_log("Machine check while not allowed. "
- "Entering checkstop state\n");
- } else {
- fprintf(stderr, "Machine check while not allowed. "
- "Entering checkstop state\n");
- }
- env->halted = 1;
- env->interrupt_request |= CPU_INTERRUPT_EXITTB;
- }
- if (0) {
- /* XXX: find a suitable condition to enable the hypervisor mode */
- new_msr |= (target_ulong)MSR_HVB;
- }
-
- /* machine check exceptions don't have ME set */
- new_msr &= ~((target_ulong)1 << MSR_ME);
-
- /* XXX: should also have something loaded in DAR / DSISR */
- switch (excp_model) {
- case POWERPC_EXCP_40x:
- srr0 = SPR_40x_SRR2;
- srr1 = SPR_40x_SRR3;
- break;
- case POWERPC_EXCP_BOOKE:
- srr0 = SPR_BOOKE_MCSRR0;
- srr1 = SPR_BOOKE_MCSRR1;
- asrr0 = SPR_BOOKE_CSRR0;
- asrr1 = SPR_BOOKE_CSRR1;
- break;
- default:
- break;
- }
- goto store_next;
- case POWERPC_EXCP_DSI: /* Data storage exception */
- LOG_EXCP("DSI exception: DSISR=" TARGET_FMT_lx" DAR=" TARGET_FMT_lx
- "\n", env->spr[SPR_DSISR], env->spr[SPR_DAR]);
- if (lpes1 == 0) {
- new_msr |= (target_ulong)MSR_HVB;
- }
- goto store_next;
- case POWERPC_EXCP_ISI: /* Instruction storage exception */
- LOG_EXCP("ISI exception: msr=" TARGET_FMT_lx ", nip=" TARGET_FMT_lx
- "\n", msr, env->nip);
- if (lpes1 == 0) {
- new_msr |= (target_ulong)MSR_HVB;
- }
- msr |= env->error_code;
- goto store_next;
- case POWERPC_EXCP_EXTERNAL: /* External input */
- if (lpes0 == 1) {
- new_msr |= (target_ulong)MSR_HVB;
- }
- goto store_next;
- case POWERPC_EXCP_ALIGN: /* Alignment exception */
- if (lpes1 == 0) {
- new_msr |= (target_ulong)MSR_HVB;
- }
- /* XXX: this is false */
- /* Get rS/rD and rA from faulting opcode */
- env->spr[SPR_DSISR] |= (ldl_code((env->nip - 4)) & 0x03FF0000) >> 16;
- goto store_current;
- case POWERPC_EXCP_PROGRAM: /* Program exception */
- switch (env->error_code & ~0xF) {
- case POWERPC_EXCP_FP:
- if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) {
- LOG_EXCP("Ignore floating point exception\n");
- env->exception_index = POWERPC_EXCP_NONE;
- env->error_code = 0;
- return;
- }
- if (lpes1 == 0) {
- new_msr |= (target_ulong)MSR_HVB;
- }
- msr |= 0x00100000;
- if (msr_fe0 == msr_fe1) {
- goto store_next;
- }
- msr |= 0x00010000;
- break;
- case POWERPC_EXCP_INVAL:
- LOG_EXCP("Invalid instruction at " TARGET_FMT_lx "\n", env->nip);
- if (lpes1 == 0) {
- new_msr |= (target_ulong)MSR_HVB;
- }
- msr |= 0x00080000;
- env->spr[SPR_BOOKE_ESR] = ESR_PIL;
- break;
- case POWERPC_EXCP_PRIV:
- if (lpes1 == 0) {
- new_msr |= (target_ulong)MSR_HVB;
- }
- msr |= 0x00040000;
- env->spr[SPR_BOOKE_ESR] = ESR_PPR;
- break;
- case POWERPC_EXCP_TRAP:
- if (lpes1 == 0) {
- new_msr |= (target_ulong)MSR_HVB;
- }
- msr |= 0x00020000;
- env->spr[SPR_BOOKE_ESR] = ESR_PTR;
- break;
- default:
- /* Should never occur */
- cpu_abort(env, "Invalid program exception %d. Aborting\n",
- env->error_code);
- break;
- }
- goto store_current;
- case POWERPC_EXCP_FPU: /* Floating-point unavailable exception */
- if (lpes1 == 0) {
- new_msr |= (target_ulong)MSR_HVB;
- }
- goto store_current;
- case POWERPC_EXCP_SYSCALL: /* System call exception */
- dump_syscall(env);
- lev = env->error_code;
- if ((lev == 1) && cpu_ppc_hypercall) {
- cpu_ppc_hypercall(env);
- return;
- }
- if (lev == 1 || (lpes0 == 0 && lpes1 == 0)) {
- new_msr |= (target_ulong)MSR_HVB;
- }
- goto store_next;
- case POWERPC_EXCP_APU: /* Auxiliary processor unavailable */
- goto store_current;
- case POWERPC_EXCP_DECR: /* Decrementer exception */
- if (lpes1 == 0) {
- new_msr |= (target_ulong)MSR_HVB;
- }
- goto store_next;
- case POWERPC_EXCP_FIT: /* Fixed-interval timer interrupt */
- /* FIT on 4xx */
- LOG_EXCP("FIT exception\n");
- goto store_next;
- case POWERPC_EXCP_WDT: /* Watchdog timer interrupt */
- LOG_EXCP("WDT exception\n");
- switch (excp_model) {
- case POWERPC_EXCP_BOOKE:
- srr0 = SPR_BOOKE_CSRR0;
- srr1 = SPR_BOOKE_CSRR1;
- break;
- default:
- break;
- }
- goto store_next;
- case POWERPC_EXCP_DTLB: /* Data TLB error */
- goto store_next;
- case POWERPC_EXCP_ITLB: /* Instruction TLB error */
- goto store_next;
- case POWERPC_EXCP_DEBUG: /* Debug interrupt */
- switch (excp_model) {
- case POWERPC_EXCP_BOOKE:
- srr0 = SPR_BOOKE_DSRR0;
- srr1 = SPR_BOOKE_DSRR1;
- asrr0 = SPR_BOOKE_CSRR0;
- asrr1 = SPR_BOOKE_CSRR1;
- break;
- default:
- break;
- }
- /* XXX: TODO */
- cpu_abort(env, "Debug exception is not implemented yet !\n");
- goto store_next;
- case POWERPC_EXCP_SPEU: /* SPE/embedded floating-point unavailable */
- env->spr[SPR_BOOKE_ESR] = ESR_SPV;
- goto store_current;
- case POWERPC_EXCP_EFPDI: /* Embedded floating-point data interrupt */
- /* XXX: TODO */
- cpu_abort(env, "Embedded floating point data exception "
- "is not implemented yet !\n");
- env->spr[SPR_BOOKE_ESR] = ESR_SPV;
- goto store_next;
- case POWERPC_EXCP_EFPRI: /* Embedded floating-point round interrupt */
- /* XXX: TODO */
- cpu_abort(env, "Embedded floating point round exception "
- "is not implemented yet !\n");
- env->spr[SPR_BOOKE_ESR] = ESR_SPV;
- goto store_next;
- case POWERPC_EXCP_EPERFM: /* Embedded performance monitor interrupt */
- /* XXX: TODO */
- cpu_abort(env,
- "Performance counter exception is not implemented yet !\n");
- goto store_next;
- case POWERPC_EXCP_DOORI: /* Embedded doorbell interrupt */
- goto store_next;
- case POWERPC_EXCP_DOORCI: /* Embedded doorbell critical interrupt */
- srr0 = SPR_BOOKE_CSRR0;
- srr1 = SPR_BOOKE_CSRR1;
- goto store_next;
- case POWERPC_EXCP_RESET: /* System reset exception */
- if (msr_pow) {
- /* indicate that we resumed from power save mode */
- msr |= 0x10000;
- } else {
- new_msr &= ~((target_ulong)1 << MSR_ME);
- }
-
- if (0) {
- /* XXX: find a suitable condition to enable the hypervisor mode */
- new_msr |= (target_ulong)MSR_HVB;
- }
- goto store_next;
- case POWERPC_EXCP_DSEG: /* Data segment exception */
- if (lpes1 == 0) {
- new_msr |= (target_ulong)MSR_HVB;
- }
- goto store_next;
- case POWERPC_EXCP_ISEG: /* Instruction segment exception */
- if (lpes1 == 0) {
- new_msr |= (target_ulong)MSR_HVB;
- }
- goto store_next;
- case POWERPC_EXCP_HDECR: /* Hypervisor decrementer exception */
- srr0 = SPR_HSRR0;
- srr1 = SPR_HSRR1;
- new_msr |= (target_ulong)MSR_HVB;
- new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
- goto store_next;
- case POWERPC_EXCP_TRACE: /* Trace exception */
- if (lpes1 == 0) {
- new_msr |= (target_ulong)MSR_HVB;
- }
- goto store_next;
- case POWERPC_EXCP_HDSI: /* Hypervisor data storage exception */
- srr0 = SPR_HSRR0;
- srr1 = SPR_HSRR1;
- new_msr |= (target_ulong)MSR_HVB;
- new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
- goto store_next;
- case POWERPC_EXCP_HISI: /* Hypervisor instruction storage exception */
- srr0 = SPR_HSRR0;
- srr1 = SPR_HSRR1;
- new_msr |= (target_ulong)MSR_HVB;
- new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
- goto store_next;
- case POWERPC_EXCP_HDSEG: /* Hypervisor data segment exception */
- srr0 = SPR_HSRR0;
- srr1 = SPR_HSRR1;
- new_msr |= (target_ulong)MSR_HVB;
- new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
- goto store_next;
- case POWERPC_EXCP_HISEG: /* Hypervisor instruction segment exception */
- srr0 = SPR_HSRR0;
- srr1 = SPR_HSRR1;
- new_msr |= (target_ulong)MSR_HVB;
- new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
- goto store_next;
- case POWERPC_EXCP_VPU: /* Vector unavailable exception */
- if (lpes1 == 0) {
- new_msr |= (target_ulong)MSR_HVB;
- }
- goto store_current;
- case POWERPC_EXCP_PIT: /* Programmable interval timer interrupt */
- LOG_EXCP("PIT exception\n");
- goto store_next;
- case POWERPC_EXCP_IO: /* IO error exception */
- /* XXX: TODO */
- cpu_abort(env, "601 IO error exception is not implemented yet !\n");
- goto store_next;
- case POWERPC_EXCP_RUNM: /* Run mode exception */
- /* XXX: TODO */
- cpu_abort(env, "601 run mode exception is not implemented yet !\n");
- goto store_next;
- case POWERPC_EXCP_EMUL: /* Emulation trap exception */
- /* XXX: TODO */
- cpu_abort(env, "602 emulation trap exception "
- "is not implemented yet !\n");
- goto store_next;
- case POWERPC_EXCP_IFTLB: /* Instruction fetch TLB error */
- if (lpes1 == 0) { /* XXX: check this */
- new_msr |= (target_ulong)MSR_HVB;
- }
- switch (excp_model) {
- case POWERPC_EXCP_602:
- case POWERPC_EXCP_603:
- case POWERPC_EXCP_603E:
- case POWERPC_EXCP_G2:
- goto tlb_miss_tgpr;
- case POWERPC_EXCP_7x5:
- goto tlb_miss;
- case POWERPC_EXCP_74xx:
- goto tlb_miss_74xx;
- default:
- cpu_abort(env, "Invalid instruction TLB miss exception\n");
- break;
- }
- break;
- case POWERPC_EXCP_DLTLB: /* Data load TLB miss */
- if (lpes1 == 0) { /* XXX: check this */
- new_msr |= (target_ulong)MSR_HVB;
- }
- switch (excp_model) {
- case POWERPC_EXCP_602:
- case POWERPC_EXCP_603:
- case POWERPC_EXCP_603E:
- case POWERPC_EXCP_G2:
- goto tlb_miss_tgpr;
- case POWERPC_EXCP_7x5:
- goto tlb_miss;
- case POWERPC_EXCP_74xx:
- goto tlb_miss_74xx;
- default:
- cpu_abort(env, "Invalid data load TLB miss exception\n");
- break;
- }
- break;
- case POWERPC_EXCP_DSTLB: /* Data store TLB miss */
- if (lpes1 == 0) { /* XXX: check this */
- new_msr |= (target_ulong)MSR_HVB;
- }
- switch (excp_model) {
- case POWERPC_EXCP_602:
- case POWERPC_EXCP_603:
- case POWERPC_EXCP_603E:
- case POWERPC_EXCP_G2:
- tlb_miss_tgpr:
- /* Swap temporary saved registers with GPRs */
- if (!(new_msr & ((target_ulong)1 << MSR_TGPR))) {
- new_msr |= (target_ulong)1 << MSR_TGPR;
- hreg_swap_gpr_tgpr(env);
- }
- goto tlb_miss;
- case POWERPC_EXCP_7x5:
- tlb_miss:
-#if defined(DEBUG_SOFTWARE_TLB)
- if (qemu_log_enabled()) {
- const char *es;
- target_ulong *miss, *cmp;
- int en;
-
- if (excp == POWERPC_EXCP_IFTLB) {
- es = "I";
- en = 'I';
- miss = &env->spr[SPR_IMISS];
- cmp = &env->spr[SPR_ICMP];
- } else {
- if (excp == POWERPC_EXCP_DLTLB) {
- es = "DL";
- } else {
- es = "DS";
- }
- en = 'D';
- miss = &env->spr[SPR_DMISS];
- cmp = &env->spr[SPR_DCMP];
- }
- qemu_log("6xx %sTLB miss: %cM " TARGET_FMT_lx " %cC "
- TARGET_FMT_lx " H1 " TARGET_FMT_lx " H2 "
- TARGET_FMT_lx " %08x\n", es, en, *miss, en, *cmp,
- env->spr[SPR_HASH1], env->spr[SPR_HASH2],
- env->error_code);
- }
-#endif
- msr |= env->crf[0] << 28;
- msr |= env->error_code; /* key, D/I, S/L bits */
- /* Set way using a LRU mechanism */
- msr |= ((env->last_way + 1) & (env->nb_ways - 1)) << 17;
- break;
- case POWERPC_EXCP_74xx:
- tlb_miss_74xx:
-#if defined(DEBUG_SOFTWARE_TLB)
- if (qemu_log_enabled()) {
- const char *es;
- target_ulong *miss, *cmp;
- int en;
-
- if (excp == POWERPC_EXCP_IFTLB) {
- es = "I";
- en = 'I';
- miss = &env->spr[SPR_TLBMISS];
- cmp = &env->spr[SPR_PTEHI];
- } else {
- if (excp == POWERPC_EXCP_DLTLB) {
- es = "DL";
- } else {
- es = "DS";
- }
- en = 'D';
- miss = &env->spr[SPR_TLBMISS];
- cmp = &env->spr[SPR_PTEHI];
- }
- qemu_log("74xx %sTLB miss: %cM " TARGET_FMT_lx " %cC "
- TARGET_FMT_lx " %08x\n", es, en, *miss, en, *cmp,
- env->error_code);
- }
-#endif
- msr |= env->error_code; /* key bit */
- break;
- default:
- cpu_abort(env, "Invalid data store TLB miss exception\n");
- break;
- }
- goto store_next;
- case POWERPC_EXCP_FPA: /* Floating-point assist exception */
- /* XXX: TODO */
- cpu_abort(env, "Floating point assist exception "
- "is not implemented yet !\n");
- goto store_next;
- case POWERPC_EXCP_DABR: /* Data address breakpoint */
- /* XXX: TODO */
- cpu_abort(env, "DABR exception is not implemented yet !\n");
- goto store_next;
- case POWERPC_EXCP_IABR: /* Instruction address breakpoint */
- /* XXX: TODO */
- cpu_abort(env, "IABR exception is not implemented yet !\n");
- goto store_next;
- case POWERPC_EXCP_SMI: /* System management interrupt */
- /* XXX: TODO */
- cpu_abort(env, "SMI exception is not implemented yet !\n");
- goto store_next;
- case POWERPC_EXCP_THERM: /* Thermal interrupt */
- /* XXX: TODO */
- cpu_abort(env, "Thermal management exception "
- "is not implemented yet !\n");
- goto store_next;
- case POWERPC_EXCP_PERFM: /* Embedded performance monitor interrupt */
- if (lpes1 == 0) {
- new_msr |= (target_ulong)MSR_HVB;
- }
- /* XXX: TODO */
- cpu_abort(env,
- "Performance counter exception is not implemented yet !\n");
- goto store_next;
- case POWERPC_EXCP_VPUA: /* Vector assist exception */
- /* XXX: TODO */
- cpu_abort(env, "VPU assist exception is not implemented yet !\n");
- goto store_next;
- case POWERPC_EXCP_SOFTP: /* Soft patch exception */
- /* XXX: TODO */
- cpu_abort(env,
- "970 soft-patch exception is not implemented yet !\n");
- goto store_next;
- case POWERPC_EXCP_MAINT: /* Maintenance exception */
- /* XXX: TODO */
- cpu_abort(env,
- "970 maintenance exception is not implemented yet !\n");
- goto store_next;
- case POWERPC_EXCP_MEXTBR: /* Maskable external breakpoint */
- /* XXX: TODO */
- cpu_abort(env, "Maskable external exception "
- "is not implemented yet !\n");
- goto store_next;
- case POWERPC_EXCP_NMEXTBR: /* Non maskable external breakpoint */
- /* XXX: TODO */
- cpu_abort(env, "Non maskable external exception "
- "is not implemented yet !\n");
- goto store_next;
- default:
- excp_invalid:
- cpu_abort(env, "Invalid PowerPC exception %d. Aborting\n", excp);
- break;
- store_current:
- /* save current instruction location */
- env->spr[srr0] = env->nip - 4;
- break;
- store_next:
- /* save next instruction location */
- env->spr[srr0] = env->nip;
- break;
- }
- /* Save MSR */
- env->spr[srr1] = msr;
- /* If any alternate SRR register are defined, duplicate saved values */
- if (asrr0 != -1) {
- env->spr[asrr0] = env->spr[srr0];
- }
- if (asrr1 != -1) {
- env->spr[asrr1] = env->spr[srr1];
- }
- /* If we disactivated any translation, flush TLBs */
- if (msr & ((1 << MSR_IR) | (1 << MSR_DR))) {
- tlb_flush(env, 1);
- }
-
- if (msr_ile) {
- new_msr |= (target_ulong)1 << MSR_LE;
- }
-
- /* Jump to handler */
- vector = env->excp_vectors[excp];
- if (vector == (target_ulong)-1ULL) {
- cpu_abort(env, "Raised an exception without defined vector %d\n",
- excp);
- }
- vector |= env->excp_prefix;
-#if defined(TARGET_PPC64)
- if (excp_model == POWERPC_EXCP_BOOKE) {
- if (!msr_icm) {
- vector = (uint32_t)vector;
- } else {
- new_msr |= (target_ulong)1 << MSR_CM;
- }
- } else {
- if (!msr_isf && !(env->mmu_model & POWERPC_MMU_64)) {
- vector = (uint32_t)vector;
- } else {
- new_msr |= (target_ulong)1 << MSR_SF;
- }
- }
-#endif
- /* XXX: we don't use hreg_store_msr here as already have treated
- * any special case that could occur. Just store MSR and update hflags
- */
- env->msr = new_msr & env->msr_mask;
- hreg_compute_hflags(env);
- env->nip = vector;
- /* Reset exception state */
- env->exception_index = POWERPC_EXCP_NONE;
- env->error_code = 0;
-
- if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
- (env->mmu_model == POWERPC_MMU_BOOKE206)) {
- /* XXX: The BookE changes address space when switching modes,
- we should probably implement that as different MMU indexes,
- but for the moment we do it the slow way and flush all. */
- tlb_flush(env, 1);
- }
-}
-
-void do_interrupt(CPUPPCState *env)
-{
- powerpc_excp(env, env->excp_model, env->exception_index);
-}
-
-void ppc_hw_interrupt(CPUPPCState *env)
-{
- int hdice;
-
-#if 0
- qemu_log_mask(CPU_LOG_INT, "%s: %p pending %08x req %08x me %d ee %d\n",
- __func__, env, env->pending_interrupts,
- env->interrupt_request, (int)msr_me, (int)msr_ee);
-#endif
- /* External reset */
- if (env->pending_interrupts & (1 << PPC_INTERRUPT_RESET)) {
- env->pending_interrupts &= ~(1 << PPC_INTERRUPT_RESET);
- powerpc_excp(env, env->excp_model, POWERPC_EXCP_RESET);
- return;
- }
- /* Machine check exception */
- if (env->pending_interrupts & (1 << PPC_INTERRUPT_MCK)) {
- env->pending_interrupts &= ~(1 << PPC_INTERRUPT_MCK);
- powerpc_excp(env, env->excp_model, POWERPC_EXCP_MCHECK);
- return;
- }
-#if 0 /* TODO */
- /* External debug exception */
- if (env->pending_interrupts & (1 << PPC_INTERRUPT_DEBUG)) {
- env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DEBUG);
- powerpc_excp(env, env->excp_model, POWERPC_EXCP_DEBUG);
- return;
- }
-#endif
- if (0) {
- /* XXX: find a suitable condition to enable the hypervisor mode */
- hdice = env->spr[SPR_LPCR] & 1;
- } else {
- hdice = 0;
- }
- if ((msr_ee != 0 || msr_hv == 0 || msr_pr != 0) && hdice != 0) {
- /* Hypervisor decrementer exception */
- if (env->pending_interrupts & (1 << PPC_INTERRUPT_HDECR)) {
- env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDECR);
- powerpc_excp(env, env->excp_model, POWERPC_EXCP_HDECR);
- return;
- }
- }
- if (msr_ce != 0) {
- /* External critical interrupt */
- if (env->pending_interrupts & (1 << PPC_INTERRUPT_CEXT)) {
- /* Taking a critical external interrupt does not clear the external
- * critical interrupt status
- */
-#if 0
- env->pending_interrupts &= ~(1 << PPC_INTERRUPT_CEXT);
-#endif
- powerpc_excp(env, env->excp_model, POWERPC_EXCP_CRITICAL);
- return;
- }
- }
- if (msr_ee != 0) {
- /* Watchdog timer on embedded PowerPC */
- if (env->pending_interrupts & (1 << PPC_INTERRUPT_WDT)) {
- env->pending_interrupts &= ~(1 << PPC_INTERRUPT_WDT);
- powerpc_excp(env, env->excp_model, POWERPC_EXCP_WDT);
- return;
- }
- if (env->pending_interrupts & (1 << PPC_INTERRUPT_CDOORBELL)) {
- env->pending_interrupts &= ~(1 << PPC_INTERRUPT_CDOORBELL);
- powerpc_excp(env, env->excp_model, POWERPC_EXCP_DOORCI);
- return;
- }
- /* Fixed interval timer on embedded PowerPC */
- if (env->pending_interrupts & (1 << PPC_INTERRUPT_FIT)) {
- env->pending_interrupts &= ~(1 << PPC_INTERRUPT_FIT);
- powerpc_excp(env, env->excp_model, POWERPC_EXCP_FIT);
- return;
- }
- /* Programmable interval timer on embedded PowerPC */
- if (env->pending_interrupts & (1 << PPC_INTERRUPT_PIT)) {
- env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PIT);
- powerpc_excp(env, env->excp_model, POWERPC_EXCP_PIT);
- return;
- }
- /* Decrementer exception */
- if (env->pending_interrupts & (1 << PPC_INTERRUPT_DECR)) {
- env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DECR);
- powerpc_excp(env, env->excp_model, POWERPC_EXCP_DECR);
- return;
- }
- /* External interrupt */
- if (env->pending_interrupts & (1 << PPC_INTERRUPT_EXT)) {
- /* Taking an external interrupt does not clear the external
- * interrupt status
- */
-#if 0
- env->pending_interrupts &= ~(1 << PPC_INTERRUPT_EXT);
-#endif
- powerpc_excp(env, env->excp_model, POWERPC_EXCP_EXTERNAL);
- return;
- }
- if (env->pending_interrupts & (1 << PPC_INTERRUPT_DOORBELL)) {
- env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DOORBELL);
- powerpc_excp(env, env->excp_model, POWERPC_EXCP_DOORI);
- return;
- }
- if (env->pending_interrupts & (1 << PPC_INTERRUPT_PERFM)) {
- env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PERFM);
- powerpc_excp(env, env->excp_model, POWERPC_EXCP_PERFM);
- return;
- }
- /* Thermal interrupt */
- if (env->pending_interrupts & (1 << PPC_INTERRUPT_THERM)) {
- env->pending_interrupts &= ~(1 << PPC_INTERRUPT_THERM);
- powerpc_excp(env, env->excp_model, POWERPC_EXCP_THERM);
- return;
- }
- }
-}
-#endif /* !CONFIG_USER_ONLY */
-
-void cpu_dump_rfi(target_ulong RA, target_ulong msr)
-{
- qemu_log("Return from exception at " TARGET_FMT_lx " with flags "
- TARGET_FMT_lx "\n", RA, msr);
-}
-
PowerPCCPU *cpu_ppc_init(const char *cpu_model)
{
PowerPCCPU *cpu;
--
1.6.0.2
^ permalink raw reply related [flat|nested] 89+ messages in thread
* [Qemu-devel] [PATCH 06/72] ppc: Split FPU and SPE ops
2012-06-23 23:06 [Qemu-devel] [PULL 00/72] ppc patch queue 2012-06-24 Alexander Graf
` (4 preceding siblings ...)
2012-06-23 23:06 ` [Qemu-devel] [PATCH 05/72] ppc: Move exception helpers from helper.c to excp_helper.c Alexander Graf
@ 2012-06-23 23:06 ` Alexander Graf
2012-06-23 23:06 ` [Qemu-devel] [PATCH 07/72] ppc: Avoid AREG0 for FPU and SPE helpers Alexander Graf
` (66 subsequent siblings)
72 siblings, 0 replies; 89+ messages in thread
From: Alexander Graf @ 2012-06-23 23:06 UTC (permalink / raw)
To: qemu-devel qemu-devel
Cc: Blue Swirl, qemu-ppc Mailing List, Andreas Färber,
Aurelien Jarno
From: Blue Swirl <blauwirbel@gmail.com>
Move FPU and SPE helpers from op_helper.c to fpu_helper.c.
Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Andreas Färber <afaerber@suse.de>
Signed-off-by: Alexander Graf <agraf@suse.de>
---
target-ppc/Makefile.objs | 2 +
target-ppc/fpu_helper.c | 1731 ++++++++++++++++++++++++++++++++++++++++++++++
target-ppc/op_helper.c | 1710 ---------------------------------------------
3 files changed, 1733 insertions(+), 1710 deletions(-)
create mode 100644 target-ppc/fpu_helper.c
diff --git a/target-ppc/Makefile.objs b/target-ppc/Makefile.objs
index a02b7bc..dde916c 100644
--- a/target-ppc/Makefile.objs
+++ b/target-ppc/Makefile.objs
@@ -3,5 +3,7 @@ obj-$(CONFIG_SOFTMMU) += machine.o
obj-$(CONFIG_KVM) += kvm.o kvm_ppc.o
obj-y += op_helper.o helper.o
obj-y += excp_helper.o
+obj-y += fpu_helper.o
+$(obj)/fpu_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
$(obj)/op_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
diff --git a/target-ppc/fpu_helper.c b/target-ppc/fpu_helper.c
new file mode 100644
index 0000000..be965d1
--- /dev/null
+++ b/target-ppc/fpu_helper.c
@@ -0,0 +1,1731 @@
+/*
+ * PowerPC floating point and SPE emulation helpers for QEMU.
+ *
+ * Copyright (c) 2003-2007 Jocelyn Mayer
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "cpu.h"
+#include "dyngen-exec.h"
+#include "helper.h"
+
+/*****************************************************************************/
+/* Floating point operations helpers */
+uint64_t helper_float32_to_float64(uint32_t arg)
+{
+ CPU_FloatU f;
+ CPU_DoubleU d;
+
+ f.l = arg;
+ d.d = float32_to_float64(f.f, &env->fp_status);
+ return d.ll;
+}
+
+uint32_t helper_float64_to_float32(uint64_t arg)
+{
+ CPU_FloatU f;
+ CPU_DoubleU d;
+
+ d.ll = arg;
+ f.f = float64_to_float32(d.d, &env->fp_status);
+ return f.l;
+}
+
+static inline int isden(float64 d)
+{
+ CPU_DoubleU u;
+
+ u.d = d;
+
+ return ((u.ll >> 52) & 0x7FF) == 0;
+}
+
+uint32_t helper_compute_fprf(uint64_t arg, uint32_t set_fprf)
+{
+ CPU_DoubleU farg;
+ int isneg;
+ int ret;
+
+ farg.ll = arg;
+ isneg = float64_is_neg(farg.d);
+ if (unlikely(float64_is_any_nan(farg.d))) {
+ if (float64_is_signaling_nan(farg.d)) {
+ /* Signaling NaN: flags are undefined */
+ ret = 0x00;
+ } else {
+ /* Quiet NaN */
+ ret = 0x11;
+ }
+ } else if (unlikely(float64_is_infinity(farg.d))) {
+ /* +/- infinity */
+ if (isneg) {
+ ret = 0x09;
+ } else {
+ ret = 0x05;
+ }
+ } else {
+ if (float64_is_zero(farg.d)) {
+ /* +/- zero */
+ if (isneg) {
+ ret = 0x12;
+ } else {
+ ret = 0x02;
+ }
+ } else {
+ if (isden(farg.d)) {
+ /* Denormalized numbers */
+ ret = 0x10;
+ } else {
+ /* Normalized numbers */
+ ret = 0x00;
+ }
+ if (isneg) {
+ ret |= 0x08;
+ } else {
+ ret |= 0x04;
+ }
+ }
+ }
+ if (set_fprf) {
+ /* We update FPSCR_FPRF */
+ env->fpscr &= ~(0x1F << FPSCR_FPRF);
+ env->fpscr |= ret << FPSCR_FPRF;
+ }
+ /* We just need fpcc to update Rc1 */
+ return ret & 0xF;
+}
+
+/* Floating-point invalid operations exception */
+static inline uint64_t fload_invalid_op_excp(int op)
+{
+ uint64_t ret = 0;
+ int ve;
+
+ ve = fpscr_ve;
+ switch (op) {
+ case POWERPC_EXCP_FP_VXSNAN:
+ env->fpscr |= 1 << FPSCR_VXSNAN;
+ break;
+ case POWERPC_EXCP_FP_VXSOFT:
+ env->fpscr |= 1 << FPSCR_VXSOFT;
+ break;
+ case POWERPC_EXCP_FP_VXISI:
+ /* Magnitude subtraction of infinities */
+ env->fpscr |= 1 << FPSCR_VXISI;
+ goto update_arith;
+ case POWERPC_EXCP_FP_VXIDI:
+ /* Division of infinity by infinity */
+ env->fpscr |= 1 << FPSCR_VXIDI;
+ goto update_arith;
+ case POWERPC_EXCP_FP_VXZDZ:
+ /* Division of zero by zero */
+ env->fpscr |= 1 << FPSCR_VXZDZ;
+ goto update_arith;
+ case POWERPC_EXCP_FP_VXIMZ:
+ /* Multiplication of zero by infinity */
+ env->fpscr |= 1 << FPSCR_VXIMZ;
+ goto update_arith;
+ case POWERPC_EXCP_FP_VXVC:
+ /* Ordered comparison of NaN */
+ env->fpscr |= 1 << FPSCR_VXVC;
+ env->fpscr &= ~(0xF << FPSCR_FPCC);
+ env->fpscr |= 0x11 << FPSCR_FPCC;
+ /* We must update the target FPR before raising the exception */
+ if (ve != 0) {
+ env->exception_index = POWERPC_EXCP_PROGRAM;
+ env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_VXVC;
+ /* Update the floating-point enabled exception summary */
+ env->fpscr |= 1 << FPSCR_FEX;
+ /* Exception is differed */
+ ve = 0;
+ }
+ break;
+ case POWERPC_EXCP_FP_VXSQRT:
+ /* Square root of a negative number */
+ env->fpscr |= 1 << FPSCR_VXSQRT;
+ update_arith:
+ env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
+ if (ve == 0) {
+ /* Set the result to quiet NaN */
+ ret = 0x7FF8000000000000ULL;
+ env->fpscr &= ~(0xF << FPSCR_FPCC);
+ env->fpscr |= 0x11 << FPSCR_FPCC;
+ }
+ break;
+ case POWERPC_EXCP_FP_VXCVI:
+ /* Invalid conversion */
+ env->fpscr |= 1 << FPSCR_VXCVI;
+ env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
+ if (ve == 0) {
+ /* Set the result to quiet NaN */
+ ret = 0x7FF8000000000000ULL;
+ env->fpscr &= ~(0xF << FPSCR_FPCC);
+ env->fpscr |= 0x11 << FPSCR_FPCC;
+ }
+ break;
+ }
+ /* Update the floating-point invalid operation summary */
+ env->fpscr |= 1 << FPSCR_VX;
+ /* Update the floating-point exception summary */
+ env->fpscr |= 1 << FPSCR_FX;
+ if (ve != 0) {
+ /* Update the floating-point enabled exception summary */
+ env->fpscr |= 1 << FPSCR_FEX;
+ if (msr_fe0 != 0 || msr_fe1 != 0) {
+ helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
+ POWERPC_EXCP_FP | op);
+ }
+ }
+ return ret;
+}
+
+static inline void float_zero_divide_excp(void)
+{
+ env->fpscr |= 1 << FPSCR_ZX;
+ env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
+ /* Update the floating-point exception summary */
+ env->fpscr |= 1 << FPSCR_FX;
+ if (fpscr_ze != 0) {
+ /* Update the floating-point enabled exception summary */
+ env->fpscr |= 1 << FPSCR_FEX;
+ if (msr_fe0 != 0 || msr_fe1 != 0) {
+ helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
+ POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX);
+ }
+ }
+}
+
+static inline void float_overflow_excp(void)
+{
+ env->fpscr |= 1 << FPSCR_OX;
+ /* Update the floating-point exception summary */
+ env->fpscr |= 1 << FPSCR_FX;
+ if (fpscr_oe != 0) {
+ /* XXX: should adjust the result */
+ /* Update the floating-point enabled exception summary */
+ env->fpscr |= 1 << FPSCR_FEX;
+ /* We must update the target FPR before raising the exception */
+ env->exception_index = POWERPC_EXCP_PROGRAM;
+ env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_OX;
+ } else {
+ env->fpscr |= 1 << FPSCR_XX;
+ env->fpscr |= 1 << FPSCR_FI;
+ }
+}
+
+static inline void float_underflow_excp(void)
+{
+ env->fpscr |= 1 << FPSCR_UX;
+ /* Update the floating-point exception summary */
+ env->fpscr |= 1 << FPSCR_FX;
+ if (fpscr_ue != 0) {
+ /* XXX: should adjust the result */
+ /* Update the floating-point enabled exception summary */
+ env->fpscr |= 1 << FPSCR_FEX;
+ /* We must update the target FPR before raising the exception */
+ env->exception_index = POWERPC_EXCP_PROGRAM;
+ env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_UX;
+ }
+}
+
+static inline void float_inexact_excp(void)
+{
+ env->fpscr |= 1 << FPSCR_XX;
+ /* Update the floating-point exception summary */
+ env->fpscr |= 1 << FPSCR_FX;
+ if (fpscr_xe != 0) {
+ /* Update the floating-point enabled exception summary */
+ env->fpscr |= 1 << FPSCR_FEX;
+ /* We must update the target FPR before raising the exception */
+ env->exception_index = POWERPC_EXCP_PROGRAM;
+ env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_XX;
+ }
+}
+
+static inline void fpscr_set_rounding_mode(void)
+{
+ int rnd_type;
+
+ /* Set rounding mode */
+ switch (fpscr_rn) {
+ case 0:
+ /* Best approximation (round to nearest) */
+ rnd_type = float_round_nearest_even;
+ break;
+ case 1:
+ /* Smaller magnitude (round toward zero) */
+ rnd_type = float_round_to_zero;
+ break;
+ case 2:
+ /* Round toward +infinite */
+ rnd_type = float_round_up;
+ break;
+ default:
+ case 3:
+ /* Round toward -infinite */
+ rnd_type = float_round_down;
+ break;
+ }
+ set_float_rounding_mode(rnd_type, &env->fp_status);
+}
+
+void helper_fpscr_clrbit(uint32_t bit)
+{
+ int prev;
+
+ prev = (env->fpscr >> bit) & 1;
+ env->fpscr &= ~(1 << bit);
+ if (prev == 1) {
+ switch (bit) {
+ case FPSCR_RN1:
+ case FPSCR_RN:
+ fpscr_set_rounding_mode();
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+void helper_fpscr_setbit(uint32_t bit)
+{
+ int prev;
+
+ prev = (env->fpscr >> bit) & 1;
+ env->fpscr |= 1 << bit;
+ if (prev == 0) {
+ switch (bit) {
+ case FPSCR_VX:
+ env->fpscr |= 1 << FPSCR_FX;
+ if (fpscr_ve) {
+ goto raise_ve;
+ }
+ case FPSCR_OX:
+ env->fpscr |= 1 << FPSCR_FX;
+ if (fpscr_oe) {
+ goto raise_oe;
+ }
+ break;
+ case FPSCR_UX:
+ env->fpscr |= 1 << FPSCR_FX;
+ if (fpscr_ue) {
+ goto raise_ue;
+ }
+ break;
+ case FPSCR_ZX:
+ env->fpscr |= 1 << FPSCR_FX;
+ if (fpscr_ze) {
+ goto raise_ze;
+ }
+ break;
+ case FPSCR_XX:
+ env->fpscr |= 1 << FPSCR_FX;
+ if (fpscr_xe) {
+ goto raise_xe;
+ }
+ break;
+ case FPSCR_VXSNAN:
+ case FPSCR_VXISI:
+ case FPSCR_VXIDI:
+ case FPSCR_VXZDZ:
+ case FPSCR_VXIMZ:
+ case FPSCR_VXVC:
+ case FPSCR_VXSOFT:
+ case FPSCR_VXSQRT:
+ case FPSCR_VXCVI:
+ env->fpscr |= 1 << FPSCR_VX;
+ env->fpscr |= 1 << FPSCR_FX;
+ if (fpscr_ve != 0) {
+ goto raise_ve;
+ }
+ break;
+ case FPSCR_VE:
+ if (fpscr_vx != 0) {
+ raise_ve:
+ env->error_code = POWERPC_EXCP_FP;
+ if (fpscr_vxsnan) {
+ env->error_code |= POWERPC_EXCP_FP_VXSNAN;
+ }
+ if (fpscr_vxisi) {
+ env->error_code |= POWERPC_EXCP_FP_VXISI;
+ }
+ if (fpscr_vxidi) {
+ env->error_code |= POWERPC_EXCP_FP_VXIDI;
+ }
+ if (fpscr_vxzdz) {
+ env->error_code |= POWERPC_EXCP_FP_VXZDZ;
+ }
+ if (fpscr_vximz) {
+ env->error_code |= POWERPC_EXCP_FP_VXIMZ;
+ }
+ if (fpscr_vxvc) {
+ env->error_code |= POWERPC_EXCP_FP_VXVC;
+ }
+ if (fpscr_vxsoft) {
+ env->error_code |= POWERPC_EXCP_FP_VXSOFT;
+ }
+ if (fpscr_vxsqrt) {
+ env->error_code |= POWERPC_EXCP_FP_VXSQRT;
+ }
+ if (fpscr_vxcvi) {
+ env->error_code |= POWERPC_EXCP_FP_VXCVI;
+ }
+ goto raise_excp;
+ }
+ break;
+ case FPSCR_OE:
+ if (fpscr_ox != 0) {
+ raise_oe:
+ env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_OX;
+ goto raise_excp;
+ }
+ break;
+ case FPSCR_UE:
+ if (fpscr_ux != 0) {
+ raise_ue:
+ env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_UX;
+ goto raise_excp;
+ }
+ break;
+ case FPSCR_ZE:
+ if (fpscr_zx != 0) {
+ raise_ze:
+ env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX;
+ goto raise_excp;
+ }
+ break;
+ case FPSCR_XE:
+ if (fpscr_xx != 0) {
+ raise_xe:
+ env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_XX;
+ goto raise_excp;
+ }
+ break;
+ case FPSCR_RN1:
+ case FPSCR_RN:
+ fpscr_set_rounding_mode();
+ break;
+ default:
+ break;
+ raise_excp:
+ /* Update the floating-point enabled exception summary */
+ env->fpscr |= 1 << FPSCR_FEX;
+ /* We have to update Rc1 before raising the exception */
+ env->exception_index = POWERPC_EXCP_PROGRAM;
+ break;
+ }
+ }
+}
+
+void helper_store_fpscr(uint64_t arg, uint32_t mask)
+{
+ /*
+ * We use only the 32 LSB of the incoming fpr
+ */
+ uint32_t prev, new;
+ int i;
+
+ prev = env->fpscr;
+ new = (uint32_t)arg;
+ new &= ~0x60000000;
+ new |= prev & 0x60000000;
+ for (i = 0; i < 8; i++) {
+ if (mask & (1 << i)) {
+ env->fpscr &= ~(0xF << (4 * i));
+ env->fpscr |= new & (0xF << (4 * i));
+ }
+ }
+ /* Update VX and FEX */
+ if (fpscr_ix != 0) {
+ env->fpscr |= 1 << FPSCR_VX;
+ } else {
+ env->fpscr &= ~(1 << FPSCR_VX);
+ }
+ if ((fpscr_ex & fpscr_eex) != 0) {
+ env->fpscr |= 1 << FPSCR_FEX;
+ env->exception_index = POWERPC_EXCP_PROGRAM;
+ /* XXX: we should compute it properly */
+ env->error_code = POWERPC_EXCP_FP;
+ } else {
+ env->fpscr &= ~(1 << FPSCR_FEX);
+ }
+ fpscr_set_rounding_mode();
+}
+
+void helper_float_check_status(void)
+{
+ if (env->exception_index == POWERPC_EXCP_PROGRAM &&
+ (env->error_code & POWERPC_EXCP_FP)) {
+ /* Differred floating-point exception after target FPR update */
+ if (msr_fe0 != 0 || msr_fe1 != 0) {
+ helper_raise_exception_err(env, env->exception_index,
+ env->error_code);
+ }
+ } else {
+ int status = get_float_exception_flags(&env->fp_status);
+ if (status & float_flag_divbyzero) {
+ float_zero_divide_excp();
+ } else if (status & float_flag_overflow) {
+ float_overflow_excp();
+ } else if (status & float_flag_underflow) {
+ float_underflow_excp();
+ } else if (status & float_flag_inexact) {
+ float_inexact_excp();
+ }
+ }
+}
+
+void helper_reset_fpstatus(void)
+{
+ set_float_exception_flags(0, &env->fp_status);
+}
+
+/* fadd - fadd. */
+uint64_t helper_fadd(uint64_t arg1, uint64_t arg2)
+{
+ CPU_DoubleU farg1, farg2;
+
+ farg1.ll = arg1;
+ farg2.ll = arg2;
+
+ if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d) &&
+ float64_is_neg(farg1.d) != float64_is_neg(farg2.d))) {
+ /* Magnitude subtraction of infinities */
+ farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
+ } else {
+ if (unlikely(float64_is_signaling_nan(farg1.d) ||
+ float64_is_signaling_nan(farg2.d))) {
+ /* sNaN addition */
+ fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
+ }
+ farg1.d = float64_add(farg1.d, farg2.d, &env->fp_status);
+ }
+
+ return farg1.ll;
+}
+
+/* fsub - fsub. */
+uint64_t helper_fsub(uint64_t arg1, uint64_t arg2)
+{
+ CPU_DoubleU farg1, farg2;
+
+ farg1.ll = arg1;
+ farg2.ll = arg2;
+
+ if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d) &&
+ float64_is_neg(farg1.d) == float64_is_neg(farg2.d))) {
+ /* Magnitude subtraction of infinities */
+ farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
+ } else {
+ if (unlikely(float64_is_signaling_nan(farg1.d) ||
+ float64_is_signaling_nan(farg2.d))) {
+ /* sNaN subtraction */
+ fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
+ }
+ farg1.d = float64_sub(farg1.d, farg2.d, &env->fp_status);
+ }
+
+ return farg1.ll;
+}
+
+/* fmul - fmul. */
+uint64_t helper_fmul(uint64_t arg1, uint64_t arg2)
+{
+ CPU_DoubleU farg1, farg2;
+
+ farg1.ll = arg1;
+ farg2.ll = arg2;
+
+ if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
+ (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
+ /* Multiplication of zero by infinity */
+ farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
+ } else {
+ if (unlikely(float64_is_signaling_nan(farg1.d) ||
+ float64_is_signaling_nan(farg2.d))) {
+ /* sNaN multiplication */
+ fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
+ }
+ farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
+ }
+
+ return farg1.ll;
+}
+
+/* fdiv - fdiv. */
+uint64_t helper_fdiv(uint64_t arg1, uint64_t arg2)
+{
+ CPU_DoubleU farg1, farg2;
+
+ farg1.ll = arg1;
+ farg2.ll = arg2;
+
+ if (unlikely(float64_is_infinity(farg1.d) &&
+ float64_is_infinity(farg2.d))) {
+ /* Division of infinity by infinity */
+ farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIDI);
+ } else if (unlikely(float64_is_zero(farg1.d) && float64_is_zero(farg2.d))) {
+ /* Division of zero by zero */
+ farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXZDZ);
+ } else {
+ if (unlikely(float64_is_signaling_nan(farg1.d) ||
+ float64_is_signaling_nan(farg2.d))) {
+ /* sNaN division */
+ fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
+ }
+ farg1.d = float64_div(farg1.d, farg2.d, &env->fp_status);
+ }
+
+ return farg1.ll;
+}
+
+/* fabs */
+uint64_t helper_fabs(uint64_t arg)
+{
+ CPU_DoubleU farg;
+
+ farg.ll = arg;
+ farg.d = float64_abs(farg.d);
+ return farg.ll;
+}
+
+/* fnabs */
+uint64_t helper_fnabs(uint64_t arg)
+{
+ CPU_DoubleU farg;
+
+ farg.ll = arg;
+ farg.d = float64_abs(farg.d);
+ farg.d = float64_chs(farg.d);
+ return farg.ll;
+}
+
+/* fneg */
+uint64_t helper_fneg(uint64_t arg)
+{
+ CPU_DoubleU farg;
+
+ farg.ll = arg;
+ farg.d = float64_chs(farg.d);
+ return farg.ll;
+}
+
+/* fctiw - fctiw. */
+uint64_t helper_fctiw(uint64_t arg)
+{
+ CPU_DoubleU farg;
+
+ farg.ll = arg;
+
+ if (unlikely(float64_is_signaling_nan(farg.d))) {
+ /* sNaN conversion */
+ farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN |
+ POWERPC_EXCP_FP_VXCVI);
+ } else if (unlikely(float64_is_quiet_nan(farg.d) ||
+ float64_is_infinity(farg.d))) {
+ /* qNan / infinity conversion */
+ farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
+ } else {
+ farg.ll = float64_to_int32(farg.d, &env->fp_status);
+ /* XXX: higher bits are not supposed to be significant.
+ * to make tests easier, return the same as a real PowerPC 750
+ */
+ farg.ll |= 0xFFF80000ULL << 32;
+ }
+ return farg.ll;
+}
+
+/* fctiwz - fctiwz. */
+uint64_t helper_fctiwz(uint64_t arg)
+{
+ CPU_DoubleU farg;
+
+ farg.ll = arg;
+
+ if (unlikely(float64_is_signaling_nan(farg.d))) {
+ /* sNaN conversion */
+ farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN |
+ POWERPC_EXCP_FP_VXCVI);
+ } else if (unlikely(float64_is_quiet_nan(farg.d) ||
+ float64_is_infinity(farg.d))) {
+ /* qNan / infinity conversion */
+ farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
+ } else {
+ farg.ll = float64_to_int32_round_to_zero(farg.d, &env->fp_status);
+ /* XXX: higher bits are not supposed to be significant.
+ * to make tests easier, return the same as a real PowerPC 750
+ */
+ farg.ll |= 0xFFF80000ULL << 32;
+ }
+ return farg.ll;
+}
+
+#if defined(TARGET_PPC64)
+/* fcfid - fcfid. */
+uint64_t helper_fcfid(uint64_t arg)
+{
+ CPU_DoubleU farg;
+
+ farg.d = int64_to_float64(arg, &env->fp_status);
+ return farg.ll;
+}
+
+/* fctid - fctid. */
+uint64_t helper_fctid(uint64_t arg)
+{
+ CPU_DoubleU farg;
+
+ farg.ll = arg;
+
+ if (unlikely(float64_is_signaling_nan(farg.d))) {
+ /* sNaN conversion */
+ farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN |
+ POWERPC_EXCP_FP_VXCVI);
+ } else if (unlikely(float64_is_quiet_nan(farg.d) ||
+ float64_is_infinity(farg.d))) {
+ /* qNan / infinity conversion */
+ farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
+ } else {
+ farg.ll = float64_to_int64(farg.d, &env->fp_status);
+ }
+ return farg.ll;
+}
+
+/* fctidz - fctidz. */
+uint64_t helper_fctidz(uint64_t arg)
+{
+ CPU_DoubleU farg;
+
+ farg.ll = arg;
+
+ if (unlikely(float64_is_signaling_nan(farg.d))) {
+ /* sNaN conversion */
+ farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN |
+ POWERPC_EXCP_FP_VXCVI);
+ } else if (unlikely(float64_is_quiet_nan(farg.d) ||
+ float64_is_infinity(farg.d))) {
+ /* qNan / infinity conversion */
+ farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
+ } else {
+ farg.ll = float64_to_int64_round_to_zero(farg.d, &env->fp_status);
+ }
+ return farg.ll;
+}
+
+#endif
+
+static inline uint64_t do_fri(uint64_t arg, int rounding_mode)
+{
+ CPU_DoubleU farg;
+
+ farg.ll = arg;
+
+ if (unlikely(float64_is_signaling_nan(farg.d))) {
+ /* sNaN round */
+ farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN |
+ POWERPC_EXCP_FP_VXCVI);
+ } else if (unlikely(float64_is_quiet_nan(farg.d) ||
+ float64_is_infinity(farg.d))) {
+ /* qNan / infinity round */
+ farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
+ } else {
+ set_float_rounding_mode(rounding_mode, &env->fp_status);
+ farg.ll = float64_round_to_int(farg.d, &env->fp_status);
+ /* Restore rounding mode from FPSCR */
+ fpscr_set_rounding_mode();
+ }
+ return farg.ll;
+}
+
+uint64_t helper_frin(uint64_t arg)
+{
+ return do_fri(arg, float_round_nearest_even);
+}
+
+uint64_t helper_friz(uint64_t arg)
+{
+ return do_fri(arg, float_round_to_zero);
+}
+
+uint64_t helper_frip(uint64_t arg)
+{
+ return do_fri(arg, float_round_up);
+}
+
+uint64_t helper_frim(uint64_t arg)
+{
+ return do_fri(arg, float_round_down);
+}
+
+/* fmadd - fmadd. */
+uint64_t helper_fmadd(uint64_t arg1, uint64_t arg2, uint64_t arg3)
+{
+ CPU_DoubleU farg1, farg2, farg3;
+
+ farg1.ll = arg1;
+ farg2.ll = arg2;
+ farg3.ll = arg3;
+
+ if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
+ (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
+ /* Multiplication of zero by infinity */
+ farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
+ } else {
+ if (unlikely(float64_is_signaling_nan(farg1.d) ||
+ float64_is_signaling_nan(farg2.d) ||
+ float64_is_signaling_nan(farg3.d))) {
+ /* sNaN operation */
+ fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
+ }
+ /* This is the way the PowerPC specification defines it */
+ float128 ft0_128, ft1_128;
+
+ ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
+ ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
+ ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
+ if (unlikely(float128_is_infinity(ft0_128) &&
+ float64_is_infinity(farg3.d) &&
+ float128_is_neg(ft0_128) != float64_is_neg(farg3.d))) {
+ /* Magnitude subtraction of infinities */
+ farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
+ } else {
+ ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
+ ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
+ farg1.d = float128_to_float64(ft0_128, &env->fp_status);
+ }
+ }
+
+ return farg1.ll;
+}
+
+/* fmsub - fmsub. */
+uint64_t helper_fmsub(uint64_t arg1, uint64_t arg2, uint64_t arg3)
+{
+ CPU_DoubleU farg1, farg2, farg3;
+
+ farg1.ll = arg1;
+ farg2.ll = arg2;
+ farg3.ll = arg3;
+
+ if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
+ (float64_is_zero(farg1.d) &&
+ float64_is_infinity(farg2.d)))) {
+ /* Multiplication of zero by infinity */
+ farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
+ } else {
+ if (unlikely(float64_is_signaling_nan(farg1.d) ||
+ float64_is_signaling_nan(farg2.d) ||
+ float64_is_signaling_nan(farg3.d))) {
+ /* sNaN operation */
+ fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
+ }
+ /* This is the way the PowerPC specification defines it */
+ float128 ft0_128, ft1_128;
+
+ ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
+ ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
+ ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
+ if (unlikely(float128_is_infinity(ft0_128) &&
+ float64_is_infinity(farg3.d) &&
+ float128_is_neg(ft0_128) == float64_is_neg(farg3.d))) {
+ /* Magnitude subtraction of infinities */
+ farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
+ } else {
+ ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
+ ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
+ farg1.d = float128_to_float64(ft0_128, &env->fp_status);
+ }
+ }
+ return farg1.ll;
+}
+
+/* fnmadd - fnmadd. */
+uint64_t helper_fnmadd(uint64_t arg1, uint64_t arg2, uint64_t arg3)
+{
+ CPU_DoubleU farg1, farg2, farg3;
+
+ farg1.ll = arg1;
+ farg2.ll = arg2;
+ farg3.ll = arg3;
+
+ if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
+ (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
+ /* Multiplication of zero by infinity */
+ farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
+ } else {
+ if (unlikely(float64_is_signaling_nan(farg1.d) ||
+ float64_is_signaling_nan(farg2.d) ||
+ float64_is_signaling_nan(farg3.d))) {
+ /* sNaN operation */
+ fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
+ }
+ /* This is the way the PowerPC specification defines it */
+ float128 ft0_128, ft1_128;
+
+ ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
+ ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
+ ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
+ if (unlikely(float128_is_infinity(ft0_128) &&
+ float64_is_infinity(farg3.d) &&
+ float128_is_neg(ft0_128) != float64_is_neg(farg3.d))) {
+ /* Magnitude subtraction of infinities */
+ farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
+ } else {
+ ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
+ ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
+ farg1.d = float128_to_float64(ft0_128, &env->fp_status);
+ }
+ if (likely(!float64_is_any_nan(farg1.d))) {
+ farg1.d = float64_chs(farg1.d);
+ }
+ }
+ return farg1.ll;
+}
+
+/* fnmsub - fnmsub. */
+uint64_t helper_fnmsub(uint64_t arg1, uint64_t arg2, uint64_t arg3)
+{
+ CPU_DoubleU farg1, farg2, farg3;
+
+ farg1.ll = arg1;
+ farg2.ll = arg2;
+ farg3.ll = arg3;
+
+ if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
+ (float64_is_zero(farg1.d) &&
+ float64_is_infinity(farg2.d)))) {
+ /* Multiplication of zero by infinity */
+ farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
+ } else {
+ if (unlikely(float64_is_signaling_nan(farg1.d) ||
+ float64_is_signaling_nan(farg2.d) ||
+ float64_is_signaling_nan(farg3.d))) {
+ /* sNaN operation */
+ fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
+ }
+ /* This is the way the PowerPC specification defines it */
+ float128 ft0_128, ft1_128;
+
+ ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
+ ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
+ ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
+ if (unlikely(float128_is_infinity(ft0_128) &&
+ float64_is_infinity(farg3.d) &&
+ float128_is_neg(ft0_128) == float64_is_neg(farg3.d))) {
+ /* Magnitude subtraction of infinities */
+ farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
+ } else {
+ ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
+ ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
+ farg1.d = float128_to_float64(ft0_128, &env->fp_status);
+ }
+ if (likely(!float64_is_any_nan(farg1.d))) {
+ farg1.d = float64_chs(farg1.d);
+ }
+ }
+ return farg1.ll;
+}
+
+/* frsp - frsp. */
+uint64_t helper_frsp(uint64_t arg)
+{
+ CPU_DoubleU farg;
+ float32 f32;
+
+ farg.ll = arg;
+
+ if (unlikely(float64_is_signaling_nan(farg.d))) {
+ /* sNaN square root */
+ fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
+ }
+ f32 = float64_to_float32(farg.d, &env->fp_status);
+ farg.d = float32_to_float64(f32, &env->fp_status);
+
+ return farg.ll;
+}
+
+/* fsqrt - fsqrt. */
+uint64_t helper_fsqrt(uint64_t arg)
+{
+ CPU_DoubleU farg;
+
+ farg.ll = arg;
+
+ if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) {
+ /* Square root of a negative nonzero number */
+ farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSQRT);
+ } else {
+ if (unlikely(float64_is_signaling_nan(farg.d))) {
+ /* sNaN square root */
+ fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
+ }
+ farg.d = float64_sqrt(farg.d, &env->fp_status);
+ }
+ return farg.ll;
+}
+
+/* fre - fre. */
+uint64_t helper_fre(uint64_t arg)
+{
+ CPU_DoubleU farg;
+
+ farg.ll = arg;
+
+ if (unlikely(float64_is_signaling_nan(farg.d))) {
+ /* sNaN reciprocal */
+ fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
+ }
+ farg.d = float64_div(float64_one, farg.d, &env->fp_status);
+ return farg.d;
+}
+
+/* fres - fres. */
+uint64_t helper_fres(uint64_t arg)
+{
+ CPU_DoubleU farg;
+ float32 f32;
+
+ farg.ll = arg;
+
+ if (unlikely(float64_is_signaling_nan(farg.d))) {
+ /* sNaN reciprocal */
+ fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
+ }
+ farg.d = float64_div(float64_one, farg.d, &env->fp_status);
+ f32 = float64_to_float32(farg.d, &env->fp_status);
+ farg.d = float32_to_float64(f32, &env->fp_status);
+
+ return farg.ll;
+}
+
+/* frsqrte - frsqrte. */
+uint64_t helper_frsqrte(uint64_t arg)
+{
+ CPU_DoubleU farg;
+ float32 f32;
+
+ farg.ll = arg;
+
+ if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) {
+ /* Reciprocal square root of a negative nonzero number */
+ farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSQRT);
+ } else {
+ if (unlikely(float64_is_signaling_nan(farg.d))) {
+ /* sNaN reciprocal square root */
+ fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
+ }
+ farg.d = float64_sqrt(farg.d, &env->fp_status);
+ farg.d = float64_div(float64_one, farg.d, &env->fp_status);
+ f32 = float64_to_float32(farg.d, &env->fp_status);
+ farg.d = float32_to_float64(f32, &env->fp_status);
+ }
+ return farg.ll;
+}
+
+/* fsel - fsel. */
+uint64_t helper_fsel(uint64_t arg1, uint64_t arg2, uint64_t arg3)
+{
+ CPU_DoubleU farg1;
+
+ farg1.ll = arg1;
+
+ if ((!float64_is_neg(farg1.d) || float64_is_zero(farg1.d)) &&
+ !float64_is_any_nan(farg1.d)) {
+ return arg2;
+ } else {
+ return arg3;
+ }
+}
+
+void helper_fcmpu(uint64_t arg1, uint64_t arg2, uint32_t crfD)
+{
+ CPU_DoubleU farg1, farg2;
+ uint32_t ret = 0;
+
+ farg1.ll = arg1;
+ farg2.ll = arg2;
+
+ if (unlikely(float64_is_any_nan(farg1.d) ||
+ float64_is_any_nan(farg2.d))) {
+ ret = 0x01UL;
+ } else if (float64_lt(farg1.d, farg2.d, &env->fp_status)) {
+ ret = 0x08UL;
+ } else if (!float64_le(farg1.d, farg2.d, &env->fp_status)) {
+ ret = 0x04UL;
+ } else {
+ ret = 0x02UL;
+ }
+
+ env->fpscr &= ~(0x0F << FPSCR_FPRF);
+ env->fpscr |= ret << FPSCR_FPRF;
+ env->crf[crfD] = ret;
+ if (unlikely(ret == 0x01UL
+ && (float64_is_signaling_nan(farg1.d) ||
+ float64_is_signaling_nan(farg2.d)))) {
+ /* sNaN comparison */
+ fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
+ }
+}
+
+void helper_fcmpo(uint64_t arg1, uint64_t arg2, uint32_t crfD)
+{
+ CPU_DoubleU farg1, farg2;
+ uint32_t ret = 0;
+
+ farg1.ll = arg1;
+ farg2.ll = arg2;
+
+ if (unlikely(float64_is_any_nan(farg1.d) ||
+ float64_is_any_nan(farg2.d))) {
+ ret = 0x01UL;
+ } else if (float64_lt(farg1.d, farg2.d, &env->fp_status)) {
+ ret = 0x08UL;
+ } else if (!float64_le(farg1.d, farg2.d, &env->fp_status)) {
+ ret = 0x04UL;
+ } else {
+ ret = 0x02UL;
+ }
+
+ env->fpscr &= ~(0x0F << FPSCR_FPRF);
+ env->fpscr |= ret << FPSCR_FPRF;
+ env->crf[crfD] = ret;
+ if (unlikely(ret == 0x01UL)) {
+ if (float64_is_signaling_nan(farg1.d) ||
+ float64_is_signaling_nan(farg2.d)) {
+ /* sNaN comparison */
+ fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN |
+ POWERPC_EXCP_FP_VXVC);
+ } else {
+ /* qNaN comparison */
+ fload_invalid_op_excp(POWERPC_EXCP_FP_VXVC);
+ }
+ }
+}
+
+/* Single-precision floating-point conversions */
+static inline uint32_t efscfsi(uint32_t val)
+{
+ CPU_FloatU u;
+
+ u.f = int32_to_float32(val, &env->vec_status);
+
+ return u.l;
+}
+
+static inline uint32_t efscfui(uint32_t val)
+{
+ CPU_FloatU u;
+
+ u.f = uint32_to_float32(val, &env->vec_status);
+
+ return u.l;
+}
+
+static inline int32_t efsctsi(uint32_t val)
+{
+ CPU_FloatU u;
+
+ u.l = val;
+ /* NaN are not treated the same way IEEE 754 does */
+ if (unlikely(float32_is_quiet_nan(u.f))) {
+ return 0;
+ }
+
+ return float32_to_int32(u.f, &env->vec_status);
+}
+
+static inline uint32_t efsctui(uint32_t val)
+{
+ CPU_FloatU u;
+
+ u.l = val;
+ /* NaN are not treated the same way IEEE 754 does */
+ if (unlikely(float32_is_quiet_nan(u.f))) {
+ return 0;
+ }
+
+ return float32_to_uint32(u.f, &env->vec_status);
+}
+
+static inline uint32_t efsctsiz(uint32_t val)
+{
+ CPU_FloatU u;
+
+ u.l = val;
+ /* NaN are not treated the same way IEEE 754 does */
+ if (unlikely(float32_is_quiet_nan(u.f))) {
+ return 0;
+ }
+
+ return float32_to_int32_round_to_zero(u.f, &env->vec_status);
+}
+
+static inline uint32_t efsctuiz(uint32_t val)
+{
+ CPU_FloatU u;
+
+ u.l = val;
+ /* NaN are not treated the same way IEEE 754 does */
+ if (unlikely(float32_is_quiet_nan(u.f))) {
+ return 0;
+ }
+
+ return float32_to_uint32_round_to_zero(u.f, &env->vec_status);
+}
+
+static inline uint32_t efscfsf(uint32_t val)
+{
+ CPU_FloatU u;
+ float32 tmp;
+
+ u.f = int32_to_float32(val, &env->vec_status);
+ tmp = int64_to_float32(1ULL << 32, &env->vec_status);
+ u.f = float32_div(u.f, tmp, &env->vec_status);
+
+ return u.l;
+}
+
+static inline uint32_t efscfuf(uint32_t val)
+{
+ CPU_FloatU u;
+ float32 tmp;
+
+ u.f = uint32_to_float32(val, &env->vec_status);
+ tmp = uint64_to_float32(1ULL << 32, &env->vec_status);
+ u.f = float32_div(u.f, tmp, &env->vec_status);
+
+ return u.l;
+}
+
+static inline uint32_t efsctsf(uint32_t val)
+{
+ CPU_FloatU u;
+ float32 tmp;
+
+ u.l = val;
+ /* NaN are not treated the same way IEEE 754 does */
+ if (unlikely(float32_is_quiet_nan(u.f))) {
+ return 0;
+ }
+ tmp = uint64_to_float32(1ULL << 32, &env->vec_status);
+ u.f = float32_mul(u.f, tmp, &env->vec_status);
+
+ return float32_to_int32(u.f, &env->vec_status);
+}
+
+static inline uint32_t efsctuf(uint32_t val)
+{
+ CPU_FloatU u;
+ float32 tmp;
+
+ u.l = val;
+ /* NaN are not treated the same way IEEE 754 does */
+ if (unlikely(float32_is_quiet_nan(u.f))) {
+ return 0;
+ }
+ tmp = uint64_to_float32(1ULL << 32, &env->vec_status);
+ u.f = float32_mul(u.f, tmp, &env->vec_status);
+
+ return float32_to_uint32(u.f, &env->vec_status);
+}
+
+#define HELPER_SPE_SINGLE_CONV(name) \
+ uint32_t helper_e##name(uint32_t val) \
+ { \
+ return e##name(val); \
+ }
+/* efscfsi */
+HELPER_SPE_SINGLE_CONV(fscfsi);
+/* efscfui */
+HELPER_SPE_SINGLE_CONV(fscfui);
+/* efscfuf */
+HELPER_SPE_SINGLE_CONV(fscfuf);
+/* efscfsf */
+HELPER_SPE_SINGLE_CONV(fscfsf);
+/* efsctsi */
+HELPER_SPE_SINGLE_CONV(fsctsi);
+/* efsctui */
+HELPER_SPE_SINGLE_CONV(fsctui);
+/* efsctsiz */
+HELPER_SPE_SINGLE_CONV(fsctsiz);
+/* efsctuiz */
+HELPER_SPE_SINGLE_CONV(fsctuiz);
+/* efsctsf */
+HELPER_SPE_SINGLE_CONV(fsctsf);
+/* efsctuf */
+HELPER_SPE_SINGLE_CONV(fsctuf);
+
+#define HELPER_SPE_VECTOR_CONV(name) \
+ uint64_t helper_ev##name(uint64_t val) \
+ { \
+ return ((uint64_t)e##name(val >> 32) << 32) | \
+ (uint64_t)e##name(val); \
+ }
+/* evfscfsi */
+HELPER_SPE_VECTOR_CONV(fscfsi);
+/* evfscfui */
+HELPER_SPE_VECTOR_CONV(fscfui);
+/* evfscfuf */
+HELPER_SPE_VECTOR_CONV(fscfuf);
+/* evfscfsf */
+HELPER_SPE_VECTOR_CONV(fscfsf);
+/* evfsctsi */
+HELPER_SPE_VECTOR_CONV(fsctsi);
+/* evfsctui */
+HELPER_SPE_VECTOR_CONV(fsctui);
+/* evfsctsiz */
+HELPER_SPE_VECTOR_CONV(fsctsiz);
+/* evfsctuiz */
+HELPER_SPE_VECTOR_CONV(fsctuiz);
+/* evfsctsf */
+HELPER_SPE_VECTOR_CONV(fsctsf);
+/* evfsctuf */
+HELPER_SPE_VECTOR_CONV(fsctuf);
+
+/* Single-precision floating-point arithmetic */
+static inline uint32_t efsadd(uint32_t op1, uint32_t op2)
+{
+ CPU_FloatU u1, u2;
+
+ u1.l = op1;
+ u2.l = op2;
+ u1.f = float32_add(u1.f, u2.f, &env->vec_status);
+ return u1.l;
+}
+
+static inline uint32_t efssub(uint32_t op1, uint32_t op2)
+{
+ CPU_FloatU u1, u2;
+
+ u1.l = op1;
+ u2.l = op2;
+ u1.f = float32_sub(u1.f, u2.f, &env->vec_status);
+ return u1.l;
+}
+
+static inline uint32_t efsmul(uint32_t op1, uint32_t op2)
+{
+ CPU_FloatU u1, u2;
+
+ u1.l = op1;
+ u2.l = op2;
+ u1.f = float32_mul(u1.f, u2.f, &env->vec_status);
+ return u1.l;
+}
+
+static inline uint32_t efsdiv(uint32_t op1, uint32_t op2)
+{
+ CPU_FloatU u1, u2;
+
+ u1.l = op1;
+ u2.l = op2;
+ u1.f = float32_div(u1.f, u2.f, &env->vec_status);
+ return u1.l;
+}
+
+#define HELPER_SPE_SINGLE_ARITH(name) \
+ uint32_t helper_e##name(uint32_t op1, uint32_t op2) \
+ { \
+ return e##name(op1, op2); \
+ }
+/* efsadd */
+HELPER_SPE_SINGLE_ARITH(fsadd);
+/* efssub */
+HELPER_SPE_SINGLE_ARITH(fssub);
+/* efsmul */
+HELPER_SPE_SINGLE_ARITH(fsmul);
+/* efsdiv */
+HELPER_SPE_SINGLE_ARITH(fsdiv);
+
+#define HELPER_SPE_VECTOR_ARITH(name) \
+ uint64_t helper_ev##name(uint64_t op1, uint64_t op2) \
+ { \
+ return ((uint64_t)e##name(op1 >> 32, op2 >> 32) << 32) | \
+ (uint64_t)e##name(op1, op2); \
+ }
+/* evfsadd */
+HELPER_SPE_VECTOR_ARITH(fsadd);
+/* evfssub */
+HELPER_SPE_VECTOR_ARITH(fssub);
+/* evfsmul */
+HELPER_SPE_VECTOR_ARITH(fsmul);
+/* evfsdiv */
+HELPER_SPE_VECTOR_ARITH(fsdiv);
+
+/* Single-precision floating-point comparisons */
+static inline uint32_t efscmplt(uint32_t op1, uint32_t op2)
+{
+ CPU_FloatU u1, u2;
+
+ u1.l = op1;
+ u2.l = op2;
+ return float32_lt(u1.f, u2.f, &env->vec_status) ? 4 : 0;
+}
+
+static inline uint32_t efscmpgt(uint32_t op1, uint32_t op2)
+{
+ CPU_FloatU u1, u2;
+
+ u1.l = op1;
+ u2.l = op2;
+ return float32_le(u1.f, u2.f, &env->vec_status) ? 0 : 4;
+}
+
+static inline uint32_t efscmpeq(uint32_t op1, uint32_t op2)
+{
+ CPU_FloatU u1, u2;
+
+ u1.l = op1;
+ u2.l = op2;
+ return float32_eq(u1.f, u2.f, &env->vec_status) ? 4 : 0;
+}
+
+static inline uint32_t efststlt(uint32_t op1, uint32_t op2)
+{
+ /* XXX: TODO: ignore special values (NaN, infinites, ...) */
+ return efscmplt(op1, op2);
+}
+
+static inline uint32_t efststgt(uint32_t op1, uint32_t op2)
+{
+ /* XXX: TODO: ignore special values (NaN, infinites, ...) */
+ return efscmpgt(op1, op2);
+}
+
+static inline uint32_t efststeq(uint32_t op1, uint32_t op2)
+{
+ /* XXX: TODO: ignore special values (NaN, infinites, ...) */
+ return efscmpeq(op1, op2);
+}
+
+#define HELPER_SINGLE_SPE_CMP(name) \
+ uint32_t helper_e##name(uint32_t op1, uint32_t op2) \
+ { \
+ return e##name(op1, op2) << 2; \
+ }
+/* efststlt */
+HELPER_SINGLE_SPE_CMP(fststlt);
+/* efststgt */
+HELPER_SINGLE_SPE_CMP(fststgt);
+/* efststeq */
+HELPER_SINGLE_SPE_CMP(fststeq);
+/* efscmplt */
+HELPER_SINGLE_SPE_CMP(fscmplt);
+/* efscmpgt */
+HELPER_SINGLE_SPE_CMP(fscmpgt);
+/* efscmpeq */
+HELPER_SINGLE_SPE_CMP(fscmpeq);
+
+static inline uint32_t evcmp_merge(int t0, int t1)
+{
+ return (t0 << 3) | (t1 << 2) | ((t0 | t1) << 1) | (t0 & t1);
+}
+
+#define HELPER_VECTOR_SPE_CMP(name) \
+ uint32_t helper_ev##name(uint64_t op1, uint64_t op2) \
+ { \
+ return evcmp_merge(e##name(op1 >> 32, op2 >> 32), e##name(op1, op2)); \
+ }
+/* evfststlt */
+HELPER_VECTOR_SPE_CMP(fststlt);
+/* evfststgt */
+HELPER_VECTOR_SPE_CMP(fststgt);
+/* evfststeq */
+HELPER_VECTOR_SPE_CMP(fststeq);
+/* evfscmplt */
+HELPER_VECTOR_SPE_CMP(fscmplt);
+/* evfscmpgt */
+HELPER_VECTOR_SPE_CMP(fscmpgt);
+/* evfscmpeq */
+HELPER_VECTOR_SPE_CMP(fscmpeq);
+
+/* Double-precision floating-point conversion */
+uint64_t helper_efdcfsi(uint32_t val)
+{
+ CPU_DoubleU u;
+
+ u.d = int32_to_float64(val, &env->vec_status);
+
+ return u.ll;
+}
+
+uint64_t helper_efdcfsid(uint64_t val)
+{
+ CPU_DoubleU u;
+
+ u.d = int64_to_float64(val, &env->vec_status);
+
+ return u.ll;
+}
+
+uint64_t helper_efdcfui(uint32_t val)
+{
+ CPU_DoubleU u;
+
+ u.d = uint32_to_float64(val, &env->vec_status);
+
+ return u.ll;
+}
+
+uint64_t helper_efdcfuid(uint64_t val)
+{
+ CPU_DoubleU u;
+
+ u.d = uint64_to_float64(val, &env->vec_status);
+
+ return u.ll;
+}
+
+uint32_t helper_efdctsi(uint64_t val)
+{
+ CPU_DoubleU u;
+
+ u.ll = val;
+ /* NaN are not treated the same way IEEE 754 does */
+ if (unlikely(float64_is_any_nan(u.d))) {
+ return 0;
+ }
+
+ return float64_to_int32(u.d, &env->vec_status);
+}
+
+uint32_t helper_efdctui(uint64_t val)
+{
+ CPU_DoubleU u;
+
+ u.ll = val;
+ /* NaN are not treated the same way IEEE 754 does */
+ if (unlikely(float64_is_any_nan(u.d))) {
+ return 0;
+ }
+
+ return float64_to_uint32(u.d, &env->vec_status);
+}
+
+uint32_t helper_efdctsiz(uint64_t val)
+{
+ CPU_DoubleU u;
+
+ u.ll = val;
+ /* NaN are not treated the same way IEEE 754 does */
+ if (unlikely(float64_is_any_nan(u.d))) {
+ return 0;
+ }
+
+ return float64_to_int32_round_to_zero(u.d, &env->vec_status);
+}
+
+uint64_t helper_efdctsidz(uint64_t val)
+{
+ CPU_DoubleU u;
+
+ u.ll = val;
+ /* NaN are not treated the same way IEEE 754 does */
+ if (unlikely(float64_is_any_nan(u.d))) {
+ return 0;
+ }
+
+ return float64_to_int64_round_to_zero(u.d, &env->vec_status);
+}
+
+uint32_t helper_efdctuiz(uint64_t val)
+{
+ CPU_DoubleU u;
+
+ u.ll = val;
+ /* NaN are not treated the same way IEEE 754 does */
+ if (unlikely(float64_is_any_nan(u.d))) {
+ return 0;
+ }
+
+ return float64_to_uint32_round_to_zero(u.d, &env->vec_status);
+}
+
+uint64_t helper_efdctuidz(uint64_t val)
+{
+ CPU_DoubleU u;
+
+ u.ll = val;
+ /* NaN are not treated the same way IEEE 754 does */
+ if (unlikely(float64_is_any_nan(u.d))) {
+ return 0;
+ }
+
+ return float64_to_uint64_round_to_zero(u.d, &env->vec_status);
+}
+
+uint64_t helper_efdcfsf(uint32_t val)
+{
+ CPU_DoubleU u;
+ float64 tmp;
+
+ u.d = int32_to_float64(val, &env->vec_status);
+ tmp = int64_to_float64(1ULL << 32, &env->vec_status);
+ u.d = float64_div(u.d, tmp, &env->vec_status);
+
+ return u.ll;
+}
+
+uint64_t helper_efdcfuf(uint32_t val)
+{
+ CPU_DoubleU u;
+ float64 tmp;
+
+ u.d = uint32_to_float64(val, &env->vec_status);
+ tmp = int64_to_float64(1ULL << 32, &env->vec_status);
+ u.d = float64_div(u.d, tmp, &env->vec_status);
+
+ return u.ll;
+}
+
+uint32_t helper_efdctsf(uint64_t val)
+{
+ CPU_DoubleU u;
+ float64 tmp;
+
+ u.ll = val;
+ /* NaN are not treated the same way IEEE 754 does */
+ if (unlikely(float64_is_any_nan(u.d))) {
+ return 0;
+ }
+ tmp = uint64_to_float64(1ULL << 32, &env->vec_status);
+ u.d = float64_mul(u.d, tmp, &env->vec_status);
+
+ return float64_to_int32(u.d, &env->vec_status);
+}
+
+uint32_t helper_efdctuf(uint64_t val)
+{
+ CPU_DoubleU u;
+ float64 tmp;
+
+ u.ll = val;
+ /* NaN are not treated the same way IEEE 754 does */
+ if (unlikely(float64_is_any_nan(u.d))) {
+ return 0;
+ }
+ tmp = uint64_to_float64(1ULL << 32, &env->vec_status);
+ u.d = float64_mul(u.d, tmp, &env->vec_status);
+
+ return float64_to_uint32(u.d, &env->vec_status);
+}
+
+uint32_t helper_efscfd(uint64_t val)
+{
+ CPU_DoubleU u1;
+ CPU_FloatU u2;
+
+ u1.ll = val;
+ u2.f = float64_to_float32(u1.d, &env->vec_status);
+
+ return u2.l;
+}
+
+uint64_t helper_efdcfs(uint32_t val)
+{
+ CPU_DoubleU u2;
+ CPU_FloatU u1;
+
+ u1.l = val;
+ u2.d = float32_to_float64(u1.f, &env->vec_status);
+
+ return u2.ll;
+}
+
+/* Double precision fixed-point arithmetic */
+uint64_t helper_efdadd(uint64_t op1, uint64_t op2)
+{
+ CPU_DoubleU u1, u2;
+
+ u1.ll = op1;
+ u2.ll = op2;
+ u1.d = float64_add(u1.d, u2.d, &env->vec_status);
+ return u1.ll;
+}
+
+uint64_t helper_efdsub(uint64_t op1, uint64_t op2)
+{
+ CPU_DoubleU u1, u2;
+
+ u1.ll = op1;
+ u2.ll = op2;
+ u1.d = float64_sub(u1.d, u2.d, &env->vec_status);
+ return u1.ll;
+}
+
+uint64_t helper_efdmul(uint64_t op1, uint64_t op2)
+{
+ CPU_DoubleU u1, u2;
+
+ u1.ll = op1;
+ u2.ll = op2;
+ u1.d = float64_mul(u1.d, u2.d, &env->vec_status);
+ return u1.ll;
+}
+
+uint64_t helper_efddiv(uint64_t op1, uint64_t op2)
+{
+ CPU_DoubleU u1, u2;
+
+ u1.ll = op1;
+ u2.ll = op2;
+ u1.d = float64_div(u1.d, u2.d, &env->vec_status);
+ return u1.ll;
+}
+
+/* Double precision floating point helpers */
+uint32_t helper_efdtstlt(uint64_t op1, uint64_t op2)
+{
+ CPU_DoubleU u1, u2;
+
+ u1.ll = op1;
+ u2.ll = op2;
+ return float64_lt(u1.d, u2.d, &env->vec_status) ? 4 : 0;
+}
+
+uint32_t helper_efdtstgt(uint64_t op1, uint64_t op2)
+{
+ CPU_DoubleU u1, u2;
+
+ u1.ll = op1;
+ u2.ll = op2;
+ return float64_le(u1.d, u2.d, &env->vec_status) ? 0 : 4;
+}
+
+uint32_t helper_efdtsteq(uint64_t op1, uint64_t op2)
+{
+ CPU_DoubleU u1, u2;
+
+ u1.ll = op1;
+ u2.ll = op2;
+ return float64_eq_quiet(u1.d, u2.d, &env->vec_status) ? 4 : 0;
+}
+
+uint32_t helper_efdcmplt(uint64_t op1, uint64_t op2)
+{
+ /* XXX: TODO: test special values (NaN, infinites, ...) */
+ return helper_efdtstlt(op1, op2);
+}
+
+uint32_t helper_efdcmpgt(uint64_t op1, uint64_t op2)
+{
+ /* XXX: TODO: test special values (NaN, infinites, ...) */
+ return helper_efdtstgt(op1, op2);
+}
+
+uint32_t helper_efdcmpeq(uint64_t op1, uint64_t op2)
+{
+ /* XXX: TODO: test special values (NaN, infinites, ...) */
+ return helper_efdtsteq(op1, op2);
+}
diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c
index eedbb42..3f677f6 100644
--- a/target-ppc/op_helper.c
+++ b/target-ppc/op_helper.c
@@ -547,1099 +547,6 @@ target_ulong helper_popcntw(target_ulong val)
#endif
/*****************************************************************************/
-/* Floating point operations helpers */
-uint64_t helper_float32_to_float64(uint32_t arg)
-{
- CPU_FloatU f;
- CPU_DoubleU d;
-
- f.l = arg;
- d.d = float32_to_float64(f.f, &env->fp_status);
- return d.ll;
-}
-
-uint32_t helper_float64_to_float32(uint64_t arg)
-{
- CPU_FloatU f;
- CPU_DoubleU d;
-
- d.ll = arg;
- f.f = float64_to_float32(d.d, &env->fp_status);
- return f.l;
-}
-
-static inline int isden(float64 d)
-{
- CPU_DoubleU u;
-
- u.d = d;
-
- return ((u.ll >> 52) & 0x7FF) == 0;
-}
-
-uint32_t helper_compute_fprf(uint64_t arg, uint32_t set_fprf)
-{
- CPU_DoubleU farg;
- int isneg;
- int ret;
-
- farg.ll = arg;
- isneg = float64_is_neg(farg.d);
- if (unlikely(float64_is_any_nan(farg.d))) {
- if (float64_is_signaling_nan(farg.d)) {
- /* Signaling NaN: flags are undefined */
- ret = 0x00;
- } else {
- /* Quiet NaN */
- ret = 0x11;
- }
- } else if (unlikely(float64_is_infinity(farg.d))) {
- /* +/- infinity */
- if (isneg) {
- ret = 0x09;
- } else {
- ret = 0x05;
- }
- } else {
- if (float64_is_zero(farg.d)) {
- /* +/- zero */
- if (isneg) {
- ret = 0x12;
- } else {
- ret = 0x02;
- }
- } else {
- if (isden(farg.d)) {
- /* Denormalized numbers */
- ret = 0x10;
- } else {
- /* Normalized numbers */
- ret = 0x00;
- }
- if (isneg) {
- ret |= 0x08;
- } else {
- ret |= 0x04;
- }
- }
- }
- if (set_fprf) {
- /* We update FPSCR_FPRF */
- env->fpscr &= ~(0x1F << FPSCR_FPRF);
- env->fpscr |= ret << FPSCR_FPRF;
- }
- /* We just need fpcc to update Rc1 */
- return ret & 0xF;
-}
-
-/* Floating-point invalid operations exception */
-static inline uint64_t fload_invalid_op_excp(int op)
-{
- uint64_t ret = 0;
- int ve;
-
- ve = fpscr_ve;
- switch (op) {
- case POWERPC_EXCP_FP_VXSNAN:
- env->fpscr |= 1 << FPSCR_VXSNAN;
- break;
- case POWERPC_EXCP_FP_VXSOFT:
- env->fpscr |= 1 << FPSCR_VXSOFT;
- break;
- case POWERPC_EXCP_FP_VXISI:
- /* Magnitude subtraction of infinities */
- env->fpscr |= 1 << FPSCR_VXISI;
- goto update_arith;
- case POWERPC_EXCP_FP_VXIDI:
- /* Division of infinity by infinity */
- env->fpscr |= 1 << FPSCR_VXIDI;
- goto update_arith;
- case POWERPC_EXCP_FP_VXZDZ:
- /* Division of zero by zero */
- env->fpscr |= 1 << FPSCR_VXZDZ;
- goto update_arith;
- case POWERPC_EXCP_FP_VXIMZ:
- /* Multiplication of zero by infinity */
- env->fpscr |= 1 << FPSCR_VXIMZ;
- goto update_arith;
- case POWERPC_EXCP_FP_VXVC:
- /* Ordered comparison of NaN */
- env->fpscr |= 1 << FPSCR_VXVC;
- env->fpscr &= ~(0xF << FPSCR_FPCC);
- env->fpscr |= 0x11 << FPSCR_FPCC;
- /* We must update the target FPR before raising the exception */
- if (ve != 0) {
- env->exception_index = POWERPC_EXCP_PROGRAM;
- env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_VXVC;
- /* Update the floating-point enabled exception summary */
- env->fpscr |= 1 << FPSCR_FEX;
- /* Exception is differed */
- ve = 0;
- }
- break;
- case POWERPC_EXCP_FP_VXSQRT:
- /* Square root of a negative number */
- env->fpscr |= 1 << FPSCR_VXSQRT;
- update_arith:
- env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
- if (ve == 0) {
- /* Set the result to quiet NaN */
- ret = 0x7FF8000000000000ULL;
- env->fpscr &= ~(0xF << FPSCR_FPCC);
- env->fpscr |= 0x11 << FPSCR_FPCC;
- }
- break;
- case POWERPC_EXCP_FP_VXCVI:
- /* Invalid conversion */
- env->fpscr |= 1 << FPSCR_VXCVI;
- env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
- if (ve == 0) {
- /* Set the result to quiet NaN */
- ret = 0x7FF8000000000000ULL;
- env->fpscr &= ~(0xF << FPSCR_FPCC);
- env->fpscr |= 0x11 << FPSCR_FPCC;
- }
- break;
- }
- /* Update the floating-point invalid operation summary */
- env->fpscr |= 1 << FPSCR_VX;
- /* Update the floating-point exception summary */
- env->fpscr |= 1 << FPSCR_FX;
- if (ve != 0) {
- /* Update the floating-point enabled exception summary */
- env->fpscr |= 1 << FPSCR_FEX;
- if (msr_fe0 != 0 || msr_fe1 != 0) {
- helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
- POWERPC_EXCP_FP | op);
- }
- }
- return ret;
-}
-
-static inline void float_zero_divide_excp(void)
-{
- env->fpscr |= 1 << FPSCR_ZX;
- env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
- /* Update the floating-point exception summary */
- env->fpscr |= 1 << FPSCR_FX;
- if (fpscr_ze != 0) {
- /* Update the floating-point enabled exception summary */
- env->fpscr |= 1 << FPSCR_FEX;
- if (msr_fe0 != 0 || msr_fe1 != 0) {
- helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
- POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX);
- }
- }
-}
-
-static inline void float_overflow_excp(void)
-{
- env->fpscr |= 1 << FPSCR_OX;
- /* Update the floating-point exception summary */
- env->fpscr |= 1 << FPSCR_FX;
- if (fpscr_oe != 0) {
- /* XXX: should adjust the result */
- /* Update the floating-point enabled exception summary */
- env->fpscr |= 1 << FPSCR_FEX;
- /* We must update the target FPR before raising the exception */
- env->exception_index = POWERPC_EXCP_PROGRAM;
- env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_OX;
- } else {
- env->fpscr |= 1 << FPSCR_XX;
- env->fpscr |= 1 << FPSCR_FI;
- }
-}
-
-static inline void float_underflow_excp(void)
-{
- env->fpscr |= 1 << FPSCR_UX;
- /* Update the floating-point exception summary */
- env->fpscr |= 1 << FPSCR_FX;
- if (fpscr_ue != 0) {
- /* XXX: should adjust the result */
- /* Update the floating-point enabled exception summary */
- env->fpscr |= 1 << FPSCR_FEX;
- /* We must update the target FPR before raising the exception */
- env->exception_index = POWERPC_EXCP_PROGRAM;
- env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_UX;
- }
-}
-
-static inline void float_inexact_excp(void)
-{
- env->fpscr |= 1 << FPSCR_XX;
- /* Update the floating-point exception summary */
- env->fpscr |= 1 << FPSCR_FX;
- if (fpscr_xe != 0) {
- /* Update the floating-point enabled exception summary */
- env->fpscr |= 1 << FPSCR_FEX;
- /* We must update the target FPR before raising the exception */
- env->exception_index = POWERPC_EXCP_PROGRAM;
- env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_XX;
- }
-}
-
-static inline void fpscr_set_rounding_mode(void)
-{
- int rnd_type;
-
- /* Set rounding mode */
- switch (fpscr_rn) {
- case 0:
- /* Best approximation (round to nearest) */
- rnd_type = float_round_nearest_even;
- break;
- case 1:
- /* Smaller magnitude (round toward zero) */
- rnd_type = float_round_to_zero;
- break;
- case 2:
- /* Round toward +infinite */
- rnd_type = float_round_up;
- break;
- default:
- case 3:
- /* Round toward -infinite */
- rnd_type = float_round_down;
- break;
- }
- set_float_rounding_mode(rnd_type, &env->fp_status);
-}
-
-void helper_fpscr_clrbit(uint32_t bit)
-{
- int prev;
-
- prev = (env->fpscr >> bit) & 1;
- env->fpscr &= ~(1 << bit);
- if (prev == 1) {
- switch (bit) {
- case FPSCR_RN1:
- case FPSCR_RN:
- fpscr_set_rounding_mode();
- break;
- default:
- break;
- }
- }
-}
-
-void helper_fpscr_setbit(uint32_t bit)
-{
- int prev;
-
- prev = (env->fpscr >> bit) & 1;
- env->fpscr |= 1 << bit;
- if (prev == 0) {
- switch (bit) {
- case FPSCR_VX:
- env->fpscr |= 1 << FPSCR_FX;
- if (fpscr_ve) {
- goto raise_ve;
- }
- case FPSCR_OX:
- env->fpscr |= 1 << FPSCR_FX;
- if (fpscr_oe) {
- goto raise_oe;
- }
- break;
- case FPSCR_UX:
- env->fpscr |= 1 << FPSCR_FX;
- if (fpscr_ue) {
- goto raise_ue;
- }
- break;
- case FPSCR_ZX:
- env->fpscr |= 1 << FPSCR_FX;
- if (fpscr_ze) {
- goto raise_ze;
- }
- break;
- case FPSCR_XX:
- env->fpscr |= 1 << FPSCR_FX;
- if (fpscr_xe) {
- goto raise_xe;
- }
- break;
- case FPSCR_VXSNAN:
- case FPSCR_VXISI:
- case FPSCR_VXIDI:
- case FPSCR_VXZDZ:
- case FPSCR_VXIMZ:
- case FPSCR_VXVC:
- case FPSCR_VXSOFT:
- case FPSCR_VXSQRT:
- case FPSCR_VXCVI:
- env->fpscr |= 1 << FPSCR_VX;
- env->fpscr |= 1 << FPSCR_FX;
- if (fpscr_ve != 0) {
- goto raise_ve;
- }
- break;
- case FPSCR_VE:
- if (fpscr_vx != 0) {
- raise_ve:
- env->error_code = POWERPC_EXCP_FP;
- if (fpscr_vxsnan) {
- env->error_code |= POWERPC_EXCP_FP_VXSNAN;
- }
- if (fpscr_vxisi) {
- env->error_code |= POWERPC_EXCP_FP_VXISI;
- }
- if (fpscr_vxidi) {
- env->error_code |= POWERPC_EXCP_FP_VXIDI;
- }
- if (fpscr_vxzdz) {
- env->error_code |= POWERPC_EXCP_FP_VXZDZ;
- }
- if (fpscr_vximz) {
- env->error_code |= POWERPC_EXCP_FP_VXIMZ;
- }
- if (fpscr_vxvc) {
- env->error_code |= POWERPC_EXCP_FP_VXVC;
- }
- if (fpscr_vxsoft) {
- env->error_code |= POWERPC_EXCP_FP_VXSOFT;
- }
- if (fpscr_vxsqrt) {
- env->error_code |= POWERPC_EXCP_FP_VXSQRT;
- }
- if (fpscr_vxcvi) {
- env->error_code |= POWERPC_EXCP_FP_VXCVI;
- }
- goto raise_excp;
- }
- break;
- case FPSCR_OE:
- if (fpscr_ox != 0) {
- raise_oe:
- env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_OX;
- goto raise_excp;
- }
- break;
- case FPSCR_UE:
- if (fpscr_ux != 0) {
- raise_ue:
- env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_UX;
- goto raise_excp;
- }
- break;
- case FPSCR_ZE:
- if (fpscr_zx != 0) {
- raise_ze:
- env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX;
- goto raise_excp;
- }
- break;
- case FPSCR_XE:
- if (fpscr_xx != 0) {
- raise_xe:
- env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_XX;
- goto raise_excp;
- }
- break;
- case FPSCR_RN1:
- case FPSCR_RN:
- fpscr_set_rounding_mode();
- break;
- default:
- break;
- raise_excp:
- /* Update the floating-point enabled exception summary */
- env->fpscr |= 1 << FPSCR_FEX;
- /* We have to update Rc1 before raising the exception */
- env->exception_index = POWERPC_EXCP_PROGRAM;
- break;
- }
- }
-}
-
-void helper_store_fpscr(uint64_t arg, uint32_t mask)
-{
- /*
- * We use only the 32 LSB of the incoming fpr
- */
- uint32_t prev, new;
- int i;
-
- prev = env->fpscr;
- new = (uint32_t)arg;
- new &= ~0x60000000;
- new |= prev & 0x60000000;
- for (i = 0; i < 8; i++) {
- if (mask & (1 << i)) {
- env->fpscr &= ~(0xF << (4 * i));
- env->fpscr |= new & (0xF << (4 * i));
- }
- }
- /* Update VX and FEX */
- if (fpscr_ix != 0) {
- env->fpscr |= 1 << FPSCR_VX;
- } else {
- env->fpscr &= ~(1 << FPSCR_VX);
- }
- if ((fpscr_ex & fpscr_eex) != 0) {
- env->fpscr |= 1 << FPSCR_FEX;
- env->exception_index = POWERPC_EXCP_PROGRAM;
- /* XXX: we should compute it properly */
- env->error_code = POWERPC_EXCP_FP;
- } else {
- env->fpscr &= ~(1 << FPSCR_FEX);
- }
- fpscr_set_rounding_mode();
-}
-
-void helper_float_check_status(void)
-{
- if (env->exception_index == POWERPC_EXCP_PROGRAM &&
- (env->error_code & POWERPC_EXCP_FP)) {
- /* Differred floating-point exception after target FPR update */
- if (msr_fe0 != 0 || msr_fe1 != 0) {
- helper_raise_exception_err(env, env->exception_index,
- env->error_code);
- }
- } else {
- int status = get_float_exception_flags(&env->fp_status);
- if (status & float_flag_divbyzero) {
- float_zero_divide_excp();
- } else if (status & float_flag_overflow) {
- float_overflow_excp();
- } else if (status & float_flag_underflow) {
- float_underflow_excp();
- } else if (status & float_flag_inexact) {
- float_inexact_excp();
- }
- }
-}
-
-void helper_reset_fpstatus(void)
-{
- set_float_exception_flags(0, &env->fp_status);
-}
-
-/* fadd - fadd. */
-uint64_t helper_fadd(uint64_t arg1, uint64_t arg2)
-{
- CPU_DoubleU farg1, farg2;
-
- farg1.ll = arg1;
- farg2.ll = arg2;
-
- if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d) &&
- float64_is_neg(farg1.d) != float64_is_neg(farg2.d))) {
- /* Magnitude subtraction of infinities */
- farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
- } else {
- if (unlikely(float64_is_signaling_nan(farg1.d) ||
- float64_is_signaling_nan(farg2.d))) {
- /* sNaN addition */
- fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
- }
- farg1.d = float64_add(farg1.d, farg2.d, &env->fp_status);
- }
-
- return farg1.ll;
-}
-
-/* fsub - fsub. */
-uint64_t helper_fsub(uint64_t arg1, uint64_t arg2)
-{
- CPU_DoubleU farg1, farg2;
-
- farg1.ll = arg1;
- farg2.ll = arg2;
-
- if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d) &&
- float64_is_neg(farg1.d) == float64_is_neg(farg2.d))) {
- /* Magnitude subtraction of infinities */
- farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
- } else {
- if (unlikely(float64_is_signaling_nan(farg1.d) ||
- float64_is_signaling_nan(farg2.d))) {
- /* sNaN subtraction */
- fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
- }
- farg1.d = float64_sub(farg1.d, farg2.d, &env->fp_status);
- }
-
- return farg1.ll;
-}
-
-/* fmul - fmul. */
-uint64_t helper_fmul(uint64_t arg1, uint64_t arg2)
-{
- CPU_DoubleU farg1, farg2;
-
- farg1.ll = arg1;
- farg2.ll = arg2;
-
- if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
- (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
- /* Multiplication of zero by infinity */
- farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
- } else {
- if (unlikely(float64_is_signaling_nan(farg1.d) ||
- float64_is_signaling_nan(farg2.d))) {
- /* sNaN multiplication */
- fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
- }
- farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
- }
-
- return farg1.ll;
-}
-
-/* fdiv - fdiv. */
-uint64_t helper_fdiv(uint64_t arg1, uint64_t arg2)
-{
- CPU_DoubleU farg1, farg2;
-
- farg1.ll = arg1;
- farg2.ll = arg2;
-
- if (unlikely(float64_is_infinity(farg1.d) &&
- float64_is_infinity(farg2.d))) {
- /* Division of infinity by infinity */
- farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIDI);
- } else if (unlikely(float64_is_zero(farg1.d) && float64_is_zero(farg2.d))) {
- /* Division of zero by zero */
- farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXZDZ);
- } else {
- if (unlikely(float64_is_signaling_nan(farg1.d) ||
- float64_is_signaling_nan(farg2.d))) {
- /* sNaN division */
- fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
- }
- farg1.d = float64_div(farg1.d, farg2.d, &env->fp_status);
- }
-
- return farg1.ll;
-}
-
-/* fabs */
-uint64_t helper_fabs(uint64_t arg)
-{
- CPU_DoubleU farg;
-
- farg.ll = arg;
- farg.d = float64_abs(farg.d);
- return farg.ll;
-}
-
-/* fnabs */
-uint64_t helper_fnabs(uint64_t arg)
-{
- CPU_DoubleU farg;
-
- farg.ll = arg;
- farg.d = float64_abs(farg.d);
- farg.d = float64_chs(farg.d);
- return farg.ll;
-}
-
-/* fneg */
-uint64_t helper_fneg(uint64_t arg)
-{
- CPU_DoubleU farg;
-
- farg.ll = arg;
- farg.d = float64_chs(farg.d);
- return farg.ll;
-}
-
-/* fctiw - fctiw. */
-uint64_t helper_fctiw(uint64_t arg)
-{
- CPU_DoubleU farg;
-
- farg.ll = arg;
-
- if (unlikely(float64_is_signaling_nan(farg.d))) {
- /* sNaN conversion */
- farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN |
- POWERPC_EXCP_FP_VXCVI);
- } else if (unlikely(float64_is_quiet_nan(farg.d) ||
- float64_is_infinity(farg.d))) {
- /* qNan / infinity conversion */
- farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
- } else {
- farg.ll = float64_to_int32(farg.d, &env->fp_status);
- /* XXX: higher bits are not supposed to be significant.
- * to make tests easier, return the same as a real PowerPC 750
- */
- farg.ll |= 0xFFF80000ULL << 32;
- }
- return farg.ll;
-}
-
-/* fctiwz - fctiwz. */
-uint64_t helper_fctiwz(uint64_t arg)
-{
- CPU_DoubleU farg;
-
- farg.ll = arg;
-
- if (unlikely(float64_is_signaling_nan(farg.d))) {
- /* sNaN conversion */
- farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN |
- POWERPC_EXCP_FP_VXCVI);
- } else if (unlikely(float64_is_quiet_nan(farg.d) ||
- float64_is_infinity(farg.d))) {
- /* qNan / infinity conversion */
- farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
- } else {
- farg.ll = float64_to_int32_round_to_zero(farg.d, &env->fp_status);
- /* XXX: higher bits are not supposed to be significant.
- * to make tests easier, return the same as a real PowerPC 750
- */
- farg.ll |= 0xFFF80000ULL << 32;
- }
- return farg.ll;
-}
-
-#if defined(TARGET_PPC64)
-/* fcfid - fcfid. */
-uint64_t helper_fcfid(uint64_t arg)
-{
- CPU_DoubleU farg;
-
- farg.d = int64_to_float64(arg, &env->fp_status);
- return farg.ll;
-}
-
-/* fctid - fctid. */
-uint64_t helper_fctid(uint64_t arg)
-{
- CPU_DoubleU farg;
-
- farg.ll = arg;
-
- if (unlikely(float64_is_signaling_nan(farg.d))) {
- /* sNaN conversion */
- farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN |
- POWERPC_EXCP_FP_VXCVI);
- } else if (unlikely(float64_is_quiet_nan(farg.d) ||
- float64_is_infinity(farg.d))) {
- /* qNan / infinity conversion */
- farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
- } else {
- farg.ll = float64_to_int64(farg.d, &env->fp_status);
- }
- return farg.ll;
-}
-
-/* fctidz - fctidz. */
-uint64_t helper_fctidz(uint64_t arg)
-{
- CPU_DoubleU farg;
-
- farg.ll = arg;
-
- if (unlikely(float64_is_signaling_nan(farg.d))) {
- /* sNaN conversion */
- farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN |
- POWERPC_EXCP_FP_VXCVI);
- } else if (unlikely(float64_is_quiet_nan(farg.d) ||
- float64_is_infinity(farg.d))) {
- /* qNan / infinity conversion */
- farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
- } else {
- farg.ll = float64_to_int64_round_to_zero(farg.d, &env->fp_status);
- }
- return farg.ll;
-}
-
-#endif
-
-static inline uint64_t do_fri(uint64_t arg, int rounding_mode)
-{
- CPU_DoubleU farg;
-
- farg.ll = arg;
-
- if (unlikely(float64_is_signaling_nan(farg.d))) {
- /* sNaN round */
- farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN |
- POWERPC_EXCP_FP_VXCVI);
- } else if (unlikely(float64_is_quiet_nan(farg.d) ||
- float64_is_infinity(farg.d))) {
- /* qNan / infinity round */
- farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
- } else {
- set_float_rounding_mode(rounding_mode, &env->fp_status);
- farg.ll = float64_round_to_int(farg.d, &env->fp_status);
- /* Restore rounding mode from FPSCR */
- fpscr_set_rounding_mode();
- }
- return farg.ll;
-}
-
-uint64_t helper_frin(uint64_t arg)
-{
- return do_fri(arg, float_round_nearest_even);
-}
-
-uint64_t helper_friz(uint64_t arg)
-{
- return do_fri(arg, float_round_to_zero);
-}
-
-uint64_t helper_frip(uint64_t arg)
-{
- return do_fri(arg, float_round_up);
-}
-
-uint64_t helper_frim(uint64_t arg)
-{
- return do_fri(arg, float_round_down);
-}
-
-/* fmadd - fmadd. */
-uint64_t helper_fmadd(uint64_t arg1, uint64_t arg2, uint64_t arg3)
-{
- CPU_DoubleU farg1, farg2, farg3;
-
- farg1.ll = arg1;
- farg2.ll = arg2;
- farg3.ll = arg3;
-
- if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
- (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
- /* Multiplication of zero by infinity */
- farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
- } else {
- if (unlikely(float64_is_signaling_nan(farg1.d) ||
- float64_is_signaling_nan(farg2.d) ||
- float64_is_signaling_nan(farg3.d))) {
- /* sNaN operation */
- fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
- }
- /* This is the way the PowerPC specification defines it */
- float128 ft0_128, ft1_128;
-
- ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
- ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
- ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
- if (unlikely(float128_is_infinity(ft0_128) &&
- float64_is_infinity(farg3.d) &&
- float128_is_neg(ft0_128) != float64_is_neg(farg3.d))) {
- /* Magnitude subtraction of infinities */
- farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
- } else {
- ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
- ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
- farg1.d = float128_to_float64(ft0_128, &env->fp_status);
- }
- }
-
- return farg1.ll;
-}
-
-/* fmsub - fmsub. */
-uint64_t helper_fmsub(uint64_t arg1, uint64_t arg2, uint64_t arg3)
-{
- CPU_DoubleU farg1, farg2, farg3;
-
- farg1.ll = arg1;
- farg2.ll = arg2;
- farg3.ll = arg3;
-
- if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
- (float64_is_zero(farg1.d) &&
- float64_is_infinity(farg2.d)))) {
- /* Multiplication of zero by infinity */
- farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
- } else {
- if (unlikely(float64_is_signaling_nan(farg1.d) ||
- float64_is_signaling_nan(farg2.d) ||
- float64_is_signaling_nan(farg3.d))) {
- /* sNaN operation */
- fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
- }
- /* This is the way the PowerPC specification defines it */
- float128 ft0_128, ft1_128;
-
- ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
- ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
- ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
- if (unlikely(float128_is_infinity(ft0_128) &&
- float64_is_infinity(farg3.d) &&
- float128_is_neg(ft0_128) == float64_is_neg(farg3.d))) {
- /* Magnitude subtraction of infinities */
- farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
- } else {
- ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
- ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
- farg1.d = float128_to_float64(ft0_128, &env->fp_status);
- }
- }
- return farg1.ll;
-}
-
-/* fnmadd - fnmadd. */
-uint64_t helper_fnmadd(uint64_t arg1, uint64_t arg2, uint64_t arg3)
-{
- CPU_DoubleU farg1, farg2, farg3;
-
- farg1.ll = arg1;
- farg2.ll = arg2;
- farg3.ll = arg3;
-
- if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
- (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
- /* Multiplication of zero by infinity */
- farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
- } else {
- if (unlikely(float64_is_signaling_nan(farg1.d) ||
- float64_is_signaling_nan(farg2.d) ||
- float64_is_signaling_nan(farg3.d))) {
- /* sNaN operation */
- fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
- }
- /* This is the way the PowerPC specification defines it */
- float128 ft0_128, ft1_128;
-
- ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
- ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
- ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
- if (unlikely(float128_is_infinity(ft0_128) &&
- float64_is_infinity(farg3.d) &&
- float128_is_neg(ft0_128) != float64_is_neg(farg3.d))) {
- /* Magnitude subtraction of infinities */
- farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
- } else {
- ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
- ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
- farg1.d = float128_to_float64(ft0_128, &env->fp_status);
- }
- if (likely(!float64_is_any_nan(farg1.d))) {
- farg1.d = float64_chs(farg1.d);
- }
- }
- return farg1.ll;
-}
-
-/* fnmsub - fnmsub. */
-uint64_t helper_fnmsub(uint64_t arg1, uint64_t arg2, uint64_t arg3)
-{
- CPU_DoubleU farg1, farg2, farg3;
-
- farg1.ll = arg1;
- farg2.ll = arg2;
- farg3.ll = arg3;
-
- if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
- (float64_is_zero(farg1.d) &&
- float64_is_infinity(farg2.d)))) {
- /* Multiplication of zero by infinity */
- farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
- } else {
- if (unlikely(float64_is_signaling_nan(farg1.d) ||
- float64_is_signaling_nan(farg2.d) ||
- float64_is_signaling_nan(farg3.d))) {
- /* sNaN operation */
- fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
- }
- /* This is the way the PowerPC specification defines it */
- float128 ft0_128, ft1_128;
-
- ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
- ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
- ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
- if (unlikely(float128_is_infinity(ft0_128) &&
- float64_is_infinity(farg3.d) &&
- float128_is_neg(ft0_128) == float64_is_neg(farg3.d))) {
- /* Magnitude subtraction of infinities */
- farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
- } else {
- ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
- ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
- farg1.d = float128_to_float64(ft0_128, &env->fp_status);
- }
- if (likely(!float64_is_any_nan(farg1.d))) {
- farg1.d = float64_chs(farg1.d);
- }
- }
- return farg1.ll;
-}
-
-/* frsp - frsp. */
-uint64_t helper_frsp(uint64_t arg)
-{
- CPU_DoubleU farg;
- float32 f32;
-
- farg.ll = arg;
-
- if (unlikely(float64_is_signaling_nan(farg.d))) {
- /* sNaN square root */
- fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
- }
- f32 = float64_to_float32(farg.d, &env->fp_status);
- farg.d = float32_to_float64(f32, &env->fp_status);
-
- return farg.ll;
-}
-
-/* fsqrt - fsqrt. */
-uint64_t helper_fsqrt(uint64_t arg)
-{
- CPU_DoubleU farg;
-
- farg.ll = arg;
-
- if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) {
- /* Square root of a negative nonzero number */
- farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSQRT);
- } else {
- if (unlikely(float64_is_signaling_nan(farg.d))) {
- /* sNaN square root */
- fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
- }
- farg.d = float64_sqrt(farg.d, &env->fp_status);
- }
- return farg.ll;
-}
-
-/* fre - fre. */
-uint64_t helper_fre(uint64_t arg)
-{
- CPU_DoubleU farg;
-
- farg.ll = arg;
-
- if (unlikely(float64_is_signaling_nan(farg.d))) {
- /* sNaN reciprocal */
- fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
- }
- farg.d = float64_div(float64_one, farg.d, &env->fp_status);
- return farg.d;
-}
-
-/* fres - fres. */
-uint64_t helper_fres(uint64_t arg)
-{
- CPU_DoubleU farg;
- float32 f32;
-
- farg.ll = arg;
-
- if (unlikely(float64_is_signaling_nan(farg.d))) {
- /* sNaN reciprocal */
- fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
- }
- farg.d = float64_div(float64_one, farg.d, &env->fp_status);
- f32 = float64_to_float32(farg.d, &env->fp_status);
- farg.d = float32_to_float64(f32, &env->fp_status);
-
- return farg.ll;
-}
-
-/* frsqrte - frsqrte. */
-uint64_t helper_frsqrte(uint64_t arg)
-{
- CPU_DoubleU farg;
- float32 f32;
-
- farg.ll = arg;
-
- if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) {
- /* Reciprocal square root of a negative nonzero number */
- farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSQRT);
- } else {
- if (unlikely(float64_is_signaling_nan(farg.d))) {
- /* sNaN reciprocal square root */
- fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
- }
- farg.d = float64_sqrt(farg.d, &env->fp_status);
- farg.d = float64_div(float64_one, farg.d, &env->fp_status);
- f32 = float64_to_float32(farg.d, &env->fp_status);
- farg.d = float32_to_float64(f32, &env->fp_status);
- }
- return farg.ll;
-}
-
-/* fsel - fsel. */
-uint64_t helper_fsel(uint64_t arg1, uint64_t arg2, uint64_t arg3)
-{
- CPU_DoubleU farg1;
-
- farg1.ll = arg1;
-
- if ((!float64_is_neg(farg1.d) || float64_is_zero(farg1.d)) &&
- !float64_is_any_nan(farg1.d)) {
- return arg2;
- } else {
- return arg3;
- }
-}
-
-void helper_fcmpu(uint64_t arg1, uint64_t arg2, uint32_t crfD)
-{
- CPU_DoubleU farg1, farg2;
- uint32_t ret = 0;
-
- farg1.ll = arg1;
- farg2.ll = arg2;
-
- if (unlikely(float64_is_any_nan(farg1.d) ||
- float64_is_any_nan(farg2.d))) {
- ret = 0x01UL;
- } else if (float64_lt(farg1.d, farg2.d, &env->fp_status)) {
- ret = 0x08UL;
- } else if (!float64_le(farg1.d, farg2.d, &env->fp_status)) {
- ret = 0x04UL;
- } else {
- ret = 0x02UL;
- }
-
- env->fpscr &= ~(0x0F << FPSCR_FPRF);
- env->fpscr |= ret << FPSCR_FPRF;
- env->crf[crfD] = ret;
- if (unlikely(ret == 0x01UL
- && (float64_is_signaling_nan(farg1.d) ||
- float64_is_signaling_nan(farg2.d)))) {
- /* sNaN comparison */
- fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
- }
-}
-
-void helper_fcmpo(uint64_t arg1, uint64_t arg2, uint32_t crfD)
-{
- CPU_DoubleU farg1, farg2;
- uint32_t ret = 0;
-
- farg1.ll = arg1;
- farg2.ll = arg2;
-
- if (unlikely(float64_is_any_nan(farg1.d) ||
- float64_is_any_nan(farg2.d))) {
- ret = 0x01UL;
- } else if (float64_lt(farg1.d, farg2.d, &env->fp_status)) {
- ret = 0x08UL;
- } else if (!float64_le(farg1.d, farg2.d, &env->fp_status)) {
- ret = 0x04UL;
- } else {
- ret = 0x02UL;
- }
-
- env->fpscr &= ~(0x0F << FPSCR_FPRF);
- env->fpscr |= ret << FPSCR_FPRF;
- env->crf[crfD] = ret;
- if (unlikely(ret == 0x01UL)) {
- if (float64_is_signaling_nan(farg1.d) ||
- float64_is_signaling_nan(farg2.d)) {
- /* sNaN comparison */
- fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN |
- POWERPC_EXCP_FP_VXVC);
- } else {
- /* qNaN comparison */
- fload_invalid_op_excp(POWERPC_EXCP_FP_VXVC);
- }
- }
-}
-
-/*****************************************************************************/
/* PowerPC 601 specific instructions (POWER bridge) */
target_ulong helper_clcs(uint32_t arg)
@@ -3125,623 +2032,6 @@ uint32_t helper_cntlzw32(uint32_t val)
return clz32(val);
}
-/* Single-precision floating-point conversions */
-static inline uint32_t efscfsi(uint32_t val)
-{
- CPU_FloatU u;
-
- u.f = int32_to_float32(val, &env->vec_status);
-
- return u.l;
-}
-
-static inline uint32_t efscfui(uint32_t val)
-{
- CPU_FloatU u;
-
- u.f = uint32_to_float32(val, &env->vec_status);
-
- return u.l;
-}
-
-static inline int32_t efsctsi(uint32_t val)
-{
- CPU_FloatU u;
-
- u.l = val;
- /* NaN are not treated the same way IEEE 754 does */
- if (unlikely(float32_is_quiet_nan(u.f))) {
- return 0;
- }
-
- return float32_to_int32(u.f, &env->vec_status);
-}
-
-static inline uint32_t efsctui(uint32_t val)
-{
- CPU_FloatU u;
-
- u.l = val;
- /* NaN are not treated the same way IEEE 754 does */
- if (unlikely(float32_is_quiet_nan(u.f))) {
- return 0;
- }
-
- return float32_to_uint32(u.f, &env->vec_status);
-}
-
-static inline uint32_t efsctsiz(uint32_t val)
-{
- CPU_FloatU u;
-
- u.l = val;
- /* NaN are not treated the same way IEEE 754 does */
- if (unlikely(float32_is_quiet_nan(u.f))) {
- return 0;
- }
-
- return float32_to_int32_round_to_zero(u.f, &env->vec_status);
-}
-
-static inline uint32_t efsctuiz(uint32_t val)
-{
- CPU_FloatU u;
-
- u.l = val;
- /* NaN are not treated the same way IEEE 754 does */
- if (unlikely(float32_is_quiet_nan(u.f))) {
- return 0;
- }
-
- return float32_to_uint32_round_to_zero(u.f, &env->vec_status);
-}
-
-static inline uint32_t efscfsf(uint32_t val)
-{
- CPU_FloatU u;
- float32 tmp;
-
- u.f = int32_to_float32(val, &env->vec_status);
- tmp = int64_to_float32(1ULL << 32, &env->vec_status);
- u.f = float32_div(u.f, tmp, &env->vec_status);
-
- return u.l;
-}
-
-static inline uint32_t efscfuf(uint32_t val)
-{
- CPU_FloatU u;
- float32 tmp;
-
- u.f = uint32_to_float32(val, &env->vec_status);
- tmp = uint64_to_float32(1ULL << 32, &env->vec_status);
- u.f = float32_div(u.f, tmp, &env->vec_status);
-
- return u.l;
-}
-
-static inline uint32_t efsctsf(uint32_t val)
-{
- CPU_FloatU u;
- float32 tmp;
-
- u.l = val;
- /* NaN are not treated the same way IEEE 754 does */
- if (unlikely(float32_is_quiet_nan(u.f))) {
- return 0;
- }
- tmp = uint64_to_float32(1ULL << 32, &env->vec_status);
- u.f = float32_mul(u.f, tmp, &env->vec_status);
-
- return float32_to_int32(u.f, &env->vec_status);
-}
-
-static inline uint32_t efsctuf(uint32_t val)
-{
- CPU_FloatU u;
- float32 tmp;
-
- u.l = val;
- /* NaN are not treated the same way IEEE 754 does */
- if (unlikely(float32_is_quiet_nan(u.f))) {
- return 0;
- }
- tmp = uint64_to_float32(1ULL << 32, &env->vec_status);
- u.f = float32_mul(u.f, tmp, &env->vec_status);
-
- return float32_to_uint32(u.f, &env->vec_status);
-}
-
-#define HELPER_SPE_SINGLE_CONV(name) \
- uint32_t helper_e##name(uint32_t val) \
- { \
- return e##name(val); \
- }
-/* efscfsi */
-HELPER_SPE_SINGLE_CONV(fscfsi);
-/* efscfui */
-HELPER_SPE_SINGLE_CONV(fscfui);
-/* efscfuf */
-HELPER_SPE_SINGLE_CONV(fscfuf);
-/* efscfsf */
-HELPER_SPE_SINGLE_CONV(fscfsf);
-/* efsctsi */
-HELPER_SPE_SINGLE_CONV(fsctsi);
-/* efsctui */
-HELPER_SPE_SINGLE_CONV(fsctui);
-/* efsctsiz */
-HELPER_SPE_SINGLE_CONV(fsctsiz);
-/* efsctuiz */
-HELPER_SPE_SINGLE_CONV(fsctuiz);
-/* efsctsf */
-HELPER_SPE_SINGLE_CONV(fsctsf);
-/* efsctuf */
-HELPER_SPE_SINGLE_CONV(fsctuf);
-
-#define HELPER_SPE_VECTOR_CONV(name) \
- uint64_t helper_ev##name(uint64_t val) \
- { \
- return ((uint64_t)e##name(val >> 32) << 32) | \
- (uint64_t)e##name(val); \
- }
-/* evfscfsi */
-HELPER_SPE_VECTOR_CONV(fscfsi);
-/* evfscfui */
-HELPER_SPE_VECTOR_CONV(fscfui);
-/* evfscfuf */
-HELPER_SPE_VECTOR_CONV(fscfuf);
-/* evfscfsf */
-HELPER_SPE_VECTOR_CONV(fscfsf);
-/* evfsctsi */
-HELPER_SPE_VECTOR_CONV(fsctsi);
-/* evfsctui */
-HELPER_SPE_VECTOR_CONV(fsctui);
-/* evfsctsiz */
-HELPER_SPE_VECTOR_CONV(fsctsiz);
-/* evfsctuiz */
-HELPER_SPE_VECTOR_CONV(fsctuiz);
-/* evfsctsf */
-HELPER_SPE_VECTOR_CONV(fsctsf);
-/* evfsctuf */
-HELPER_SPE_VECTOR_CONV(fsctuf);
-
-/* Single-precision floating-point arithmetic */
-static inline uint32_t efsadd(uint32_t op1, uint32_t op2)
-{
- CPU_FloatU u1, u2;
-
- u1.l = op1;
- u2.l = op2;
- u1.f = float32_add(u1.f, u2.f, &env->vec_status);
- return u1.l;
-}
-
-static inline uint32_t efssub(uint32_t op1, uint32_t op2)
-{
- CPU_FloatU u1, u2;
-
- u1.l = op1;
- u2.l = op2;
- u1.f = float32_sub(u1.f, u2.f, &env->vec_status);
- return u1.l;
-}
-
-static inline uint32_t efsmul(uint32_t op1, uint32_t op2)
-{
- CPU_FloatU u1, u2;
-
- u1.l = op1;
- u2.l = op2;
- u1.f = float32_mul(u1.f, u2.f, &env->vec_status);
- return u1.l;
-}
-
-static inline uint32_t efsdiv(uint32_t op1, uint32_t op2)
-{
- CPU_FloatU u1, u2;
-
- u1.l = op1;
- u2.l = op2;
- u1.f = float32_div(u1.f, u2.f, &env->vec_status);
- return u1.l;
-}
-
-#define HELPER_SPE_SINGLE_ARITH(name) \
- uint32_t helper_e##name(uint32_t op1, uint32_t op2) \
- { \
- return e##name(op1, op2); \
- }
-/* efsadd */
-HELPER_SPE_SINGLE_ARITH(fsadd);
-/* efssub */
-HELPER_SPE_SINGLE_ARITH(fssub);
-/* efsmul */
-HELPER_SPE_SINGLE_ARITH(fsmul);
-/* efsdiv */
-HELPER_SPE_SINGLE_ARITH(fsdiv);
-
-#define HELPER_SPE_VECTOR_ARITH(name) \
- uint64_t helper_ev##name(uint64_t op1, uint64_t op2) \
- { \
- return ((uint64_t)e##name(op1 >> 32, op2 >> 32) << 32) | \
- (uint64_t)e##name(op1, op2); \
- }
-/* evfsadd */
-HELPER_SPE_VECTOR_ARITH(fsadd);
-/* evfssub */
-HELPER_SPE_VECTOR_ARITH(fssub);
-/* evfsmul */
-HELPER_SPE_VECTOR_ARITH(fsmul);
-/* evfsdiv */
-HELPER_SPE_VECTOR_ARITH(fsdiv);
-
-/* Single-precision floating-point comparisons */
-static inline uint32_t efscmplt(uint32_t op1, uint32_t op2)
-{
- CPU_FloatU u1, u2;
-
- u1.l = op1;
- u2.l = op2;
- return float32_lt(u1.f, u2.f, &env->vec_status) ? 4 : 0;
-}
-
-static inline uint32_t efscmpgt(uint32_t op1, uint32_t op2)
-{
- CPU_FloatU u1, u2;
-
- u1.l = op1;
- u2.l = op2;
- return float32_le(u1.f, u2.f, &env->vec_status) ? 0 : 4;
-}
-
-static inline uint32_t efscmpeq(uint32_t op1, uint32_t op2)
-{
- CPU_FloatU u1, u2;
-
- u1.l = op1;
- u2.l = op2;
- return float32_eq(u1.f, u2.f, &env->vec_status) ? 4 : 0;
-}
-
-static inline uint32_t efststlt(uint32_t op1, uint32_t op2)
-{
- /* XXX: TODO: ignore special values (NaN, infinites, ...) */
- return efscmplt(op1, op2);
-}
-
-static inline uint32_t efststgt(uint32_t op1, uint32_t op2)
-{
- /* XXX: TODO: ignore special values (NaN, infinites, ...) */
- return efscmpgt(op1, op2);
-}
-
-static inline uint32_t efststeq(uint32_t op1, uint32_t op2)
-{
- /* XXX: TODO: ignore special values (NaN, infinites, ...) */
- return efscmpeq(op1, op2);
-}
-
-#define HELPER_SINGLE_SPE_CMP(name) \
- uint32_t helper_e##name(uint32_t op1, uint32_t op2) \
- { \
- return e##name(op1, op2) << 2; \
- }
-/* efststlt */
-HELPER_SINGLE_SPE_CMP(fststlt);
-/* efststgt */
-HELPER_SINGLE_SPE_CMP(fststgt);
-/* efststeq */
-HELPER_SINGLE_SPE_CMP(fststeq);
-/* efscmplt */
-HELPER_SINGLE_SPE_CMP(fscmplt);
-/* efscmpgt */
-HELPER_SINGLE_SPE_CMP(fscmpgt);
-/* efscmpeq */
-HELPER_SINGLE_SPE_CMP(fscmpeq);
-
-static inline uint32_t evcmp_merge(int t0, int t1)
-{
- return (t0 << 3) | (t1 << 2) | ((t0 | t1) << 1) | (t0 & t1);
-}
-
-#define HELPER_VECTOR_SPE_CMP(name) \
- uint32_t helper_ev##name(uint64_t op1, uint64_t op2) \
- { \
- return evcmp_merge(e##name(op1 >> 32, op2 >> 32), e##name(op1, op2)); \
- }
-/* evfststlt */
-HELPER_VECTOR_SPE_CMP(fststlt);
-/* evfststgt */
-HELPER_VECTOR_SPE_CMP(fststgt);
-/* evfststeq */
-HELPER_VECTOR_SPE_CMP(fststeq);
-/* evfscmplt */
-HELPER_VECTOR_SPE_CMP(fscmplt);
-/* evfscmpgt */
-HELPER_VECTOR_SPE_CMP(fscmpgt);
-/* evfscmpeq */
-HELPER_VECTOR_SPE_CMP(fscmpeq);
-
-/* Double-precision floating-point conversion */
-uint64_t helper_efdcfsi(uint32_t val)
-{
- CPU_DoubleU u;
-
- u.d = int32_to_float64(val, &env->vec_status);
-
- return u.ll;
-}
-
-uint64_t helper_efdcfsid(uint64_t val)
-{
- CPU_DoubleU u;
-
- u.d = int64_to_float64(val, &env->vec_status);
-
- return u.ll;
-}
-
-uint64_t helper_efdcfui(uint32_t val)
-{
- CPU_DoubleU u;
-
- u.d = uint32_to_float64(val, &env->vec_status);
-
- return u.ll;
-}
-
-uint64_t helper_efdcfuid(uint64_t val)
-{
- CPU_DoubleU u;
-
- u.d = uint64_to_float64(val, &env->vec_status);
-
- return u.ll;
-}
-
-uint32_t helper_efdctsi(uint64_t val)
-{
- CPU_DoubleU u;
-
- u.ll = val;
- /* NaN are not treated the same way IEEE 754 does */
- if (unlikely(float64_is_any_nan(u.d))) {
- return 0;
- }
-
- return float64_to_int32(u.d, &env->vec_status);
-}
-
-uint32_t helper_efdctui(uint64_t val)
-{
- CPU_DoubleU u;
-
- u.ll = val;
- /* NaN are not treated the same way IEEE 754 does */
- if (unlikely(float64_is_any_nan(u.d))) {
- return 0;
- }
-
- return float64_to_uint32(u.d, &env->vec_status);
-}
-
-uint32_t helper_efdctsiz(uint64_t val)
-{
- CPU_DoubleU u;
-
- u.ll = val;
- /* NaN are not treated the same way IEEE 754 does */
- if (unlikely(float64_is_any_nan(u.d))) {
- return 0;
- }
-
- return float64_to_int32_round_to_zero(u.d, &env->vec_status);
-}
-
-uint64_t helper_efdctsidz(uint64_t val)
-{
- CPU_DoubleU u;
-
- u.ll = val;
- /* NaN are not treated the same way IEEE 754 does */
- if (unlikely(float64_is_any_nan(u.d))) {
- return 0;
- }
-
- return float64_to_int64_round_to_zero(u.d, &env->vec_status);
-}
-
-uint32_t helper_efdctuiz(uint64_t val)
-{
- CPU_DoubleU u;
-
- u.ll = val;
- /* NaN are not treated the same way IEEE 754 does */
- if (unlikely(float64_is_any_nan(u.d))) {
- return 0;
- }
-
- return float64_to_uint32_round_to_zero(u.d, &env->vec_status);
-}
-
-uint64_t helper_efdctuidz(uint64_t val)
-{
- CPU_DoubleU u;
-
- u.ll = val;
- /* NaN are not treated the same way IEEE 754 does */
- if (unlikely(float64_is_any_nan(u.d))) {
- return 0;
- }
-
- return float64_to_uint64_round_to_zero(u.d, &env->vec_status);
-}
-
-uint64_t helper_efdcfsf(uint32_t val)
-{
- CPU_DoubleU u;
- float64 tmp;
-
- u.d = int32_to_float64(val, &env->vec_status);
- tmp = int64_to_float64(1ULL << 32, &env->vec_status);
- u.d = float64_div(u.d, tmp, &env->vec_status);
-
- return u.ll;
-}
-
-uint64_t helper_efdcfuf(uint32_t val)
-{
- CPU_DoubleU u;
- float64 tmp;
-
- u.d = uint32_to_float64(val, &env->vec_status);
- tmp = int64_to_float64(1ULL << 32, &env->vec_status);
- u.d = float64_div(u.d, tmp, &env->vec_status);
-
- return u.ll;
-}
-
-uint32_t helper_efdctsf(uint64_t val)
-{
- CPU_DoubleU u;
- float64 tmp;
-
- u.ll = val;
- /* NaN are not treated the same way IEEE 754 does */
- if (unlikely(float64_is_any_nan(u.d))) {
- return 0;
- }
- tmp = uint64_to_float64(1ULL << 32, &env->vec_status);
- u.d = float64_mul(u.d, tmp, &env->vec_status);
-
- return float64_to_int32(u.d, &env->vec_status);
-}
-
-uint32_t helper_efdctuf(uint64_t val)
-{
- CPU_DoubleU u;
- float64 tmp;
-
- u.ll = val;
- /* NaN are not treated the same way IEEE 754 does */
- if (unlikely(float64_is_any_nan(u.d))) {
- return 0;
- }
- tmp = uint64_to_float64(1ULL << 32, &env->vec_status);
- u.d = float64_mul(u.d, tmp, &env->vec_status);
-
- return float64_to_uint32(u.d, &env->vec_status);
-}
-
-uint32_t helper_efscfd(uint64_t val)
-{
- CPU_DoubleU u1;
- CPU_FloatU u2;
-
- u1.ll = val;
- u2.f = float64_to_float32(u1.d, &env->vec_status);
-
- return u2.l;
-}
-
-uint64_t helper_efdcfs(uint32_t val)
-{
- CPU_DoubleU u2;
- CPU_FloatU u1;
-
- u1.l = val;
- u2.d = float32_to_float64(u1.f, &env->vec_status);
-
- return u2.ll;
-}
-
-/* Double precision fixed-point arithmetic */
-uint64_t helper_efdadd(uint64_t op1, uint64_t op2)
-{
- CPU_DoubleU u1, u2;
-
- u1.ll = op1;
- u2.ll = op2;
- u1.d = float64_add(u1.d, u2.d, &env->vec_status);
- return u1.ll;
-}
-
-uint64_t helper_efdsub(uint64_t op1, uint64_t op2)
-{
- CPU_DoubleU u1, u2;
-
- u1.ll = op1;
- u2.ll = op2;
- u1.d = float64_sub(u1.d, u2.d, &env->vec_status);
- return u1.ll;
-}
-
-uint64_t helper_efdmul(uint64_t op1, uint64_t op2)
-{
- CPU_DoubleU u1, u2;
-
- u1.ll = op1;
- u2.ll = op2;
- u1.d = float64_mul(u1.d, u2.d, &env->vec_status);
- return u1.ll;
-}
-
-uint64_t helper_efddiv(uint64_t op1, uint64_t op2)
-{
- CPU_DoubleU u1, u2;
-
- u1.ll = op1;
- u2.ll = op2;
- u1.d = float64_div(u1.d, u2.d, &env->vec_status);
- return u1.ll;
-}
-
-/* Double precision floating point helpers */
-uint32_t helper_efdtstlt(uint64_t op1, uint64_t op2)
-{
- CPU_DoubleU u1, u2;
-
- u1.ll = op1;
- u2.ll = op2;
- return float64_lt(u1.d, u2.d, &env->vec_status) ? 4 : 0;
-}
-
-uint32_t helper_efdtstgt(uint64_t op1, uint64_t op2)
-{
- CPU_DoubleU u1, u2;
-
- u1.ll = op1;
- u2.ll = op2;
- return float64_le(u1.d, u2.d, &env->vec_status) ? 0 : 4;
-}
-
-uint32_t helper_efdtsteq(uint64_t op1, uint64_t op2)
-{
- CPU_DoubleU u1, u2;
-
- u1.ll = op1;
- u2.ll = op2;
- return float64_eq_quiet(u1.d, u2.d, &env->vec_status) ? 4 : 0;
-}
-
-uint32_t helper_efdcmplt(uint64_t op1, uint64_t op2)
-{
- /* XXX: TODO: test special values (NaN, infinites, ...) */
- return helper_efdtstlt(op1, op2);
-}
-
-uint32_t helper_efdcmpgt(uint64_t op1, uint64_t op2)
-{
- /* XXX: TODO: test special values (NaN, infinites, ...) */
- return helper_efdtstgt(op1, op2);
-}
-
-uint32_t helper_efdcmpeq(uint64_t op1, uint64_t op2)
-{
- /* XXX: TODO: test special values (NaN, infinites, ...) */
- return helper_efdtsteq(op1, op2);
-}
-
/*****************************************************************************/
/* Softmmu support */
#if !defined(CONFIG_USER_ONLY)
--
1.6.0.2
^ permalink raw reply related [flat|nested] 89+ messages in thread
* [Qemu-devel] [PATCH 07/72] ppc: Avoid AREG0 for FPU and SPE helpers
2012-06-23 23:06 [Qemu-devel] [PULL 00/72] ppc patch queue 2012-06-24 Alexander Graf
` (5 preceding siblings ...)
2012-06-23 23:06 ` [Qemu-devel] [PATCH 06/72] ppc: Split FPU and SPE ops Alexander Graf
@ 2012-06-23 23:06 ` Alexander Graf
2012-06-23 23:06 ` [Qemu-devel] [PATCH 08/72] ppc: Split integer and vector ops Alexander Graf
` (65 subsequent siblings)
72 siblings, 0 replies; 89+ messages in thread
From: Alexander Graf @ 2012-06-23 23:06 UTC (permalink / raw)
To: qemu-devel qemu-devel
Cc: Blue Swirl, qemu-ppc Mailing List, Andreas Färber,
Aurelien Jarno
From: Blue Swirl <blauwirbel@gmail.com>
Add an explicit CPUPPCState parameter instead of relying on AREG0.
Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Andreas Färber <afaerber@suse.de>
Signed-off-by: Alexander Graf <agraf@suse.de>
---
target-ppc/Makefile.objs | 1 -
target-ppc/fpu_helper.c | 350 +++++++++++++++++++++++----------------------
target-ppc/helper.h | 204 ++++++++++++++--------------
target-ppc/translate.c | 113 +++++++++-------
4 files changed, 346 insertions(+), 322 deletions(-)
diff --git a/target-ppc/Makefile.objs b/target-ppc/Makefile.objs
index dde916c..5bea9c3 100644
--- a/target-ppc/Makefile.objs
+++ b/target-ppc/Makefile.objs
@@ -5,5 +5,4 @@ obj-y += op_helper.o helper.o
obj-y += excp_helper.o
obj-y += fpu_helper.o
-$(obj)/fpu_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
$(obj)/op_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
diff --git a/target-ppc/fpu_helper.c b/target-ppc/fpu_helper.c
index be965d1..d90636f 100644
--- a/target-ppc/fpu_helper.c
+++ b/target-ppc/fpu_helper.c
@@ -17,12 +17,11 @@
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include "cpu.h"
-#include "dyngen-exec.h"
#include "helper.h"
/*****************************************************************************/
/* Floating point operations helpers */
-uint64_t helper_float32_to_float64(uint32_t arg)
+uint64_t helper_float32_to_float64(CPUPPCState *env, uint32_t arg)
{
CPU_FloatU f;
CPU_DoubleU d;
@@ -32,7 +31,7 @@ uint64_t helper_float32_to_float64(uint32_t arg)
return d.ll;
}
-uint32_t helper_float64_to_float32(uint64_t arg)
+uint32_t helper_float64_to_float32(CPUPPCState *env, uint64_t arg)
{
CPU_FloatU f;
CPU_DoubleU d;
@@ -51,7 +50,7 @@ static inline int isden(float64 d)
return ((u.ll >> 52) & 0x7FF) == 0;
}
-uint32_t helper_compute_fprf(uint64_t arg, uint32_t set_fprf)
+uint32_t helper_compute_fprf(CPUPPCState *env, uint64_t arg, uint32_t set_fprf)
{
CPU_DoubleU farg;
int isneg;
@@ -107,7 +106,7 @@ uint32_t helper_compute_fprf(uint64_t arg, uint32_t set_fprf)
}
/* Floating-point invalid operations exception */
-static inline uint64_t fload_invalid_op_excp(int op)
+static inline uint64_t fload_invalid_op_excp(CPUPPCState *env, int op)
{
uint64_t ret = 0;
int ve;
@@ -190,7 +189,7 @@ static inline uint64_t fload_invalid_op_excp(int op)
return ret;
}
-static inline void float_zero_divide_excp(void)
+static inline void float_zero_divide_excp(CPUPPCState *env)
{
env->fpscr |= 1 << FPSCR_ZX;
env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
@@ -206,7 +205,7 @@ static inline void float_zero_divide_excp(void)
}
}
-static inline void float_overflow_excp(void)
+static inline void float_overflow_excp(CPUPPCState *env)
{
env->fpscr |= 1 << FPSCR_OX;
/* Update the floating-point exception summary */
@@ -224,7 +223,7 @@ static inline void float_overflow_excp(void)
}
}
-static inline void float_underflow_excp(void)
+static inline void float_underflow_excp(CPUPPCState *env)
{
env->fpscr |= 1 << FPSCR_UX;
/* Update the floating-point exception summary */
@@ -239,7 +238,7 @@ static inline void float_underflow_excp(void)
}
}
-static inline void float_inexact_excp(void)
+static inline void float_inexact_excp(CPUPPCState *env)
{
env->fpscr |= 1 << FPSCR_XX;
/* Update the floating-point exception summary */
@@ -253,7 +252,7 @@ static inline void float_inexact_excp(void)
}
}
-static inline void fpscr_set_rounding_mode(void)
+static inline void fpscr_set_rounding_mode(CPUPPCState *env)
{
int rnd_type;
@@ -280,7 +279,7 @@ static inline void fpscr_set_rounding_mode(void)
set_float_rounding_mode(rnd_type, &env->fp_status);
}
-void helper_fpscr_clrbit(uint32_t bit)
+void helper_fpscr_clrbit(CPUPPCState *env, uint32_t bit)
{
int prev;
@@ -290,7 +289,7 @@ void helper_fpscr_clrbit(uint32_t bit)
switch (bit) {
case FPSCR_RN1:
case FPSCR_RN:
- fpscr_set_rounding_mode();
+ fpscr_set_rounding_mode(env);
break;
default:
break;
@@ -298,7 +297,7 @@ void helper_fpscr_clrbit(uint32_t bit)
}
}
-void helper_fpscr_setbit(uint32_t bit)
+void helper_fpscr_setbit(CPUPPCState *env, uint32_t bit)
{
int prev;
@@ -414,7 +413,7 @@ void helper_fpscr_setbit(uint32_t bit)
break;
case FPSCR_RN1:
case FPSCR_RN:
- fpscr_set_rounding_mode();
+ fpscr_set_rounding_mode(env);
break;
default:
break;
@@ -428,7 +427,7 @@ void helper_fpscr_setbit(uint32_t bit)
}
}
-void helper_store_fpscr(uint64_t arg, uint32_t mask)
+void helper_store_fpscr(CPUPPCState *env, uint64_t arg, uint32_t mask)
{
/*
* We use only the 32 LSB of the incoming fpr
@@ -460,10 +459,10 @@ void helper_store_fpscr(uint64_t arg, uint32_t mask)
} else {
env->fpscr &= ~(1 << FPSCR_FEX);
}
- fpscr_set_rounding_mode();
+ fpscr_set_rounding_mode(env);
}
-void helper_float_check_status(void)
+void helper_float_check_status(CPUPPCState *env)
{
if (env->exception_index == POWERPC_EXCP_PROGRAM &&
(env->error_code & POWERPC_EXCP_FP)) {
@@ -475,24 +474,24 @@ void helper_float_check_status(void)
} else {
int status = get_float_exception_flags(&env->fp_status);
if (status & float_flag_divbyzero) {
- float_zero_divide_excp();
+ float_zero_divide_excp(env);
} else if (status & float_flag_overflow) {
- float_overflow_excp();
+ float_overflow_excp(env);
} else if (status & float_flag_underflow) {
- float_underflow_excp();
+ float_underflow_excp(env);
} else if (status & float_flag_inexact) {
- float_inexact_excp();
+ float_inexact_excp(env);
}
}
}
-void helper_reset_fpstatus(void)
+void helper_reset_fpstatus(CPUPPCState *env)
{
set_float_exception_flags(0, &env->fp_status);
}
/* fadd - fadd. */
-uint64_t helper_fadd(uint64_t arg1, uint64_t arg2)
+uint64_t helper_fadd(CPUPPCState *env, uint64_t arg1, uint64_t arg2)
{
CPU_DoubleU farg1, farg2;
@@ -502,12 +501,12 @@ uint64_t helper_fadd(uint64_t arg1, uint64_t arg2)
if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d) &&
float64_is_neg(farg1.d) != float64_is_neg(farg2.d))) {
/* Magnitude subtraction of infinities */
- farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
+ farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI);
} else {
if (unlikely(float64_is_signaling_nan(farg1.d) ||
float64_is_signaling_nan(farg2.d))) {
/* sNaN addition */
- fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN);
}
farg1.d = float64_add(farg1.d, farg2.d, &env->fp_status);
}
@@ -516,7 +515,7 @@ uint64_t helper_fadd(uint64_t arg1, uint64_t arg2)
}
/* fsub - fsub. */
-uint64_t helper_fsub(uint64_t arg1, uint64_t arg2)
+uint64_t helper_fsub(CPUPPCState *env, uint64_t arg1, uint64_t arg2)
{
CPU_DoubleU farg1, farg2;
@@ -526,12 +525,12 @@ uint64_t helper_fsub(uint64_t arg1, uint64_t arg2)
if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d) &&
float64_is_neg(farg1.d) == float64_is_neg(farg2.d))) {
/* Magnitude subtraction of infinities */
- farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
+ farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI);
} else {
if (unlikely(float64_is_signaling_nan(farg1.d) ||
float64_is_signaling_nan(farg2.d))) {
/* sNaN subtraction */
- fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN);
}
farg1.d = float64_sub(farg1.d, farg2.d, &env->fp_status);
}
@@ -540,7 +539,7 @@ uint64_t helper_fsub(uint64_t arg1, uint64_t arg2)
}
/* fmul - fmul. */
-uint64_t helper_fmul(uint64_t arg1, uint64_t arg2)
+uint64_t helper_fmul(CPUPPCState *env, uint64_t arg1, uint64_t arg2)
{
CPU_DoubleU farg1, farg2;
@@ -550,12 +549,12 @@ uint64_t helper_fmul(uint64_t arg1, uint64_t arg2)
if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
(float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
/* Multiplication of zero by infinity */
- farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
+ farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ);
} else {
if (unlikely(float64_is_signaling_nan(farg1.d) ||
float64_is_signaling_nan(farg2.d))) {
/* sNaN multiplication */
- fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN);
}
farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
}
@@ -564,7 +563,7 @@ uint64_t helper_fmul(uint64_t arg1, uint64_t arg2)
}
/* fdiv - fdiv. */
-uint64_t helper_fdiv(uint64_t arg1, uint64_t arg2)
+uint64_t helper_fdiv(CPUPPCState *env, uint64_t arg1, uint64_t arg2)
{
CPU_DoubleU farg1, farg2;
@@ -574,15 +573,15 @@ uint64_t helper_fdiv(uint64_t arg1, uint64_t arg2)
if (unlikely(float64_is_infinity(farg1.d) &&
float64_is_infinity(farg2.d))) {
/* Division of infinity by infinity */
- farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIDI);
+ farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIDI);
} else if (unlikely(float64_is_zero(farg1.d) && float64_is_zero(farg2.d))) {
/* Division of zero by zero */
- farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXZDZ);
+ farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXZDZ);
} else {
if (unlikely(float64_is_signaling_nan(farg1.d) ||
float64_is_signaling_nan(farg2.d))) {
/* sNaN division */
- fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN);
}
farg1.d = float64_div(farg1.d, farg2.d, &env->fp_status);
}
@@ -591,7 +590,7 @@ uint64_t helper_fdiv(uint64_t arg1, uint64_t arg2)
}
/* fabs */
-uint64_t helper_fabs(uint64_t arg)
+uint64_t helper_fabs(CPUPPCState *env, uint64_t arg)
{
CPU_DoubleU farg;
@@ -601,7 +600,7 @@ uint64_t helper_fabs(uint64_t arg)
}
/* fnabs */
-uint64_t helper_fnabs(uint64_t arg)
+uint64_t helper_fnabs(CPUPPCState *env, uint64_t arg)
{
CPU_DoubleU farg;
@@ -612,7 +611,7 @@ uint64_t helper_fnabs(uint64_t arg)
}
/* fneg */
-uint64_t helper_fneg(uint64_t arg)
+uint64_t helper_fneg(CPUPPCState *env, uint64_t arg)
{
CPU_DoubleU farg;
@@ -622,7 +621,7 @@ uint64_t helper_fneg(uint64_t arg)
}
/* fctiw - fctiw. */
-uint64_t helper_fctiw(uint64_t arg)
+uint64_t helper_fctiw(CPUPPCState *env, uint64_t arg)
{
CPU_DoubleU farg;
@@ -630,12 +629,12 @@ uint64_t helper_fctiw(uint64_t arg)
if (unlikely(float64_is_signaling_nan(farg.d))) {
/* sNaN conversion */
- farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN |
+ farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN |
POWERPC_EXCP_FP_VXCVI);
} else if (unlikely(float64_is_quiet_nan(farg.d) ||
float64_is_infinity(farg.d))) {
/* qNan / infinity conversion */
- farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
+ farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI);
} else {
farg.ll = float64_to_int32(farg.d, &env->fp_status);
/* XXX: higher bits are not supposed to be significant.
@@ -647,7 +646,7 @@ uint64_t helper_fctiw(uint64_t arg)
}
/* fctiwz - fctiwz. */
-uint64_t helper_fctiwz(uint64_t arg)
+uint64_t helper_fctiwz(CPUPPCState *env, uint64_t arg)
{
CPU_DoubleU farg;
@@ -655,12 +654,12 @@ uint64_t helper_fctiwz(uint64_t arg)
if (unlikely(float64_is_signaling_nan(farg.d))) {
/* sNaN conversion */
- farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN |
+ farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN |
POWERPC_EXCP_FP_VXCVI);
} else if (unlikely(float64_is_quiet_nan(farg.d) ||
float64_is_infinity(farg.d))) {
/* qNan / infinity conversion */
- farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
+ farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI);
} else {
farg.ll = float64_to_int32_round_to_zero(farg.d, &env->fp_status);
/* XXX: higher bits are not supposed to be significant.
@@ -673,7 +672,7 @@ uint64_t helper_fctiwz(uint64_t arg)
#if defined(TARGET_PPC64)
/* fcfid - fcfid. */
-uint64_t helper_fcfid(uint64_t arg)
+uint64_t helper_fcfid(CPUPPCState *env, uint64_t arg)
{
CPU_DoubleU farg;
@@ -682,7 +681,7 @@ uint64_t helper_fcfid(uint64_t arg)
}
/* fctid - fctid. */
-uint64_t helper_fctid(uint64_t arg)
+uint64_t helper_fctid(CPUPPCState *env, uint64_t arg)
{
CPU_DoubleU farg;
@@ -690,12 +689,12 @@ uint64_t helper_fctid(uint64_t arg)
if (unlikely(float64_is_signaling_nan(farg.d))) {
/* sNaN conversion */
- farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN |
+ farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN |
POWERPC_EXCP_FP_VXCVI);
} else if (unlikely(float64_is_quiet_nan(farg.d) ||
float64_is_infinity(farg.d))) {
/* qNan / infinity conversion */
- farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
+ farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI);
} else {
farg.ll = float64_to_int64(farg.d, &env->fp_status);
}
@@ -703,7 +702,7 @@ uint64_t helper_fctid(uint64_t arg)
}
/* fctidz - fctidz. */
-uint64_t helper_fctidz(uint64_t arg)
+uint64_t helper_fctidz(CPUPPCState *env, uint64_t arg)
{
CPU_DoubleU farg;
@@ -711,12 +710,12 @@ uint64_t helper_fctidz(uint64_t arg)
if (unlikely(float64_is_signaling_nan(farg.d))) {
/* sNaN conversion */
- farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN |
+ farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN |
POWERPC_EXCP_FP_VXCVI);
} else if (unlikely(float64_is_quiet_nan(farg.d) ||
float64_is_infinity(farg.d))) {
/* qNan / infinity conversion */
- farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
+ farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI);
} else {
farg.ll = float64_to_int64_round_to_zero(farg.d, &env->fp_status);
}
@@ -725,7 +724,8 @@ uint64_t helper_fctidz(uint64_t arg)
#endif
-static inline uint64_t do_fri(uint64_t arg, int rounding_mode)
+static inline uint64_t do_fri(CPUPPCState *env, uint64_t arg,
+ int rounding_mode)
{
CPU_DoubleU farg;
@@ -733,43 +733,44 @@ static inline uint64_t do_fri(uint64_t arg, int rounding_mode)
if (unlikely(float64_is_signaling_nan(farg.d))) {
/* sNaN round */
- farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN |
+ farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN |
POWERPC_EXCP_FP_VXCVI);
} else if (unlikely(float64_is_quiet_nan(farg.d) ||
float64_is_infinity(farg.d))) {
/* qNan / infinity round */
- farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
+ farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI);
} else {
set_float_rounding_mode(rounding_mode, &env->fp_status);
farg.ll = float64_round_to_int(farg.d, &env->fp_status);
/* Restore rounding mode from FPSCR */
- fpscr_set_rounding_mode();
+ fpscr_set_rounding_mode(env);
}
return farg.ll;
}
-uint64_t helper_frin(uint64_t arg)
+uint64_t helper_frin(CPUPPCState *env, uint64_t arg)
{
- return do_fri(arg, float_round_nearest_even);
+ return do_fri(env, arg, float_round_nearest_even);
}
-uint64_t helper_friz(uint64_t arg)
+uint64_t helper_friz(CPUPPCState *env, uint64_t arg)
{
- return do_fri(arg, float_round_to_zero);
+ return do_fri(env, arg, float_round_to_zero);
}
-uint64_t helper_frip(uint64_t arg)
+uint64_t helper_frip(CPUPPCState *env, uint64_t arg)
{
- return do_fri(arg, float_round_up);
+ return do_fri(env, arg, float_round_up);
}
-uint64_t helper_frim(uint64_t arg)
+uint64_t helper_frim(CPUPPCState *env, uint64_t arg)
{
- return do_fri(arg, float_round_down);
+ return do_fri(env, arg, float_round_down);
}
/* fmadd - fmadd. */
-uint64_t helper_fmadd(uint64_t arg1, uint64_t arg2, uint64_t arg3)
+uint64_t helper_fmadd(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
+ uint64_t arg3)
{
CPU_DoubleU farg1, farg2, farg3;
@@ -780,13 +781,13 @@ uint64_t helper_fmadd(uint64_t arg1, uint64_t arg2, uint64_t arg3)
if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
(float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
/* Multiplication of zero by infinity */
- farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
+ farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ);
} else {
if (unlikely(float64_is_signaling_nan(farg1.d) ||
float64_is_signaling_nan(farg2.d) ||
float64_is_signaling_nan(farg3.d))) {
/* sNaN operation */
- fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN);
}
/* This is the way the PowerPC specification defines it */
float128 ft0_128, ft1_128;
@@ -798,7 +799,7 @@ uint64_t helper_fmadd(uint64_t arg1, uint64_t arg2, uint64_t arg3)
float64_is_infinity(farg3.d) &&
float128_is_neg(ft0_128) != float64_is_neg(farg3.d))) {
/* Magnitude subtraction of infinities */
- farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
+ farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI);
} else {
ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
@@ -810,7 +811,8 @@ uint64_t helper_fmadd(uint64_t arg1, uint64_t arg2, uint64_t arg3)
}
/* fmsub - fmsub. */
-uint64_t helper_fmsub(uint64_t arg1, uint64_t arg2, uint64_t arg3)
+uint64_t helper_fmsub(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
+ uint64_t arg3)
{
CPU_DoubleU farg1, farg2, farg3;
@@ -822,13 +824,13 @@ uint64_t helper_fmsub(uint64_t arg1, uint64_t arg2, uint64_t arg3)
(float64_is_zero(farg1.d) &&
float64_is_infinity(farg2.d)))) {
/* Multiplication of zero by infinity */
- farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
+ farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ);
} else {
if (unlikely(float64_is_signaling_nan(farg1.d) ||
float64_is_signaling_nan(farg2.d) ||
float64_is_signaling_nan(farg3.d))) {
/* sNaN operation */
- fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN);
}
/* This is the way the PowerPC specification defines it */
float128 ft0_128, ft1_128;
@@ -840,7 +842,7 @@ uint64_t helper_fmsub(uint64_t arg1, uint64_t arg2, uint64_t arg3)
float64_is_infinity(farg3.d) &&
float128_is_neg(ft0_128) == float64_is_neg(farg3.d))) {
/* Magnitude subtraction of infinities */
- farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
+ farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI);
} else {
ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
@@ -851,7 +853,8 @@ uint64_t helper_fmsub(uint64_t arg1, uint64_t arg2, uint64_t arg3)
}
/* fnmadd - fnmadd. */
-uint64_t helper_fnmadd(uint64_t arg1, uint64_t arg2, uint64_t arg3)
+uint64_t helper_fnmadd(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
+ uint64_t arg3)
{
CPU_DoubleU farg1, farg2, farg3;
@@ -862,13 +865,13 @@ uint64_t helper_fnmadd(uint64_t arg1, uint64_t arg2, uint64_t arg3)
if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
(float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
/* Multiplication of zero by infinity */
- farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
+ farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ);
} else {
if (unlikely(float64_is_signaling_nan(farg1.d) ||
float64_is_signaling_nan(farg2.d) ||
float64_is_signaling_nan(farg3.d))) {
/* sNaN operation */
- fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN);
}
/* This is the way the PowerPC specification defines it */
float128 ft0_128, ft1_128;
@@ -880,7 +883,7 @@ uint64_t helper_fnmadd(uint64_t arg1, uint64_t arg2, uint64_t arg3)
float64_is_infinity(farg3.d) &&
float128_is_neg(ft0_128) != float64_is_neg(farg3.d))) {
/* Magnitude subtraction of infinities */
- farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
+ farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI);
} else {
ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
@@ -894,7 +897,8 @@ uint64_t helper_fnmadd(uint64_t arg1, uint64_t arg2, uint64_t arg3)
}
/* fnmsub - fnmsub. */
-uint64_t helper_fnmsub(uint64_t arg1, uint64_t arg2, uint64_t arg3)
+uint64_t helper_fnmsub(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
+ uint64_t arg3)
{
CPU_DoubleU farg1, farg2, farg3;
@@ -906,13 +910,13 @@ uint64_t helper_fnmsub(uint64_t arg1, uint64_t arg2, uint64_t arg3)
(float64_is_zero(farg1.d) &&
float64_is_infinity(farg2.d)))) {
/* Multiplication of zero by infinity */
- farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
+ farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ);
} else {
if (unlikely(float64_is_signaling_nan(farg1.d) ||
float64_is_signaling_nan(farg2.d) ||
float64_is_signaling_nan(farg3.d))) {
/* sNaN operation */
- fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN);
}
/* This is the way the PowerPC specification defines it */
float128 ft0_128, ft1_128;
@@ -924,7 +928,7 @@ uint64_t helper_fnmsub(uint64_t arg1, uint64_t arg2, uint64_t arg3)
float64_is_infinity(farg3.d) &&
float128_is_neg(ft0_128) == float64_is_neg(farg3.d))) {
/* Magnitude subtraction of infinities */
- farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
+ farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI);
} else {
ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
@@ -938,7 +942,7 @@ uint64_t helper_fnmsub(uint64_t arg1, uint64_t arg2, uint64_t arg3)
}
/* frsp - frsp. */
-uint64_t helper_frsp(uint64_t arg)
+uint64_t helper_frsp(CPUPPCState *env, uint64_t arg)
{
CPU_DoubleU farg;
float32 f32;
@@ -947,7 +951,7 @@ uint64_t helper_frsp(uint64_t arg)
if (unlikely(float64_is_signaling_nan(farg.d))) {
/* sNaN square root */
- fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN);
}
f32 = float64_to_float32(farg.d, &env->fp_status);
farg.d = float32_to_float64(f32, &env->fp_status);
@@ -956,7 +960,7 @@ uint64_t helper_frsp(uint64_t arg)
}
/* fsqrt - fsqrt. */
-uint64_t helper_fsqrt(uint64_t arg)
+uint64_t helper_fsqrt(CPUPPCState *env, uint64_t arg)
{
CPU_DoubleU farg;
@@ -964,11 +968,11 @@ uint64_t helper_fsqrt(uint64_t arg)
if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) {
/* Square root of a negative nonzero number */
- farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSQRT);
+ farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT);
} else {
if (unlikely(float64_is_signaling_nan(farg.d))) {
/* sNaN square root */
- fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN);
}
farg.d = float64_sqrt(farg.d, &env->fp_status);
}
@@ -976,7 +980,7 @@ uint64_t helper_fsqrt(uint64_t arg)
}
/* fre - fre. */
-uint64_t helper_fre(uint64_t arg)
+uint64_t helper_fre(CPUPPCState *env, uint64_t arg)
{
CPU_DoubleU farg;
@@ -984,14 +988,14 @@ uint64_t helper_fre(uint64_t arg)
if (unlikely(float64_is_signaling_nan(farg.d))) {
/* sNaN reciprocal */
- fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN);
}
farg.d = float64_div(float64_one, farg.d, &env->fp_status);
return farg.d;
}
/* fres - fres. */
-uint64_t helper_fres(uint64_t arg)
+uint64_t helper_fres(CPUPPCState *env, uint64_t arg)
{
CPU_DoubleU farg;
float32 f32;
@@ -1000,7 +1004,7 @@ uint64_t helper_fres(uint64_t arg)
if (unlikely(float64_is_signaling_nan(farg.d))) {
/* sNaN reciprocal */
- fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN);
}
farg.d = float64_div(float64_one, farg.d, &env->fp_status);
f32 = float64_to_float32(farg.d, &env->fp_status);
@@ -1010,7 +1014,7 @@ uint64_t helper_fres(uint64_t arg)
}
/* frsqrte - frsqrte. */
-uint64_t helper_frsqrte(uint64_t arg)
+uint64_t helper_frsqrte(CPUPPCState *env, uint64_t arg)
{
CPU_DoubleU farg;
float32 f32;
@@ -1019,11 +1023,11 @@ uint64_t helper_frsqrte(uint64_t arg)
if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) {
/* Reciprocal square root of a negative nonzero number */
- farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSQRT);
+ farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT);
} else {
if (unlikely(float64_is_signaling_nan(farg.d))) {
/* sNaN reciprocal square root */
- fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN);
}
farg.d = float64_sqrt(farg.d, &env->fp_status);
farg.d = float64_div(float64_one, farg.d, &env->fp_status);
@@ -1034,7 +1038,8 @@ uint64_t helper_frsqrte(uint64_t arg)
}
/* fsel - fsel. */
-uint64_t helper_fsel(uint64_t arg1, uint64_t arg2, uint64_t arg3)
+uint64_t helper_fsel(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
+ uint64_t arg3)
{
CPU_DoubleU farg1;
@@ -1048,7 +1053,8 @@ uint64_t helper_fsel(uint64_t arg1, uint64_t arg2, uint64_t arg3)
}
}
-void helper_fcmpu(uint64_t arg1, uint64_t arg2, uint32_t crfD)
+void helper_fcmpu(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
+ uint32_t crfD)
{
CPU_DoubleU farg1, farg2;
uint32_t ret = 0;
@@ -1074,11 +1080,12 @@ void helper_fcmpu(uint64_t arg1, uint64_t arg2, uint32_t crfD)
&& (float64_is_signaling_nan(farg1.d) ||
float64_is_signaling_nan(farg2.d)))) {
/* sNaN comparison */
- fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN);
}
}
-void helper_fcmpo(uint64_t arg1, uint64_t arg2, uint32_t crfD)
+void helper_fcmpo(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
+ uint32_t crfD)
{
CPU_DoubleU farg1, farg2;
uint32_t ret = 0;
@@ -1104,17 +1111,17 @@ void helper_fcmpo(uint64_t arg1, uint64_t arg2, uint32_t crfD)
if (float64_is_signaling_nan(farg1.d) ||
float64_is_signaling_nan(farg2.d)) {
/* sNaN comparison */
- fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN |
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN |
POWERPC_EXCP_FP_VXVC);
} else {
/* qNaN comparison */
- fload_invalid_op_excp(POWERPC_EXCP_FP_VXVC);
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXVC);
}
}
}
/* Single-precision floating-point conversions */
-static inline uint32_t efscfsi(uint32_t val)
+static inline uint32_t efscfsi(CPUPPCState *env, uint32_t val)
{
CPU_FloatU u;
@@ -1123,7 +1130,7 @@ static inline uint32_t efscfsi(uint32_t val)
return u.l;
}
-static inline uint32_t efscfui(uint32_t val)
+static inline uint32_t efscfui(CPUPPCState *env, uint32_t val)
{
CPU_FloatU u;
@@ -1132,7 +1139,7 @@ static inline uint32_t efscfui(uint32_t val)
return u.l;
}
-static inline int32_t efsctsi(uint32_t val)
+static inline int32_t efsctsi(CPUPPCState *env, uint32_t val)
{
CPU_FloatU u;
@@ -1145,7 +1152,7 @@ static inline int32_t efsctsi(uint32_t val)
return float32_to_int32(u.f, &env->vec_status);
}
-static inline uint32_t efsctui(uint32_t val)
+static inline uint32_t efsctui(CPUPPCState *env, uint32_t val)
{
CPU_FloatU u;
@@ -1158,7 +1165,7 @@ static inline uint32_t efsctui(uint32_t val)
return float32_to_uint32(u.f, &env->vec_status);
}
-static inline uint32_t efsctsiz(uint32_t val)
+static inline uint32_t efsctsiz(CPUPPCState *env, uint32_t val)
{
CPU_FloatU u;
@@ -1171,7 +1178,7 @@ static inline uint32_t efsctsiz(uint32_t val)
return float32_to_int32_round_to_zero(u.f, &env->vec_status);
}
-static inline uint32_t efsctuiz(uint32_t val)
+static inline uint32_t efsctuiz(CPUPPCState *env, uint32_t val)
{
CPU_FloatU u;
@@ -1184,7 +1191,7 @@ static inline uint32_t efsctuiz(uint32_t val)
return float32_to_uint32_round_to_zero(u.f, &env->vec_status);
}
-static inline uint32_t efscfsf(uint32_t val)
+static inline uint32_t efscfsf(CPUPPCState *env, uint32_t val)
{
CPU_FloatU u;
float32 tmp;
@@ -1196,7 +1203,7 @@ static inline uint32_t efscfsf(uint32_t val)
return u.l;
}
-static inline uint32_t efscfuf(uint32_t val)
+static inline uint32_t efscfuf(CPUPPCState *env, uint32_t val)
{
CPU_FloatU u;
float32 tmp;
@@ -1208,7 +1215,7 @@ static inline uint32_t efscfuf(uint32_t val)
return u.l;
}
-static inline uint32_t efsctsf(uint32_t val)
+static inline uint32_t efsctsf(CPUPPCState *env, uint32_t val)
{
CPU_FloatU u;
float32 tmp;
@@ -1224,7 +1231,7 @@ static inline uint32_t efsctsf(uint32_t val)
return float32_to_int32(u.f, &env->vec_status);
}
-static inline uint32_t efsctuf(uint32_t val)
+static inline uint32_t efsctuf(CPUPPCState *env, uint32_t val)
{
CPU_FloatU u;
float32 tmp;
@@ -1240,10 +1247,10 @@ static inline uint32_t efsctuf(uint32_t val)
return float32_to_uint32(u.f, &env->vec_status);
}
-#define HELPER_SPE_SINGLE_CONV(name) \
- uint32_t helper_e##name(uint32_t val) \
- { \
- return e##name(val); \
+#define HELPER_SPE_SINGLE_CONV(name) \
+ uint32_t helper_e##name(CPUPPCState *env, uint32_t val) \
+ { \
+ return e##name(env, val); \
}
/* efscfsi */
HELPER_SPE_SINGLE_CONV(fscfsi);
@@ -1266,11 +1273,11 @@ HELPER_SPE_SINGLE_CONV(fsctsf);
/* efsctuf */
HELPER_SPE_SINGLE_CONV(fsctuf);
-#define HELPER_SPE_VECTOR_CONV(name) \
- uint64_t helper_ev##name(uint64_t val) \
- { \
- return ((uint64_t)e##name(val >> 32) << 32) | \
- (uint64_t)e##name(val); \
+#define HELPER_SPE_VECTOR_CONV(name) \
+ uint64_t helper_ev##name(CPUPPCState *env, uint64_t val) \
+ { \
+ return ((uint64_t)e##name(env, val >> 32) << 32) | \
+ (uint64_t)e##name(env, val); \
}
/* evfscfsi */
HELPER_SPE_VECTOR_CONV(fscfsi);
@@ -1294,7 +1301,7 @@ HELPER_SPE_VECTOR_CONV(fsctsf);
HELPER_SPE_VECTOR_CONV(fsctuf);
/* Single-precision floating-point arithmetic */
-static inline uint32_t efsadd(uint32_t op1, uint32_t op2)
+static inline uint32_t efsadd(CPUPPCState *env, uint32_t op1, uint32_t op2)
{
CPU_FloatU u1, u2;
@@ -1304,7 +1311,7 @@ static inline uint32_t efsadd(uint32_t op1, uint32_t op2)
return u1.l;
}
-static inline uint32_t efssub(uint32_t op1, uint32_t op2)
+static inline uint32_t efssub(CPUPPCState *env, uint32_t op1, uint32_t op2)
{
CPU_FloatU u1, u2;
@@ -1314,7 +1321,7 @@ static inline uint32_t efssub(uint32_t op1, uint32_t op2)
return u1.l;
}
-static inline uint32_t efsmul(uint32_t op1, uint32_t op2)
+static inline uint32_t efsmul(CPUPPCState *env, uint32_t op1, uint32_t op2)
{
CPU_FloatU u1, u2;
@@ -1324,7 +1331,7 @@ static inline uint32_t efsmul(uint32_t op1, uint32_t op2)
return u1.l;
}
-static inline uint32_t efsdiv(uint32_t op1, uint32_t op2)
+static inline uint32_t efsdiv(CPUPPCState *env, uint32_t op1, uint32_t op2)
{
CPU_FloatU u1, u2;
@@ -1334,10 +1341,10 @@ static inline uint32_t efsdiv(uint32_t op1, uint32_t op2)
return u1.l;
}
-#define HELPER_SPE_SINGLE_ARITH(name) \
- uint32_t helper_e##name(uint32_t op1, uint32_t op2) \
- { \
- return e##name(op1, op2); \
+#define HELPER_SPE_SINGLE_ARITH(name) \
+ uint32_t helper_e##name(CPUPPCState *env, uint32_t op1, uint32_t op2) \
+ { \
+ return e##name(env, op1, op2); \
}
/* efsadd */
HELPER_SPE_SINGLE_ARITH(fsadd);
@@ -1349,10 +1356,10 @@ HELPER_SPE_SINGLE_ARITH(fsmul);
HELPER_SPE_SINGLE_ARITH(fsdiv);
#define HELPER_SPE_VECTOR_ARITH(name) \
- uint64_t helper_ev##name(uint64_t op1, uint64_t op2) \
+ uint64_t helper_ev##name(CPUPPCState *env, uint64_t op1, uint64_t op2) \
{ \
- return ((uint64_t)e##name(op1 >> 32, op2 >> 32) << 32) | \
- (uint64_t)e##name(op1, op2); \
+ return ((uint64_t)e##name(env, op1 >> 32, op2 >> 32) << 32) | \
+ (uint64_t)e##name(env, op1, op2); \
}
/* evfsadd */
HELPER_SPE_VECTOR_ARITH(fsadd);
@@ -1364,7 +1371,7 @@ HELPER_SPE_VECTOR_ARITH(fsmul);
HELPER_SPE_VECTOR_ARITH(fsdiv);
/* Single-precision floating-point comparisons */
-static inline uint32_t efscmplt(uint32_t op1, uint32_t op2)
+static inline uint32_t efscmplt(CPUPPCState *env, uint32_t op1, uint32_t op2)
{
CPU_FloatU u1, u2;
@@ -1373,7 +1380,7 @@ static inline uint32_t efscmplt(uint32_t op1, uint32_t op2)
return float32_lt(u1.f, u2.f, &env->vec_status) ? 4 : 0;
}
-static inline uint32_t efscmpgt(uint32_t op1, uint32_t op2)
+static inline uint32_t efscmpgt(CPUPPCState *env, uint32_t op1, uint32_t op2)
{
CPU_FloatU u1, u2;
@@ -1382,7 +1389,7 @@ static inline uint32_t efscmpgt(uint32_t op1, uint32_t op2)
return float32_le(u1.f, u2.f, &env->vec_status) ? 0 : 4;
}
-static inline uint32_t efscmpeq(uint32_t op1, uint32_t op2)
+static inline uint32_t efscmpeq(CPUPPCState *env, uint32_t op1, uint32_t op2)
{
CPU_FloatU u1, u2;
@@ -1391,28 +1398,28 @@ static inline uint32_t efscmpeq(uint32_t op1, uint32_t op2)
return float32_eq(u1.f, u2.f, &env->vec_status) ? 4 : 0;
}
-static inline uint32_t efststlt(uint32_t op1, uint32_t op2)
+static inline uint32_t efststlt(CPUPPCState *env, uint32_t op1, uint32_t op2)
{
/* XXX: TODO: ignore special values (NaN, infinites, ...) */
- return efscmplt(op1, op2);
+ return efscmplt(env, op1, op2);
}
-static inline uint32_t efststgt(uint32_t op1, uint32_t op2)
+static inline uint32_t efststgt(CPUPPCState *env, uint32_t op1, uint32_t op2)
{
/* XXX: TODO: ignore special values (NaN, infinites, ...) */
- return efscmpgt(op1, op2);
+ return efscmpgt(env, op1, op2);
}
-static inline uint32_t efststeq(uint32_t op1, uint32_t op2)
+static inline uint32_t efststeq(CPUPPCState *env, uint32_t op1, uint32_t op2)
{
/* XXX: TODO: ignore special values (NaN, infinites, ...) */
- return efscmpeq(op1, op2);
+ return efscmpeq(env, op1, op2);
}
-#define HELPER_SINGLE_SPE_CMP(name) \
- uint32_t helper_e##name(uint32_t op1, uint32_t op2) \
- { \
- return e##name(op1, op2) << 2; \
+#define HELPER_SINGLE_SPE_CMP(name) \
+ uint32_t helper_e##name(CPUPPCState *env, uint32_t op1, uint32_t op2) \
+ { \
+ return e##name(env, op1, op2) << 2; \
}
/* efststlt */
HELPER_SINGLE_SPE_CMP(fststlt);
@@ -1433,9 +1440,10 @@ static inline uint32_t evcmp_merge(int t0, int t1)
}
#define HELPER_VECTOR_SPE_CMP(name) \
- uint32_t helper_ev##name(uint64_t op1, uint64_t op2) \
+ uint32_t helper_ev##name(CPUPPCState *env, uint64_t op1, uint64_t op2) \
{ \
- return evcmp_merge(e##name(op1 >> 32, op2 >> 32), e##name(op1, op2)); \
+ return evcmp_merge(e##name(env, op1 >> 32, op2 >> 32), \
+ e##name(env, op1, op2)); \
}
/* evfststlt */
HELPER_VECTOR_SPE_CMP(fststlt);
@@ -1451,7 +1459,7 @@ HELPER_VECTOR_SPE_CMP(fscmpgt);
HELPER_VECTOR_SPE_CMP(fscmpeq);
/* Double-precision floating-point conversion */
-uint64_t helper_efdcfsi(uint32_t val)
+uint64_t helper_efdcfsi(CPUPPCState *env, uint32_t val)
{
CPU_DoubleU u;
@@ -1460,7 +1468,7 @@ uint64_t helper_efdcfsi(uint32_t val)
return u.ll;
}
-uint64_t helper_efdcfsid(uint64_t val)
+uint64_t helper_efdcfsid(CPUPPCState *env, uint64_t val)
{
CPU_DoubleU u;
@@ -1469,7 +1477,7 @@ uint64_t helper_efdcfsid(uint64_t val)
return u.ll;
}
-uint64_t helper_efdcfui(uint32_t val)
+uint64_t helper_efdcfui(CPUPPCState *env, uint32_t val)
{
CPU_DoubleU u;
@@ -1478,7 +1486,7 @@ uint64_t helper_efdcfui(uint32_t val)
return u.ll;
}
-uint64_t helper_efdcfuid(uint64_t val)
+uint64_t helper_efdcfuid(CPUPPCState *env, uint64_t val)
{
CPU_DoubleU u;
@@ -1487,7 +1495,7 @@ uint64_t helper_efdcfuid(uint64_t val)
return u.ll;
}
-uint32_t helper_efdctsi(uint64_t val)
+uint32_t helper_efdctsi(CPUPPCState *env, uint64_t val)
{
CPU_DoubleU u;
@@ -1500,7 +1508,7 @@ uint32_t helper_efdctsi(uint64_t val)
return float64_to_int32(u.d, &env->vec_status);
}
-uint32_t helper_efdctui(uint64_t val)
+uint32_t helper_efdctui(CPUPPCState *env, uint64_t val)
{
CPU_DoubleU u;
@@ -1513,7 +1521,7 @@ uint32_t helper_efdctui(uint64_t val)
return float64_to_uint32(u.d, &env->vec_status);
}
-uint32_t helper_efdctsiz(uint64_t val)
+uint32_t helper_efdctsiz(CPUPPCState *env, uint64_t val)
{
CPU_DoubleU u;
@@ -1526,7 +1534,7 @@ uint32_t helper_efdctsiz(uint64_t val)
return float64_to_int32_round_to_zero(u.d, &env->vec_status);
}
-uint64_t helper_efdctsidz(uint64_t val)
+uint64_t helper_efdctsidz(CPUPPCState *env, uint64_t val)
{
CPU_DoubleU u;
@@ -1539,7 +1547,7 @@ uint64_t helper_efdctsidz(uint64_t val)
return float64_to_int64_round_to_zero(u.d, &env->vec_status);
}
-uint32_t helper_efdctuiz(uint64_t val)
+uint32_t helper_efdctuiz(CPUPPCState *env, uint64_t val)
{
CPU_DoubleU u;
@@ -1552,7 +1560,7 @@ uint32_t helper_efdctuiz(uint64_t val)
return float64_to_uint32_round_to_zero(u.d, &env->vec_status);
}
-uint64_t helper_efdctuidz(uint64_t val)
+uint64_t helper_efdctuidz(CPUPPCState *env, uint64_t val)
{
CPU_DoubleU u;
@@ -1565,7 +1573,7 @@ uint64_t helper_efdctuidz(uint64_t val)
return float64_to_uint64_round_to_zero(u.d, &env->vec_status);
}
-uint64_t helper_efdcfsf(uint32_t val)
+uint64_t helper_efdcfsf(CPUPPCState *env, uint32_t val)
{
CPU_DoubleU u;
float64 tmp;
@@ -1577,7 +1585,7 @@ uint64_t helper_efdcfsf(uint32_t val)
return u.ll;
}
-uint64_t helper_efdcfuf(uint32_t val)
+uint64_t helper_efdcfuf(CPUPPCState *env, uint32_t val)
{
CPU_DoubleU u;
float64 tmp;
@@ -1589,7 +1597,7 @@ uint64_t helper_efdcfuf(uint32_t val)
return u.ll;
}
-uint32_t helper_efdctsf(uint64_t val)
+uint32_t helper_efdctsf(CPUPPCState *env, uint64_t val)
{
CPU_DoubleU u;
float64 tmp;
@@ -1605,7 +1613,7 @@ uint32_t helper_efdctsf(uint64_t val)
return float64_to_int32(u.d, &env->vec_status);
}
-uint32_t helper_efdctuf(uint64_t val)
+uint32_t helper_efdctuf(CPUPPCState *env, uint64_t val)
{
CPU_DoubleU u;
float64 tmp;
@@ -1621,7 +1629,7 @@ uint32_t helper_efdctuf(uint64_t val)
return float64_to_uint32(u.d, &env->vec_status);
}
-uint32_t helper_efscfd(uint64_t val)
+uint32_t helper_efscfd(CPUPPCState *env, uint64_t val)
{
CPU_DoubleU u1;
CPU_FloatU u2;
@@ -1632,7 +1640,7 @@ uint32_t helper_efscfd(uint64_t val)
return u2.l;
}
-uint64_t helper_efdcfs(uint32_t val)
+uint64_t helper_efdcfs(CPUPPCState *env, uint32_t val)
{
CPU_DoubleU u2;
CPU_FloatU u1;
@@ -1644,7 +1652,7 @@ uint64_t helper_efdcfs(uint32_t val)
}
/* Double precision fixed-point arithmetic */
-uint64_t helper_efdadd(uint64_t op1, uint64_t op2)
+uint64_t helper_efdadd(CPUPPCState *env, uint64_t op1, uint64_t op2)
{
CPU_DoubleU u1, u2;
@@ -1654,7 +1662,7 @@ uint64_t helper_efdadd(uint64_t op1, uint64_t op2)
return u1.ll;
}
-uint64_t helper_efdsub(uint64_t op1, uint64_t op2)
+uint64_t helper_efdsub(CPUPPCState *env, uint64_t op1, uint64_t op2)
{
CPU_DoubleU u1, u2;
@@ -1664,7 +1672,7 @@ uint64_t helper_efdsub(uint64_t op1, uint64_t op2)
return u1.ll;
}
-uint64_t helper_efdmul(uint64_t op1, uint64_t op2)
+uint64_t helper_efdmul(CPUPPCState *env, uint64_t op1, uint64_t op2)
{
CPU_DoubleU u1, u2;
@@ -1674,7 +1682,7 @@ uint64_t helper_efdmul(uint64_t op1, uint64_t op2)
return u1.ll;
}
-uint64_t helper_efddiv(uint64_t op1, uint64_t op2)
+uint64_t helper_efddiv(CPUPPCState *env, uint64_t op1, uint64_t op2)
{
CPU_DoubleU u1, u2;
@@ -1685,7 +1693,7 @@ uint64_t helper_efddiv(uint64_t op1, uint64_t op2)
}
/* Double precision floating point helpers */
-uint32_t helper_efdtstlt(uint64_t op1, uint64_t op2)
+uint32_t helper_efdtstlt(CPUPPCState *env, uint64_t op1, uint64_t op2)
{
CPU_DoubleU u1, u2;
@@ -1694,7 +1702,7 @@ uint32_t helper_efdtstlt(uint64_t op1, uint64_t op2)
return float64_lt(u1.d, u2.d, &env->vec_status) ? 4 : 0;
}
-uint32_t helper_efdtstgt(uint64_t op1, uint64_t op2)
+uint32_t helper_efdtstgt(CPUPPCState *env, uint64_t op1, uint64_t op2)
{
CPU_DoubleU u1, u2;
@@ -1703,7 +1711,7 @@ uint32_t helper_efdtstgt(uint64_t op1, uint64_t op2)
return float64_le(u1.d, u2.d, &env->vec_status) ? 0 : 4;
}
-uint32_t helper_efdtsteq(uint64_t op1, uint64_t op2)
+uint32_t helper_efdtsteq(CPUPPCState *env, uint64_t op1, uint64_t op2)
{
CPU_DoubleU u1, u2;
@@ -1712,20 +1720,20 @@ uint32_t helper_efdtsteq(uint64_t op1, uint64_t op2)
return float64_eq_quiet(u1.d, u2.d, &env->vec_status) ? 4 : 0;
}
-uint32_t helper_efdcmplt(uint64_t op1, uint64_t op2)
+uint32_t helper_efdcmplt(CPUPPCState *env, uint64_t op1, uint64_t op2)
{
/* XXX: TODO: test special values (NaN, infinites, ...) */
- return helper_efdtstlt(op1, op2);
+ return helper_efdtstlt(env, op1, op2);
}
-uint32_t helper_efdcmpgt(uint64_t op1, uint64_t op2)
+uint32_t helper_efdcmpgt(CPUPPCState *env, uint64_t op1, uint64_t op2)
{
/* XXX: TODO: test special values (NaN, infinites, ...) */
- return helper_efdtstgt(op1, op2);
+ return helper_efdtstgt(env, op1, op2);
}
-uint32_t helper_efdcmpeq(uint64_t op1, uint64_t op2)
+uint32_t helper_efdcmpeq(CPUPPCState *env, uint64_t op1, uint64_t op2)
{
/* XXX: TODO: test special values (NaN, infinites, ...) */
- return helper_efdtsteq(op1, op2);
+ return helper_efdtsteq(env, op1, op2);
}
diff --git a/target-ppc/helper.h b/target-ppc/helper.h
index a4562ae..0aba7f8 100644
--- a/target-ppc/helper.h
+++ b/target-ppc/helper.h
@@ -50,47 +50,47 @@ DEF_HELPER_FLAGS_1(cntlsw32, TCG_CALL_CONST | TCG_CALL_PURE, i32, i32)
DEF_HELPER_FLAGS_1(cntlzw32, TCG_CALL_CONST | TCG_CALL_PURE, i32, i32)
DEF_HELPER_FLAGS_2(brinc, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl, tl)
-DEF_HELPER_0(float_check_status, void)
-DEF_HELPER_0(reset_fpstatus, void)
-DEF_HELPER_2(compute_fprf, i32, i64, i32)
-DEF_HELPER_2(store_fpscr, void, i64, i32)
-DEF_HELPER_1(fpscr_clrbit, void, i32)
-DEF_HELPER_1(fpscr_setbit, void, i32)
-DEF_HELPER_1(float64_to_float32, i32, i64)
-DEF_HELPER_1(float32_to_float64, i64, i32)
+DEF_HELPER_1(float_check_status, void, env)
+DEF_HELPER_1(reset_fpstatus, void, env)
+DEF_HELPER_3(compute_fprf, i32, env, i64, i32)
+DEF_HELPER_3(store_fpscr, void, env, i64, i32)
+DEF_HELPER_2(fpscr_clrbit, void, env, i32)
+DEF_HELPER_2(fpscr_setbit, void, env, i32)
+DEF_HELPER_2(float64_to_float32, i32, env, i64)
+DEF_HELPER_2(float32_to_float64, i64, env, i32)
-DEF_HELPER_3(fcmpo, void, i64, i64, i32)
-DEF_HELPER_3(fcmpu, void, i64, i64, i32)
+DEF_HELPER_4(fcmpo, void, env, i64, i64, i32)
+DEF_HELPER_4(fcmpu, void, env, i64, i64, i32)
-DEF_HELPER_1(fctiw, i64, i64)
-DEF_HELPER_1(fctiwz, i64, i64)
+DEF_HELPER_2(fctiw, i64, env, i64)
+DEF_HELPER_2(fctiwz, i64, env, i64)
#if defined(TARGET_PPC64)
-DEF_HELPER_1(fcfid, i64, i64)
-DEF_HELPER_1(fctid, i64, i64)
-DEF_HELPER_1(fctidz, i64, i64)
+DEF_HELPER_2(fcfid, i64, env, i64)
+DEF_HELPER_2(fctid, i64, env, i64)
+DEF_HELPER_2(fctidz, i64, env, i64)
#endif
-DEF_HELPER_1(frsp, i64, i64)
-DEF_HELPER_1(frin, i64, i64)
-DEF_HELPER_1(friz, i64, i64)
-DEF_HELPER_1(frip, i64, i64)
-DEF_HELPER_1(frim, i64, i64)
+DEF_HELPER_2(frsp, i64, env, i64)
+DEF_HELPER_2(frin, i64, env, i64)
+DEF_HELPER_2(friz, i64, env, i64)
+DEF_HELPER_2(frip, i64, env, i64)
+DEF_HELPER_2(frim, i64, env, i64)
-DEF_HELPER_2(fadd, i64, i64, i64)
-DEF_HELPER_2(fsub, i64, i64, i64)
-DEF_HELPER_2(fmul, i64, i64, i64)
-DEF_HELPER_2(fdiv, i64, i64, i64)
-DEF_HELPER_3(fmadd, i64, i64, i64, i64)
-DEF_HELPER_3(fmsub, i64, i64, i64, i64)
-DEF_HELPER_3(fnmadd, i64, i64, i64, i64)
-DEF_HELPER_3(fnmsub, i64, i64, i64, i64)
-DEF_HELPER_1(fabs, i64, i64)
-DEF_HELPER_1(fnabs, i64, i64)
-DEF_HELPER_1(fneg, i64, i64)
-DEF_HELPER_1(fsqrt, i64, i64)
-DEF_HELPER_1(fre, i64, i64)
-DEF_HELPER_1(fres, i64, i64)
-DEF_HELPER_1(frsqrte, i64, i64)
-DEF_HELPER_3(fsel, i64, i64, i64, i64)
+DEF_HELPER_3(fadd, i64, env, i64, i64)
+DEF_HELPER_3(fsub, i64, env, i64, i64)
+DEF_HELPER_3(fmul, i64, env, i64, i64)
+DEF_HELPER_3(fdiv, i64, env, i64, i64)
+DEF_HELPER_4(fmadd, i64, env, i64, i64, i64)
+DEF_HELPER_4(fmsub, i64, env, i64, i64, i64)
+DEF_HELPER_4(fnmadd, i64, env, i64, i64, i64)
+DEF_HELPER_4(fnmsub, i64, env, i64, i64, i64)
+DEF_HELPER_2(fabs, i64, env, i64)
+DEF_HELPER_2(fnabs, i64, env, i64)
+DEF_HELPER_2(fneg, i64, env, i64)
+DEF_HELPER_2(fsqrt, i64, env, i64)
+DEF_HELPER_2(fre, i64, env, i64)
+DEF_HELPER_2(fres, i64, env, i64)
+DEF_HELPER_2(frsqrte, i64, env, i64)
+DEF_HELPER_4(fsel, i64, env, i64, i64, i64)
#define dh_alias_avr ptr
#define dh_ctype_avr ppc_avr_t *
@@ -256,72 +256,72 @@ DEF_HELPER_3(vcfsx, void, avr, avr, i32)
DEF_HELPER_3(vctuxs, void, avr, avr, i32)
DEF_HELPER_3(vctsxs, void, avr, avr, i32)
-DEF_HELPER_1(efscfsi, i32, i32)
-DEF_HELPER_1(efscfui, i32, i32)
-DEF_HELPER_1(efscfuf, i32, i32)
-DEF_HELPER_1(efscfsf, i32, i32)
-DEF_HELPER_1(efsctsi, i32, i32)
-DEF_HELPER_1(efsctui, i32, i32)
-DEF_HELPER_1(efsctsiz, i32, i32)
-DEF_HELPER_1(efsctuiz, i32, i32)
-DEF_HELPER_1(efsctsf, i32, i32)
-DEF_HELPER_1(efsctuf, i32, i32)
-DEF_HELPER_1(evfscfsi, i64, i64)
-DEF_HELPER_1(evfscfui, i64, i64)
-DEF_HELPER_1(evfscfuf, i64, i64)
-DEF_HELPER_1(evfscfsf, i64, i64)
-DEF_HELPER_1(evfsctsi, i64, i64)
-DEF_HELPER_1(evfsctui, i64, i64)
-DEF_HELPER_1(evfsctsiz, i64, i64)
-DEF_HELPER_1(evfsctuiz, i64, i64)
-DEF_HELPER_1(evfsctsf, i64, i64)
-DEF_HELPER_1(evfsctuf, i64, i64)
-DEF_HELPER_2(efsadd, i32, i32, i32)
-DEF_HELPER_2(efssub, i32, i32, i32)
-DEF_HELPER_2(efsmul, i32, i32, i32)
-DEF_HELPER_2(efsdiv, i32, i32, i32)
-DEF_HELPER_2(evfsadd, i64, i64, i64)
-DEF_HELPER_2(evfssub, i64, i64, i64)
-DEF_HELPER_2(evfsmul, i64, i64, i64)
-DEF_HELPER_2(evfsdiv, i64, i64, i64)
-DEF_HELPER_2(efststlt, i32, i32, i32)
-DEF_HELPER_2(efststgt, i32, i32, i32)
-DEF_HELPER_2(efststeq, i32, i32, i32)
-DEF_HELPER_2(efscmplt, i32, i32, i32)
-DEF_HELPER_2(efscmpgt, i32, i32, i32)
-DEF_HELPER_2(efscmpeq, i32, i32, i32)
-DEF_HELPER_2(evfststlt, i32, i64, i64)
-DEF_HELPER_2(evfststgt, i32, i64, i64)
-DEF_HELPER_2(evfststeq, i32, i64, i64)
-DEF_HELPER_2(evfscmplt, i32, i64, i64)
-DEF_HELPER_2(evfscmpgt, i32, i64, i64)
-DEF_HELPER_2(evfscmpeq, i32, i64, i64)
-DEF_HELPER_1(efdcfsi, i64, i32)
-DEF_HELPER_1(efdcfsid, i64, i64)
-DEF_HELPER_1(efdcfui, i64, i32)
-DEF_HELPER_1(efdcfuid, i64, i64)
-DEF_HELPER_1(efdctsi, i32, i64)
-DEF_HELPER_1(efdctui, i32, i64)
-DEF_HELPER_1(efdctsiz, i32, i64)
-DEF_HELPER_1(efdctsidz, i64, i64)
-DEF_HELPER_1(efdctuiz, i32, i64)
-DEF_HELPER_1(efdctuidz, i64, i64)
-DEF_HELPER_1(efdcfsf, i64, i32)
-DEF_HELPER_1(efdcfuf, i64, i32)
-DEF_HELPER_1(efdctsf, i32, i64)
-DEF_HELPER_1(efdctuf, i32, i64)
-DEF_HELPER_1(efscfd, i32, i64)
-DEF_HELPER_1(efdcfs, i64, i32)
-DEF_HELPER_2(efdadd, i64, i64, i64)
-DEF_HELPER_2(efdsub, i64, i64, i64)
-DEF_HELPER_2(efdmul, i64, i64, i64)
-DEF_HELPER_2(efddiv, i64, i64, i64)
-DEF_HELPER_2(efdtstlt, i32, i64, i64)
-DEF_HELPER_2(efdtstgt, i32, i64, i64)
-DEF_HELPER_2(efdtsteq, i32, i64, i64)
-DEF_HELPER_2(efdcmplt, i32, i64, i64)
-DEF_HELPER_2(efdcmpgt, i32, i64, i64)
-DEF_HELPER_2(efdcmpeq, i32, i64, i64)
+DEF_HELPER_2(efscfsi, i32, env, i32)
+DEF_HELPER_2(efscfui, i32, env, i32)
+DEF_HELPER_2(efscfuf, i32, env, i32)
+DEF_HELPER_2(efscfsf, i32, env, i32)
+DEF_HELPER_2(efsctsi, i32, env, i32)
+DEF_HELPER_2(efsctui, i32, env, i32)
+DEF_HELPER_2(efsctsiz, i32, env, i32)
+DEF_HELPER_2(efsctuiz, i32, env, i32)
+DEF_HELPER_2(efsctsf, i32, env, i32)
+DEF_HELPER_2(efsctuf, i32, env, i32)
+DEF_HELPER_2(evfscfsi, i64, env, i64)
+DEF_HELPER_2(evfscfui, i64, env, i64)
+DEF_HELPER_2(evfscfuf, i64, env, i64)
+DEF_HELPER_2(evfscfsf, i64, env, i64)
+DEF_HELPER_2(evfsctsi, i64, env, i64)
+DEF_HELPER_2(evfsctui, i64, env, i64)
+DEF_HELPER_2(evfsctsiz, i64, env, i64)
+DEF_HELPER_2(evfsctuiz, i64, env, i64)
+DEF_HELPER_2(evfsctsf, i64, env, i64)
+DEF_HELPER_2(evfsctuf, i64, env, i64)
+DEF_HELPER_3(efsadd, i32, env, i32, i32)
+DEF_HELPER_3(efssub, i32, env, i32, i32)
+DEF_HELPER_3(efsmul, i32, env, i32, i32)
+DEF_HELPER_3(efsdiv, i32, env, i32, i32)
+DEF_HELPER_3(evfsadd, i64, env, i64, i64)
+DEF_HELPER_3(evfssub, i64, env, i64, i64)
+DEF_HELPER_3(evfsmul, i64, env, i64, i64)
+DEF_HELPER_3(evfsdiv, i64, env, i64, i64)
+DEF_HELPER_3(efststlt, i32, env, i32, i32)
+DEF_HELPER_3(efststgt, i32, env, i32, i32)
+DEF_HELPER_3(efststeq, i32, env, i32, i32)
+DEF_HELPER_3(efscmplt, i32, env, i32, i32)
+DEF_HELPER_3(efscmpgt, i32, env, i32, i32)
+DEF_HELPER_3(efscmpeq, i32, env, i32, i32)
+DEF_HELPER_3(evfststlt, i32, env, i64, i64)
+DEF_HELPER_3(evfststgt, i32, env, i64, i64)
+DEF_HELPER_3(evfststeq, i32, env, i64, i64)
+DEF_HELPER_3(evfscmplt, i32, env, i64, i64)
+DEF_HELPER_3(evfscmpgt, i32, env, i64, i64)
+DEF_HELPER_3(evfscmpeq, i32, env, i64, i64)
+DEF_HELPER_2(efdcfsi, i64, env, i32)
+DEF_HELPER_2(efdcfsid, i64, env, i64)
+DEF_HELPER_2(efdcfui, i64, env, i32)
+DEF_HELPER_2(efdcfuid, i64, env, i64)
+DEF_HELPER_2(efdctsi, i32, env, i64)
+DEF_HELPER_2(efdctui, i32, env, i64)
+DEF_HELPER_2(efdctsiz, i32, env, i64)
+DEF_HELPER_2(efdctsidz, i64, env, i64)
+DEF_HELPER_2(efdctuiz, i32, env, i64)
+DEF_HELPER_2(efdctuidz, i64, env, i64)
+DEF_HELPER_2(efdcfsf, i64, env, i32)
+DEF_HELPER_2(efdcfuf, i64, env, i32)
+DEF_HELPER_2(efdctsf, i32, env, i64)
+DEF_HELPER_2(efdctuf, i32, env, i64)
+DEF_HELPER_2(efscfd, i32, env, i64)
+DEF_HELPER_2(efdcfs, i64, env, i32)
+DEF_HELPER_3(efdadd, i64, env, i64, i64)
+DEF_HELPER_3(efdsub, i64, env, i64, i64)
+DEF_HELPER_3(efdmul, i64, env, i64, i64)
+DEF_HELPER_3(efddiv, i64, env, i64, i64)
+DEF_HELPER_3(efdtstlt, i32, env, i64, i64)
+DEF_HELPER_3(efdtstgt, i32, env, i64, i64)
+DEF_HELPER_3(efdtsteq, i32, env, i64, i64)
+DEF_HELPER_3(efdcmplt, i32, env, i64, i64)
+DEF_HELPER_3(efdcmpgt, i32, env, i64, i64)
+DEF_HELPER_3(efdcmpeq, i32, env, i64, i64)
#if !defined(CONFIG_USER_ONLY)
DEF_HELPER_1(4xx_tlbre_hi, tl, tl)
diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index 02626ae..c8b7982 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -219,7 +219,7 @@ struct opc_handler_t {
static inline void gen_reset_fpstatus(void)
{
- gen_helper_reset_fpstatus();
+ gen_helper_reset_fpstatus(cpu_env);
}
static inline void gen_compute_fprf(TCGv_i64 arg, int set_fprf, int set_rc)
@@ -229,15 +229,15 @@ static inline void gen_compute_fprf(TCGv_i64 arg, int set_fprf, int set_rc)
if (set_fprf != 0) {
/* This case might be optimized later */
tcg_gen_movi_i32(t0, 1);
- gen_helper_compute_fprf(t0, arg, t0);
+ gen_helper_compute_fprf(t0, cpu_env, arg, t0);
if (unlikely(set_rc)) {
tcg_gen_mov_i32(cpu_crf[1], t0);
}
- gen_helper_float_check_status();
+ gen_helper_float_check_status(cpu_env);
} else if (unlikely(set_rc)) {
/* We always need to compute fpcc */
tcg_gen_movi_i32(t0, 0);
- gen_helper_compute_fprf(t0, arg, t0);
+ gen_helper_compute_fprf(t0, cpu_env, arg, t0);
tcg_gen_mov_i32(cpu_crf[1], t0);
}
@@ -2027,10 +2027,12 @@ static void gen_f##name(DisasContext *ctx) \
/* NIP cannot be restored if the memory exception comes from an helper */ \
gen_update_nip(ctx, ctx->nip - 4); \
gen_reset_fpstatus(); \
- gen_helper_f##op(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rA(ctx->opcode)], \
+ gen_helper_f##op(cpu_fpr[rD(ctx->opcode)], cpu_env, \
+ cpu_fpr[rA(ctx->opcode)], \
cpu_fpr[rC(ctx->opcode)], cpu_fpr[rB(ctx->opcode)]); \
if (isfloat) { \
- gen_helper_frsp(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rD(ctx->opcode)]); \
+ gen_helper_frsp(cpu_fpr[rD(ctx->opcode)], cpu_env, \
+ cpu_fpr[rD(ctx->opcode)]); \
} \
gen_compute_fprf(cpu_fpr[rD(ctx->opcode)], set_fprf, \
Rc(ctx->opcode) != 0); \
@@ -2050,10 +2052,12 @@ static void gen_f##name(DisasContext *ctx) \
/* NIP cannot be restored if the memory exception comes from an helper */ \
gen_update_nip(ctx, ctx->nip - 4); \
gen_reset_fpstatus(); \
- gen_helper_f##op(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rA(ctx->opcode)], \
+ gen_helper_f##op(cpu_fpr[rD(ctx->opcode)], cpu_env, \
+ cpu_fpr[rA(ctx->opcode)], \
cpu_fpr[rB(ctx->opcode)]); \
if (isfloat) { \
- gen_helper_frsp(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rD(ctx->opcode)]); \
+ gen_helper_frsp(cpu_fpr[rD(ctx->opcode)], cpu_env, \
+ cpu_fpr[rD(ctx->opcode)]); \
} \
gen_compute_fprf(cpu_fpr[rD(ctx->opcode)], \
set_fprf, Rc(ctx->opcode) != 0); \
@@ -2072,10 +2076,12 @@ static void gen_f##name(DisasContext *ctx) \
/* NIP cannot be restored if the memory exception comes from an helper */ \
gen_update_nip(ctx, ctx->nip - 4); \
gen_reset_fpstatus(); \
- gen_helper_f##op(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rA(ctx->opcode)], \
- cpu_fpr[rC(ctx->opcode)]); \
+ gen_helper_f##op(cpu_fpr[rD(ctx->opcode)], cpu_env, \
+ cpu_fpr[rA(ctx->opcode)], \
+ cpu_fpr[rC(ctx->opcode)]); \
if (isfloat) { \
- gen_helper_frsp(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rD(ctx->opcode)]); \
+ gen_helper_frsp(cpu_fpr[rD(ctx->opcode)], cpu_env, \
+ cpu_fpr[rD(ctx->opcode)]); \
} \
gen_compute_fprf(cpu_fpr[rD(ctx->opcode)], \
set_fprf, Rc(ctx->opcode) != 0); \
@@ -2094,7 +2100,8 @@ static void gen_f##name(DisasContext *ctx) \
/* NIP cannot be restored if the memory exception comes from an helper */ \
gen_update_nip(ctx, ctx->nip - 4); \
gen_reset_fpstatus(); \
- gen_helper_f##name(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rB(ctx->opcode)]); \
+ gen_helper_f##name(cpu_fpr[rD(ctx->opcode)], cpu_env, \
+ cpu_fpr[rB(ctx->opcode)]); \
gen_compute_fprf(cpu_fpr[rD(ctx->opcode)], \
set_fprf, Rc(ctx->opcode) != 0); \
}
@@ -2109,7 +2116,8 @@ static void gen_f##name(DisasContext *ctx) \
/* NIP cannot be restored if the memory exception comes from an helper */ \
gen_update_nip(ctx, ctx->nip - 4); \
gen_reset_fpstatus(); \
- gen_helper_f##name(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rB(ctx->opcode)]); \
+ gen_helper_f##name(cpu_fpr[rD(ctx->opcode)], cpu_env, \
+ cpu_fpr[rB(ctx->opcode)]); \
gen_compute_fprf(cpu_fpr[rD(ctx->opcode)], \
set_fprf, Rc(ctx->opcode) != 0); \
}
@@ -2140,8 +2148,10 @@ static void gen_frsqrtes(DisasContext *ctx)
/* NIP cannot be restored if the memory exception comes from an helper */
gen_update_nip(ctx, ctx->nip - 4);
gen_reset_fpstatus();
- gen_helper_frsqrte(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rB(ctx->opcode)]);
- gen_helper_frsp(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rD(ctx->opcode)]);
+ gen_helper_frsqrte(cpu_fpr[rD(ctx->opcode)], cpu_env,
+ cpu_fpr[rB(ctx->opcode)]);
+ gen_helper_frsp(cpu_fpr[rD(ctx->opcode)], cpu_env,
+ cpu_fpr[rD(ctx->opcode)]);
gen_compute_fprf(cpu_fpr[rD(ctx->opcode)], 1, Rc(ctx->opcode) != 0);
}
@@ -2161,7 +2171,8 @@ static void gen_fsqrt(DisasContext *ctx)
/* NIP cannot be restored if the memory exception comes from an helper */
gen_update_nip(ctx, ctx->nip - 4);
gen_reset_fpstatus();
- gen_helper_fsqrt(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rB(ctx->opcode)]);
+ gen_helper_fsqrt(cpu_fpr[rD(ctx->opcode)], cpu_env,
+ cpu_fpr[rB(ctx->opcode)]);
gen_compute_fprf(cpu_fpr[rD(ctx->opcode)], 1, Rc(ctx->opcode) != 0);
}
@@ -2174,8 +2185,10 @@ static void gen_fsqrts(DisasContext *ctx)
/* NIP cannot be restored if the memory exception comes from an helper */
gen_update_nip(ctx, ctx->nip - 4);
gen_reset_fpstatus();
- gen_helper_fsqrt(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rB(ctx->opcode)]);
- gen_helper_frsp(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rD(ctx->opcode)]);
+ gen_helper_fsqrt(cpu_fpr[rD(ctx->opcode)], cpu_env,
+ cpu_fpr[rB(ctx->opcode)]);
+ gen_helper_frsp(cpu_fpr[rD(ctx->opcode)], cpu_env,
+ cpu_fpr[rD(ctx->opcode)]);
gen_compute_fprf(cpu_fpr[rD(ctx->opcode)], 1, Rc(ctx->opcode) != 0);
}
@@ -2228,9 +2241,10 @@ static void gen_fcmpo(DisasContext *ctx)
gen_update_nip(ctx, ctx->nip - 4);
gen_reset_fpstatus();
crf = tcg_const_i32(crfD(ctx->opcode));
- gen_helper_fcmpo(cpu_fpr[rA(ctx->opcode)], cpu_fpr[rB(ctx->opcode)], crf);
+ gen_helper_fcmpo(cpu_env, cpu_fpr[rA(ctx->opcode)],
+ cpu_fpr[rB(ctx->opcode)], crf);
tcg_temp_free_i32(crf);
- gen_helper_float_check_status();
+ gen_helper_float_check_status(cpu_env);
}
/* fcmpu */
@@ -2245,9 +2259,10 @@ static void gen_fcmpu(DisasContext *ctx)
gen_update_nip(ctx, ctx->nip - 4);
gen_reset_fpstatus();
crf = tcg_const_i32(crfD(ctx->opcode));
- gen_helper_fcmpu(cpu_fpr[rA(ctx->opcode)], cpu_fpr[rB(ctx->opcode)], crf);
+ gen_helper_fcmpu(cpu_env, cpu_fpr[rA(ctx->opcode)],
+ cpu_fpr[rB(ctx->opcode)], crf);
tcg_temp_free_i32(crf);
- gen_helper_float_check_status();
+ gen_helper_float_check_status(cpu_env);
}
/*** Floating-point move ***/
@@ -2319,7 +2334,7 @@ static void gen_mtfsb0(DisasContext *ctx)
/* NIP cannot be restored if the memory exception comes from an helper */
gen_update_nip(ctx, ctx->nip - 4);
t0 = tcg_const_i32(crb);
- gen_helper_fpscr_clrbit(t0);
+ gen_helper_fpscr_clrbit(cpu_env, t0);
tcg_temp_free_i32(t0);
}
if (unlikely(Rc(ctx->opcode) != 0)) {
@@ -2344,14 +2359,14 @@ static void gen_mtfsb1(DisasContext *ctx)
/* NIP cannot be restored if the memory exception comes from an helper */
gen_update_nip(ctx, ctx->nip - 4);
t0 = tcg_const_i32(crb);
- gen_helper_fpscr_setbit(t0);
+ gen_helper_fpscr_setbit(cpu_env, t0);
tcg_temp_free_i32(t0);
}
if (unlikely(Rc(ctx->opcode) != 0)) {
tcg_gen_shri_i32(cpu_crf[1], cpu_fpscr, FPSCR_OX);
}
/* We can raise a differed exception */
- gen_helper_float_check_status();
+ gen_helper_float_check_status(cpu_env);
}
/* mtfsf */
@@ -2371,13 +2386,13 @@ static void gen_mtfsf(DisasContext *ctx)
t0 = tcg_const_i32(0xff);
else
t0 = tcg_const_i32(FM(ctx->opcode));
- gen_helper_store_fpscr(cpu_fpr[rB(ctx->opcode)], t0);
+ gen_helper_store_fpscr(cpu_env, cpu_fpr[rB(ctx->opcode)], t0);
tcg_temp_free_i32(t0);
if (unlikely(Rc(ctx->opcode) != 0)) {
tcg_gen_shri_i32(cpu_crf[1], cpu_fpscr, FPSCR_OX);
}
/* We can raise a differed exception */
- gen_helper_float_check_status();
+ gen_helper_float_check_status(cpu_env);
}
/* mtfsfi */
@@ -2398,14 +2413,14 @@ static void gen_mtfsfi(DisasContext *ctx)
gen_reset_fpstatus();
t0 = tcg_const_i64(FPIMM(ctx->opcode) << (4 * sh));
t1 = tcg_const_i32(1 << sh);
- gen_helper_store_fpscr(t0, t1);
+ gen_helper_store_fpscr(cpu_env, t0, t1);
tcg_temp_free_i64(t0);
tcg_temp_free_i32(t1);
if (unlikely(Rc(ctx->opcode) != 0)) {
tcg_gen_shri_i32(cpu_crf[1], cpu_fpscr, FPSCR_OX);
}
/* We can raise a differed exception */
- gen_helper_float_check_status();
+ gen_helper_float_check_status(cpu_env);
}
/*** Addressing modes ***/
@@ -3303,7 +3318,7 @@ static inline void gen_qemu_ld32fs(DisasContext *ctx, TCGv_i64 arg1, TCGv arg2)
gen_qemu_ld32u(ctx, t0, arg2);
tcg_gen_trunc_tl_i32(t1, t0);
tcg_temp_free(t0);
- gen_helper_float32_to_float64(arg1, t1);
+ gen_helper_float32_to_float64(arg1, cpu_env, t1);
tcg_temp_free_i32(t1);
}
@@ -3393,7 +3408,7 @@ static inline void gen_qemu_st32fs(DisasContext *ctx, TCGv_i64 arg1, TCGv arg2)
{
TCGv_i32 t0 = tcg_temp_new_i32();
TCGv t1 = tcg_temp_new();
- gen_helper_float64_to_float32(t0, arg1);
+ gen_helper_float64_to_float32(t0, cpu_env, arg1);
tcg_gen_extu_i32_tl(t1, t0);
tcg_temp_free_i32(t0);
gen_qemu_st32(ctx, t1, arg2);
@@ -8010,7 +8025,7 @@ static inline void gen_##name(DisasContext *ctx) \
TCGv t1; \
t0 = tcg_temp_new_i32(); \
tcg_gen_trunc_tl_i32(t0, cpu_gpr[rB(ctx->opcode)]); \
- gen_helper_##name(t0, t0); \
+ gen_helper_##name(t0, cpu_env, t0); \
t1 = tcg_temp_new(); \
tcg_gen_extu_i32_tl(t1, t0); \
tcg_temp_free_i32(t0); \
@@ -8025,7 +8040,7 @@ static inline void gen_##name(DisasContext *ctx) \
TCGv_i32 t0; \
TCGv t1; \
t0 = tcg_temp_new_i32(); \
- gen_helper_##name(t0, cpu_gpr[rB(ctx->opcode)]); \
+ gen_helper_##name(t0, cpu_env, cpu_gpr[rB(ctx->opcode)]); \
t1 = tcg_temp_new(); \
tcg_gen_extu_i32_tl(t1, t0); \
tcg_temp_free_i32(t0); \
@@ -8039,13 +8054,14 @@ static inline void gen_##name(DisasContext *ctx) \
{ \
TCGv_i32 t0 = tcg_temp_new_i32(); \
tcg_gen_trunc_tl_i32(t0, cpu_gpr[rB(ctx->opcode)]); \
- gen_helper_##name(cpu_gpr[rD(ctx->opcode)], t0); \
+ gen_helper_##name(cpu_gpr[rD(ctx->opcode)], cpu_env, t0); \
tcg_temp_free_i32(t0); \
}
#define GEN_SPEFPUOP_CONV_64_64(name) \
static inline void gen_##name(DisasContext *ctx) \
{ \
- gen_helper_##name(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]); \
+ gen_helper_##name(cpu_gpr[rD(ctx->opcode)], cpu_env, \
+ cpu_gpr[rB(ctx->opcode)]); \
}
#define GEN_SPEFPUOP_ARITH2_32_32(name) \
static inline void gen_##name(DisasContext *ctx) \
@@ -8060,7 +8076,7 @@ static inline void gen_##name(DisasContext *ctx) \
t1 = tcg_temp_new_i32(); \
tcg_gen_trunc_tl_i32(t0, cpu_gpr[rA(ctx->opcode)]); \
tcg_gen_trunc_tl_i32(t1, cpu_gpr[rB(ctx->opcode)]); \
- gen_helper_##name(t0, t0, t1); \
+ gen_helper_##name(t0, cpu_env, t0, t1); \
tcg_temp_free_i32(t1); \
t2 = tcg_temp_new(); \
tcg_gen_extu_i32_tl(t2, t0); \
@@ -8077,8 +8093,8 @@ static inline void gen_##name(DisasContext *ctx) \
gen_exception(ctx, POWERPC_EXCP_SPEU); \
return; \
} \
- gen_helper_##name(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], \
- cpu_gpr[rB(ctx->opcode)]); \
+ gen_helper_##name(cpu_gpr[rD(ctx->opcode)], cpu_env, \
+ cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]); \
}
#define GEN_SPEFPUOP_COMP_32(name) \
static inline void gen_##name(DisasContext *ctx) \
@@ -8092,7 +8108,7 @@ static inline void gen_##name(DisasContext *ctx) \
t1 = tcg_temp_new_i32(); \
tcg_gen_trunc_tl_i32(t0, cpu_gpr[rA(ctx->opcode)]); \
tcg_gen_trunc_tl_i32(t1, cpu_gpr[rB(ctx->opcode)]); \
- gen_helper_##name(cpu_crf[crfD(ctx->opcode)], t0, t1); \
+ gen_helper_##name(cpu_crf[crfD(ctx->opcode)], cpu_env, t0, t1); \
tcg_temp_free_i32(t0); \
tcg_temp_free_i32(t1); \
}
@@ -8103,28 +8119,29 @@ static inline void gen_##name(DisasContext *ctx) \
gen_exception(ctx, POWERPC_EXCP_SPEU); \
return; \
} \
- gen_helper_##name(cpu_crf[crfD(ctx->opcode)], \
+ gen_helper_##name(cpu_crf[crfD(ctx->opcode)], cpu_env, \
cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]); \
}
#else
#define GEN_SPEFPUOP_CONV_32_32(name) \
static inline void gen_##name(DisasContext *ctx) \
{ \
- gen_helper_##name(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]); \
+ gen_helper_##name(cpu_gpr[rD(ctx->opcode)], cpu_env, \
+ cpu_gpr[rB(ctx->opcode)]); \
}
#define GEN_SPEFPUOP_CONV_32_64(name) \
static inline void gen_##name(DisasContext *ctx) \
{ \
TCGv_i64 t0 = tcg_temp_new_i64(); \
gen_load_gpr64(t0, rB(ctx->opcode)); \
- gen_helper_##name(cpu_gpr[rD(ctx->opcode)], t0); \
+ gen_helper_##name(cpu_gpr[rD(ctx->opcode)], cpu_env, t0); \
tcg_temp_free_i64(t0); \
}
#define GEN_SPEFPUOP_CONV_64_32(name) \
static inline void gen_##name(DisasContext *ctx) \
{ \
TCGv_i64 t0 = tcg_temp_new_i64(); \
- gen_helper_##name(t0, cpu_gpr[rB(ctx->opcode)]); \
+ gen_helper_##name(t0, cpu_env, cpu_gpr[rB(ctx->opcode)]); \
gen_store_gpr64(rD(ctx->opcode), t0); \
tcg_temp_free_i64(t0); \
}
@@ -8133,7 +8150,7 @@ static inline void gen_##name(DisasContext *ctx) \
{ \
TCGv_i64 t0 = tcg_temp_new_i64(); \
gen_load_gpr64(t0, rB(ctx->opcode)); \
- gen_helper_##name(t0, t0); \
+ gen_helper_##name(t0, cpu_env, t0); \
gen_store_gpr64(rD(ctx->opcode), t0); \
tcg_temp_free_i64(t0); \
}
@@ -8144,7 +8161,7 @@ static inline void gen_##name(DisasContext *ctx) \
gen_exception(ctx, POWERPC_EXCP_SPEU); \
return; \
} \
- gen_helper_##name(cpu_gpr[rD(ctx->opcode)], \
+ gen_helper_##name(cpu_gpr[rD(ctx->opcode)], cpu_env, \
cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]); \
}
#define GEN_SPEFPUOP_ARITH2_64_64(name) \
@@ -8159,7 +8176,7 @@ static inline void gen_##name(DisasContext *ctx) \
t1 = tcg_temp_new_i64(); \
gen_load_gpr64(t0, rA(ctx->opcode)); \
gen_load_gpr64(t1, rB(ctx->opcode)); \
- gen_helper_##name(t0, t0, t1); \
+ gen_helper_##name(t0, cpu_env, t0, t1); \
gen_store_gpr64(rD(ctx->opcode), t0); \
tcg_temp_free_i64(t0); \
tcg_temp_free_i64(t1); \
@@ -8171,7 +8188,7 @@ static inline void gen_##name(DisasContext *ctx) \
gen_exception(ctx, POWERPC_EXCP_SPEU); \
return; \
} \
- gen_helper_##name(cpu_crf[crfD(ctx->opcode)], \
+ gen_helper_##name(cpu_crf[crfD(ctx->opcode)], cpu_env, \
cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]); \
}
#define GEN_SPEFPUOP_COMP_64(name) \
@@ -8186,7 +8203,7 @@ static inline void gen_##name(DisasContext *ctx) \
t1 = tcg_temp_new_i64(); \
gen_load_gpr64(t0, rA(ctx->opcode)); \
gen_load_gpr64(t1, rB(ctx->opcode)); \
- gen_helper_##name(cpu_crf[crfD(ctx->opcode)], t0, t1); \
+ gen_helper_##name(cpu_crf[crfD(ctx->opcode)], cpu_env, t0, t1); \
tcg_temp_free_i64(t0); \
tcg_temp_free_i64(t1); \
}
--
1.6.0.2
^ permalink raw reply related [flat|nested] 89+ messages in thread
* [Qemu-devel] [PATCH 08/72] ppc: Split integer and vector ops
2012-06-23 23:06 [Qemu-devel] [PULL 00/72] ppc patch queue 2012-06-24 Alexander Graf
` (6 preceding siblings ...)
2012-06-23 23:06 ` [Qemu-devel] [PATCH 07/72] ppc: Avoid AREG0 for FPU and SPE helpers Alexander Graf
@ 2012-06-23 23:06 ` Alexander Graf
2012-06-23 23:06 ` [Qemu-devel] [PATCH 09/72] ppc: Avoid AREG0 for integer and vector helpers Alexander Graf
` (64 subsequent siblings)
72 siblings, 0 replies; 89+ messages in thread
From: Alexander Graf @ 2012-06-23 23:06 UTC (permalink / raw)
To: qemu-devel qemu-devel
Cc: Blue Swirl, qemu-ppc Mailing List, Andreas Färber,
Aurelien Jarno
From: Blue Swirl <blauwirbel@gmail.com>
Move integer and vector ops to int_helper.c.
Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Andreas Färber <afaerber@suse.de>
Signed-off-by: Alexander Graf <agraf@suse.de>
---
target-ppc/Makefile.objs | 2 +
target-ppc/int_helper.c | 1538 ++++++++++++++++++++++++++++++++++++++++++++++
target-ppc/op_helper.c | 1500 --------------------------------------------
3 files changed, 1540 insertions(+), 1500 deletions(-)
create mode 100644 target-ppc/int_helper.c
diff --git a/target-ppc/Makefile.objs b/target-ppc/Makefile.objs
index 5bea9c3..97e440b 100644
--- a/target-ppc/Makefile.objs
+++ b/target-ppc/Makefile.objs
@@ -4,5 +4,7 @@ obj-$(CONFIG_KVM) += kvm.o kvm_ppc.o
obj-y += op_helper.o helper.o
obj-y += excp_helper.o
obj-y += fpu_helper.o
+obj-y += int_helper.o
+$(obj)/int_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
$(obj)/op_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
diff --git a/target-ppc/int_helper.c b/target-ppc/int_helper.c
new file mode 100644
index 0000000..71c7304
--- /dev/null
+++ b/target-ppc/int_helper.c
@@ -0,0 +1,1538 @@
+/*
+ * PowerPC integer and vector emulation helpers for QEMU.
+ *
+ * Copyright (c) 2003-2007 Jocelyn Mayer
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "cpu.h"
+#include "dyngen-exec.h"
+#include "host-utils.h"
+#include "helper.h"
+
+#include "helper_regs.h"
+/*****************************************************************************/
+/* Fixed point operations helpers */
+#if defined(TARGET_PPC64)
+
+/* multiply high word */
+uint64_t helper_mulhd(uint64_t arg1, uint64_t arg2)
+{
+ uint64_t tl, th;
+
+ muls64(&tl, &th, arg1, arg2);
+ return th;
+}
+
+/* multiply high word unsigned */
+uint64_t helper_mulhdu(uint64_t arg1, uint64_t arg2)
+{
+ uint64_t tl, th;
+
+ mulu64(&tl, &th, arg1, arg2);
+ return th;
+}
+
+uint64_t helper_mulldo(uint64_t arg1, uint64_t arg2)
+{
+ int64_t th;
+ uint64_t tl;
+
+ muls64(&tl, (uint64_t *)&th, arg1, arg2);
+ /* If th != 0 && th != -1, then we had an overflow */
+ if (likely((uint64_t)(th + 1) <= 1)) {
+ env->xer &= ~(1 << XER_OV);
+ } else {
+ env->xer |= (1 << XER_OV) | (1 << XER_SO);
+ }
+ return (int64_t)tl;
+}
+#endif
+
+target_ulong helper_cntlzw(target_ulong t)
+{
+ return clz32(t);
+}
+
+#if defined(TARGET_PPC64)
+target_ulong helper_cntlzd(target_ulong t)
+{
+ return clz64(t);
+}
+#endif
+
+/* shift right arithmetic helper */
+target_ulong helper_sraw(target_ulong value, target_ulong shift)
+{
+ int32_t ret;
+
+ if (likely(!(shift & 0x20))) {
+ if (likely((uint32_t)shift != 0)) {
+ shift &= 0x1f;
+ ret = (int32_t)value >> shift;
+ if (likely(ret >= 0 || (value & ((1 << shift) - 1)) == 0)) {
+ env->xer &= ~(1 << XER_CA);
+ } else {
+ env->xer |= (1 << XER_CA);
+ }
+ } else {
+ ret = (int32_t)value;
+ env->xer &= ~(1 << XER_CA);
+ }
+ } else {
+ ret = (int32_t)value >> 31;
+ if (ret) {
+ env->xer |= (1 << XER_CA);
+ } else {
+ env->xer &= ~(1 << XER_CA);
+ }
+ }
+ return (target_long)ret;
+}
+
+#if defined(TARGET_PPC64)
+target_ulong helper_srad(target_ulong value, target_ulong shift)
+{
+ int64_t ret;
+
+ if (likely(!(shift & 0x40))) {
+ if (likely((uint64_t)shift != 0)) {
+ shift &= 0x3f;
+ ret = (int64_t)value >> shift;
+ if (likely(ret >= 0 || (value & ((1 << shift) - 1)) == 0)) {
+ env->xer &= ~(1 << XER_CA);
+ } else {
+ env->xer |= (1 << XER_CA);
+ }
+ } else {
+ ret = (int64_t)value;
+ env->xer &= ~(1 << XER_CA);
+ }
+ } else {
+ ret = (int64_t)value >> 63;
+ if (ret) {
+ env->xer |= (1 << XER_CA);
+ } else {
+ env->xer &= ~(1 << XER_CA);
+ }
+ }
+ return ret;
+}
+#endif
+
+#if defined(TARGET_PPC64)
+target_ulong helper_popcntb(target_ulong val)
+{
+ val = (val & 0x5555555555555555ULL) + ((val >> 1) &
+ 0x5555555555555555ULL);
+ val = (val & 0x3333333333333333ULL) + ((val >> 2) &
+ 0x3333333333333333ULL);
+ val = (val & 0x0f0f0f0f0f0f0f0fULL) + ((val >> 4) &
+ 0x0f0f0f0f0f0f0f0fULL);
+ return val;
+}
+
+target_ulong helper_popcntw(target_ulong val)
+{
+ val = (val & 0x5555555555555555ULL) + ((val >> 1) &
+ 0x5555555555555555ULL);
+ val = (val & 0x3333333333333333ULL) + ((val >> 2) &
+ 0x3333333333333333ULL);
+ val = (val & 0x0f0f0f0f0f0f0f0fULL) + ((val >> 4) &
+ 0x0f0f0f0f0f0f0f0fULL);
+ val = (val & 0x00ff00ff00ff00ffULL) + ((val >> 8) &
+ 0x00ff00ff00ff00ffULL);
+ val = (val & 0x0000ffff0000ffffULL) + ((val >> 16) &
+ 0x0000ffff0000ffffULL);
+ return val;
+}
+
+target_ulong helper_popcntd(target_ulong val)
+{
+ return ctpop64(val);
+}
+#else
+target_ulong helper_popcntb(target_ulong val)
+{
+ val = (val & 0x55555555) + ((val >> 1) & 0x55555555);
+ val = (val & 0x33333333) + ((val >> 2) & 0x33333333);
+ val = (val & 0x0f0f0f0f) + ((val >> 4) & 0x0f0f0f0f);
+ return val;
+}
+
+target_ulong helper_popcntw(target_ulong val)
+{
+ val = (val & 0x55555555) + ((val >> 1) & 0x55555555);
+ val = (val & 0x33333333) + ((val >> 2) & 0x33333333);
+ val = (val & 0x0f0f0f0f) + ((val >> 4) & 0x0f0f0f0f);
+ val = (val & 0x00ff00ff) + ((val >> 8) & 0x00ff00ff);
+ val = (val & 0x0000ffff) + ((val >> 16) & 0x0000ffff);
+ return val;
+}
+#endif
+
+/*****************************************************************************/
+/* PowerPC 601 specific instructions (POWER bridge) */
+target_ulong helper_div(target_ulong arg1, target_ulong arg2)
+{
+ uint64_t tmp = (uint64_t)arg1 << 32 | env->spr[SPR_MQ];
+
+ if (((int32_t)tmp == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
+ (int32_t)arg2 == 0) {
+ env->spr[SPR_MQ] = 0;
+ return INT32_MIN;
+ } else {
+ env->spr[SPR_MQ] = tmp % arg2;
+ return tmp / (int32_t)arg2;
+ }
+}
+
+target_ulong helper_divo(target_ulong arg1, target_ulong arg2)
+{
+ uint64_t tmp = (uint64_t)arg1 << 32 | env->spr[SPR_MQ];
+
+ if (((int32_t)tmp == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
+ (int32_t)arg2 == 0) {
+ env->xer |= (1 << XER_OV) | (1 << XER_SO);
+ env->spr[SPR_MQ] = 0;
+ return INT32_MIN;
+ } else {
+ env->spr[SPR_MQ] = tmp % arg2;
+ tmp /= (int32_t)arg2;
+ if ((int32_t)tmp != tmp) {
+ env->xer |= (1 << XER_OV) | (1 << XER_SO);
+ } else {
+ env->xer &= ~(1 << XER_OV);
+ }
+ return tmp;
+ }
+}
+
+target_ulong helper_divs(target_ulong arg1, target_ulong arg2)
+{
+ if (((int32_t)arg1 == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
+ (int32_t)arg2 == 0) {
+ env->spr[SPR_MQ] = 0;
+ return INT32_MIN;
+ } else {
+ env->spr[SPR_MQ] = (int32_t)arg1 % (int32_t)arg2;
+ return (int32_t)arg1 / (int32_t)arg2;
+ }
+}
+
+target_ulong helper_divso(target_ulong arg1, target_ulong arg2)
+{
+ if (((int32_t)arg1 == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
+ (int32_t)arg2 == 0) {
+ env->xer |= (1 << XER_OV) | (1 << XER_SO);
+ env->spr[SPR_MQ] = 0;
+ return INT32_MIN;
+ } else {
+ env->xer &= ~(1 << XER_OV);
+ env->spr[SPR_MQ] = (int32_t)arg1 % (int32_t)arg2;
+ return (int32_t)arg1 / (int32_t)arg2;
+ }
+}
+
+/*****************************************************************************/
+/* 602 specific instructions */
+/* mfrom is the most crazy instruction ever seen, imho ! */
+/* Real implementation uses a ROM table. Do the same */
+/* Extremely decomposed:
+ * -arg / 256
+ * return 256 * log10(10 + 1.0) + 0.5
+ */
+#if !defined(CONFIG_USER_ONLY)
+target_ulong helper_602_mfrom(target_ulong arg)
+{
+ if (likely(arg < 602)) {
+#include "mfrom_table.c"
+ return mfrom_ROM_table[arg];
+ } else {
+ return 0;
+ }
+}
+#endif
+
+/*****************************************************************************/
+/* Altivec extension helpers */
+#if defined(HOST_WORDS_BIGENDIAN)
+#define HI_IDX 0
+#define LO_IDX 1
+#else
+#define HI_IDX 1
+#define LO_IDX 0
+#endif
+
+#if defined(HOST_WORDS_BIGENDIAN)
+#define VECTOR_FOR_INORDER_I(index, element) \
+ for (index = 0; index < ARRAY_SIZE(r->element); index++)
+#else
+#define VECTOR_FOR_INORDER_I(index, element) \
+ for (index = ARRAY_SIZE(r->element)-1; index >= 0; index--)
+#endif
+
+/* If X is a NaN, store the corresponding QNaN into RESULT. Otherwise,
+ * execute the following block. */
+#define DO_HANDLE_NAN(result, x) \
+ if (float32_is_any_nan(x)) { \
+ CPU_FloatU __f; \
+ __f.f = x; \
+ __f.l = __f.l | (1 << 22); /* Set QNaN bit. */ \
+ result = __f.f; \
+ } else
+
+#define HANDLE_NAN1(result, x) \
+ DO_HANDLE_NAN(result, x)
+#define HANDLE_NAN2(result, x, y) \
+ DO_HANDLE_NAN(result, x) DO_HANDLE_NAN(result, y)
+#define HANDLE_NAN3(result, x, y, z) \
+ DO_HANDLE_NAN(result, x) DO_HANDLE_NAN(result, y) DO_HANDLE_NAN(result, z)
+
+/* Saturating arithmetic helpers. */
+#define SATCVT(from, to, from_type, to_type, min, max) \
+ static inline to_type cvt##from##to(from_type x, int *sat) \
+ { \
+ to_type r; \
+ \
+ if (x < (from_type)min) { \
+ r = min; \
+ *sat = 1; \
+ } else if (x > (from_type)max) { \
+ r = max; \
+ *sat = 1; \
+ } else { \
+ r = x; \
+ } \
+ return r; \
+ }
+#define SATCVTU(from, to, from_type, to_type, min, max) \
+ static inline to_type cvt##from##to(from_type x, int *sat) \
+ { \
+ to_type r; \
+ \
+ if (x > (from_type)max) { \
+ r = max; \
+ *sat = 1; \
+ } else { \
+ r = x; \
+ } \
+ return r; \
+ }
+SATCVT(sh, sb, int16_t, int8_t, INT8_MIN, INT8_MAX)
+SATCVT(sw, sh, int32_t, int16_t, INT16_MIN, INT16_MAX)
+SATCVT(sd, sw, int64_t, int32_t, INT32_MIN, INT32_MAX)
+
+SATCVTU(uh, ub, uint16_t, uint8_t, 0, UINT8_MAX)
+SATCVTU(uw, uh, uint32_t, uint16_t, 0, UINT16_MAX)
+SATCVTU(ud, uw, uint64_t, uint32_t, 0, UINT32_MAX)
+SATCVT(sh, ub, int16_t, uint8_t, 0, UINT8_MAX)
+SATCVT(sw, uh, int32_t, uint16_t, 0, UINT16_MAX)
+SATCVT(sd, uw, int64_t, uint32_t, 0, UINT32_MAX)
+#undef SATCVT
+#undef SATCVTU
+
+void helper_lvsl(ppc_avr_t *r, target_ulong sh)
+{
+ int i, j = (sh & 0xf);
+
+ VECTOR_FOR_INORDER_I(i, u8) {
+ r->u8[i] = j++;
+ }
+}
+
+void helper_lvsr(ppc_avr_t *r, target_ulong sh)
+{
+ int i, j = 0x10 - (sh & 0xf);
+
+ VECTOR_FOR_INORDER_I(i, u8) {
+ r->u8[i] = j++;
+ }
+}
+
+void helper_mtvscr(ppc_avr_t *r)
+{
+#if defined(HOST_WORDS_BIGENDIAN)
+ env->vscr = r->u32[3];
+#else
+ env->vscr = r->u32[0];
+#endif
+ set_flush_to_zero(vscr_nj, &env->vec_status);
+}
+
+void helper_vaddcuw(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
+ r->u32[i] = ~a->u32[i] < b->u32[i];
+ }
+}
+
+#define VARITH_DO(name, op, element) \
+ void helper_v##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
+ { \
+ int i; \
+ \
+ for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
+ r->element[i] = a->element[i] op b->element[i]; \
+ } \
+ }
+#define VARITH(suffix, element) \
+ VARITH_DO(add##suffix, +, element) \
+ VARITH_DO(sub##suffix, -, element)
+VARITH(ubm, u8)
+VARITH(uhm, u16)
+VARITH(uwm, u32)
+#undef VARITH_DO
+#undef VARITH
+
+#define VARITHFP(suffix, func) \
+ void helper_v##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
+ { \
+ int i; \
+ \
+ for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
+ HANDLE_NAN2(r->f[i], a->f[i], b->f[i]) { \
+ r->f[i] = func(a->f[i], b->f[i], &env->vec_status); \
+ } \
+ } \
+ }
+VARITHFP(addfp, float32_add)
+VARITHFP(subfp, float32_sub)
+#undef VARITHFP
+
+#define VARITHSAT_CASE(type, op, cvt, element) \
+ { \
+ type result = (type)a->element[i] op (type)b->element[i]; \
+ r->element[i] = cvt(result, &sat); \
+ }
+
+#define VARITHSAT_DO(name, op, optype, cvt, element) \
+ void helper_v##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
+ { \
+ int sat = 0; \
+ int i; \
+ \
+ for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
+ switch (sizeof(r->element[0])) { \
+ case 1: \
+ VARITHSAT_CASE(optype, op, cvt, element); \
+ break; \
+ case 2: \
+ VARITHSAT_CASE(optype, op, cvt, element); \
+ break; \
+ case 4: \
+ VARITHSAT_CASE(optype, op, cvt, element); \
+ break; \
+ } \
+ } \
+ if (sat) { \
+ env->vscr |= (1 << VSCR_SAT); \
+ } \
+ }
+#define VARITHSAT_SIGNED(suffix, element, optype, cvt) \
+ VARITHSAT_DO(adds##suffix##s, +, optype, cvt, element) \
+ VARITHSAT_DO(subs##suffix##s, -, optype, cvt, element)
+#define VARITHSAT_UNSIGNED(suffix, element, optype, cvt) \
+ VARITHSAT_DO(addu##suffix##s, +, optype, cvt, element) \
+ VARITHSAT_DO(subu##suffix##s, -, optype, cvt, element)
+VARITHSAT_SIGNED(b, s8, int16_t, cvtshsb)
+VARITHSAT_SIGNED(h, s16, int32_t, cvtswsh)
+VARITHSAT_SIGNED(w, s32, int64_t, cvtsdsw)
+VARITHSAT_UNSIGNED(b, u8, uint16_t, cvtshub)
+VARITHSAT_UNSIGNED(h, u16, uint32_t, cvtswuh)
+VARITHSAT_UNSIGNED(w, u32, uint64_t, cvtsduw)
+#undef VARITHSAT_CASE
+#undef VARITHSAT_DO
+#undef VARITHSAT_SIGNED
+#undef VARITHSAT_UNSIGNED
+
+#define VAVG_DO(name, element, etype) \
+ void helper_v##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
+ { \
+ int i; \
+ \
+ for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
+ etype x = (etype)a->element[i] + (etype)b->element[i] + 1; \
+ r->element[i] = x >> 1; \
+ } \
+ }
+
+#define VAVG(type, signed_element, signed_type, unsigned_element, \
+ unsigned_type) \
+ VAVG_DO(avgs##type, signed_element, signed_type) \
+ VAVG_DO(avgu##type, unsigned_element, unsigned_type)
+VAVG(b, s8, int16_t, u8, uint16_t)
+VAVG(h, s16, int32_t, u16, uint32_t)
+VAVG(w, s32, int64_t, u32, uint64_t)
+#undef VAVG_DO
+#undef VAVG
+
+#define VCF(suffix, cvt, element) \
+ void helper_vcf##suffix(ppc_avr_t *r, ppc_avr_t *b, uint32_t uim) \
+ { \
+ int i; \
+ \
+ for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
+ float32 t = cvt(b->element[i], &env->vec_status); \
+ r->f[i] = float32_scalbn(t, -uim, &env->vec_status); \
+ } \
+ }
+VCF(ux, uint32_to_float32, u32)
+VCF(sx, int32_to_float32, s32)
+#undef VCF
+
+#define VCMP_DO(suffix, compare, element, record) \
+ void helper_vcmp##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
+ { \
+ uint32_t ones = (uint32_t)-1; \
+ uint32_t all = ones; \
+ uint32_t none = 0; \
+ int i; \
+ \
+ for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
+ uint32_t result = (a->element[i] compare b->element[i] ? \
+ ones : 0x0); \
+ switch (sizeof(a->element[0])) { \
+ case 4: \
+ r->u32[i] = result; \
+ break; \
+ case 2: \
+ r->u16[i] = result; \
+ break; \
+ case 1: \
+ r->u8[i] = result; \
+ break; \
+ } \
+ all &= result; \
+ none |= result; \
+ } \
+ if (record) { \
+ env->crf[6] = ((all != 0) << 3) | ((none == 0) << 1); \
+ } \
+ }
+#define VCMP(suffix, compare, element) \
+ VCMP_DO(suffix, compare, element, 0) \
+ VCMP_DO(suffix##_dot, compare, element, 1)
+VCMP(equb, ==, u8)
+VCMP(equh, ==, u16)
+VCMP(equw, ==, u32)
+VCMP(gtub, >, u8)
+VCMP(gtuh, >, u16)
+VCMP(gtuw, >, u32)
+VCMP(gtsb, >, s8)
+VCMP(gtsh, >, s16)
+VCMP(gtsw, >, s32)
+#undef VCMP_DO
+#undef VCMP
+
+#define VCMPFP_DO(suffix, compare, order, record) \
+ void helper_vcmp##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
+ { \
+ uint32_t ones = (uint32_t)-1; \
+ uint32_t all = ones; \
+ uint32_t none = 0; \
+ int i; \
+ \
+ for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
+ uint32_t result; \
+ int rel = float32_compare_quiet(a->f[i], b->f[i], \
+ &env->vec_status); \
+ if (rel == float_relation_unordered) { \
+ result = 0; \
+ } else if (rel compare order) { \
+ result = ones; \
+ } else { \
+ result = 0; \
+ } \
+ r->u32[i] = result; \
+ all &= result; \
+ none |= result; \
+ } \
+ if (record) { \
+ env->crf[6] = ((all != 0) << 3) | ((none == 0) << 1); \
+ } \
+ }
+#define VCMPFP(suffix, compare, order) \
+ VCMPFP_DO(suffix, compare, order, 0) \
+ VCMPFP_DO(suffix##_dot, compare, order, 1)
+VCMPFP(eqfp, ==, float_relation_equal)
+VCMPFP(gefp, !=, float_relation_less)
+VCMPFP(gtfp, ==, float_relation_greater)
+#undef VCMPFP_DO
+#undef VCMPFP
+
+static inline void vcmpbfp_internal(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b,
+ int record)
+{
+ int i;
+ int all_in = 0;
+
+ for (i = 0; i < ARRAY_SIZE(r->f); i++) {
+ int le_rel = float32_compare_quiet(a->f[i], b->f[i], &env->vec_status);
+ if (le_rel == float_relation_unordered) {
+ r->u32[i] = 0xc0000000;
+ /* ALL_IN does not need to be updated here. */
+ } else {
+ float32 bneg = float32_chs(b->f[i]);
+ int ge_rel = float32_compare_quiet(a->f[i], bneg, &env->vec_status);
+ int le = le_rel != float_relation_greater;
+ int ge = ge_rel != float_relation_less;
+
+ r->u32[i] = ((!le) << 31) | ((!ge) << 30);
+ all_in |= (!le | !ge);
+ }
+ }
+ if (record) {
+ env->crf[6] = (all_in == 0) << 1;
+ }
+}
+
+void helper_vcmpbfp(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
+{
+ vcmpbfp_internal(r, a, b, 0);
+}
+
+void helper_vcmpbfp_dot(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
+{
+ vcmpbfp_internal(r, a, b, 1);
+}
+
+#define VCT(suffix, satcvt, element) \
+ void helper_vct##suffix(ppc_avr_t *r, ppc_avr_t *b, uint32_t uim) \
+ { \
+ int i; \
+ int sat = 0; \
+ float_status s = env->vec_status; \
+ \
+ set_float_rounding_mode(float_round_to_zero, &s); \
+ for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
+ if (float32_is_any_nan(b->f[i])) { \
+ r->element[i] = 0; \
+ } else { \
+ float64 t = float32_to_float64(b->f[i], &s); \
+ int64_t j; \
+ \
+ t = float64_scalbn(t, uim, &s); \
+ j = float64_to_int64(t, &s); \
+ r->element[i] = satcvt(j, &sat); \
+ } \
+ } \
+ if (sat) { \
+ env->vscr |= (1 << VSCR_SAT); \
+ } \
+ }
+VCT(uxs, cvtsduw, u32)
+VCT(sxs, cvtsdsw, s32)
+#undef VCT
+
+void helper_vmaddfp(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(r->f); i++) {
+ HANDLE_NAN3(r->f[i], a->f[i], b->f[i], c->f[i]) {
+ /* Need to do the computation in higher precision and round
+ * once at the end. */
+ float64 af, bf, cf, t;
+
+ af = float32_to_float64(a->f[i], &env->vec_status);
+ bf = float32_to_float64(b->f[i], &env->vec_status);
+ cf = float32_to_float64(c->f[i], &env->vec_status);
+ t = float64_mul(af, cf, &env->vec_status);
+ t = float64_add(t, bf, &env->vec_status);
+ r->f[i] = float64_to_float32(t, &env->vec_status);
+ }
+ }
+}
+
+void helper_vmhaddshs(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
+{
+ int sat = 0;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
+ int32_t prod = a->s16[i] * b->s16[i];
+ int32_t t = (int32_t)c->s16[i] + (prod >> 15);
+
+ r->s16[i] = cvtswsh(t, &sat);
+ }
+
+ if (sat) {
+ env->vscr |= (1 << VSCR_SAT);
+ }
+}
+
+void helper_vmhraddshs(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
+{
+ int sat = 0;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
+ int32_t prod = a->s16[i] * b->s16[i] + 0x00004000;
+ int32_t t = (int32_t)c->s16[i] + (prod >> 15);
+ r->s16[i] = cvtswsh(t, &sat);
+ }
+
+ if (sat) {
+ env->vscr |= (1 << VSCR_SAT);
+ }
+}
+
+#define VMINMAX_DO(name, compare, element) \
+ void helper_v##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
+ { \
+ int i; \
+ \
+ for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
+ if (a->element[i] compare b->element[i]) { \
+ r->element[i] = b->element[i]; \
+ } else { \
+ r->element[i] = a->element[i]; \
+ } \
+ } \
+ }
+#define VMINMAX(suffix, element) \
+ VMINMAX_DO(min##suffix, >, element) \
+ VMINMAX_DO(max##suffix, <, element)
+VMINMAX(sb, s8)
+VMINMAX(sh, s16)
+VMINMAX(sw, s32)
+VMINMAX(ub, u8)
+VMINMAX(uh, u16)
+VMINMAX(uw, u32)
+#undef VMINMAX_DO
+#undef VMINMAX
+
+#define VMINMAXFP(suffix, rT, rF) \
+ void helper_v##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
+ { \
+ int i; \
+ \
+ for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
+ HANDLE_NAN2(r->f[i], a->f[i], b->f[i]) { \
+ if (float32_lt_quiet(a->f[i], b->f[i], \
+ &env->vec_status)) { \
+ r->f[i] = rT->f[i]; \
+ } else { \
+ r->f[i] = rF->f[i]; \
+ } \
+ } \
+ } \
+ }
+VMINMAXFP(minfp, a, b)
+VMINMAXFP(maxfp, b, a)
+#undef VMINMAXFP
+
+void helper_vmladduhm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
+ int32_t prod = a->s16[i] * b->s16[i];
+ r->s16[i] = (int16_t) (prod + c->s16[i]);
+ }
+}
+
+#define VMRG_DO(name, element, highp) \
+ void helper_v##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
+ { \
+ ppc_avr_t result; \
+ int i; \
+ size_t n_elems = ARRAY_SIZE(r->element); \
+ \
+ for (i = 0; i < n_elems / 2; i++) { \
+ if (highp) { \
+ result.element[i*2+HI_IDX] = a->element[i]; \
+ result.element[i*2+LO_IDX] = b->element[i]; \
+ } else { \
+ result.element[n_elems - i * 2 - (1 + HI_IDX)] = \
+ b->element[n_elems - i - 1]; \
+ result.element[n_elems - i * 2 - (1 + LO_IDX)] = \
+ a->element[n_elems - i - 1]; \
+ } \
+ } \
+ *r = result; \
+ }
+#if defined(HOST_WORDS_BIGENDIAN)
+#define MRGHI 0
+#define MRGLO 1
+#else
+#define MRGHI 1
+#define MRGLO 0
+#endif
+#define VMRG(suffix, element) \
+ VMRG_DO(mrgl##suffix, element, MRGHI) \
+ VMRG_DO(mrgh##suffix, element, MRGLO)
+VMRG(b, u8)
+VMRG(h, u16)
+VMRG(w, u32)
+#undef VMRG_DO
+#undef VMRG
+#undef MRGHI
+#undef MRGLO
+
+void helper_vmsummbm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
+{
+ int32_t prod[16];
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(r->s8); i++) {
+ prod[i] = (int32_t)a->s8[i] * b->u8[i];
+ }
+
+ VECTOR_FOR_INORDER_I(i, s32) {
+ r->s32[i] = c->s32[i] + prod[4 * i] + prod[4 * i + 1] +
+ prod[4 * i + 2] + prod[4 * i + 3];
+ }
+}
+
+void helper_vmsumshm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
+{
+ int32_t prod[8];
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
+ prod[i] = a->s16[i] * b->s16[i];
+ }
+
+ VECTOR_FOR_INORDER_I(i, s32) {
+ r->s32[i] = c->s32[i] + prod[2 * i] + prod[2 * i + 1];
+ }
+}
+
+void helper_vmsumshs(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
+{
+ int32_t prod[8];
+ int i;
+ int sat = 0;
+
+ for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
+ prod[i] = (int32_t)a->s16[i] * b->s16[i];
+ }
+
+ VECTOR_FOR_INORDER_I(i, s32) {
+ int64_t t = (int64_t)c->s32[i] + prod[2 * i] + prod[2 * i + 1];
+
+ r->u32[i] = cvtsdsw(t, &sat);
+ }
+
+ if (sat) {
+ env->vscr |= (1 << VSCR_SAT);
+ }
+}
+
+void helper_vmsumubm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
+{
+ uint16_t prod[16];
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
+ prod[i] = a->u8[i] * b->u8[i];
+ }
+
+ VECTOR_FOR_INORDER_I(i, u32) {
+ r->u32[i] = c->u32[i] + prod[4 * i] + prod[4 * i + 1] +
+ prod[4 * i + 2] + prod[4 * i + 3];
+ }
+}
+
+void helper_vmsumuhm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
+{
+ uint32_t prod[8];
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(r->u16); i++) {
+ prod[i] = a->u16[i] * b->u16[i];
+ }
+
+ VECTOR_FOR_INORDER_I(i, u32) {
+ r->u32[i] = c->u32[i] + prod[2 * i] + prod[2 * i + 1];
+ }
+}
+
+void helper_vmsumuhs(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
+{
+ uint32_t prod[8];
+ int i;
+ int sat = 0;
+
+ for (i = 0; i < ARRAY_SIZE(r->u16); i++) {
+ prod[i] = a->u16[i] * b->u16[i];
+ }
+
+ VECTOR_FOR_INORDER_I(i, s32) {
+ uint64_t t = (uint64_t)c->u32[i] + prod[2 * i] + prod[2 * i + 1];
+
+ r->u32[i] = cvtuduw(t, &sat);
+ }
+
+ if (sat) {
+ env->vscr |= (1 << VSCR_SAT);
+ }
+}
+
+#define VMUL_DO(name, mul_element, prod_element, evenp) \
+ void helper_v##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
+ { \
+ int i; \
+ \
+ VECTOR_FOR_INORDER_I(i, prod_element) { \
+ if (evenp) { \
+ r->prod_element[i] = a->mul_element[i * 2 + HI_IDX] * \
+ b->mul_element[i * 2 + HI_IDX]; \
+ } else { \
+ r->prod_element[i] = a->mul_element[i * 2 + LO_IDX] * \
+ b->mul_element[i * 2 + LO_IDX]; \
+ } \
+ } \
+ }
+#define VMUL(suffix, mul_element, prod_element) \
+ VMUL_DO(mule##suffix, mul_element, prod_element, 1) \
+ VMUL_DO(mulo##suffix, mul_element, prod_element, 0)
+VMUL(sb, s8, s16)
+VMUL(sh, s16, s32)
+VMUL(ub, u8, u16)
+VMUL(uh, u16, u32)
+#undef VMUL_DO
+#undef VMUL
+
+void helper_vnmsubfp(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(r->f); i++) {
+ HANDLE_NAN3(r->f[i], a->f[i], b->f[i], c->f[i]) {
+ /* Need to do the computation is higher precision and round
+ * once at the end. */
+ float64 af, bf, cf, t;
+
+ af = float32_to_float64(a->f[i], &env->vec_status);
+ bf = float32_to_float64(b->f[i], &env->vec_status);
+ cf = float32_to_float64(c->f[i], &env->vec_status);
+ t = float64_mul(af, cf, &env->vec_status);
+ t = float64_sub(t, bf, &env->vec_status);
+ t = float64_chs(t);
+ r->f[i] = float64_to_float32(t, &env->vec_status);
+ }
+ }
+}
+
+void helper_vperm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
+{
+ ppc_avr_t result;
+ int i;
+
+ VECTOR_FOR_INORDER_I(i, u8) {
+ int s = c->u8[i] & 0x1f;
+#if defined(HOST_WORDS_BIGENDIAN)
+ int index = s & 0xf;
+#else
+ int index = 15 - (s & 0xf);
+#endif
+
+ if (s & 0x10) {
+ result.u8[i] = b->u8[index];
+ } else {
+ result.u8[i] = a->u8[index];
+ }
+ }
+ *r = result;
+}
+
+#if defined(HOST_WORDS_BIGENDIAN)
+#define PKBIG 1
+#else
+#define PKBIG 0
+#endif
+void helper_vpkpx(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
+{
+ int i, j;
+ ppc_avr_t result;
+#if defined(HOST_WORDS_BIGENDIAN)
+ const ppc_avr_t *x[2] = { a, b };
+#else
+ const ppc_avr_t *x[2] = { b, a };
+#endif
+
+ VECTOR_FOR_INORDER_I(i, u64) {
+ VECTOR_FOR_INORDER_I(j, u32) {
+ uint32_t e = x[i]->u32[j];
+
+ result.u16[4*i+j] = (((e >> 9) & 0xfc00) |
+ ((e >> 6) & 0x3e0) |
+ ((e >> 3) & 0x1f));
+ }
+ }
+ *r = result;
+}
+
+#define VPK(suffix, from, to, cvt, dosat) \
+ void helper_vpk##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
+ { \
+ int i; \
+ int sat = 0; \
+ ppc_avr_t result; \
+ ppc_avr_t *a0 = PKBIG ? a : b; \
+ ppc_avr_t *a1 = PKBIG ? b : a; \
+ \
+ VECTOR_FOR_INORDER_I(i, from) { \
+ result.to[i] = cvt(a0->from[i], &sat); \
+ result.to[i+ARRAY_SIZE(r->from)] = cvt(a1->from[i], &sat); \
+ } \
+ *r = result; \
+ if (dosat && sat) { \
+ env->vscr |= (1 << VSCR_SAT); \
+ } \
+ }
+#define I(x, y) (x)
+VPK(shss, s16, s8, cvtshsb, 1)
+VPK(shus, s16, u8, cvtshub, 1)
+VPK(swss, s32, s16, cvtswsh, 1)
+VPK(swus, s32, u16, cvtswuh, 1)
+VPK(uhus, u16, u8, cvtuhub, 1)
+VPK(uwus, u32, u16, cvtuwuh, 1)
+VPK(uhum, u16, u8, I, 0)
+VPK(uwum, u32, u16, I, 0)
+#undef I
+#undef VPK
+#undef PKBIG
+
+void helper_vrefp(ppc_avr_t *r, ppc_avr_t *b)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(r->f); i++) {
+ HANDLE_NAN1(r->f[i], b->f[i]) {
+ r->f[i] = float32_div(float32_one, b->f[i], &env->vec_status);
+ }
+ }
+}
+
+#define VRFI(suffix, rounding) \
+ void helper_vrfi##suffix(ppc_avr_t *r, ppc_avr_t *b) \
+ { \
+ int i; \
+ float_status s = env->vec_status; \
+ \
+ set_float_rounding_mode(rounding, &s); \
+ for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
+ HANDLE_NAN1(r->f[i], b->f[i]) { \
+ r->f[i] = float32_round_to_int (b->f[i], &s); \
+ } \
+ } \
+ }
+VRFI(n, float_round_nearest_even)
+VRFI(m, float_round_down)
+VRFI(p, float_round_up)
+VRFI(z, float_round_to_zero)
+#undef VRFI
+
+#define VROTATE(suffix, element) \
+ void helper_vrl##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
+ { \
+ int i; \
+ \
+ for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
+ unsigned int mask = ((1 << \
+ (3 + (sizeof(a->element[0]) >> 1))) \
+ - 1); \
+ unsigned int shift = b->element[i] & mask; \
+ r->element[i] = (a->element[i] << shift) | \
+ (a->element[i] >> (sizeof(a->element[0]) * 8 - shift)); \
+ } \
+ }
+VROTATE(b, u8)
+VROTATE(h, u16)
+VROTATE(w, u32)
+#undef VROTATE
+
+void helper_vrsqrtefp(ppc_avr_t *r, ppc_avr_t *b)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(r->f); i++) {
+ HANDLE_NAN1(r->f[i], b->f[i]) {
+ float32 t = float32_sqrt(b->f[i], &env->vec_status);
+
+ r->f[i] = float32_div(float32_one, t, &env->vec_status);
+ }
+ }
+}
+
+void helper_vsel(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
+{
+ r->u64[0] = (a->u64[0] & ~c->u64[0]) | (b->u64[0] & c->u64[0]);
+ r->u64[1] = (a->u64[1] & ~c->u64[1]) | (b->u64[1] & c->u64[1]);
+}
+
+void helper_vexptefp(ppc_avr_t *r, ppc_avr_t *b)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(r->f); i++) {
+ HANDLE_NAN1(r->f[i], b->f[i]) {
+ r->f[i] = float32_exp2(b->f[i], &env->vec_status);
+ }
+ }
+}
+
+void helper_vlogefp(ppc_avr_t *r, ppc_avr_t *b)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(r->f); i++) {
+ HANDLE_NAN1(r->f[i], b->f[i]) {
+ r->f[i] = float32_log2(b->f[i], &env->vec_status);
+ }
+ }
+}
+
+#if defined(HOST_WORDS_BIGENDIAN)
+#define LEFT 0
+#define RIGHT 1
+#else
+#define LEFT 1
+#define RIGHT 0
+#endif
+/* The specification says that the results are undefined if all of the
+ * shift counts are not identical. We check to make sure that they are
+ * to conform to what real hardware appears to do. */
+#define VSHIFT(suffix, leftp) \
+ void helper_vs##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
+ { \
+ int shift = b->u8[LO_IDX*15] & 0x7; \
+ int doit = 1; \
+ int i; \
+ \
+ for (i = 0; i < ARRAY_SIZE(r->u8); i++) { \
+ doit = doit && ((b->u8[i] & 0x7) == shift); \
+ } \
+ if (doit) { \
+ if (shift == 0) { \
+ *r = *a; \
+ } else if (leftp) { \
+ uint64_t carry = a->u64[LO_IDX] >> (64 - shift); \
+ \
+ r->u64[HI_IDX] = (a->u64[HI_IDX] << shift) | carry; \
+ r->u64[LO_IDX] = a->u64[LO_IDX] << shift; \
+ } else { \
+ uint64_t carry = a->u64[HI_IDX] << (64 - shift); \
+ \
+ r->u64[LO_IDX] = (a->u64[LO_IDX] >> shift) | carry; \
+ r->u64[HI_IDX] = a->u64[HI_IDX] >> shift; \
+ } \
+ } \
+ }
+VSHIFT(l, LEFT)
+VSHIFT(r, RIGHT)
+#undef VSHIFT
+#undef LEFT
+#undef RIGHT
+
+#define VSL(suffix, element) \
+ void helper_vsl##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
+ { \
+ int i; \
+ \
+ for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
+ unsigned int mask = ((1 << \
+ (3 + (sizeof(a->element[0]) >> 1))) \
+ - 1); \
+ unsigned int shift = b->element[i] & mask; \
+ \
+ r->element[i] = a->element[i] << shift; \
+ } \
+ }
+VSL(b, u8)
+VSL(h, u16)
+VSL(w, u32)
+#undef VSL
+
+void helper_vsldoi(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t shift)
+{
+ int sh = shift & 0xf;
+ int i;
+ ppc_avr_t result;
+
+#if defined(HOST_WORDS_BIGENDIAN)
+ for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
+ int index = sh + i;
+ if (index > 0xf) {
+ result.u8[i] = b->u8[index - 0x10];
+ } else {
+ result.u8[i] = a->u8[index];
+ }
+ }
+#else
+ for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
+ int index = (16 - sh) + i;
+ if (index > 0xf) {
+ result.u8[i] = a->u8[index - 0x10];
+ } else {
+ result.u8[i] = b->u8[index];
+ }
+ }
+#endif
+ *r = result;
+}
+
+void helper_vslo(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
+{
+ int sh = (b->u8[LO_IDX*0xf] >> 3) & 0xf;
+
+#if defined(HOST_WORDS_BIGENDIAN)
+ memmove(&r->u8[0], &a->u8[sh], 16 - sh);
+ memset(&r->u8[16-sh], 0, sh);
+#else
+ memmove(&r->u8[sh], &a->u8[0], 16 - sh);
+ memset(&r->u8[0], 0, sh);
+#endif
+}
+
+/* Experimental testing shows that hardware masks the immediate. */
+#define _SPLAT_MASKED(element) (splat & (ARRAY_SIZE(r->element) - 1))
+#if defined(HOST_WORDS_BIGENDIAN)
+#define SPLAT_ELEMENT(element) _SPLAT_MASKED(element)
+#else
+#define SPLAT_ELEMENT(element) \
+ (ARRAY_SIZE(r->element) - 1 - _SPLAT_MASKED(element))
+#endif
+#define VSPLT(suffix, element) \
+ void helper_vsplt##suffix(ppc_avr_t *r, ppc_avr_t *b, uint32_t splat) \
+ { \
+ uint32_t s = b->element[SPLAT_ELEMENT(element)]; \
+ int i; \
+ \
+ for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
+ r->element[i] = s; \
+ } \
+ }
+VSPLT(b, u8)
+VSPLT(h, u16)
+VSPLT(w, u32)
+#undef VSPLT
+#undef SPLAT_ELEMENT
+#undef _SPLAT_MASKED
+
+#define VSPLTI(suffix, element, splat_type) \
+ void helper_vspltis##suffix(ppc_avr_t *r, uint32_t splat) \
+ { \
+ splat_type x = (int8_t)(splat << 3) >> 3; \
+ int i; \
+ \
+ for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
+ r->element[i] = x; \
+ } \
+ }
+VSPLTI(b, s8, int8_t)
+VSPLTI(h, s16, int16_t)
+VSPLTI(w, s32, int32_t)
+#undef VSPLTI
+
+#define VSR(suffix, element) \
+ void helper_vsr##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
+ { \
+ int i; \
+ \
+ for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
+ unsigned int mask = ((1 << \
+ (3 + (sizeof(a->element[0]) >> 1))) \
+ - 1); \
+ unsigned int shift = b->element[i] & mask; \
+ \
+ r->element[i] = a->element[i] >> shift; \
+ } \
+ }
+VSR(ab, s8)
+VSR(ah, s16)
+VSR(aw, s32)
+VSR(b, u8)
+VSR(h, u16)
+VSR(w, u32)
+#undef VSR
+
+void helper_vsro(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
+{
+ int sh = (b->u8[LO_IDX * 0xf] >> 3) & 0xf;
+
+#if defined(HOST_WORDS_BIGENDIAN)
+ memmove(&r->u8[sh], &a->u8[0], 16 - sh);
+ memset(&r->u8[0], 0, sh);
+#else
+ memmove(&r->u8[0], &a->u8[sh], 16 - sh);
+ memset(&r->u8[16 - sh], 0, sh);
+#endif
+}
+
+void helper_vsubcuw(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
+ r->u32[i] = a->u32[i] >= b->u32[i];
+ }
+}
+
+void helper_vsumsws(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
+{
+ int64_t t;
+ int i, upper;
+ ppc_avr_t result;
+ int sat = 0;
+
+#if defined(HOST_WORDS_BIGENDIAN)
+ upper = ARRAY_SIZE(r->s32)-1;
+#else
+ upper = 0;
+#endif
+ t = (int64_t)b->s32[upper];
+ for (i = 0; i < ARRAY_SIZE(r->s32); i++) {
+ t += a->s32[i];
+ result.s32[i] = 0;
+ }
+ result.s32[upper] = cvtsdsw(t, &sat);
+ *r = result;
+
+ if (sat) {
+ env->vscr |= (1 << VSCR_SAT);
+ }
+}
+
+void helper_vsum2sws(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
+{
+ int i, j, upper;
+ ppc_avr_t result;
+ int sat = 0;
+
+#if defined(HOST_WORDS_BIGENDIAN)
+ upper = 1;
+#else
+ upper = 0;
+#endif
+ for (i = 0; i < ARRAY_SIZE(r->u64); i++) {
+ int64_t t = (int64_t)b->s32[upper + i * 2];
+
+ result.u64[i] = 0;
+ for (j = 0; j < ARRAY_SIZE(r->u64); j++) {
+ t += a->s32[2 * i + j];
+ }
+ result.s32[upper + i * 2] = cvtsdsw(t, &sat);
+ }
+
+ *r = result;
+ if (sat) {
+ env->vscr |= (1 << VSCR_SAT);
+ }
+}
+
+void helper_vsum4sbs(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
+{
+ int i, j;
+ int sat = 0;
+
+ for (i = 0; i < ARRAY_SIZE(r->s32); i++) {
+ int64_t t = (int64_t)b->s32[i];
+
+ for (j = 0; j < ARRAY_SIZE(r->s32); j++) {
+ t += a->s8[4 * i + j];
+ }
+ r->s32[i] = cvtsdsw(t, &sat);
+ }
+
+ if (sat) {
+ env->vscr |= (1 << VSCR_SAT);
+ }
+}
+
+void helper_vsum4shs(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
+{
+ int sat = 0;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(r->s32); i++) {
+ int64_t t = (int64_t)b->s32[i];
+
+ t += a->s16[2 * i] + a->s16[2 * i + 1];
+ r->s32[i] = cvtsdsw(t, &sat);
+ }
+
+ if (sat) {
+ env->vscr |= (1 << VSCR_SAT);
+ }
+}
+
+void helper_vsum4ubs(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
+{
+ int i, j;
+ int sat = 0;
+
+ for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
+ uint64_t t = (uint64_t)b->u32[i];
+
+ for (j = 0; j < ARRAY_SIZE(r->u32); j++) {
+ t += a->u8[4 * i + j];
+ }
+ r->u32[i] = cvtuduw(t, &sat);
+ }
+
+ if (sat) {
+ env->vscr |= (1 << VSCR_SAT);
+ }
+}
+
+#if defined(HOST_WORDS_BIGENDIAN)
+#define UPKHI 1
+#define UPKLO 0
+#else
+#define UPKHI 0
+#define UPKLO 1
+#endif
+#define VUPKPX(suffix, hi) \
+ void helper_vupk##suffix(ppc_avr_t *r, ppc_avr_t *b) \
+ { \
+ int i; \
+ ppc_avr_t result; \
+ \
+ for (i = 0; i < ARRAY_SIZE(r->u32); i++) { \
+ uint16_t e = b->u16[hi ? i : i+4]; \
+ uint8_t a = (e >> 15) ? 0xff : 0; \
+ uint8_t r = (e >> 10) & 0x1f; \
+ uint8_t g = (e >> 5) & 0x1f; \
+ uint8_t b = e & 0x1f; \
+ \
+ result.u32[i] = (a << 24) | (r << 16) | (g << 8) | b; \
+ } \
+ *r = result; \
+ }
+VUPKPX(lpx, UPKLO)
+VUPKPX(hpx, UPKHI)
+#undef VUPKPX
+
+#define VUPK(suffix, unpacked, packee, hi) \
+ void helper_vupk##suffix(ppc_avr_t *r, ppc_avr_t *b) \
+ { \
+ int i; \
+ ppc_avr_t result; \
+ \
+ if (hi) { \
+ for (i = 0; i < ARRAY_SIZE(r->unpacked); i++) { \
+ result.unpacked[i] = b->packee[i]; \
+ } \
+ } else { \
+ for (i = ARRAY_SIZE(r->unpacked); i < ARRAY_SIZE(r->packee); \
+ i++) { \
+ result.unpacked[i - ARRAY_SIZE(r->unpacked)] = b->packee[i]; \
+ } \
+ } \
+ *r = result; \
+ }
+VUPK(hsb, s16, s8, UPKHI)
+VUPK(hsh, s32, s16, UPKHI)
+VUPK(lsb, s16, s8, UPKLO)
+VUPK(lsh, s32, s16, UPKLO)
+#undef VUPK
+#undef UPKHI
+#undef UPKLO
+
+#undef DO_HANDLE_NAN
+#undef HANDLE_NAN1
+#undef HANDLE_NAN2
+#undef HANDLE_NAN3
+#undef VECTOR_FOR_INORDER_I
+#undef HI_IDX
+#undef LO_IDX
+
+/*****************************************************************************/
+/* SPE extension helpers */
+/* Use a table to make this quicker */
+static uint8_t hbrev[16] = {
+ 0x0, 0x8, 0x4, 0xC, 0x2, 0xA, 0x6, 0xE,
+ 0x1, 0x9, 0x5, 0xD, 0x3, 0xB, 0x7, 0xF,
+};
+
+static inline uint8_t byte_reverse(uint8_t val)
+{
+ return hbrev[val >> 4] | (hbrev[val & 0xF] << 4);
+}
+
+static inline uint32_t word_reverse(uint32_t val)
+{
+ return byte_reverse(val >> 24) | (byte_reverse(val >> 16) << 8) |
+ (byte_reverse(val >> 8) << 16) | (byte_reverse(val) << 24);
+}
+
+#define MASKBITS 16 /* Random value - to be fixed (implementation dependent) */
+target_ulong helper_brinc(target_ulong arg1, target_ulong arg2)
+{
+ uint32_t a, b, d, mask;
+
+ mask = UINT32_MAX >> (32 - MASKBITS);
+ a = arg1 & mask;
+ b = arg2 & mask;
+ d = word_reverse(1 + word_reverse(a | ~b));
+ return (arg1 & ~mask) | (d & b);
+}
+
+uint32_t helper_cntlsw32(uint32_t val)
+{
+ if (val & 0x80000000) {
+ return clz32(~val);
+ } else {
+ return clz32(val);
+ }
+}
+
+uint32_t helper_cntlzw32(uint32_t val)
+{
+ return clz32(val);
+}
+
+/* 440 specific */
+target_ulong helper_dlmzb(target_ulong high, target_ulong low,
+ uint32_t update_Rc)
+{
+ target_ulong mask;
+ int i;
+
+ i = 1;
+ for (mask = 0xFF000000; mask != 0; mask = mask >> 8) {
+ if ((high & mask) == 0) {
+ if (update_Rc) {
+ env->crf[0] = 0x4;
+ }
+ goto done;
+ }
+ i++;
+ }
+ for (mask = 0xFF000000; mask != 0; mask = mask >> 8) {
+ if ((low & mask) == 0) {
+ if (update_Rc) {
+ env->crf[0] = 0x8;
+ }
+ goto done;
+ }
+ i++;
+ }
+ if (update_Rc) {
+ env->crf[0] = 0x2;
+ }
+ done:
+ env->xer = (env->xer & ~0x7F) | i;
+ if (update_Rc) {
+ env->crf[0] |= xer_so;
+ }
+ return i;
+}
diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c
index 3f677f6..55b9e9d 100644
--- a/target-ppc/op_helper.c
+++ b/target-ppc/op_helper.c
@@ -387,166 +387,6 @@ target_ulong helper_lscbx(target_ulong addr, uint32_t reg, uint32_t ra,
}
/*****************************************************************************/
-/* Fixed point operations helpers */
-#if defined(TARGET_PPC64)
-
-/* multiply high word */
-uint64_t helper_mulhd(uint64_t arg1, uint64_t arg2)
-{
- uint64_t tl, th;
-
- muls64(&tl, &th, arg1, arg2);
- return th;
-}
-
-/* multiply high word unsigned */
-uint64_t helper_mulhdu(uint64_t arg1, uint64_t arg2)
-{
- uint64_t tl, th;
-
- mulu64(&tl, &th, arg1, arg2);
- return th;
-}
-
-uint64_t helper_mulldo(uint64_t arg1, uint64_t arg2)
-{
- int64_t th;
- uint64_t tl;
-
- muls64(&tl, (uint64_t *)&th, arg1, arg2);
- /* If th != 0 && th != -1, then we had an overflow */
- if (likely((uint64_t)(th + 1) <= 1)) {
- env->xer &= ~(1 << XER_OV);
- } else {
- env->xer |= (1 << XER_OV) | (1 << XER_SO);
- }
- return (int64_t)tl;
-}
-#endif
-
-target_ulong helper_cntlzw(target_ulong t)
-{
- return clz32(t);
-}
-
-#if defined(TARGET_PPC64)
-target_ulong helper_cntlzd(target_ulong t)
-{
- return clz64(t);
-}
-#endif
-
-/* shift right arithmetic helper */
-target_ulong helper_sraw(target_ulong value, target_ulong shift)
-{
- int32_t ret;
-
- if (likely(!(shift & 0x20))) {
- if (likely((uint32_t)shift != 0)) {
- shift &= 0x1f;
- ret = (int32_t)value >> shift;
- if (likely(ret >= 0 || (value & ((1 << shift) - 1)) == 0)) {
- env->xer &= ~(1 << XER_CA);
- } else {
- env->xer |= (1 << XER_CA);
- }
- } else {
- ret = (int32_t)value;
- env->xer &= ~(1 << XER_CA);
- }
- } else {
- ret = (int32_t)value >> 31;
- if (ret) {
- env->xer |= (1 << XER_CA);
- } else {
- env->xer &= ~(1 << XER_CA);
- }
- }
- return (target_long)ret;
-}
-
-#if defined(TARGET_PPC64)
-target_ulong helper_srad(target_ulong value, target_ulong shift)
-{
- int64_t ret;
-
- if (likely(!(shift & 0x40))) {
- if (likely((uint64_t)shift != 0)) {
- shift &= 0x3f;
- ret = (int64_t)value >> shift;
- if (likely(ret >= 0 || (value & ((1 << shift) - 1)) == 0)) {
- env->xer &= ~(1 << XER_CA);
- } else {
- env->xer |= (1 << XER_CA);
- }
- } else {
- ret = (int64_t)value;
- env->xer &= ~(1 << XER_CA);
- }
- } else {
- ret = (int64_t)value >> 63;
- if (ret) {
- env->xer |= (1 << XER_CA);
- } else {
- env->xer &= ~(1 << XER_CA);
- }
- }
- return ret;
-}
-#endif
-
-#if defined(TARGET_PPC64)
-target_ulong helper_popcntb(target_ulong val)
-{
- val = (val & 0x5555555555555555ULL) + ((val >> 1) &
- 0x5555555555555555ULL);
- val = (val & 0x3333333333333333ULL) + ((val >> 2) &
- 0x3333333333333333ULL);
- val = (val & 0x0f0f0f0f0f0f0f0fULL) + ((val >> 4) &
- 0x0f0f0f0f0f0f0f0fULL);
- return val;
-}
-
-target_ulong helper_popcntw(target_ulong val)
-{
- val = (val & 0x5555555555555555ULL) + ((val >> 1) &
- 0x5555555555555555ULL);
- val = (val & 0x3333333333333333ULL) + ((val >> 2) &
- 0x3333333333333333ULL);
- val = (val & 0x0f0f0f0f0f0f0f0fULL) + ((val >> 4) &
- 0x0f0f0f0f0f0f0f0fULL);
- val = (val & 0x00ff00ff00ff00ffULL) + ((val >> 8) &
- 0x00ff00ff00ff00ffULL);
- val = (val & 0x0000ffff0000ffffULL) + ((val >> 16) &
- 0x0000ffff0000ffffULL);
- return val;
-}
-
-target_ulong helper_popcntd(target_ulong val)
-{
- return ctpop64(val);
-}
-#else
-target_ulong helper_popcntb(target_ulong val)
-{
- val = (val & 0x55555555) + ((val >> 1) & 0x55555555);
- val = (val & 0x33333333) + ((val >> 2) & 0x33333333);
- val = (val & 0x0f0f0f0f) + ((val >> 4) & 0x0f0f0f0f);
- return val;
-}
-
-target_ulong helper_popcntw(target_ulong val)
-{
- val = (val & 0x55555555) + ((val >> 1) & 0x55555555);
- val = (val & 0x33333333) + ((val >> 2) & 0x33333333);
- val = (val & 0x0f0f0f0f) + ((val >> 4) & 0x0f0f0f0f);
- val = (val & 0x00ff00ff) + ((val >> 8) & 0x00ff00ff);
- val = (val & 0x0000ffff) + ((val >> 16) & 0x0000ffff);
- return val;
-}
-#endif
-
-/*****************************************************************************/
/* PowerPC 601 specific instructions (POWER bridge) */
target_ulong helper_clcs(uint32_t arg)
@@ -577,67 +417,6 @@ target_ulong helper_clcs(uint32_t arg)
}
}
-target_ulong helper_div(target_ulong arg1, target_ulong arg2)
-{
- uint64_t tmp = (uint64_t)arg1 << 32 | env->spr[SPR_MQ];
-
- if (((int32_t)tmp == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
- (int32_t)arg2 == 0) {
- env->spr[SPR_MQ] = 0;
- return INT32_MIN;
- } else {
- env->spr[SPR_MQ] = tmp % arg2;
- return tmp / (int32_t)arg2;
- }
-}
-
-target_ulong helper_divo(target_ulong arg1, target_ulong arg2)
-{
- uint64_t tmp = (uint64_t)arg1 << 32 | env->spr[SPR_MQ];
-
- if (((int32_t)tmp == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
- (int32_t)arg2 == 0) {
- env->xer |= (1 << XER_OV) | (1 << XER_SO);
- env->spr[SPR_MQ] = 0;
- return INT32_MIN;
- } else {
- env->spr[SPR_MQ] = tmp % arg2;
- tmp /= (int32_t)arg2;
- if ((int32_t)tmp != tmp) {
- env->xer |= (1 << XER_OV) | (1 << XER_SO);
- } else {
- env->xer &= ~(1 << XER_OV);
- }
- return tmp;
- }
-}
-
-target_ulong helper_divs(target_ulong arg1, target_ulong arg2)
-{
- if (((int32_t)arg1 == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
- (int32_t)arg2 == 0) {
- env->spr[SPR_MQ] = 0;
- return INT32_MIN;
- } else {
- env->spr[SPR_MQ] = (int32_t)arg1 % (int32_t)arg2;
- return (int32_t)arg1 / (int32_t)arg2;
- }
-}
-
-target_ulong helper_divso(target_ulong arg1, target_ulong arg2)
-{
- if (((int32_t)arg1 == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
- (int32_t)arg2 == 0) {
- env->xer |= (1 << XER_OV) | (1 << XER_SO);
- env->spr[SPR_MQ] = 0;
- return INT32_MIN;
- } else {
- env->xer &= ~(1 << XER_OV);
- env->spr[SPR_MQ] = (int32_t)arg1 % (int32_t)arg2;
- return (int32_t)arg1 / (int32_t)arg2;
- }
-}
-
#if !defined(CONFIG_USER_ONLY)
target_ulong helper_rac(target_ulong addr)
{
@@ -660,26 +439,6 @@ target_ulong helper_rac(target_ulong addr)
#endif
/*****************************************************************************/
-/* 602 specific instructions */
-/* mfrom is the most crazy instruction ever seen, imho ! */
-/* Real implementation uses a ROM table. Do the same */
-/* Extremely decomposed:
- * -arg / 256
- * return 256 * log10(10 + 1.0) + 0.5
- */
-#if !defined(CONFIG_USER_ONLY)
-target_ulong helper_602_mfrom(target_ulong arg)
-{
- if (likely(arg < 602)) {
-#include "mfrom_table.c"
- return mfrom_ROM_table[arg];
- } else {
- return 0;
- }
-}
-#endif
-
-/*****************************************************************************/
/* Embedded PowerPC specific helpers */
/* XXX: to be improved to check access rights when in user-mode */
@@ -716,43 +475,6 @@ void helper_store_dcr(target_ulong dcrn, target_ulong val)
}
}
-/* 440 specific */
-target_ulong helper_dlmzb(target_ulong high, target_ulong low,
- uint32_t update_Rc)
-{
- target_ulong mask;
- int i;
-
- i = 1;
- for (mask = 0xFF000000; mask != 0; mask = mask >> 8) {
- if ((high & mask) == 0) {
- if (update_Rc) {
- env->crf[0] = 0x4;
- }
- goto done;
- }
- i++;
- }
- for (mask = 0xFF000000; mask != 0; mask = mask >> 8) {
- if ((low & mask) == 0) {
- if (update_Rc) {
- env->crf[0] = 0x8;
- }
- goto done;
- }
- i++;
- }
- if (update_Rc) {
- env->crf[0] = 0x2;
- }
- done:
- env->xer = (env->xer & ~0x7F) | i;
- if (update_Rc) {
- env->crf[0] |= xer_so;
- }
- return i;
-}
-
/*****************************************************************************/
/* Altivec extension helpers */
#if defined(HOST_WORDS_BIGENDIAN)
@@ -763,74 +485,6 @@ target_ulong helper_dlmzb(target_ulong high, target_ulong low,
#define LO_IDX 0
#endif
-#if defined(HOST_WORDS_BIGENDIAN)
-#define VECTOR_FOR_INORDER_I(index, element) \
- for (index = 0; index < ARRAY_SIZE(r->element); index++)
-#else
-#define VECTOR_FOR_INORDER_I(index, element) \
- for (index = ARRAY_SIZE(r->element)-1; index >= 0; index--)
-#endif
-
-/* If X is a NaN, store the corresponding QNaN into RESULT. Otherwise,
- * execute the following block. */
-#define DO_HANDLE_NAN(result, x) \
- if (float32_is_any_nan(x)) { \
- CPU_FloatU __f; \
- __f.f = x; \
- __f.l = __f.l | (1 << 22); /* Set QNaN bit. */ \
- result = __f.f; \
- } else
-
-#define HANDLE_NAN1(result, x) \
- DO_HANDLE_NAN(result, x)
-#define HANDLE_NAN2(result, x, y) \
- DO_HANDLE_NAN(result, x) DO_HANDLE_NAN(result, y)
-#define HANDLE_NAN3(result, x, y, z) \
- DO_HANDLE_NAN(result, x) DO_HANDLE_NAN(result, y) DO_HANDLE_NAN(result, z)
-
-/* Saturating arithmetic helpers. */
-#define SATCVT(from, to, from_type, to_type, min, max) \
- static inline to_type cvt##from##to(from_type x, int *sat) \
- { \
- to_type r; \
- \
- if (x < (from_type)min) { \
- r = min; \
- *sat = 1; \
- } else if (x > (from_type)max) { \
- r = max; \
- *sat = 1; \
- } else { \
- r = x; \
- } \
- return r; \
- }
-#define SATCVTU(from, to, from_type, to_type, min, max) \
- static inline to_type cvt##from##to(from_type x, int *sat) \
- { \
- to_type r; \
- \
- if (x > (from_type)max) { \
- r = max; \
- *sat = 1; \
- } else { \
- r = x; \
- } \
- return r; \
- }
-SATCVT(sh, sb, int16_t, int8_t, INT8_MIN, INT8_MAX)
-SATCVT(sw, sh, int32_t, int16_t, INT16_MIN, INT16_MAX)
-SATCVT(sd, sw, int64_t, int32_t, INT32_MIN, INT32_MAX)
-
-SATCVTU(uh, ub, uint16_t, uint8_t, 0, UINT8_MAX)
-SATCVTU(uw, uh, uint32_t, uint16_t, 0, UINT16_MAX)
-SATCVTU(ud, uw, uint64_t, uint32_t, 0, UINT32_MAX)
-SATCVT(sh, ub, int16_t, uint8_t, 0, UINT8_MAX)
-SATCVT(sw, uh, int32_t, uint16_t, 0, UINT16_MAX)
-SATCVT(sd, uw, int64_t, uint32_t, 0, UINT32_MAX)
-#undef SATCVT
-#undef SATCVTU
-
#define LVE(name, access, swap, element) \
void helper_##name(ppc_avr_t *r, target_ulong addr) \
{ \
@@ -854,24 +508,6 @@ LVE(lvewx, ldl, bswap32, u32)
#undef I
#undef LVE
-void helper_lvsl(ppc_avr_t *r, target_ulong sh)
-{
- int i, j = (sh & 0xf);
-
- VECTOR_FOR_INORDER_I(i, u8) {
- r->u8[i] = j++;
- }
-}
-
-void helper_lvsr(ppc_avr_t *r, target_ulong sh)
-{
- int i, j = 0x10 - (sh & 0xf);
-
- VECTOR_FOR_INORDER_I(i, u8) {
- r->u8[i] = j++;
- }
-}
-
#define STVE(name, access, swap, element) \
void helper_##name(ppc_avr_t *r, target_ulong addr) \
{ \
@@ -893,1146 +529,10 @@ STVE(stvewx, stl, bswap32, u32)
#undef I
#undef LVE
-void helper_mtvscr(ppc_avr_t *r)
-{
-#if defined(HOST_WORDS_BIGENDIAN)
- env->vscr = r->u32[3];
-#else
- env->vscr = r->u32[0];
-#endif
- set_flush_to_zero(vscr_nj, &env->vec_status);
-}
-
-void helper_vaddcuw(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
- r->u32[i] = ~a->u32[i] < b->u32[i];
- }
-}
-
-#define VARITH_DO(name, op, element) \
- void helper_v##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
- { \
- int i; \
- \
- for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
- r->element[i] = a->element[i] op b->element[i]; \
- } \
- }
-#define VARITH(suffix, element) \
- VARITH_DO(add##suffix, +, element) \
- VARITH_DO(sub##suffix, -, element)
-VARITH(ubm, u8)
-VARITH(uhm, u16)
-VARITH(uwm, u32)
-#undef VARITH_DO
-#undef VARITH
-
-#define VARITHFP(suffix, func) \
- void helper_v##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
- { \
- int i; \
- \
- for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
- HANDLE_NAN2(r->f[i], a->f[i], b->f[i]) { \
- r->f[i] = func(a->f[i], b->f[i], &env->vec_status); \
- } \
- } \
- }
-VARITHFP(addfp, float32_add)
-VARITHFP(subfp, float32_sub)
-#undef VARITHFP
-
-#define VARITHSAT_CASE(type, op, cvt, element) \
- { \
- type result = (type)a->element[i] op (type)b->element[i]; \
- r->element[i] = cvt(result, &sat); \
- }
-
-#define VARITHSAT_DO(name, op, optype, cvt, element) \
- void helper_v##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
- { \
- int sat = 0; \
- int i; \
- \
- for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
- switch (sizeof(r->element[0])) { \
- case 1: \
- VARITHSAT_CASE(optype, op, cvt, element); \
- break; \
- case 2: \
- VARITHSAT_CASE(optype, op, cvt, element); \
- break; \
- case 4: \
- VARITHSAT_CASE(optype, op, cvt, element); \
- break; \
- } \
- } \
- if (sat) { \
- env->vscr |= (1 << VSCR_SAT); \
- } \
- }
-#define VARITHSAT_SIGNED(suffix, element, optype, cvt) \
- VARITHSAT_DO(adds##suffix##s, +, optype, cvt, element) \
- VARITHSAT_DO(subs##suffix##s, -, optype, cvt, element)
-#define VARITHSAT_UNSIGNED(suffix, element, optype, cvt) \
- VARITHSAT_DO(addu##suffix##s, +, optype, cvt, element) \
- VARITHSAT_DO(subu##suffix##s, -, optype, cvt, element)
-VARITHSAT_SIGNED(b, s8, int16_t, cvtshsb)
-VARITHSAT_SIGNED(h, s16, int32_t, cvtswsh)
-VARITHSAT_SIGNED(w, s32, int64_t, cvtsdsw)
-VARITHSAT_UNSIGNED(b, u8, uint16_t, cvtshub)
-VARITHSAT_UNSIGNED(h, u16, uint32_t, cvtswuh)
-VARITHSAT_UNSIGNED(w, u32, uint64_t, cvtsduw)
-#undef VARITHSAT_CASE
-#undef VARITHSAT_DO
-#undef VARITHSAT_SIGNED
-#undef VARITHSAT_UNSIGNED
-
-#define VAVG_DO(name, element, etype) \
- void helper_v##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
- { \
- int i; \
- \
- for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
- etype x = (etype)a->element[i] + (etype)b->element[i] + 1; \
- r->element[i] = x >> 1; \
- } \
- }
-
-#define VAVG(type, signed_element, signed_type, unsigned_element, \
- unsigned_type) \
- VAVG_DO(avgs##type, signed_element, signed_type) \
- VAVG_DO(avgu##type, unsigned_element, unsigned_type)
-VAVG(b, s8, int16_t, u8, uint16_t)
-VAVG(h, s16, int32_t, u16, uint32_t)
-VAVG(w, s32, int64_t, u32, uint64_t)
-#undef VAVG_DO
-#undef VAVG
-
-#define VCF(suffix, cvt, element) \
- void helper_vcf##suffix(ppc_avr_t *r, ppc_avr_t *b, uint32_t uim) \
- { \
- int i; \
- \
- for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
- float32 t = cvt(b->element[i], &env->vec_status); \
- r->f[i] = float32_scalbn(t, -uim, &env->vec_status); \
- } \
- }
-VCF(ux, uint32_to_float32, u32)
-VCF(sx, int32_to_float32, s32)
-#undef VCF
-
-#define VCMP_DO(suffix, compare, element, record) \
- void helper_vcmp##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
- { \
- uint32_t ones = (uint32_t)-1; \
- uint32_t all = ones; \
- uint32_t none = 0; \
- int i; \
- \
- for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
- uint32_t result = (a->element[i] compare b->element[i] ? \
- ones : 0x0); \
- switch (sizeof(a->element[0])) { \
- case 4: \
- r->u32[i] = result; \
- break; \
- case 2: \
- r->u16[i] = result; \
- break; \
- case 1: \
- r->u8[i] = result; \
- break; \
- } \
- all &= result; \
- none |= result; \
- } \
- if (record) { \
- env->crf[6] = ((all != 0) << 3) | ((none == 0) << 1); \
- } \
- }
-#define VCMP(suffix, compare, element) \
- VCMP_DO(suffix, compare, element, 0) \
- VCMP_DO(suffix##_dot, compare, element, 1)
-VCMP(equb, ==, u8)
-VCMP(equh, ==, u16)
-VCMP(equw, ==, u32)
-VCMP(gtub, >, u8)
-VCMP(gtuh, >, u16)
-VCMP(gtuw, >, u32)
-VCMP(gtsb, >, s8)
-VCMP(gtsh, >, s16)
-VCMP(gtsw, >, s32)
-#undef VCMP_DO
-#undef VCMP
-
-#define VCMPFP_DO(suffix, compare, order, record) \
- void helper_vcmp##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
- { \
- uint32_t ones = (uint32_t)-1; \
- uint32_t all = ones; \
- uint32_t none = 0; \
- int i; \
- \
- for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
- uint32_t result; \
- int rel = float32_compare_quiet(a->f[i], b->f[i], \
- &env->vec_status); \
- if (rel == float_relation_unordered) { \
- result = 0; \
- } else if (rel compare order) { \
- result = ones; \
- } else { \
- result = 0; \
- } \
- r->u32[i] = result; \
- all &= result; \
- none |= result; \
- } \
- if (record) { \
- env->crf[6] = ((all != 0) << 3) | ((none == 0) << 1); \
- } \
- }
-#define VCMPFP(suffix, compare, order) \
- VCMPFP_DO(suffix, compare, order, 0) \
- VCMPFP_DO(suffix##_dot, compare, order, 1)
-VCMPFP(eqfp, ==, float_relation_equal)
-VCMPFP(gefp, !=, float_relation_less)
-VCMPFP(gtfp, ==, float_relation_greater)
-#undef VCMPFP_DO
-#undef VCMPFP
-
-static inline void vcmpbfp_internal(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b,
- int record)
-{
- int i;
- int all_in = 0;
-
- for (i = 0; i < ARRAY_SIZE(r->f); i++) {
- int le_rel = float32_compare_quiet(a->f[i], b->f[i], &env->vec_status);
- if (le_rel == float_relation_unordered) {
- r->u32[i] = 0xc0000000;
- /* ALL_IN does not need to be updated here. */
- } else {
- float32 bneg = float32_chs(b->f[i]);
- int ge_rel = float32_compare_quiet(a->f[i], bneg, &env->vec_status);
- int le = le_rel != float_relation_greater;
- int ge = ge_rel != float_relation_less;
-
- r->u32[i] = ((!le) << 31) | ((!ge) << 30);
- all_in |= (!le | !ge);
- }
- }
- if (record) {
- env->crf[6] = (all_in == 0) << 1;
- }
-}
-
-void helper_vcmpbfp(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
-{
- vcmpbfp_internal(r, a, b, 0);
-}
-
-void helper_vcmpbfp_dot(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
-{
- vcmpbfp_internal(r, a, b, 1);
-}
-
-#define VCT(suffix, satcvt, element) \
- void helper_vct##suffix(ppc_avr_t *r, ppc_avr_t *b, uint32_t uim) \
- { \
- int i; \
- int sat = 0; \
- float_status s = env->vec_status; \
- \
- set_float_rounding_mode(float_round_to_zero, &s); \
- for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
- if (float32_is_any_nan(b->f[i])) { \
- r->element[i] = 0; \
- } else { \
- float64 t = float32_to_float64(b->f[i], &s); \
- int64_t j; \
- \
- t = float64_scalbn(t, uim, &s); \
- j = float64_to_int64(t, &s); \
- r->element[i] = satcvt(j, &sat); \
- } \
- } \
- if (sat) { \
- env->vscr |= (1 << VSCR_SAT); \
- } \
- }
-VCT(uxs, cvtsduw, u32)
-VCT(sxs, cvtsdsw, s32)
-#undef VCT
-
-void helper_vmaddfp(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(r->f); i++) {
- HANDLE_NAN3(r->f[i], a->f[i], b->f[i], c->f[i]) {
- /* Need to do the computation in higher precision and round
- * once at the end. */
- float64 af, bf, cf, t;
-
- af = float32_to_float64(a->f[i], &env->vec_status);
- bf = float32_to_float64(b->f[i], &env->vec_status);
- cf = float32_to_float64(c->f[i], &env->vec_status);
- t = float64_mul(af, cf, &env->vec_status);
- t = float64_add(t, bf, &env->vec_status);
- r->f[i] = float64_to_float32(t, &env->vec_status);
- }
- }
-}
-
-void helper_vmhaddshs(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
-{
- int sat = 0;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
- int32_t prod = a->s16[i] * b->s16[i];
- int32_t t = (int32_t)c->s16[i] + (prod >> 15);
-
- r->s16[i] = cvtswsh(t, &sat);
- }
-
- if (sat) {
- env->vscr |= (1 << VSCR_SAT);
- }
-}
-
-void helper_vmhraddshs(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
-{
- int sat = 0;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
- int32_t prod = a->s16[i] * b->s16[i] + 0x00004000;
- int32_t t = (int32_t)c->s16[i] + (prod >> 15);
- r->s16[i] = cvtswsh(t, &sat);
- }
-
- if (sat) {
- env->vscr |= (1 << VSCR_SAT);
- }
-}
-
-#define VMINMAX_DO(name, compare, element) \
- void helper_v##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
- { \
- int i; \
- \
- for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
- if (a->element[i] compare b->element[i]) { \
- r->element[i] = b->element[i]; \
- } else { \
- r->element[i] = a->element[i]; \
- } \
- } \
- }
-#define VMINMAX(suffix, element) \
- VMINMAX_DO(min##suffix, >, element) \
- VMINMAX_DO(max##suffix, <, element)
-VMINMAX(sb, s8)
-VMINMAX(sh, s16)
-VMINMAX(sw, s32)
-VMINMAX(ub, u8)
-VMINMAX(uh, u16)
-VMINMAX(uw, u32)
-#undef VMINMAX_DO
-#undef VMINMAX
-
-#define VMINMAXFP(suffix, rT, rF) \
- void helper_v##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
- { \
- int i; \
- \
- for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
- HANDLE_NAN2(r->f[i], a->f[i], b->f[i]) { \
- if (float32_lt_quiet(a->f[i], b->f[i], \
- &env->vec_status)) { \
- r->f[i] = rT->f[i]; \
- } else { \
- r->f[i] = rF->f[i]; \
- } \
- } \
- } \
- }
-VMINMAXFP(minfp, a, b)
-VMINMAXFP(maxfp, b, a)
-#undef VMINMAXFP
-
-void helper_vmladduhm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
- int32_t prod = a->s16[i] * b->s16[i];
- r->s16[i] = (int16_t) (prod + c->s16[i]);
- }
-}
-
-#define VMRG_DO(name, element, highp) \
- void helper_v##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
- { \
- ppc_avr_t result; \
- int i; \
- size_t n_elems = ARRAY_SIZE(r->element); \
- \
- for (i = 0; i < n_elems / 2; i++) { \
- if (highp) { \
- result.element[i*2+HI_IDX] = a->element[i]; \
- result.element[i*2+LO_IDX] = b->element[i]; \
- } else { \
- result.element[n_elems - i * 2 - (1 + HI_IDX)] = \
- b->element[n_elems - i - 1]; \
- result.element[n_elems - i * 2 - (1 + LO_IDX)] = \
- a->element[n_elems - i - 1]; \
- } \
- } \
- *r = result; \
- }
-#if defined(HOST_WORDS_BIGENDIAN)
-#define MRGHI 0
-#define MRGLO 1
-#else
-#define MRGHI 1
-#define MRGLO 0
-#endif
-#define VMRG(suffix, element) \
- VMRG_DO(mrgl##suffix, element, MRGHI) \
- VMRG_DO(mrgh##suffix, element, MRGLO)
-VMRG(b, u8)
-VMRG(h, u16)
-VMRG(w, u32)
-#undef VMRG_DO
-#undef VMRG
-#undef MRGHI
-#undef MRGLO
-
-void helper_vmsummbm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
-{
- int32_t prod[16];
- int i;
-
- for (i = 0; i < ARRAY_SIZE(r->s8); i++) {
- prod[i] = (int32_t)a->s8[i] * b->u8[i];
- }
-
- VECTOR_FOR_INORDER_I(i, s32) {
- r->s32[i] = c->s32[i] + prod[4 * i] + prod[4 * i + 1] +
- prod[4 * i + 2] + prod[4 * i + 3];
- }
-}
-
-void helper_vmsumshm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
-{
- int32_t prod[8];
- int i;
-
- for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
- prod[i] = a->s16[i] * b->s16[i];
- }
-
- VECTOR_FOR_INORDER_I(i, s32) {
- r->s32[i] = c->s32[i] + prod[2 * i] + prod[2 * i + 1];
- }
-}
-
-void helper_vmsumshs(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
-{
- int32_t prod[8];
- int i;
- int sat = 0;
-
- for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
- prod[i] = (int32_t)a->s16[i] * b->s16[i];
- }
-
- VECTOR_FOR_INORDER_I(i, s32) {
- int64_t t = (int64_t)c->s32[i] + prod[2 * i] + prod[2 * i + 1];
-
- r->u32[i] = cvtsdsw(t, &sat);
- }
-
- if (sat) {
- env->vscr |= (1 << VSCR_SAT);
- }
-}
-
-void helper_vmsumubm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
-{
- uint16_t prod[16];
- int i;
-
- for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
- prod[i] = a->u8[i] * b->u8[i];
- }
-
- VECTOR_FOR_INORDER_I(i, u32) {
- r->u32[i] = c->u32[i] + prod[4 * i] + prod[4 * i + 1] +
- prod[4 * i + 2] + prod[4 * i + 3];
- }
-}
-
-void helper_vmsumuhm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
-{
- uint32_t prod[8];
- int i;
-
- for (i = 0; i < ARRAY_SIZE(r->u16); i++) {
- prod[i] = a->u16[i] * b->u16[i];
- }
-
- VECTOR_FOR_INORDER_I(i, u32) {
- r->u32[i] = c->u32[i] + prod[2 * i] + prod[2 * i + 1];
- }
-}
-
-void helper_vmsumuhs(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
-{
- uint32_t prod[8];
- int i;
- int sat = 0;
-
- for (i = 0; i < ARRAY_SIZE(r->u16); i++) {
- prod[i] = a->u16[i] * b->u16[i];
- }
-
- VECTOR_FOR_INORDER_I(i, s32) {
- uint64_t t = (uint64_t)c->u32[i] + prod[2 * i] + prod[2 * i + 1];
-
- r->u32[i] = cvtuduw(t, &sat);
- }
-
- if (sat) {
- env->vscr |= (1 << VSCR_SAT);
- }
-}
-
-#define VMUL_DO(name, mul_element, prod_element, evenp) \
- void helper_v##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
- { \
- int i; \
- \
- VECTOR_FOR_INORDER_I(i, prod_element) { \
- if (evenp) { \
- r->prod_element[i] = a->mul_element[i * 2 + HI_IDX] * \
- b->mul_element[i * 2 + HI_IDX]; \
- } else { \
- r->prod_element[i] = a->mul_element[i * 2 + LO_IDX] * \
- b->mul_element[i * 2 + LO_IDX]; \
- } \
- } \
- }
-#define VMUL(suffix, mul_element, prod_element) \
- VMUL_DO(mule##suffix, mul_element, prod_element, 1) \
- VMUL_DO(mulo##suffix, mul_element, prod_element, 0)
-VMUL(sb, s8, s16)
-VMUL(sh, s16, s32)
-VMUL(ub, u8, u16)
-VMUL(uh, u16, u32)
-#undef VMUL_DO
-#undef VMUL
-
-void helper_vnmsubfp(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(r->f); i++) {
- HANDLE_NAN3(r->f[i], a->f[i], b->f[i], c->f[i]) {
- /* Need to do the computation is higher precision and round
- * once at the end. */
- float64 af, bf, cf, t;
-
- af = float32_to_float64(a->f[i], &env->vec_status);
- bf = float32_to_float64(b->f[i], &env->vec_status);
- cf = float32_to_float64(c->f[i], &env->vec_status);
- t = float64_mul(af, cf, &env->vec_status);
- t = float64_sub(t, bf, &env->vec_status);
- t = float64_chs(t);
- r->f[i] = float64_to_float32(t, &env->vec_status);
- }
- }
-}
-
-void helper_vperm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
-{
- ppc_avr_t result;
- int i;
-
- VECTOR_FOR_INORDER_I(i, u8) {
- int s = c->u8[i] & 0x1f;
-#if defined(HOST_WORDS_BIGENDIAN)
- int index = s & 0xf;
-#else
- int index = 15 - (s & 0xf);
-#endif
-
- if (s & 0x10) {
- result.u8[i] = b->u8[index];
- } else {
- result.u8[i] = a->u8[index];
- }
- }
- *r = result;
-}
-
-#if defined(HOST_WORDS_BIGENDIAN)
-#define PKBIG 1
-#else
-#define PKBIG 0
-#endif
-void helper_vpkpx(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
-{
- int i, j;
- ppc_avr_t result;
-#if defined(HOST_WORDS_BIGENDIAN)
- const ppc_avr_t *x[2] = { a, b };
-#else
- const ppc_avr_t *x[2] = { b, a };
-#endif
-
- VECTOR_FOR_INORDER_I(i, u64) {
- VECTOR_FOR_INORDER_I(j, u32) {
- uint32_t e = x[i]->u32[j];
-
- result.u16[4*i+j] = (((e >> 9) & 0xfc00) |
- ((e >> 6) & 0x3e0) |
- ((e >> 3) & 0x1f));
- }
- }
- *r = result;
-}
-
-#define VPK(suffix, from, to, cvt, dosat) \
- void helper_vpk##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
- { \
- int i; \
- int sat = 0; \
- ppc_avr_t result; \
- ppc_avr_t *a0 = PKBIG ? a : b; \
- ppc_avr_t *a1 = PKBIG ? b : a; \
- \
- VECTOR_FOR_INORDER_I(i, from) { \
- result.to[i] = cvt(a0->from[i], &sat); \
- result.to[i+ARRAY_SIZE(r->from)] = cvt(a1->from[i], &sat); \
- } \
- *r = result; \
- if (dosat && sat) { \
- env->vscr |= (1 << VSCR_SAT); \
- } \
- }
-#define I(x, y) (x)
-VPK(shss, s16, s8, cvtshsb, 1)
-VPK(shus, s16, u8, cvtshub, 1)
-VPK(swss, s32, s16, cvtswsh, 1)
-VPK(swus, s32, u16, cvtswuh, 1)
-VPK(uhus, u16, u8, cvtuhub, 1)
-VPK(uwus, u32, u16, cvtuwuh, 1)
-VPK(uhum, u16, u8, I, 0)
-VPK(uwum, u32, u16, I, 0)
-#undef I
-#undef VPK
-#undef PKBIG
-
-void helper_vrefp(ppc_avr_t *r, ppc_avr_t *b)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(r->f); i++) {
- HANDLE_NAN1(r->f[i], b->f[i]) {
- r->f[i] = float32_div(float32_one, b->f[i], &env->vec_status);
- }
- }
-}
-
-#define VRFI(suffix, rounding) \
- void helper_vrfi##suffix(ppc_avr_t *r, ppc_avr_t *b) \
- { \
- int i; \
- float_status s = env->vec_status; \
- \
- set_float_rounding_mode(rounding, &s); \
- for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
- HANDLE_NAN1(r->f[i], b->f[i]) { \
- r->f[i] = float32_round_to_int (b->f[i], &s); \
- } \
- } \
- }
-VRFI(n, float_round_nearest_even)
-VRFI(m, float_round_down)
-VRFI(p, float_round_up)
-VRFI(z, float_round_to_zero)
-#undef VRFI
-
-#define VROTATE(suffix, element) \
- void helper_vrl##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
- { \
- int i; \
- \
- for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
- unsigned int mask = ((1 << \
- (3 + (sizeof(a->element[0]) >> 1))) \
- - 1); \
- unsigned int shift = b->element[i] & mask; \
- r->element[i] = (a->element[i] << shift) | \
- (a->element[i] >> (sizeof(a->element[0]) * 8 - shift)); \
- } \
- }
-VROTATE(b, u8)
-VROTATE(h, u16)
-VROTATE(w, u32)
-#undef VROTATE
-
-void helper_vrsqrtefp(ppc_avr_t *r, ppc_avr_t *b)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(r->f); i++) {
- HANDLE_NAN1(r->f[i], b->f[i]) {
- float32 t = float32_sqrt(b->f[i], &env->vec_status);
-
- r->f[i] = float32_div(float32_one, t, &env->vec_status);
- }
- }
-}
-
-void helper_vsel(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
-{
- r->u64[0] = (a->u64[0] & ~c->u64[0]) | (b->u64[0] & c->u64[0]);
- r->u64[1] = (a->u64[1] & ~c->u64[1]) | (b->u64[1] & c->u64[1]);
-}
-
-void helper_vexptefp(ppc_avr_t *r, ppc_avr_t *b)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(r->f); i++) {
- HANDLE_NAN1(r->f[i], b->f[i]) {
- r->f[i] = float32_exp2(b->f[i], &env->vec_status);
- }
- }
-}
-
-void helper_vlogefp(ppc_avr_t *r, ppc_avr_t *b)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(r->f); i++) {
- HANDLE_NAN1(r->f[i], b->f[i]) {
- r->f[i] = float32_log2(b->f[i], &env->vec_status);
- }
- }
-}
-
-#if defined(HOST_WORDS_BIGENDIAN)
-#define LEFT 0
-#define RIGHT 1
-#else
-#define LEFT 1
-#define RIGHT 0
-#endif
-/* The specification says that the results are undefined if all of the
- * shift counts are not identical. We check to make sure that they are
- * to conform to what real hardware appears to do. */
-#define VSHIFT(suffix, leftp) \
- void helper_vs##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
- { \
- int shift = b->u8[LO_IDX*15] & 0x7; \
- int doit = 1; \
- int i; \
- \
- for (i = 0; i < ARRAY_SIZE(r->u8); i++) { \
- doit = doit && ((b->u8[i] & 0x7) == shift); \
- } \
- if (doit) { \
- if (shift == 0) { \
- *r = *a; \
- } else if (leftp) { \
- uint64_t carry = a->u64[LO_IDX] >> (64 - shift); \
- \
- r->u64[HI_IDX] = (a->u64[HI_IDX] << shift) | carry; \
- r->u64[LO_IDX] = a->u64[LO_IDX] << shift; \
- } else { \
- uint64_t carry = a->u64[HI_IDX] << (64 - shift); \
- \
- r->u64[LO_IDX] = (a->u64[LO_IDX] >> shift) | carry; \
- r->u64[HI_IDX] = a->u64[HI_IDX] >> shift; \
- } \
- } \
- }
-VSHIFT(l, LEFT)
-VSHIFT(r, RIGHT)
-#undef VSHIFT
-#undef LEFT
-#undef RIGHT
-
-#define VSL(suffix, element) \
- void helper_vsl##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
- { \
- int i; \
- \
- for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
- unsigned int mask = ((1 << \
- (3 + (sizeof(a->element[0]) >> 1))) \
- - 1); \
- unsigned int shift = b->element[i] & mask; \
- \
- r->element[i] = a->element[i] << shift; \
- } \
- }
-VSL(b, u8)
-VSL(h, u16)
-VSL(w, u32)
-#undef VSL
-
-void helper_vsldoi(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t shift)
-{
- int sh = shift & 0xf;
- int i;
- ppc_avr_t result;
-
-#if defined(HOST_WORDS_BIGENDIAN)
- for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
- int index = sh + i;
- if (index > 0xf) {
- result.u8[i] = b->u8[index - 0x10];
- } else {
- result.u8[i] = a->u8[index];
- }
- }
-#else
- for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
- int index = (16 - sh) + i;
- if (index > 0xf) {
- result.u8[i] = a->u8[index - 0x10];
- } else {
- result.u8[i] = b->u8[index];
- }
- }
-#endif
- *r = result;
-}
-
-void helper_vslo(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
-{
- int sh = (b->u8[LO_IDX*0xf] >> 3) & 0xf;
-
-#if defined(HOST_WORDS_BIGENDIAN)
- memmove(&r->u8[0], &a->u8[sh], 16 - sh);
- memset(&r->u8[16-sh], 0, sh);
-#else
- memmove(&r->u8[sh], &a->u8[0], 16 - sh);
- memset(&r->u8[0], 0, sh);
-#endif
-}
-
-/* Experimental testing shows that hardware masks the immediate. */
-#define _SPLAT_MASKED(element) (splat & (ARRAY_SIZE(r->element) - 1))
-#if defined(HOST_WORDS_BIGENDIAN)
-#define SPLAT_ELEMENT(element) _SPLAT_MASKED(element)
-#else
-#define SPLAT_ELEMENT(element) \
- (ARRAY_SIZE(r->element) - 1 - _SPLAT_MASKED(element))
-#endif
-#define VSPLT(suffix, element) \
- void helper_vsplt##suffix(ppc_avr_t *r, ppc_avr_t *b, uint32_t splat) \
- { \
- uint32_t s = b->element[SPLAT_ELEMENT(element)]; \
- int i; \
- \
- for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
- r->element[i] = s; \
- } \
- }
-VSPLT(b, u8)
-VSPLT(h, u16)
-VSPLT(w, u32)
-#undef VSPLT
-#undef SPLAT_ELEMENT
-#undef _SPLAT_MASKED
-
-#define VSPLTI(suffix, element, splat_type) \
- void helper_vspltis##suffix(ppc_avr_t *r, uint32_t splat) \
- { \
- splat_type x = (int8_t)(splat << 3) >> 3; \
- int i; \
- \
- for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
- r->element[i] = x; \
- } \
- }
-VSPLTI(b, s8, int8_t)
-VSPLTI(h, s16, int16_t)
-VSPLTI(w, s32, int32_t)
-#undef VSPLTI
-
-#define VSR(suffix, element) \
- void helper_vsr##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
- { \
- int i; \
- \
- for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
- unsigned int mask = ((1 << \
- (3 + (sizeof(a->element[0]) >> 1))) \
- - 1); \
- unsigned int shift = b->element[i] & mask; \
- \
- r->element[i] = a->element[i] >> shift; \
- } \
- }
-VSR(ab, s8)
-VSR(ah, s16)
-VSR(aw, s32)
-VSR(b, u8)
-VSR(h, u16)
-VSR(w, u32)
-#undef VSR
-
-void helper_vsro(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
-{
- int sh = (b->u8[LO_IDX * 0xf] >> 3) & 0xf;
-
-#if defined(HOST_WORDS_BIGENDIAN)
- memmove(&r->u8[sh], &a->u8[0], 16 - sh);
- memset(&r->u8[0], 0, sh);
-#else
- memmove(&r->u8[0], &a->u8[sh], 16 - sh);
- memset(&r->u8[16 - sh], 0, sh);
-#endif
-}
-
-void helper_vsubcuw(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
- r->u32[i] = a->u32[i] >= b->u32[i];
- }
-}
-
-void helper_vsumsws(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
-{
- int64_t t;
- int i, upper;
- ppc_avr_t result;
- int sat = 0;
-
-#if defined(HOST_WORDS_BIGENDIAN)
- upper = ARRAY_SIZE(r->s32)-1;
-#else
- upper = 0;
-#endif
- t = (int64_t)b->s32[upper];
- for (i = 0; i < ARRAY_SIZE(r->s32); i++) {
- t += a->s32[i];
- result.s32[i] = 0;
- }
- result.s32[upper] = cvtsdsw(t, &sat);
- *r = result;
-
- if (sat) {
- env->vscr |= (1 << VSCR_SAT);
- }
-}
-
-void helper_vsum2sws(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
-{
- int i, j, upper;
- ppc_avr_t result;
- int sat = 0;
-
-#if defined(HOST_WORDS_BIGENDIAN)
- upper = 1;
-#else
- upper = 0;
-#endif
- for (i = 0; i < ARRAY_SIZE(r->u64); i++) {
- int64_t t = (int64_t)b->s32[upper + i * 2];
-
- result.u64[i] = 0;
- for (j = 0; j < ARRAY_SIZE(r->u64); j++) {
- t += a->s32[2 * i + j];
- }
- result.s32[upper + i * 2] = cvtsdsw(t, &sat);
- }
-
- *r = result;
- if (sat) {
- env->vscr |= (1 << VSCR_SAT);
- }
-}
-
-void helper_vsum4sbs(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
-{
- int i, j;
- int sat = 0;
-
- for (i = 0; i < ARRAY_SIZE(r->s32); i++) {
- int64_t t = (int64_t)b->s32[i];
-
- for (j = 0; j < ARRAY_SIZE(r->s32); j++) {
- t += a->s8[4 * i + j];
- }
- r->s32[i] = cvtsdsw(t, &sat);
- }
-
- if (sat) {
- env->vscr |= (1 << VSCR_SAT);
- }
-}
-
-void helper_vsum4shs(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
-{
- int sat = 0;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(r->s32); i++) {
- int64_t t = (int64_t)b->s32[i];
-
- t += a->s16[2 * i] + a->s16[2 * i + 1];
- r->s32[i] = cvtsdsw(t, &sat);
- }
-
- if (sat) {
- env->vscr |= (1 << VSCR_SAT);
- }
-}
-
-void helper_vsum4ubs(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
-{
- int i, j;
- int sat = 0;
-
- for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
- uint64_t t = (uint64_t)b->u32[i];
-
- for (j = 0; j < ARRAY_SIZE(r->u32); j++) {
- t += a->u8[4 * i + j];
- }
- r->u32[i] = cvtuduw(t, &sat);
- }
-
- if (sat) {
- env->vscr |= (1 << VSCR_SAT);
- }
-}
-
-#if defined(HOST_WORDS_BIGENDIAN)
-#define UPKHI 1
-#define UPKLO 0
-#else
-#define UPKHI 0
-#define UPKLO 1
-#endif
-#define VUPKPX(suffix, hi) \
- void helper_vupk##suffix(ppc_avr_t *r, ppc_avr_t *b) \
- { \
- int i; \
- ppc_avr_t result; \
- \
- for (i = 0; i < ARRAY_SIZE(r->u32); i++) { \
- uint16_t e = b->u16[hi ? i : i+4]; \
- uint8_t a = (e >> 15) ? 0xff : 0; \
- uint8_t r = (e >> 10) & 0x1f; \
- uint8_t g = (e >> 5) & 0x1f; \
- uint8_t b = e & 0x1f; \
- \
- result.u32[i] = (a << 24) | (r << 16) | (g << 8) | b; \
- } \
- *r = result; \
- }
-VUPKPX(lpx, UPKLO)
-VUPKPX(hpx, UPKHI)
-#undef VUPKPX
-
-#define VUPK(suffix, unpacked, packee, hi) \
- void helper_vupk##suffix(ppc_avr_t *r, ppc_avr_t *b) \
- { \
- int i; \
- ppc_avr_t result; \
- \
- if (hi) { \
- for (i = 0; i < ARRAY_SIZE(r->unpacked); i++) { \
- result.unpacked[i] = b->packee[i]; \
- } \
- } else { \
- for (i = ARRAY_SIZE(r->unpacked); i < ARRAY_SIZE(r->packee); \
- i++) { \
- result.unpacked[i - ARRAY_SIZE(r->unpacked)] = b->packee[i]; \
- } \
- } \
- *r = result; \
- }
-VUPK(hsb, s16, s8, UPKHI)
-VUPK(hsh, s32, s16, UPKHI)
-VUPK(lsb, s16, s8, UPKLO)
-VUPK(lsh, s32, s16, UPKLO)
-#undef VUPK
-#undef UPKHI
-#undef UPKLO
-
-#undef DO_HANDLE_NAN
-#undef HANDLE_NAN1
-#undef HANDLE_NAN2
-#undef HANDLE_NAN3
-#undef VECTOR_FOR_INORDER_I
#undef HI_IDX
#undef LO_IDX
/*****************************************************************************/
-/* SPE extension helpers */
-/* Use a table to make this quicker */
-static uint8_t hbrev[16] = {
- 0x0, 0x8, 0x4, 0xC, 0x2, 0xA, 0x6, 0xE,
- 0x1, 0x9, 0x5, 0xD, 0x3, 0xB, 0x7, 0xF,
-};
-
-static inline uint8_t byte_reverse(uint8_t val)
-{
- return hbrev[val >> 4] | (hbrev[val & 0xF] << 4);
-}
-
-static inline uint32_t word_reverse(uint32_t val)
-{
- return byte_reverse(val >> 24) | (byte_reverse(val >> 16) << 8) |
- (byte_reverse(val >> 8) << 16) | (byte_reverse(val) << 24);
-}
-
-#define MASKBITS 16 /* Random value - to be fixed (implementation dependent) */
-target_ulong helper_brinc(target_ulong arg1, target_ulong arg2)
-{
- uint32_t a, b, d, mask;
-
- mask = UINT32_MAX >> (32 - MASKBITS);
- a = arg1 & mask;
- b = arg2 & mask;
- d = word_reverse(1 + word_reverse(a | ~b));
- return (arg1 & ~mask) | (d & b);
-}
-
-uint32_t helper_cntlsw32(uint32_t val)
-{
- if (val & 0x80000000) {
- return clz32(~val);
- } else {
- return clz32(val);
- }
-}
-
-uint32_t helper_cntlzw32(uint32_t val)
-{
- return clz32(val);
-}
-
-/*****************************************************************************/
/* Softmmu support */
#if !defined(CONFIG_USER_ONLY)
--
1.6.0.2
^ permalink raw reply related [flat|nested] 89+ messages in thread
* [Qemu-devel] [PATCH 09/72] ppc: Avoid AREG0 for integer and vector helpers
2012-06-23 23:06 [Qemu-devel] [PULL 00/72] ppc patch queue 2012-06-24 Alexander Graf
` (7 preceding siblings ...)
2012-06-23 23:06 ` [Qemu-devel] [PATCH 08/72] ppc: Split integer and vector ops Alexander Graf
@ 2012-06-23 23:06 ` Alexander Graf
2012-06-23 23:06 ` [Qemu-devel] [PATCH 10/72] ppc: Split MMU etc. helpers from op_helper.c Alexander Graf
` (63 subsequent siblings)
72 siblings, 0 replies; 89+ messages in thread
From: Alexander Graf @ 2012-06-23 23:06 UTC (permalink / raw)
To: qemu-devel qemu-devel
Cc: Blue Swirl, qemu-ppc Mailing List, Andreas Färber,
Aurelien Jarno
From: Blue Swirl <blauwirbel@gmail.com>
Add an explicit CPUPPCState parameter instead of relying on AREG0.
Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Andreas Färber <afaerber@suse.de>
[fix unwanted whitespace line in Makefile.target]
Signed-off-by: Alexander Graf <agraf@suse.de>
---
target-ppc/Makefile.objs | 1 -
target-ppc/helper.h | 176 +++++++++++++++++++++++-----------------------
target-ppc/int_helper.c | 120 +++++++++++++++++++------------
target-ppc/translate.c | 174 +++++++++++++++++++++++++++++++--------------
4 files changed, 280 insertions(+), 191 deletions(-)
diff --git a/target-ppc/Makefile.objs b/target-ppc/Makefile.objs
index 97e440b..5d63400 100644
--- a/target-ppc/Makefile.objs
+++ b/target-ppc/Makefile.objs
@@ -6,5 +6,4 @@ obj-y += excp_helper.o
obj-y += fpu_helper.o
obj-y += int_helper.o
-$(obj)/int_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
$(obj)/op_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
diff --git a/target-ppc/helper.h b/target-ppc/helper.h
index 0aba7f8..7074bad 100644
--- a/target-ppc/helper.h
+++ b/target-ppc/helper.h
@@ -33,17 +33,17 @@ DEF_HELPER_4(lscbx, tl, tl, i32, i32, i32)
#if defined(TARGET_PPC64)
DEF_HELPER_FLAGS_2(mulhd, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64)
DEF_HELPER_FLAGS_2(mulhdu, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64)
-DEF_HELPER_2(mulldo, i64, i64, i64)
+DEF_HELPER_3(mulldo, i64, env, i64, i64)
#endif
DEF_HELPER_FLAGS_1(cntlzw, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl)
DEF_HELPER_FLAGS_1(popcntb, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl)
DEF_HELPER_FLAGS_1(popcntw, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl)
-DEF_HELPER_2(sraw, tl, tl, tl)
+DEF_HELPER_3(sraw, tl, env, tl, tl)
#if defined(TARGET_PPC64)
DEF_HELPER_FLAGS_1(cntlzd, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl)
DEF_HELPER_FLAGS_1(popcntd, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl)
-DEF_HELPER_2(srad, tl, tl, tl)
+DEF_HELPER_3(srad, tl, env, tl, tl)
#endif
DEF_HELPER_FLAGS_1(cntlsw32, TCG_CALL_CONST | TCG_CALL_PURE, i32, i32)
@@ -120,32 +120,32 @@ DEF_HELPER_3(vminuw, void, avr, avr, avr)
DEF_HELPER_3(vmaxub, void, avr, avr, avr)
DEF_HELPER_3(vmaxuh, void, avr, avr, avr)
DEF_HELPER_3(vmaxuw, void, avr, avr, avr)
-DEF_HELPER_3(vcmpequb, void, avr, avr, avr)
-DEF_HELPER_3(vcmpequh, void, avr, avr, avr)
-DEF_HELPER_3(vcmpequw, void, avr, avr, avr)
-DEF_HELPER_3(vcmpgtub, void, avr, avr, avr)
-DEF_HELPER_3(vcmpgtuh, void, avr, avr, avr)
-DEF_HELPER_3(vcmpgtuw, void, avr, avr, avr)
-DEF_HELPER_3(vcmpgtsb, void, avr, avr, avr)
-DEF_HELPER_3(vcmpgtsh, void, avr, avr, avr)
-DEF_HELPER_3(vcmpgtsw, void, avr, avr, avr)
-DEF_HELPER_3(vcmpeqfp, void, avr, avr, avr)
-DEF_HELPER_3(vcmpgefp, void, avr, avr, avr)
-DEF_HELPER_3(vcmpgtfp, void, avr, avr, avr)
-DEF_HELPER_3(vcmpbfp, void, avr, avr, avr)
-DEF_HELPER_3(vcmpequb_dot, void, avr, avr, avr)
-DEF_HELPER_3(vcmpequh_dot, void, avr, avr, avr)
-DEF_HELPER_3(vcmpequw_dot, void, avr, avr, avr)
-DEF_HELPER_3(vcmpgtub_dot, void, avr, avr, avr)
-DEF_HELPER_3(vcmpgtuh_dot, void, avr, avr, avr)
-DEF_HELPER_3(vcmpgtuw_dot, void, avr, avr, avr)
-DEF_HELPER_3(vcmpgtsb_dot, void, avr, avr, avr)
-DEF_HELPER_3(vcmpgtsh_dot, void, avr, avr, avr)
-DEF_HELPER_3(vcmpgtsw_dot, void, avr, avr, avr)
-DEF_HELPER_3(vcmpeqfp_dot, void, avr, avr, avr)
-DEF_HELPER_3(vcmpgefp_dot, void, avr, avr, avr)
-DEF_HELPER_3(vcmpgtfp_dot, void, avr, avr, avr)
-DEF_HELPER_3(vcmpbfp_dot, void, avr, avr, avr)
+DEF_HELPER_4(vcmpequb, void, env, avr, avr, avr)
+DEF_HELPER_4(vcmpequh, void, env, avr, avr, avr)
+DEF_HELPER_4(vcmpequw, void, env, avr, avr, avr)
+DEF_HELPER_4(vcmpgtub, void, env, avr, avr, avr)
+DEF_HELPER_4(vcmpgtuh, void, env, avr, avr, avr)
+DEF_HELPER_4(vcmpgtuw, void, env, avr, avr, avr)
+DEF_HELPER_4(vcmpgtsb, void, env, avr, avr, avr)
+DEF_HELPER_4(vcmpgtsh, void, env, avr, avr, avr)
+DEF_HELPER_4(vcmpgtsw, void, env, avr, avr, avr)
+DEF_HELPER_4(vcmpeqfp, void, env, avr, avr, avr)
+DEF_HELPER_4(vcmpgefp, void, env, avr, avr, avr)
+DEF_HELPER_4(vcmpgtfp, void, env, avr, avr, avr)
+DEF_HELPER_4(vcmpbfp, void, env, avr, avr, avr)
+DEF_HELPER_4(vcmpequb_dot, void, env, avr, avr, avr)
+DEF_HELPER_4(vcmpequh_dot, void, env, avr, avr, avr)
+DEF_HELPER_4(vcmpequw_dot, void, env, avr, avr, avr)
+DEF_HELPER_4(vcmpgtub_dot, void, env, avr, avr, avr)
+DEF_HELPER_4(vcmpgtuh_dot, void, env, avr, avr, avr)
+DEF_HELPER_4(vcmpgtuw_dot, void, env, avr, avr, avr)
+DEF_HELPER_4(vcmpgtsb_dot, void, env, avr, avr, avr)
+DEF_HELPER_4(vcmpgtsh_dot, void, env, avr, avr, avr)
+DEF_HELPER_4(vcmpgtsw_dot, void, env, avr, avr, avr)
+DEF_HELPER_4(vcmpeqfp_dot, void, env, avr, avr, avr)
+DEF_HELPER_4(vcmpgefp_dot, void, env, avr, avr, avr)
+DEF_HELPER_4(vcmpgtfp_dot, void, env, avr, avr, avr)
+DEF_HELPER_4(vcmpbfp_dot, void, env, avr, avr, avr)
DEF_HELPER_3(vmrglb, void, avr, avr, avr)
DEF_HELPER_3(vmrglh, void, avr, avr, avr)
DEF_HELPER_3(vmrglw, void, avr, avr, avr)
@@ -175,18 +175,18 @@ DEF_HELPER_3(vaddcuw, void, avr, avr, avr)
DEF_HELPER_3(vsubcuw, void, avr, avr, avr)
DEF_HELPER_2(lvsl, void, avr, tl);
DEF_HELPER_2(lvsr, void, avr, tl);
-DEF_HELPER_3(vaddsbs, void, avr, avr, avr)
-DEF_HELPER_3(vaddshs, void, avr, avr, avr)
-DEF_HELPER_3(vaddsws, void, avr, avr, avr)
-DEF_HELPER_3(vsubsbs, void, avr, avr, avr)
-DEF_HELPER_3(vsubshs, void, avr, avr, avr)
-DEF_HELPER_3(vsubsws, void, avr, avr, avr)
-DEF_HELPER_3(vaddubs, void, avr, avr, avr)
-DEF_HELPER_3(vadduhs, void, avr, avr, avr)
-DEF_HELPER_3(vadduws, void, avr, avr, avr)
-DEF_HELPER_3(vsububs, void, avr, avr, avr)
-DEF_HELPER_3(vsubuhs, void, avr, avr, avr)
-DEF_HELPER_3(vsubuws, void, avr, avr, avr)
+DEF_HELPER_4(vaddsbs, void, env, avr, avr, avr)
+DEF_HELPER_4(vaddshs, void, env, avr, avr, avr)
+DEF_HELPER_4(vaddsws, void, env, avr, avr, avr)
+DEF_HELPER_4(vsubsbs, void, env, avr, avr, avr)
+DEF_HELPER_4(vsubshs, void, env, avr, avr, avr)
+DEF_HELPER_4(vsubsws, void, env, avr, avr, avr)
+DEF_HELPER_4(vaddubs, void, env, avr, avr, avr)
+DEF_HELPER_4(vadduhs, void, env, avr, avr, avr)
+DEF_HELPER_4(vadduws, void, env, avr, avr, avr)
+DEF_HELPER_4(vsububs, void, env, avr, avr, avr)
+DEF_HELPER_4(vsubuhs, void, env, avr, avr, avr)
+DEF_HELPER_4(vsubuws, void, env, avr, avr, avr)
DEF_HELPER_3(vrlb, void, avr, avr, avr)
DEF_HELPER_3(vrlh, void, avr, avr, avr)
DEF_HELPER_3(vrlw, void, avr, avr, avr)
@@ -205,56 +205,56 @@ DEF_HELPER_2(vupkhsb, void, avr, avr)
DEF_HELPER_2(vupkhsh, void, avr, avr)
DEF_HELPER_2(vupklsb, void, avr, avr)
DEF_HELPER_2(vupklsh, void, avr, avr)
-DEF_HELPER_4(vmsumubm, void, avr, avr, avr, avr)
-DEF_HELPER_4(vmsummbm, void, avr, avr, avr, avr)
-DEF_HELPER_4(vsel, void, avr, avr, avr, avr)
-DEF_HELPER_4(vperm, void, avr, avr, avr, avr)
-DEF_HELPER_3(vpkshss, void, avr, avr, avr)
-DEF_HELPER_3(vpkshus, void, avr, avr, avr)
-DEF_HELPER_3(vpkswss, void, avr, avr, avr)
-DEF_HELPER_3(vpkswus, void, avr, avr, avr)
-DEF_HELPER_3(vpkuhus, void, avr, avr, avr)
-DEF_HELPER_3(vpkuwus, void, avr, avr, avr)
-DEF_HELPER_3(vpkuhum, void, avr, avr, avr)
-DEF_HELPER_3(vpkuwum, void, avr, avr, avr)
+DEF_HELPER_5(vmsumubm, void, env, avr, avr, avr, avr)
+DEF_HELPER_5(vmsummbm, void, env, avr, avr, avr, avr)
+DEF_HELPER_5(vsel, void, env, avr, avr, avr, avr)
+DEF_HELPER_5(vperm, void, env, avr, avr, avr, avr)
+DEF_HELPER_4(vpkshss, void, env, avr, avr, avr)
+DEF_HELPER_4(vpkshus, void, env, avr, avr, avr)
+DEF_HELPER_4(vpkswss, void, env, avr, avr, avr)
+DEF_HELPER_4(vpkswus, void, env, avr, avr, avr)
+DEF_HELPER_4(vpkuhus, void, env, avr, avr, avr)
+DEF_HELPER_4(vpkuwus, void, env, avr, avr, avr)
+DEF_HELPER_4(vpkuhum, void, env, avr, avr, avr)
+DEF_HELPER_4(vpkuwum, void, env, avr, avr, avr)
DEF_HELPER_3(vpkpx, void, avr, avr, avr)
-DEF_HELPER_4(vmhaddshs, void, avr, avr, avr, avr)
-DEF_HELPER_4(vmhraddshs, void, avr, avr, avr, avr)
-DEF_HELPER_4(vmsumuhm, void, avr, avr, avr, avr)
-DEF_HELPER_4(vmsumuhs, void, avr, avr, avr, avr)
-DEF_HELPER_4(vmsumshm, void, avr, avr, avr, avr)
-DEF_HELPER_4(vmsumshs, void, avr, avr, avr, avr)
+DEF_HELPER_5(vmhaddshs, void, env, avr, avr, avr, avr)
+DEF_HELPER_5(vmhraddshs, void, env, avr, avr, avr, avr)
+DEF_HELPER_5(vmsumuhm, void, env, avr, avr, avr, avr)
+DEF_HELPER_5(vmsumuhs, void, env, avr, avr, avr, avr)
+DEF_HELPER_5(vmsumshm, void, env, avr, avr, avr, avr)
+DEF_HELPER_5(vmsumshs, void, env, avr, avr, avr, avr)
DEF_HELPER_4(vmladduhm, void, avr, avr, avr, avr)
-DEF_HELPER_1(mtvscr, void, avr);
+DEF_HELPER_2(mtvscr, void, env, avr);
DEF_HELPER_2(lvebx, void, avr, tl)
DEF_HELPER_2(lvehx, void, avr, tl)
DEF_HELPER_2(lvewx, void, avr, tl)
DEF_HELPER_2(stvebx, void, avr, tl)
DEF_HELPER_2(stvehx, void, avr, tl)
DEF_HELPER_2(stvewx, void, avr, tl)
-DEF_HELPER_3(vsumsws, void, avr, avr, avr)
-DEF_HELPER_3(vsum2sws, void, avr, avr, avr)
-DEF_HELPER_3(vsum4sbs, void, avr, avr, avr)
-DEF_HELPER_3(vsum4shs, void, avr, avr, avr)
-DEF_HELPER_3(vsum4ubs, void, avr, avr, avr)
-DEF_HELPER_3(vaddfp, void, avr, avr, avr)
-DEF_HELPER_3(vsubfp, void, avr, avr, avr)
-DEF_HELPER_3(vmaxfp, void, avr, avr, avr)
-DEF_HELPER_3(vminfp, void, avr, avr, avr)
-DEF_HELPER_2(vrefp, void, avr, avr)
-DEF_HELPER_2(vrsqrtefp, void, avr, avr)
-DEF_HELPER_4(vmaddfp, void, avr, avr, avr, avr)
-DEF_HELPER_4(vnmsubfp, void, avr, avr, avr, avr)
-DEF_HELPER_2(vexptefp, void, avr, avr)
-DEF_HELPER_2(vlogefp, void, avr, avr)
-DEF_HELPER_2(vrfim, void, avr, avr)
-DEF_HELPER_2(vrfin, void, avr, avr)
-DEF_HELPER_2(vrfip, void, avr, avr)
-DEF_HELPER_2(vrfiz, void, avr, avr)
-DEF_HELPER_3(vcfux, void, avr, avr, i32)
-DEF_HELPER_3(vcfsx, void, avr, avr, i32)
-DEF_HELPER_3(vctuxs, void, avr, avr, i32)
-DEF_HELPER_3(vctsxs, void, avr, avr, i32)
+DEF_HELPER_4(vsumsws, void, env, avr, avr, avr)
+DEF_HELPER_4(vsum2sws, void, env, avr, avr, avr)
+DEF_HELPER_4(vsum4sbs, void, env, avr, avr, avr)
+DEF_HELPER_4(vsum4shs, void, env, avr, avr, avr)
+DEF_HELPER_4(vsum4ubs, void, env, avr, avr, avr)
+DEF_HELPER_4(vaddfp, void, env, avr, avr, avr)
+DEF_HELPER_4(vsubfp, void, env, avr, avr, avr)
+DEF_HELPER_4(vmaxfp, void, env, avr, avr, avr)
+DEF_HELPER_4(vminfp, void, env, avr, avr, avr)
+DEF_HELPER_3(vrefp, void, env, avr, avr)
+DEF_HELPER_3(vrsqrtefp, void, env, avr, avr)
+DEF_HELPER_5(vmaddfp, void, env, avr, avr, avr, avr)
+DEF_HELPER_5(vnmsubfp, void, env, avr, avr, avr, avr)
+DEF_HELPER_3(vexptefp, void, env, avr, avr)
+DEF_HELPER_3(vlogefp, void, env, avr, avr)
+DEF_HELPER_3(vrfim, void, env, avr, avr)
+DEF_HELPER_3(vrfin, void, env, avr, avr)
+DEF_HELPER_3(vrfip, void, env, avr, avr)
+DEF_HELPER_3(vrfiz, void, env, avr, avr)
+DEF_HELPER_4(vcfux, void, env, avr, avr, i32)
+DEF_HELPER_4(vcfsx, void, env, avr, avr, i32)
+DEF_HELPER_4(vctuxs, void, env, avr, avr, i32)
+DEF_HELPER_4(vctsxs, void, env, avr, avr, i32)
DEF_HELPER_2(efscfsi, i32, env, i32)
DEF_HELPER_2(efscfui, i32, env, i32)
@@ -362,15 +362,15 @@ DEF_HELPER_1(msgsnd, void, tl)
DEF_HELPER_2(msgclr, void, env, tl)
#endif
-DEF_HELPER_3(dlmzb, tl, tl, tl, i32)
+DEF_HELPER_4(dlmzb, tl, env, tl, tl, i32)
DEF_HELPER_FLAGS_1(clcs, TCG_CALL_CONST | TCG_CALL_PURE, tl, i32)
#if !defined(CONFIG_USER_ONLY)
DEF_HELPER_1(rac, tl, tl)
#endif
-DEF_HELPER_2(div, tl, tl, tl)
-DEF_HELPER_2(divo, tl, tl, tl)
-DEF_HELPER_2(divs, tl, tl, tl)
-DEF_HELPER_2(divso, tl, tl, tl)
+DEF_HELPER_3(div, tl, env, tl, tl)
+DEF_HELPER_3(divo, tl, env, tl, tl)
+DEF_HELPER_3(divs, tl, env, tl, tl)
+DEF_HELPER_3(divso, tl, env, tl, tl)
DEF_HELPER_1(load_dcr, tl, tl);
DEF_HELPER_2(store_dcr, void, tl, tl)
diff --git a/target-ppc/int_helper.c b/target-ppc/int_helper.c
index 71c7304..3173f11 100644
--- a/target-ppc/int_helper.c
+++ b/target-ppc/int_helper.c
@@ -17,7 +17,6 @@
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include "cpu.h"
-#include "dyngen-exec.h"
#include "host-utils.h"
#include "helper.h"
@@ -44,7 +43,7 @@ uint64_t helper_mulhdu(uint64_t arg1, uint64_t arg2)
return th;
}
-uint64_t helper_mulldo(uint64_t arg1, uint64_t arg2)
+uint64_t helper_mulldo(CPUPPCState *env, uint64_t arg1, uint64_t arg2)
{
int64_t th;
uint64_t tl;
@@ -73,7 +72,8 @@ target_ulong helper_cntlzd(target_ulong t)
#endif
/* shift right arithmetic helper */
-target_ulong helper_sraw(target_ulong value, target_ulong shift)
+target_ulong helper_sraw(CPUPPCState *env, target_ulong value,
+ target_ulong shift)
{
int32_t ret;
@@ -102,7 +102,8 @@ target_ulong helper_sraw(target_ulong value, target_ulong shift)
}
#if defined(TARGET_PPC64)
-target_ulong helper_srad(target_ulong value, target_ulong shift)
+target_ulong helper_srad(CPUPPCState *env, target_ulong value,
+ target_ulong shift)
{
int64_t ret;
@@ -184,7 +185,7 @@ target_ulong helper_popcntw(target_ulong val)
/*****************************************************************************/
/* PowerPC 601 specific instructions (POWER bridge) */
-target_ulong helper_div(target_ulong arg1, target_ulong arg2)
+target_ulong helper_div(CPUPPCState *env, target_ulong arg1, target_ulong arg2)
{
uint64_t tmp = (uint64_t)arg1 << 32 | env->spr[SPR_MQ];
@@ -198,7 +199,8 @@ target_ulong helper_div(target_ulong arg1, target_ulong arg2)
}
}
-target_ulong helper_divo(target_ulong arg1, target_ulong arg2)
+target_ulong helper_divo(CPUPPCState *env, target_ulong arg1,
+ target_ulong arg2)
{
uint64_t tmp = (uint64_t)arg1 << 32 | env->spr[SPR_MQ];
@@ -219,7 +221,8 @@ target_ulong helper_divo(target_ulong arg1, target_ulong arg2)
}
}
-target_ulong helper_divs(target_ulong arg1, target_ulong arg2)
+target_ulong helper_divs(CPUPPCState *env, target_ulong arg1,
+ target_ulong arg2)
{
if (((int32_t)arg1 == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
(int32_t)arg2 == 0) {
@@ -231,7 +234,8 @@ target_ulong helper_divs(target_ulong arg1, target_ulong arg2)
}
}
-target_ulong helper_divso(target_ulong arg1, target_ulong arg2)
+target_ulong helper_divso(CPUPPCState *env, target_ulong arg1,
+ target_ulong arg2)
{
if (((int32_t)arg1 == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
(int32_t)arg2 == 0) {
@@ -361,7 +365,7 @@ void helper_lvsr(ppc_avr_t *r, target_ulong sh)
}
}
-void helper_mtvscr(ppc_avr_t *r)
+void helper_mtvscr(CPUPPCState *env, ppc_avr_t *r)
{
#if defined(HOST_WORDS_BIGENDIAN)
env->vscr = r->u32[3];
@@ -399,7 +403,8 @@ VARITH(uwm, u32)
#undef VARITH
#define VARITHFP(suffix, func) \
- void helper_v##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
+ void helper_v##suffix(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, \
+ ppc_avr_t *b) \
{ \
int i; \
\
@@ -420,7 +425,8 @@ VARITHFP(subfp, float32_sub)
}
#define VARITHSAT_DO(name, op, optype, cvt, element) \
- void helper_v##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
+ void helper_v##name(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, \
+ ppc_avr_t *b) \
{ \
int sat = 0; \
int i; \
@@ -481,7 +487,8 @@ VAVG(w, s32, int64_t, u32, uint64_t)
#undef VAVG
#define VCF(suffix, cvt, element) \
- void helper_vcf##suffix(ppc_avr_t *r, ppc_avr_t *b, uint32_t uim) \
+ void helper_vcf##suffix(CPUPPCState *env, ppc_avr_t *r, \
+ ppc_avr_t *b, uint32_t uim) \
{ \
int i; \
\
@@ -495,7 +502,8 @@ VCF(sx, int32_to_float32, s32)
#undef VCF
#define VCMP_DO(suffix, compare, element, record) \
- void helper_vcmp##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
+ void helper_vcmp##suffix(CPUPPCState *env, ppc_avr_t *r, \
+ ppc_avr_t *a, ppc_avr_t *b) \
{ \
uint32_t ones = (uint32_t)-1; \
uint32_t all = ones; \
@@ -539,7 +547,8 @@ VCMP(gtsw, >, s32)
#undef VCMP
#define VCMPFP_DO(suffix, compare, order, record) \
- void helper_vcmp##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
+ void helper_vcmp##suffix(CPUPPCState *env, ppc_avr_t *r, \
+ ppc_avr_t *a, ppc_avr_t *b) \
{ \
uint32_t ones = (uint32_t)-1; \
uint32_t all = ones; \
@@ -574,8 +583,8 @@ VCMPFP(gtfp, ==, float_relation_greater)
#undef VCMPFP_DO
#undef VCMPFP
-static inline void vcmpbfp_internal(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b,
- int record)
+static inline void vcmpbfp_internal(CPUPPCState *env, ppc_avr_t *r,
+ ppc_avr_t *a, ppc_avr_t *b, int record)
{
int i;
int all_in = 0;
@@ -600,18 +609,20 @@ static inline void vcmpbfp_internal(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b,
}
}
-void helper_vcmpbfp(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
+void helper_vcmpbfp(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
{
- vcmpbfp_internal(r, a, b, 0);
+ vcmpbfp_internal(env, r, a, b, 0);
}
-void helper_vcmpbfp_dot(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
+void helper_vcmpbfp_dot(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
+ ppc_avr_t *b)
{
- vcmpbfp_internal(r, a, b, 1);
+ vcmpbfp_internal(env, r, a, b, 1);
}
#define VCT(suffix, satcvt, element) \
- void helper_vct##suffix(ppc_avr_t *r, ppc_avr_t *b, uint32_t uim) \
+ void helper_vct##suffix(CPUPPCState *env, ppc_avr_t *r, \
+ ppc_avr_t *b, uint32_t uim) \
{ \
int i; \
int sat = 0; \
@@ -638,7 +649,8 @@ VCT(uxs, cvtsduw, u32)
VCT(sxs, cvtsdsw, s32)
#undef VCT
-void helper_vmaddfp(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
+void helper_vmaddfp(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b,
+ ppc_avr_t *c)
{
int i;
@@ -658,7 +670,8 @@ void helper_vmaddfp(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
}
}
-void helper_vmhaddshs(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
+void helper_vmhaddshs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
+ ppc_avr_t *b, ppc_avr_t *c)
{
int sat = 0;
int i;
@@ -675,7 +688,8 @@ void helper_vmhaddshs(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
}
}
-void helper_vmhraddshs(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
+void helper_vmhraddshs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
+ ppc_avr_t *b, ppc_avr_t *c)
{
int sat = 0;
int i;
@@ -717,7 +731,8 @@ VMINMAX(uw, u32)
#undef VMINMAX
#define VMINMAXFP(suffix, rT, rF) \
- void helper_v##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
+ void helper_v##suffix(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, \
+ ppc_avr_t *b) \
{ \
int i; \
\
@@ -784,7 +799,8 @@ VMRG(w, u32)
#undef MRGHI
#undef MRGLO
-void helper_vmsummbm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
+void helper_vmsummbm(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
+ ppc_avr_t *b, ppc_avr_t *c)
{
int32_t prod[16];
int i;
@@ -799,7 +815,8 @@ void helper_vmsummbm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
}
}
-void helper_vmsumshm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
+void helper_vmsumshm(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
+ ppc_avr_t *b, ppc_avr_t *c)
{
int32_t prod[8];
int i;
@@ -813,7 +830,8 @@ void helper_vmsumshm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
}
}
-void helper_vmsumshs(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
+void helper_vmsumshs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
+ ppc_avr_t *b, ppc_avr_t *c)
{
int32_t prod[8];
int i;
@@ -834,7 +852,8 @@ void helper_vmsumshs(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
}
}
-void helper_vmsumubm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
+void helper_vmsumubm(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
+ ppc_avr_t *b, ppc_avr_t *c)
{
uint16_t prod[16];
int i;
@@ -849,7 +868,8 @@ void helper_vmsumubm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
}
}
-void helper_vmsumuhm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
+void helper_vmsumuhm(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
+ ppc_avr_t *b, ppc_avr_t *c)
{
uint32_t prod[8];
int i;
@@ -863,7 +883,8 @@ void helper_vmsumuhm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
}
}
-void helper_vmsumuhs(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
+void helper_vmsumuhs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
+ ppc_avr_t *b, ppc_avr_t *c)
{
uint32_t prod[8];
int i;
@@ -909,7 +930,8 @@ VMUL(uh, u16, u32)
#undef VMUL_DO
#undef VMUL
-void helper_vnmsubfp(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
+void helper_vnmsubfp(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
+ ppc_avr_t *b, ppc_avr_t *c)
{
int i;
@@ -930,7 +952,8 @@ void helper_vnmsubfp(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
}
}
-void helper_vperm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
+void helper_vperm(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b,
+ ppc_avr_t *c)
{
ppc_avr_t result;
int i;
@@ -980,7 +1003,8 @@ void helper_vpkpx(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
}
#define VPK(suffix, from, to, cvt, dosat) \
- void helper_vpk##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
+ void helper_vpk##suffix(CPUPPCState *env, ppc_avr_t *r, \
+ ppc_avr_t *a, ppc_avr_t *b) \
{ \
int i; \
int sat = 0; \
@@ -1010,7 +1034,7 @@ VPK(uwum, u32, u16, I, 0)
#undef VPK
#undef PKBIG
-void helper_vrefp(ppc_avr_t *r, ppc_avr_t *b)
+void helper_vrefp(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *b)
{
int i;
@@ -1022,7 +1046,8 @@ void helper_vrefp(ppc_avr_t *r, ppc_avr_t *b)
}
#define VRFI(suffix, rounding) \
- void helper_vrfi##suffix(ppc_avr_t *r, ppc_avr_t *b) \
+ void helper_vrfi##suffix(CPUPPCState *env, ppc_avr_t *r, \
+ ppc_avr_t *b) \
{ \
int i; \
float_status s = env->vec_status; \
@@ -1059,7 +1084,7 @@ VROTATE(h, u16)
VROTATE(w, u32)
#undef VROTATE
-void helper_vrsqrtefp(ppc_avr_t *r, ppc_avr_t *b)
+void helper_vrsqrtefp(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *b)
{
int i;
@@ -1072,13 +1097,14 @@ void helper_vrsqrtefp(ppc_avr_t *r, ppc_avr_t *b)
}
}
-void helper_vsel(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
+void helper_vsel(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b,
+ ppc_avr_t *c)
{
r->u64[0] = (a->u64[0] & ~c->u64[0]) | (b->u64[0] & c->u64[0]);
r->u64[1] = (a->u64[1] & ~c->u64[1]) | (b->u64[1] & c->u64[1]);
}
-void helper_vexptefp(ppc_avr_t *r, ppc_avr_t *b)
+void helper_vexptefp(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *b)
{
int i;
@@ -1089,7 +1115,7 @@ void helper_vexptefp(ppc_avr_t *r, ppc_avr_t *b)
}
}
-void helper_vlogefp(ppc_avr_t *r, ppc_avr_t *b)
+void helper_vlogefp(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *b)
{
int i;
@@ -1286,7 +1312,7 @@ void helper_vsubcuw(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
}
}
-void helper_vsumsws(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
+void helper_vsumsws(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
{
int64_t t;
int i, upper;
@@ -1311,7 +1337,7 @@ void helper_vsumsws(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
}
}
-void helper_vsum2sws(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
+void helper_vsum2sws(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
{
int i, j, upper;
ppc_avr_t result;
@@ -1338,7 +1364,7 @@ void helper_vsum2sws(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
}
}
-void helper_vsum4sbs(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
+void helper_vsum4sbs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
{
int i, j;
int sat = 0;
@@ -1357,7 +1383,7 @@ void helper_vsum4sbs(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
}
}
-void helper_vsum4shs(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
+void helper_vsum4shs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
{
int sat = 0;
int i;
@@ -1374,7 +1400,7 @@ void helper_vsum4shs(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
}
}
-void helper_vsum4ubs(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
+void helper_vsum4ubs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
{
int i, j;
int sat = 0;
@@ -1501,8 +1527,8 @@ uint32_t helper_cntlzw32(uint32_t val)
}
/* 440 specific */
-target_ulong helper_dlmzb(target_ulong high, target_ulong low,
- uint32_t update_Rc)
+target_ulong helper_dlmzb(CPUPPCState *env, target_ulong high,
+ target_ulong low, uint32_t update_Rc)
{
target_ulong mask;
int i;
diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index c8b7982..eb3cd5a 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -1181,8 +1181,16 @@ static void gen_mulld(DisasContext *ctx)
if (unlikely(Rc(ctx->opcode) != 0))
gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
}
+
/* mulldo mulldo. */
-GEN_INT_ARITH_MUL_HELPER(mulldo, 0x17);
+static void gen_mulldo(DisasContext *ctx)
+{
+ gen_helper_mulldo(cpu_gpr[rD(ctx->opcode)], cpu_env,
+ cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
+ if (unlikely(Rc(ctx->opcode) != 0)) {
+ gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
+ }
+}
#endif
/* neg neg. nego nego. */
@@ -1869,7 +1877,7 @@ static void gen_slw(DisasContext *ctx)
/* sraw & sraw. */
static void gen_sraw(DisasContext *ctx)
{
- gen_helper_sraw(cpu_gpr[rA(ctx->opcode)],
+ gen_helper_sraw(cpu_gpr[rA(ctx->opcode)], cpu_env,
cpu_gpr[rS(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
if (unlikely(Rc(ctx->opcode) != 0))
gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
@@ -1953,7 +1961,7 @@ static void gen_sld(DisasContext *ctx)
/* srad & srad. */
static void gen_srad(DisasContext *ctx)
{
- gen_helper_srad(cpu_gpr[rA(ctx->opcode)],
+ gen_helper_srad(cpu_gpr[rA(ctx->opcode)], cpu_env,
cpu_gpr[rS(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
if (unlikely(Rc(ctx->opcode) != 0))
gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
@@ -4550,7 +4558,8 @@ static void gen_clcs(DisasContext *ctx)
/* div - div. */
static void gen_div(DisasContext *ctx)
{
- gen_helper_div(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
+ gen_helper_div(cpu_gpr[rD(ctx->opcode)], cpu_env, cpu_gpr[rA(ctx->opcode)],
+ cpu_gpr[rB(ctx->opcode)]);
if (unlikely(Rc(ctx->opcode) != 0))
gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
}
@@ -4558,7 +4567,8 @@ static void gen_div(DisasContext *ctx)
/* divo - divo. */
static void gen_divo(DisasContext *ctx)
{
- gen_helper_divo(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
+ gen_helper_divo(cpu_gpr[rD(ctx->opcode)], cpu_env, cpu_gpr[rA(ctx->opcode)],
+ cpu_gpr[rB(ctx->opcode)]);
if (unlikely(Rc(ctx->opcode) != 0))
gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
}
@@ -4566,7 +4576,8 @@ static void gen_divo(DisasContext *ctx)
/* divs - divs. */
static void gen_divs(DisasContext *ctx)
{
- gen_helper_divs(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
+ gen_helper_divs(cpu_gpr[rD(ctx->opcode)], cpu_env, cpu_gpr[rA(ctx->opcode)],
+ cpu_gpr[rB(ctx->opcode)]);
if (unlikely(Rc(ctx->opcode) != 0))
gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
}
@@ -4574,7 +4585,8 @@ static void gen_divs(DisasContext *ctx)
/* divso - divso. */
static void gen_divso(DisasContext *ctx)
{
- gen_helper_divso(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
+ gen_helper_divso(cpu_gpr[rD(ctx->opcode)], cpu_env,
+ cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
if (unlikely(Rc(ctx->opcode) != 0))
gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
}
@@ -6237,8 +6249,8 @@ static void gen_wrteei(DisasContext *ctx)
static void gen_dlmzb(DisasContext *ctx)
{
TCGv_i32 t0 = tcg_const_i32(Rc(ctx->opcode));
- gen_helper_dlmzb(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)],
- cpu_gpr[rB(ctx->opcode)], t0);
+ gen_helper_dlmzb(cpu_gpr[rA(ctx->opcode)], cpu_env,
+ cpu_gpr[rS(ctx->opcode)], cpu_gpr[rB(ctx->opcode)], t0);
tcg_temp_free_i32(t0);
}
@@ -6457,7 +6469,7 @@ static void gen_mtvscr(DisasContext *ctx)
return;
}
p = gen_avr_ptr(rD(ctx->opcode));
- gen_helper_mtvscr(p);
+ gen_helper_mtvscr(cpu_env, p);
tcg_temp_free_ptr(p);
}
@@ -6496,6 +6508,23 @@ static void glue(gen_, name)(DisasContext *ctx)
tcg_temp_free_ptr(rd); \
}
+#define GEN_VXFORM_ENV(name, opc2, opc3) \
+static void glue(gen_, name)(DisasContext *ctx) \
+{ \
+ TCGv_ptr ra, rb, rd; \
+ if (unlikely(!ctx->altivec_enabled)) { \
+ gen_exception(ctx, POWERPC_EXCP_VPU); \
+ return; \
+ } \
+ ra = gen_avr_ptr(rA(ctx->opcode)); \
+ rb = gen_avr_ptr(rB(ctx->opcode)); \
+ rd = gen_avr_ptr(rD(ctx->opcode)); \
+ gen_helper_##name(rd, cpu_env, ra, rb); \
+ tcg_temp_free_ptr(ra); \
+ tcg_temp_free_ptr(rb); \
+ tcg_temp_free_ptr(rd); \
+}
+
GEN_VXFORM(vaddubm, 0, 0);
GEN_VXFORM(vadduhm, 0, 1);
GEN_VXFORM(vadduwm, 0, 2);
@@ -6547,41 +6576,41 @@ GEN_VXFORM(vslo, 6, 16);
GEN_VXFORM(vsro, 6, 17);
GEN_VXFORM(vaddcuw, 0, 6);
GEN_VXFORM(vsubcuw, 0, 22);
-GEN_VXFORM(vaddubs, 0, 8);
-GEN_VXFORM(vadduhs, 0, 9);
-GEN_VXFORM(vadduws, 0, 10);
-GEN_VXFORM(vaddsbs, 0, 12);
-GEN_VXFORM(vaddshs, 0, 13);
-GEN_VXFORM(vaddsws, 0, 14);
-GEN_VXFORM(vsububs, 0, 24);
-GEN_VXFORM(vsubuhs, 0, 25);
-GEN_VXFORM(vsubuws, 0, 26);
-GEN_VXFORM(vsubsbs, 0, 28);
-GEN_VXFORM(vsubshs, 0, 29);
-GEN_VXFORM(vsubsws, 0, 30);
+GEN_VXFORM_ENV(vaddubs, 0, 8);
+GEN_VXFORM_ENV(vadduhs, 0, 9);
+GEN_VXFORM_ENV(vadduws, 0, 10);
+GEN_VXFORM_ENV(vaddsbs, 0, 12);
+GEN_VXFORM_ENV(vaddshs, 0, 13);
+GEN_VXFORM_ENV(vaddsws, 0, 14);
+GEN_VXFORM_ENV(vsububs, 0, 24);
+GEN_VXFORM_ENV(vsubuhs, 0, 25);
+GEN_VXFORM_ENV(vsubuws, 0, 26);
+GEN_VXFORM_ENV(vsubsbs, 0, 28);
+GEN_VXFORM_ENV(vsubshs, 0, 29);
+GEN_VXFORM_ENV(vsubsws, 0, 30);
GEN_VXFORM(vrlb, 2, 0);
GEN_VXFORM(vrlh, 2, 1);
GEN_VXFORM(vrlw, 2, 2);
GEN_VXFORM(vsl, 2, 7);
GEN_VXFORM(vsr, 2, 11);
-GEN_VXFORM(vpkuhum, 7, 0);
-GEN_VXFORM(vpkuwum, 7, 1);
-GEN_VXFORM(vpkuhus, 7, 2);
-GEN_VXFORM(vpkuwus, 7, 3);
-GEN_VXFORM(vpkshus, 7, 4);
-GEN_VXFORM(vpkswus, 7, 5);
-GEN_VXFORM(vpkshss, 7, 6);
-GEN_VXFORM(vpkswss, 7, 7);
+GEN_VXFORM_ENV(vpkuhum, 7, 0);
+GEN_VXFORM_ENV(vpkuwum, 7, 1);
+GEN_VXFORM_ENV(vpkuhus, 7, 2);
+GEN_VXFORM_ENV(vpkuwus, 7, 3);
+GEN_VXFORM_ENV(vpkshus, 7, 4);
+GEN_VXFORM_ENV(vpkswus, 7, 5);
+GEN_VXFORM_ENV(vpkshss, 7, 6);
+GEN_VXFORM_ENV(vpkswss, 7, 7);
GEN_VXFORM(vpkpx, 7, 12);
-GEN_VXFORM(vsum4ubs, 4, 24);
-GEN_VXFORM(vsum4sbs, 4, 28);
-GEN_VXFORM(vsum4shs, 4, 25);
-GEN_VXFORM(vsum2sws, 4, 26);
-GEN_VXFORM(vsumsws, 4, 30);
-GEN_VXFORM(vaddfp, 5, 0);
-GEN_VXFORM(vsubfp, 5, 1);
-GEN_VXFORM(vmaxfp, 5, 16);
-GEN_VXFORM(vminfp, 5, 17);
+GEN_VXFORM_ENV(vsum4ubs, 4, 24);
+GEN_VXFORM_ENV(vsum4sbs, 4, 28);
+GEN_VXFORM_ENV(vsum4shs, 4, 25);
+GEN_VXFORM_ENV(vsum2sws, 4, 26);
+GEN_VXFORM_ENV(vsumsws, 4, 30);
+GEN_VXFORM_ENV(vaddfp, 5, 0);
+GEN_VXFORM_ENV(vsubfp, 5, 1);
+GEN_VXFORM_ENV(vmaxfp, 5, 16);
+GEN_VXFORM_ENV(vminfp, 5, 17);
#define GEN_VXRFORM1(opname, name, str, opc2, opc3) \
static void glue(gen_, name)(DisasContext *ctx) \
@@ -6594,7 +6623,7 @@ static void glue(gen_, name)(DisasContext *ctx) \
ra = gen_avr_ptr(rA(ctx->opcode)); \
rb = gen_avr_ptr(rB(ctx->opcode)); \
rd = gen_avr_ptr(rD(ctx->opcode)); \
- gen_helper_##opname (rd, ra, rb); \
+ gen_helper_##opname(cpu_env, rd, ra, rb); \
tcg_temp_free_ptr(ra); \
tcg_temp_free_ptr(rb); \
tcg_temp_free_ptr(rd); \
@@ -6653,20 +6682,36 @@ static void glue(gen_, name)(DisasContext *ctx)
tcg_temp_free_ptr(rd); \
}
+#define GEN_VXFORM_NOA_ENV(name, opc2, opc3) \
+static void glue(gen_, name)(DisasContext *ctx) \
+ { \
+ TCGv_ptr rb, rd; \
+ \
+ if (unlikely(!ctx->altivec_enabled)) { \
+ gen_exception(ctx, POWERPC_EXCP_VPU); \
+ return; \
+ } \
+ rb = gen_avr_ptr(rB(ctx->opcode)); \
+ rd = gen_avr_ptr(rD(ctx->opcode)); \
+ gen_helper_##name(cpu_env, rd, rb); \
+ tcg_temp_free_ptr(rb); \
+ tcg_temp_free_ptr(rd); \
+ }
+
GEN_VXFORM_NOA(vupkhsb, 7, 8);
GEN_VXFORM_NOA(vupkhsh, 7, 9);
GEN_VXFORM_NOA(vupklsb, 7, 10);
GEN_VXFORM_NOA(vupklsh, 7, 11);
GEN_VXFORM_NOA(vupkhpx, 7, 13);
GEN_VXFORM_NOA(vupklpx, 7, 15);
-GEN_VXFORM_NOA(vrefp, 5, 4);
-GEN_VXFORM_NOA(vrsqrtefp, 5, 5);
-GEN_VXFORM_NOA(vexptefp, 5, 6);
-GEN_VXFORM_NOA(vlogefp, 5, 7);
-GEN_VXFORM_NOA(vrfim, 5, 8);
-GEN_VXFORM_NOA(vrfin, 5, 9);
-GEN_VXFORM_NOA(vrfip, 5, 10);
-GEN_VXFORM_NOA(vrfiz, 5, 11);
+GEN_VXFORM_NOA_ENV(vrefp, 5, 4);
+GEN_VXFORM_NOA_ENV(vrsqrtefp, 5, 5);
+GEN_VXFORM_NOA_ENV(vexptefp, 5, 6);
+GEN_VXFORM_NOA_ENV(vlogefp, 5, 7);
+GEN_VXFORM_NOA_ENV(vrfim, 5, 8);
+GEN_VXFORM_NOA_ENV(vrfin, 5, 9);
+GEN_VXFORM_NOA_ENV(vrfip, 5, 10);
+GEN_VXFORM_NOA_ENV(vrfiz, 5, 11);
#define GEN_VXFORM_SIMM(name, opc2, opc3) \
static void glue(gen_, name)(DisasContext *ctx) \
@@ -6702,13 +6747,32 @@ static void glue(gen_, name)(DisasContext *ctx)
tcg_temp_free_ptr(rd); \
}
+#define GEN_VXFORM_UIMM_ENV(name, opc2, opc3) \
+static void glue(gen_, name)(DisasContext *ctx) \
+ { \
+ TCGv_ptr rb, rd; \
+ TCGv_i32 uimm; \
+ \
+ if (unlikely(!ctx->altivec_enabled)) { \
+ gen_exception(ctx, POWERPC_EXCP_VPU); \
+ return; \
+ } \
+ uimm = tcg_const_i32(UIMM5(ctx->opcode)); \
+ rb = gen_avr_ptr(rB(ctx->opcode)); \
+ rd = gen_avr_ptr(rD(ctx->opcode)); \
+ gen_helper_##name(cpu_env, rd, rb, uimm); \
+ tcg_temp_free_i32(uimm); \
+ tcg_temp_free_ptr(rb); \
+ tcg_temp_free_ptr(rd); \
+ }
+
GEN_VXFORM_UIMM(vspltb, 6, 8);
GEN_VXFORM_UIMM(vsplth, 6, 9);
GEN_VXFORM_UIMM(vspltw, 6, 10);
-GEN_VXFORM_UIMM(vcfux, 5, 12);
-GEN_VXFORM_UIMM(vcfsx, 5, 13);
-GEN_VXFORM_UIMM(vctuxs, 5, 14);
-GEN_VXFORM_UIMM(vctsxs, 5, 15);
+GEN_VXFORM_UIMM_ENV(vcfux, 5, 12);
+GEN_VXFORM_UIMM_ENV(vcfsx, 5, 13);
+GEN_VXFORM_UIMM_ENV(vctuxs, 5, 14);
+GEN_VXFORM_UIMM_ENV(vctsxs, 5, 15);
static void gen_vsldoi(DisasContext *ctx)
{
@@ -6730,7 +6794,7 @@ static void gen_vsldoi(DisasContext *ctx)
}
#define GEN_VAFORM_PAIRED(name0, name1, opc2) \
-static void glue(gen_, name0##_##name1)(DisasContext *ctx) \
+static void glue(gen_, name0##_##name1)(DisasContext *ctx) \
{ \
TCGv_ptr ra, rb, rc, rd; \
if (unlikely(!ctx->altivec_enabled)) { \
@@ -6742,9 +6806,9 @@ static void glue(gen_, name0##_##name1)(DisasContext *ctx)
rc = gen_avr_ptr(rC(ctx->opcode)); \
rd = gen_avr_ptr(rD(ctx->opcode)); \
if (Rc(ctx->opcode)) { \
- gen_helper_##name1 (rd, ra, rb, rc); \
+ gen_helper_##name1(cpu_env, rd, ra, rb, rc); \
} else { \
- gen_helper_##name0 (rd, ra, rb, rc); \
+ gen_helper_##name0(cpu_env, rd, ra, rb, rc); \
} \
tcg_temp_free_ptr(ra); \
tcg_temp_free_ptr(rb); \
--
1.6.0.2
^ permalink raw reply related [flat|nested] 89+ messages in thread
* [Qemu-devel] [PATCH 10/72] ppc: Split MMU etc. helpers from op_helper.c
2012-06-23 23:06 [Qemu-devel] [PULL 00/72] ppc patch queue 2012-06-24 Alexander Graf
` (8 preceding siblings ...)
2012-06-23 23:06 ` [Qemu-devel] [PATCH 09/72] ppc: Avoid AREG0 for integer and vector helpers Alexander Graf
@ 2012-06-23 23:06 ` Alexander Graf
2012-06-23 23:06 ` [Qemu-devel] [PATCH 11/72] ppc: Avoid AREG0 for MMU etc. helpers Alexander Graf
` (62 subsequent siblings)
72 siblings, 0 replies; 89+ messages in thread
From: Alexander Graf @ 2012-06-23 23:06 UTC (permalink / raw)
To: qemu-devel qemu-devel
Cc: Blue Swirl, qemu-ppc Mailing List, Andreas Färber,
Aurelien Jarno
From: Blue Swirl <blauwirbel@gmail.com>
Move MMU, TLB, SLB and BAT ops to mmu_helper.c.
Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Andreas Färber <afaerber@suse.de>
Signed-off-by: Alexander Graf <agraf@suse.de>
---
target-ppc/Makefile.objs | 2 +
target-ppc/mmu_helper.c | 882 ++++++++++++++++++++++++++++++++++++++++++++++
target-ppc/op_helper.c | 854 --------------------------------------------
3 files changed, 884 insertions(+), 854 deletions(-)
create mode 100644 target-ppc/mmu_helper.c
diff --git a/target-ppc/Makefile.objs b/target-ppc/Makefile.objs
index 5d63400..0f89c2c 100644
--- a/target-ppc/Makefile.objs
+++ b/target-ppc/Makefile.objs
@@ -5,5 +5,7 @@ obj-y += op_helper.o helper.o
obj-y += excp_helper.o
obj-y += fpu_helper.o
obj-y += int_helper.o
+obj-y += mmu_helper.o
+$(obj)/mmu_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
$(obj)/op_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
diff --git a/target-ppc/mmu_helper.c b/target-ppc/mmu_helper.c
new file mode 100644
index 0000000..81800b6
--- /dev/null
+++ b/target-ppc/mmu_helper.c
@@ -0,0 +1,882 @@
+/*
+ * PowerPC MMU, TLB, SLB and BAT emulation helpers for QEMU.
+ *
+ * Copyright (c) 2003-2007 Jocelyn Mayer
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "cpu.h"
+#include "dyngen-exec.h"
+#include "helper.h"
+
+//#define DEBUG_SOFTWARE_TLB
+
+#ifdef DEBUG_SOFTWARE_TLB
+# define LOG_SWTLB(...) qemu_log(__VA_ARGS__)
+#else
+# define LOG_SWTLB(...) do { } while (0)
+#endif
+
+/*****************************************************************************/
+/* SPR accesses */
+
+#if !defined(CONFIG_USER_ONLY)
+void helper_store_ibatu(uint32_t nr, target_ulong val)
+{
+ ppc_store_ibatu(env, nr, val);
+}
+
+void helper_store_ibatl(uint32_t nr, target_ulong val)
+{
+ ppc_store_ibatl(env, nr, val);
+}
+
+void helper_store_dbatu(uint32_t nr, target_ulong val)
+{
+ ppc_store_dbatu(env, nr, val);
+}
+
+void helper_store_dbatl(uint32_t nr, target_ulong val)
+{
+ ppc_store_dbatl(env, nr, val);
+}
+
+void helper_store_601_batl(uint32_t nr, target_ulong val)
+{
+ ppc_store_ibatl_601(env, nr, val);
+}
+
+void helper_store_601_batu(uint32_t nr, target_ulong val)
+{
+ ppc_store_ibatu_601(env, nr, val);
+}
+
+/* Segment registers load and store */
+target_ulong helper_load_sr(target_ulong sr_num)
+{
+#if defined(TARGET_PPC64)
+ if (env->mmu_model & POWERPC_MMU_64) {
+ return ppc_load_sr(env, sr_num);
+ }
+#endif
+ return env->sr[sr_num];
+}
+
+void helper_store_sr(target_ulong sr_num, target_ulong val)
+{
+ ppc_store_sr(env, sr_num, val);
+}
+
+/* SLB management */
+#if defined(TARGET_PPC64)
+void helper_store_slb(target_ulong rb, target_ulong rs)
+{
+ if (ppc_store_slb(env, rb, rs) < 0) {
+ helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
+ POWERPC_EXCP_INVAL);
+ }
+}
+
+target_ulong helper_load_slb_esid(target_ulong rb)
+{
+ target_ulong rt;
+
+ if (ppc_load_slb_esid(env, rb, &rt) < 0) {
+ helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
+ POWERPC_EXCP_INVAL);
+ }
+ return rt;
+}
+
+target_ulong helper_load_slb_vsid(target_ulong rb)
+{
+ target_ulong rt;
+
+ if (ppc_load_slb_vsid(env, rb, &rt) < 0) {
+ helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
+ POWERPC_EXCP_INVAL);
+ }
+ return rt;
+}
+
+void helper_slbia(void)
+{
+ ppc_slb_invalidate_all(env);
+}
+
+void helper_slbie(target_ulong addr)
+{
+ ppc_slb_invalidate_one(env, addr);
+}
+
+#endif /* defined(TARGET_PPC64) */
+
+/* TLB management */
+void helper_tlbia(void)
+{
+ ppc_tlb_invalidate_all(env);
+}
+
+void helper_tlbie(target_ulong addr)
+{
+ ppc_tlb_invalidate_one(env, addr);
+}
+
+/* Software driven TLBs management */
+/* PowerPC 602/603 software TLB load instructions helpers */
+static void do_6xx_tlb(target_ulong new_EPN, int is_code)
+{
+ target_ulong RPN, CMP, EPN;
+ int way;
+
+ RPN = env->spr[SPR_RPA];
+ if (is_code) {
+ CMP = env->spr[SPR_ICMP];
+ EPN = env->spr[SPR_IMISS];
+ } else {
+ CMP = env->spr[SPR_DCMP];
+ EPN = env->spr[SPR_DMISS];
+ }
+ way = (env->spr[SPR_SRR1] >> 17) & 1;
+ (void)EPN; /* avoid a compiler warning */
+ LOG_SWTLB("%s: EPN " TARGET_FMT_lx " " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
+ " PTE1 " TARGET_FMT_lx " way %d\n", __func__, new_EPN, EPN, CMP,
+ RPN, way);
+ /* Store this TLB */
+ ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
+ way, is_code, CMP, RPN);
+}
+
+void helper_6xx_tlbd(target_ulong EPN)
+{
+ do_6xx_tlb(EPN, 0);
+}
+
+void helper_6xx_tlbi(target_ulong EPN)
+{
+ do_6xx_tlb(EPN, 1);
+}
+
+/* PowerPC 74xx software TLB load instructions helpers */
+static void do_74xx_tlb(target_ulong new_EPN, int is_code)
+{
+ target_ulong RPN, CMP, EPN;
+ int way;
+
+ RPN = env->spr[SPR_PTELO];
+ CMP = env->spr[SPR_PTEHI];
+ EPN = env->spr[SPR_TLBMISS] & ~0x3;
+ way = env->spr[SPR_TLBMISS] & 0x3;
+ (void)EPN; /* avoid a compiler warning */
+ LOG_SWTLB("%s: EPN " TARGET_FMT_lx " " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
+ " PTE1 " TARGET_FMT_lx " way %d\n", __func__, new_EPN, EPN, CMP,
+ RPN, way);
+ /* Store this TLB */
+ ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
+ way, is_code, CMP, RPN);
+}
+
+void helper_74xx_tlbd(target_ulong EPN)
+{
+ do_74xx_tlb(EPN, 0);
+}
+
+void helper_74xx_tlbi(target_ulong EPN)
+{
+ do_74xx_tlb(EPN, 1);
+}
+
+/*****************************************************************************/
+/* PowerPC 601 specific instructions (POWER bridge) */
+
+target_ulong helper_rac(target_ulong addr)
+{
+ mmu_ctx_t ctx;
+ int nb_BATs;
+ target_ulong ret = 0;
+
+ /* We don't have to generate many instances of this instruction,
+ * as rac is supervisor only.
+ */
+ /* XXX: FIX THIS: Pretend we have no BAT */
+ nb_BATs = env->nb_BATs;
+ env->nb_BATs = 0;
+ if (get_physical_address(env, &ctx, addr, 0, ACCESS_INT) == 0) {
+ ret = ctx.raddr;
+ }
+ env->nb_BATs = nb_BATs;
+ return ret;
+}
+
+static inline target_ulong booke_tlb_to_page_size(int size)
+{
+ return 1024 << (2 * size);
+}
+
+static inline int booke_page_size_to_tlb(target_ulong page_size)
+{
+ int size;
+
+ switch (page_size) {
+ case 0x00000400UL:
+ size = 0x0;
+ break;
+ case 0x00001000UL:
+ size = 0x1;
+ break;
+ case 0x00004000UL:
+ size = 0x2;
+ break;
+ case 0x00010000UL:
+ size = 0x3;
+ break;
+ case 0x00040000UL:
+ size = 0x4;
+ break;
+ case 0x00100000UL:
+ size = 0x5;
+ break;
+ case 0x00400000UL:
+ size = 0x6;
+ break;
+ case 0x01000000UL:
+ size = 0x7;
+ break;
+ case 0x04000000UL:
+ size = 0x8;
+ break;
+ case 0x10000000UL:
+ size = 0x9;
+ break;
+ case 0x40000000UL:
+ size = 0xA;
+ break;
+#if defined(TARGET_PPC64)
+ case 0x000100000000ULL:
+ size = 0xB;
+ break;
+ case 0x000400000000ULL:
+ size = 0xC;
+ break;
+ case 0x001000000000ULL:
+ size = 0xD;
+ break;
+ case 0x004000000000ULL:
+ size = 0xE;
+ break;
+ case 0x010000000000ULL:
+ size = 0xF;
+ break;
+#endif
+ default:
+ size = -1;
+ break;
+ }
+
+ return size;
+}
+
+/* Helpers for 4xx TLB management */
+#define PPC4XX_TLB_ENTRY_MASK 0x0000003f /* Mask for 64 TLB entries */
+
+#define PPC4XX_TLBHI_V 0x00000040
+#define PPC4XX_TLBHI_E 0x00000020
+#define PPC4XX_TLBHI_SIZE_MIN 0
+#define PPC4XX_TLBHI_SIZE_MAX 7
+#define PPC4XX_TLBHI_SIZE_DEFAULT 1
+#define PPC4XX_TLBHI_SIZE_SHIFT 7
+#define PPC4XX_TLBHI_SIZE_MASK 0x00000007
+
+#define PPC4XX_TLBLO_EX 0x00000200
+#define PPC4XX_TLBLO_WR 0x00000100
+#define PPC4XX_TLBLO_ATTR_MASK 0x000000FF
+#define PPC4XX_TLBLO_RPN_MASK 0xFFFFFC00
+
+target_ulong helper_4xx_tlbre_hi(target_ulong entry)
+{
+ ppcemb_tlb_t *tlb;
+ target_ulong ret;
+ int size;
+
+ entry &= PPC4XX_TLB_ENTRY_MASK;
+ tlb = &env->tlb.tlbe[entry];
+ ret = tlb->EPN;
+ if (tlb->prot & PAGE_VALID) {
+ ret |= PPC4XX_TLBHI_V;
+ }
+ size = booke_page_size_to_tlb(tlb->size);
+ if (size < PPC4XX_TLBHI_SIZE_MIN || size > PPC4XX_TLBHI_SIZE_MAX) {
+ size = PPC4XX_TLBHI_SIZE_DEFAULT;
+ }
+ ret |= size << PPC4XX_TLBHI_SIZE_SHIFT;
+ env->spr[SPR_40x_PID] = tlb->PID;
+ return ret;
+}
+
+target_ulong helper_4xx_tlbre_lo(target_ulong entry)
+{
+ ppcemb_tlb_t *tlb;
+ target_ulong ret;
+
+ entry &= PPC4XX_TLB_ENTRY_MASK;
+ tlb = &env->tlb.tlbe[entry];
+ ret = tlb->RPN;
+ if (tlb->prot & PAGE_EXEC) {
+ ret |= PPC4XX_TLBLO_EX;
+ }
+ if (tlb->prot & PAGE_WRITE) {
+ ret |= PPC4XX_TLBLO_WR;
+ }
+ return ret;
+}
+
+void helper_4xx_tlbwe_hi(target_ulong entry, target_ulong val)
+{
+ ppcemb_tlb_t *tlb;
+ target_ulong page, end;
+
+ LOG_SWTLB("%s entry %d val " TARGET_FMT_lx "\n", __func__, (int)entry,
+ val);
+ entry &= PPC4XX_TLB_ENTRY_MASK;
+ tlb = &env->tlb.tlbe[entry];
+ /* Invalidate previous TLB (if it's valid) */
+ if (tlb->prot & PAGE_VALID) {
+ end = tlb->EPN + tlb->size;
+ LOG_SWTLB("%s: invalidate old TLB %d start " TARGET_FMT_lx " end "
+ TARGET_FMT_lx "\n", __func__, (int)entry, tlb->EPN, end);
+ for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) {
+ tlb_flush_page(env, page);
+ }
+ }
+ tlb->size = booke_tlb_to_page_size((val >> PPC4XX_TLBHI_SIZE_SHIFT)
+ & PPC4XX_TLBHI_SIZE_MASK);
+ /* We cannot handle TLB size < TARGET_PAGE_SIZE.
+ * If this ever occurs, one should use the ppcemb target instead
+ * of the ppc or ppc64 one
+ */
+ if ((val & PPC4XX_TLBHI_V) && tlb->size < TARGET_PAGE_SIZE) {
+ cpu_abort(env, "TLB size " TARGET_FMT_lu " < %u "
+ "are not supported (%d)\n",
+ tlb->size, TARGET_PAGE_SIZE, (int)((val >> 7) & 0x7));
+ }
+ tlb->EPN = val & ~(tlb->size - 1);
+ if (val & PPC4XX_TLBHI_V) {
+ tlb->prot |= PAGE_VALID;
+ if (val & PPC4XX_TLBHI_E) {
+ /* XXX: TO BE FIXED */
+ cpu_abort(env,
+ "Little-endian TLB entries are not supported by now\n");
+ }
+ } else {
+ tlb->prot &= ~PAGE_VALID;
+ }
+ tlb->PID = env->spr[SPR_40x_PID]; /* PID */
+ LOG_SWTLB("%s: set up TLB %d RPN " TARGET_FMT_plx " EPN " TARGET_FMT_lx
+ " size " TARGET_FMT_lx " prot %c%c%c%c PID %d\n", __func__,
+ (int)entry, tlb->RPN, tlb->EPN, tlb->size,
+ tlb->prot & PAGE_READ ? 'r' : '-',
+ tlb->prot & PAGE_WRITE ? 'w' : '-',
+ tlb->prot & PAGE_EXEC ? 'x' : '-',
+ tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
+ /* Invalidate new TLB (if valid) */
+ if (tlb->prot & PAGE_VALID) {
+ end = tlb->EPN + tlb->size;
+ LOG_SWTLB("%s: invalidate TLB %d start " TARGET_FMT_lx " end "
+ TARGET_FMT_lx "\n", __func__, (int)entry, tlb->EPN, end);
+ for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) {
+ tlb_flush_page(env, page);
+ }
+ }
+}
+
+void helper_4xx_tlbwe_lo(target_ulong entry, target_ulong val)
+{
+ ppcemb_tlb_t *tlb;
+
+ LOG_SWTLB("%s entry %i val " TARGET_FMT_lx "\n", __func__, (int)entry,
+ val);
+ entry &= PPC4XX_TLB_ENTRY_MASK;
+ tlb = &env->tlb.tlbe[entry];
+ tlb->attr = val & PPC4XX_TLBLO_ATTR_MASK;
+ tlb->RPN = val & PPC4XX_TLBLO_RPN_MASK;
+ tlb->prot = PAGE_READ;
+ if (val & PPC4XX_TLBLO_EX) {
+ tlb->prot |= PAGE_EXEC;
+ }
+ if (val & PPC4XX_TLBLO_WR) {
+ tlb->prot |= PAGE_WRITE;
+ }
+ LOG_SWTLB("%s: set up TLB %d RPN " TARGET_FMT_plx " EPN " TARGET_FMT_lx
+ " size " TARGET_FMT_lx " prot %c%c%c%c PID %d\n", __func__,
+ (int)entry, tlb->RPN, tlb->EPN, tlb->size,
+ tlb->prot & PAGE_READ ? 'r' : '-',
+ tlb->prot & PAGE_WRITE ? 'w' : '-',
+ tlb->prot & PAGE_EXEC ? 'x' : '-',
+ tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
+}
+
+target_ulong helper_4xx_tlbsx(target_ulong address)
+{
+ return ppcemb_tlb_search(env, address, env->spr[SPR_40x_PID]);
+}
+
+/* PowerPC 440 TLB management */
+void helper_440_tlbwe(uint32_t word, target_ulong entry, target_ulong value)
+{
+ ppcemb_tlb_t *tlb;
+ target_ulong EPN, RPN, size;
+ int do_flush_tlbs;
+
+ LOG_SWTLB("%s word %d entry %d value " TARGET_FMT_lx "\n",
+ __func__, word, (int)entry, value);
+ do_flush_tlbs = 0;
+ entry &= 0x3F;
+ tlb = &env->tlb.tlbe[entry];
+ switch (word) {
+ default:
+ /* Just here to please gcc */
+ case 0:
+ EPN = value & 0xFFFFFC00;
+ if ((tlb->prot & PAGE_VALID) && EPN != tlb->EPN) {
+ do_flush_tlbs = 1;
+ }
+ tlb->EPN = EPN;
+ size = booke_tlb_to_page_size((value >> 4) & 0xF);
+ if ((tlb->prot & PAGE_VALID) && tlb->size < size) {
+ do_flush_tlbs = 1;
+ }
+ tlb->size = size;
+ tlb->attr &= ~0x1;
+ tlb->attr |= (value >> 8) & 1;
+ if (value & 0x200) {
+ tlb->prot |= PAGE_VALID;
+ } else {
+ if (tlb->prot & PAGE_VALID) {
+ tlb->prot &= ~PAGE_VALID;
+ do_flush_tlbs = 1;
+ }
+ }
+ tlb->PID = env->spr[SPR_440_MMUCR] & 0x000000FF;
+ if (do_flush_tlbs) {
+ tlb_flush(env, 1);
+ }
+ break;
+ case 1:
+ RPN = value & 0xFFFFFC0F;
+ if ((tlb->prot & PAGE_VALID) && tlb->RPN != RPN) {
+ tlb_flush(env, 1);
+ }
+ tlb->RPN = RPN;
+ break;
+ case 2:
+ tlb->attr = (tlb->attr & 0x1) | (value & 0x0000FF00);
+ tlb->prot = tlb->prot & PAGE_VALID;
+ if (value & 0x1) {
+ tlb->prot |= PAGE_READ << 4;
+ }
+ if (value & 0x2) {
+ tlb->prot |= PAGE_WRITE << 4;
+ }
+ if (value & 0x4) {
+ tlb->prot |= PAGE_EXEC << 4;
+ }
+ if (value & 0x8) {
+ tlb->prot |= PAGE_READ;
+ }
+ if (value & 0x10) {
+ tlb->prot |= PAGE_WRITE;
+ }
+ if (value & 0x20) {
+ tlb->prot |= PAGE_EXEC;
+ }
+ break;
+ }
+}
+
+target_ulong helper_440_tlbre(uint32_t word, target_ulong entry)
+{
+ ppcemb_tlb_t *tlb;
+ target_ulong ret;
+ int size;
+
+ entry &= 0x3F;
+ tlb = &env->tlb.tlbe[entry];
+ switch (word) {
+ default:
+ /* Just here to please gcc */
+ case 0:
+ ret = tlb->EPN;
+ size = booke_page_size_to_tlb(tlb->size);
+ if (size < 0 || size > 0xF) {
+ size = 1;
+ }
+ ret |= size << 4;
+ if (tlb->attr & 0x1) {
+ ret |= 0x100;
+ }
+ if (tlb->prot & PAGE_VALID) {
+ ret |= 0x200;
+ }
+ env->spr[SPR_440_MMUCR] &= ~0x000000FF;
+ env->spr[SPR_440_MMUCR] |= tlb->PID;
+ break;
+ case 1:
+ ret = tlb->RPN;
+ break;
+ case 2:
+ ret = tlb->attr & ~0x1;
+ if (tlb->prot & (PAGE_READ << 4)) {
+ ret |= 0x1;
+ }
+ if (tlb->prot & (PAGE_WRITE << 4)) {
+ ret |= 0x2;
+ }
+ if (tlb->prot & (PAGE_EXEC << 4)) {
+ ret |= 0x4;
+ }
+ if (tlb->prot & PAGE_READ) {
+ ret |= 0x8;
+ }
+ if (tlb->prot & PAGE_WRITE) {
+ ret |= 0x10;
+ }
+ if (tlb->prot & PAGE_EXEC) {
+ ret |= 0x20;
+ }
+ break;
+ }
+ return ret;
+}
+
+target_ulong helper_440_tlbsx(target_ulong address)
+{
+ return ppcemb_tlb_search(env, address, env->spr[SPR_440_MMUCR] & 0xFF);
+}
+
+/* PowerPC BookE 2.06 TLB management */
+
+static ppcmas_tlb_t *booke206_cur_tlb(CPUPPCState *env)
+{
+ uint32_t tlbncfg = 0;
+ int esel = (env->spr[SPR_BOOKE_MAS0] & MAS0_ESEL_MASK) >> MAS0_ESEL_SHIFT;
+ int ea = (env->spr[SPR_BOOKE_MAS2] & MAS2_EPN_MASK);
+ int tlb;
+
+ tlb = (env->spr[SPR_BOOKE_MAS0] & MAS0_TLBSEL_MASK) >> MAS0_TLBSEL_SHIFT;
+ tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlb];
+
+ if ((tlbncfg & TLBnCFG_HES) && (env->spr[SPR_BOOKE_MAS0] & MAS0_HES)) {
+ cpu_abort(env, "we don't support HES yet\n");
+ }
+
+ return booke206_get_tlbm(env, tlb, ea, esel);
+}
+
+void helper_booke_setpid(uint32_t pidn, target_ulong pid)
+{
+ env->spr[pidn] = pid;
+ /* changing PIDs mean we're in a different address space now */
+ tlb_flush(env, 1);
+}
+
+void helper_booke206_tlbwe(void)
+{
+ uint32_t tlbncfg, tlbn;
+ ppcmas_tlb_t *tlb;
+ uint32_t size_tlb, size_ps;
+
+ switch (env->spr[SPR_BOOKE_MAS0] & MAS0_WQ_MASK) {
+ case MAS0_WQ_ALWAYS:
+ /* good to go, write that entry */
+ break;
+ case MAS0_WQ_COND:
+ /* XXX check if reserved */
+ if (0) {
+ return;
+ }
+ break;
+ case MAS0_WQ_CLR_RSRV:
+ /* XXX clear entry */
+ return;
+ default:
+ /* no idea what to do */
+ return;
+ }
+
+ if (((env->spr[SPR_BOOKE_MAS0] & MAS0_ATSEL) == MAS0_ATSEL_LRAT) &&
+ !msr_gs) {
+ /* XXX we don't support direct LRAT setting yet */
+ fprintf(stderr, "cpu: don't support LRAT setting yet\n");
+ return;
+ }
+
+ tlbn = (env->spr[SPR_BOOKE_MAS0] & MAS0_TLBSEL_MASK) >> MAS0_TLBSEL_SHIFT;
+ tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlbn];
+
+ tlb = booke206_cur_tlb(env);
+
+ if (!tlb) {
+ helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
+ POWERPC_EXCP_INVAL |
+ POWERPC_EXCP_INVAL_INVAL);
+ }
+
+ /* check that we support the targeted size */
+ size_tlb = (env->spr[SPR_BOOKE_MAS1] & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
+ size_ps = booke206_tlbnps(env, tlbn);
+ if ((env->spr[SPR_BOOKE_MAS1] & MAS1_VALID) && (tlbncfg & TLBnCFG_AVAIL) &&
+ !(size_ps & (1 << size_tlb))) {
+ helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
+ POWERPC_EXCP_INVAL |
+ POWERPC_EXCP_INVAL_INVAL);
+ }
+
+ if (msr_gs) {
+ cpu_abort(env, "missing HV implementation\n");
+ }
+ tlb->mas7_3 = ((uint64_t)env->spr[SPR_BOOKE_MAS7] << 32) |
+ env->spr[SPR_BOOKE_MAS3];
+ tlb->mas1 = env->spr[SPR_BOOKE_MAS1];
+
+ /* MAV 1.0 only */
+ if (!(tlbncfg & TLBnCFG_AVAIL)) {
+ /* force !AVAIL TLB entries to correct page size */
+ tlb->mas1 &= ~MAS1_TSIZE_MASK;
+ /* XXX can be configured in MMUCSR0 */
+ tlb->mas1 |= (tlbncfg & TLBnCFG_MINSIZE) >> 12;
+ }
+
+ /* XXX needs to change when supporting 64-bit e500 */
+ tlb->mas2 = env->spr[SPR_BOOKE_MAS2] & 0xffffffff;
+
+ if (!(tlbncfg & TLBnCFG_IPROT)) {
+ /* no IPROT supported by TLB */
+ tlb->mas1 &= ~MAS1_IPROT;
+ }
+
+ if (booke206_tlb_to_page_size(env, tlb) == TARGET_PAGE_SIZE) {
+ tlb_flush_page(env, tlb->mas2 & MAS2_EPN_MASK);
+ } else {
+ tlb_flush(env, 1);
+ }
+}
+
+static inline void booke206_tlb_to_mas(CPUPPCState *env, ppcmas_tlb_t *tlb)
+{
+ int tlbn = booke206_tlbm_to_tlbn(env, tlb);
+ int way = booke206_tlbm_to_way(env, tlb);
+
+ env->spr[SPR_BOOKE_MAS0] = tlbn << MAS0_TLBSEL_SHIFT;
+ env->spr[SPR_BOOKE_MAS0] |= way << MAS0_ESEL_SHIFT;
+ env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
+
+ env->spr[SPR_BOOKE_MAS1] = tlb->mas1;
+ env->spr[SPR_BOOKE_MAS2] = tlb->mas2;
+ env->spr[SPR_BOOKE_MAS3] = tlb->mas7_3;
+ env->spr[SPR_BOOKE_MAS7] = tlb->mas7_3 >> 32;
+}
+
+void helper_booke206_tlbre(void)
+{
+ ppcmas_tlb_t *tlb = NULL;
+
+ tlb = booke206_cur_tlb(env);
+ if (!tlb) {
+ env->spr[SPR_BOOKE_MAS1] = 0;
+ } else {
+ booke206_tlb_to_mas(env, tlb);
+ }
+}
+
+void helper_booke206_tlbsx(target_ulong address)
+{
+ ppcmas_tlb_t *tlb = NULL;
+ int i, j;
+ target_phys_addr_t raddr;
+ uint32_t spid, sas;
+
+ spid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID_MASK) >> MAS6_SPID_SHIFT;
+ sas = env->spr[SPR_BOOKE_MAS6] & MAS6_SAS;
+
+ for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
+ int ways = booke206_tlb_ways(env, i);
+
+ for (j = 0; j < ways; j++) {
+ tlb = booke206_get_tlbm(env, i, address, j);
+
+ if (!tlb) {
+ continue;
+ }
+
+ if (ppcmas_tlb_check(env, tlb, &raddr, address, spid)) {
+ continue;
+ }
+
+ if (sas != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) {
+ continue;
+ }
+
+ booke206_tlb_to_mas(env, tlb);
+ return;
+ }
+ }
+
+ /* no entry found, fill with defaults */
+ env->spr[SPR_BOOKE_MAS0] = env->spr[SPR_BOOKE_MAS4] & MAS4_TLBSELD_MASK;
+ env->spr[SPR_BOOKE_MAS1] = env->spr[SPR_BOOKE_MAS4] & MAS4_TSIZED_MASK;
+ env->spr[SPR_BOOKE_MAS2] = env->spr[SPR_BOOKE_MAS4] & MAS4_WIMGED_MASK;
+ env->spr[SPR_BOOKE_MAS3] = 0;
+ env->spr[SPR_BOOKE_MAS7] = 0;
+
+ if (env->spr[SPR_BOOKE_MAS6] & MAS6_SAS) {
+ env->spr[SPR_BOOKE_MAS1] |= MAS1_TS;
+ }
+
+ env->spr[SPR_BOOKE_MAS1] |= (env->spr[SPR_BOOKE_MAS6] >> 16)
+ << MAS1_TID_SHIFT;
+
+ /* next victim logic */
+ env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_ESEL_SHIFT;
+ env->last_way++;
+ env->last_way &= booke206_tlb_ways(env, 0) - 1;
+ env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
+}
+
+static inline void booke206_invalidate_ea_tlb(CPUPPCState *env, int tlbn,
+ uint32_t ea)
+{
+ int i;
+ int ways = booke206_tlb_ways(env, tlbn);
+ target_ulong mask;
+
+ for (i = 0; i < ways; i++) {
+ ppcmas_tlb_t *tlb = booke206_get_tlbm(env, tlbn, ea, i);
+ if (!tlb) {
+ continue;
+ }
+ mask = ~(booke206_tlb_to_page_size(env, tlb) - 1);
+ if (((tlb->mas2 & MAS2_EPN_MASK) == (ea & mask)) &&
+ !(tlb->mas1 & MAS1_IPROT)) {
+ tlb->mas1 &= ~MAS1_VALID;
+ }
+ }
+}
+
+void helper_booke206_tlbivax(target_ulong address)
+{
+ if (address & 0x4) {
+ /* flush all entries */
+ if (address & 0x8) {
+ /* flush all of TLB1 */
+ booke206_flush_tlb(env, BOOKE206_FLUSH_TLB1, 1);
+ } else {
+ /* flush all of TLB0 */
+ booke206_flush_tlb(env, BOOKE206_FLUSH_TLB0, 0);
+ }
+ return;
+ }
+
+ if (address & 0x8) {
+ /* flush TLB1 entries */
+ booke206_invalidate_ea_tlb(env, 1, address);
+ tlb_flush(env, 1);
+ } else {
+ /* flush TLB0 entries */
+ booke206_invalidate_ea_tlb(env, 0, address);
+ tlb_flush_page(env, address & MAS2_EPN_MASK);
+ }
+}
+
+void helper_booke206_tlbilx0(target_ulong address)
+{
+ /* XXX missing LPID handling */
+ booke206_flush_tlb(env, -1, 1);
+}
+
+void helper_booke206_tlbilx1(target_ulong address)
+{
+ int i, j;
+ int tid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID);
+ ppcmas_tlb_t *tlb = env->tlb.tlbm;
+ int tlb_size;
+
+ /* XXX missing LPID handling */
+ for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
+ tlb_size = booke206_tlb_size(env, i);
+ for (j = 0; j < tlb_size; j++) {
+ if (!(tlb[j].mas1 & MAS1_IPROT) &&
+ ((tlb[j].mas1 & MAS1_TID_MASK) == tid)) {
+ tlb[j].mas1 &= ~MAS1_VALID;
+ }
+ }
+ tlb += booke206_tlb_size(env, i);
+ }
+ tlb_flush(env, 1);
+}
+
+void helper_booke206_tlbilx3(target_ulong address)
+{
+ int i, j;
+ ppcmas_tlb_t *tlb;
+ int tid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID);
+ int pid = tid >> MAS6_SPID_SHIFT;
+ int sgs = env->spr[SPR_BOOKE_MAS5] & MAS5_SGS;
+ int ind = (env->spr[SPR_BOOKE_MAS6] & MAS6_SIND) ? MAS1_IND : 0;
+ /* XXX check for unsupported isize and raise an invalid opcode then */
+ int size = env->spr[SPR_BOOKE_MAS6] & MAS6_ISIZE_MASK;
+ /* XXX implement MAV2 handling */
+ bool mav2 = false;
+
+ /* XXX missing LPID handling */
+ /* flush by pid and ea */
+ for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
+ int ways = booke206_tlb_ways(env, i);
+
+ for (j = 0; j < ways; j++) {
+ tlb = booke206_get_tlbm(env, i, address, j);
+ if (!tlb) {
+ continue;
+ }
+ if ((ppcmas_tlb_check(env, tlb, NULL, address, pid) != 0) ||
+ (tlb->mas1 & MAS1_IPROT) ||
+ ((tlb->mas1 & MAS1_IND) != ind) ||
+ ((tlb->mas8 & MAS8_TGS) != sgs)) {
+ continue;
+ }
+ if (mav2 && ((tlb->mas1 & MAS1_TSIZE_MASK) != size)) {
+ /* XXX only check when MMUCFG[TWC] || TLBnCFG[HES] */
+ continue;
+ }
+ /* XXX e500mc doesn't match SAS, but other cores might */
+ tlb->mas1 &= ~MAS1_VALID;
+ }
+ }
+ tlb_flush(env, 1);
+}
+
+void helper_booke206_tlbflush(uint32_t type)
+{
+ int flags = 0;
+
+ if (type & 2) {
+ flags |= BOOKE206_FLUSH_TLB1;
+ }
+
+ if (type & 4) {
+ flags |= BOOKE206_FLUSH_TLB0;
+ }
+
+ booke206_flush_tlb(env, flags, 1);
+}
+#endif
diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c
index 55b9e9d..c854c71 100644
--- a/target-ppc/op_helper.c
+++ b/target-ppc/op_helper.c
@@ -29,13 +29,6 @@
#endif /* !defined(CONFIG_USER_ONLY) */
//#define DEBUG_OP
-//#define DEBUG_SOFTWARE_TLB
-
-#ifdef DEBUG_SOFTWARE_TLB
-# define LOG_SWTLB(...) qemu_log(__VA_ARGS__)
-#else
-# define LOG_SWTLB(...) do { } while (0)
-#endif
/*****************************************************************************/
/* SPR accesses */
@@ -196,36 +189,6 @@ void helper_store_booke_tsr(target_ulong val)
{
store_booke_tsr(env, val);
}
-
-void helper_store_ibatu(uint32_t nr, target_ulong val)
-{
- ppc_store_ibatu(env, nr, val);
-}
-
-void helper_store_ibatl(uint32_t nr, target_ulong val)
-{
- ppc_store_ibatl(env, nr, val);
-}
-
-void helper_store_dbatu(uint32_t nr, target_ulong val)
-{
- ppc_store_dbatu(env, nr, val);
-}
-
-void helper_store_dbatl(uint32_t nr, target_ulong val)
-{
- ppc_store_dbatl(env, nr, val);
-}
-
-void helper_store_601_batl(uint32_t nr, target_ulong val)
-{
- ppc_store_ibatl_601(env, nr, val);
-}
-
-void helper_store_601_batu(uint32_t nr, target_ulong val)
-{
- ppc_store_ibatu_601(env, nr, val);
-}
#endif
/*****************************************************************************/
@@ -417,27 +380,6 @@ target_ulong helper_clcs(uint32_t arg)
}
}
-#if !defined(CONFIG_USER_ONLY)
-target_ulong helper_rac(target_ulong addr)
-{
- mmu_ctx_t ctx;
- int nb_BATs;
- target_ulong ret = 0;
-
- /* We don't have to generate many instances of this instruction,
- * as rac is supervisor only.
- */
- /* XXX: FIX THIS: Pretend we have no BAT */
- nb_BATs = env->nb_BATs;
- env->nb_BATs = 0;
- if (get_physical_address(env, &ctx, addr, 0, ACCESS_INT) == 0) {
- ret = ctx.raddr;
- }
- env->nb_BATs = nb_BATs;
- return ret;
-}
-#endif
-
/*****************************************************************************/
/* Embedded PowerPC specific helpers */
@@ -578,800 +520,4 @@ void tlb_fill(CPUPPCState *env1, target_ulong addr, int is_write, int mmu_idx,
}
env = saved_env;
}
-
-/* Segment registers load and store */
-target_ulong helper_load_sr(target_ulong sr_num)
-{
-#if defined(TARGET_PPC64)
- if (env->mmu_model & POWERPC_MMU_64) {
- return ppc_load_sr(env, sr_num);
- }
-#endif
- return env->sr[sr_num];
-}
-
-void helper_store_sr(target_ulong sr_num, target_ulong val)
-{
- ppc_store_sr(env, sr_num, val);
-}
-
-/* SLB management */
-#if defined(TARGET_PPC64)
-void helper_store_slb(target_ulong rb, target_ulong rs)
-{
- if (ppc_store_slb(env, rb, rs) < 0) {
- helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
- POWERPC_EXCP_INVAL);
- }
-}
-
-target_ulong helper_load_slb_esid(target_ulong rb)
-{
- target_ulong rt;
-
- if (ppc_load_slb_esid(env, rb, &rt) < 0) {
- helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
- POWERPC_EXCP_INVAL);
- }
- return rt;
-}
-
-target_ulong helper_load_slb_vsid(target_ulong rb)
-{
- target_ulong rt;
-
- if (ppc_load_slb_vsid(env, rb, &rt) < 0) {
- helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
- POWERPC_EXCP_INVAL);
- }
- return rt;
-}
-
-void helper_slbia(void)
-{
- ppc_slb_invalidate_all(env);
-}
-
-void helper_slbie(target_ulong addr)
-{
- ppc_slb_invalidate_one(env, addr);
-}
-
-#endif /* defined(TARGET_PPC64) */
-
-/* TLB management */
-void helper_tlbia(void)
-{
- ppc_tlb_invalidate_all(env);
-}
-
-void helper_tlbie(target_ulong addr)
-{
- ppc_tlb_invalidate_one(env, addr);
-}
-
-/* Software driven TLBs management */
-/* PowerPC 602/603 software TLB load instructions helpers */
-static void do_6xx_tlb(target_ulong new_EPN, int is_code)
-{
- target_ulong RPN, CMP, EPN;
- int way;
-
- RPN = env->spr[SPR_RPA];
- if (is_code) {
- CMP = env->spr[SPR_ICMP];
- EPN = env->spr[SPR_IMISS];
- } else {
- CMP = env->spr[SPR_DCMP];
- EPN = env->spr[SPR_DMISS];
- }
- way = (env->spr[SPR_SRR1] >> 17) & 1;
- (void)EPN; /* avoid a compiler warning */
- LOG_SWTLB("%s: EPN " TARGET_FMT_lx " " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
- " PTE1 " TARGET_FMT_lx " way %d\n", __func__, new_EPN, EPN, CMP,
- RPN, way);
- /* Store this TLB */
- ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
- way, is_code, CMP, RPN);
-}
-
-void helper_6xx_tlbd(target_ulong EPN)
-{
- do_6xx_tlb(EPN, 0);
-}
-
-void helper_6xx_tlbi(target_ulong EPN)
-{
- do_6xx_tlb(EPN, 1);
-}
-
-/* PowerPC 74xx software TLB load instructions helpers */
-static void do_74xx_tlb(target_ulong new_EPN, int is_code)
-{
- target_ulong RPN, CMP, EPN;
- int way;
-
- RPN = env->spr[SPR_PTELO];
- CMP = env->spr[SPR_PTEHI];
- EPN = env->spr[SPR_TLBMISS] & ~0x3;
- way = env->spr[SPR_TLBMISS] & 0x3;
- (void)EPN; /* avoid a compiler warning */
- LOG_SWTLB("%s: EPN " TARGET_FMT_lx " " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
- " PTE1 " TARGET_FMT_lx " way %d\n", __func__, new_EPN, EPN, CMP,
- RPN, way);
- /* Store this TLB */
- ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
- way, is_code, CMP, RPN);
-}
-
-void helper_74xx_tlbd(target_ulong EPN)
-{
- do_74xx_tlb(EPN, 0);
-}
-
-void helper_74xx_tlbi(target_ulong EPN)
-{
- do_74xx_tlb(EPN, 1);
-}
-
-static inline target_ulong booke_tlb_to_page_size(int size)
-{
- return 1024 << (2 * size);
-}
-
-static inline int booke_page_size_to_tlb(target_ulong page_size)
-{
- int size;
-
- switch (page_size) {
- case 0x00000400UL:
- size = 0x0;
- break;
- case 0x00001000UL:
- size = 0x1;
- break;
- case 0x00004000UL:
- size = 0x2;
- break;
- case 0x00010000UL:
- size = 0x3;
- break;
- case 0x00040000UL:
- size = 0x4;
- break;
- case 0x00100000UL:
- size = 0x5;
- break;
- case 0x00400000UL:
- size = 0x6;
- break;
- case 0x01000000UL:
- size = 0x7;
- break;
- case 0x04000000UL:
- size = 0x8;
- break;
- case 0x10000000UL:
- size = 0x9;
- break;
- case 0x40000000UL:
- size = 0xA;
- break;
-#if defined(TARGET_PPC64)
- case 0x000100000000ULL:
- size = 0xB;
- break;
- case 0x000400000000ULL:
- size = 0xC;
- break;
- case 0x001000000000ULL:
- size = 0xD;
- break;
- case 0x004000000000ULL:
- size = 0xE;
- break;
- case 0x010000000000ULL:
- size = 0xF;
- break;
-#endif
- default:
- size = -1;
- break;
- }
-
- return size;
-}
-
-/* Helpers for 4xx TLB management */
-#define PPC4XX_TLB_ENTRY_MASK 0x0000003f /* Mask for 64 TLB entries */
-
-#define PPC4XX_TLBHI_V 0x00000040
-#define PPC4XX_TLBHI_E 0x00000020
-#define PPC4XX_TLBHI_SIZE_MIN 0
-#define PPC4XX_TLBHI_SIZE_MAX 7
-#define PPC4XX_TLBHI_SIZE_DEFAULT 1
-#define PPC4XX_TLBHI_SIZE_SHIFT 7
-#define PPC4XX_TLBHI_SIZE_MASK 0x00000007
-
-#define PPC4XX_TLBLO_EX 0x00000200
-#define PPC4XX_TLBLO_WR 0x00000100
-#define PPC4XX_TLBLO_ATTR_MASK 0x000000FF
-#define PPC4XX_TLBLO_RPN_MASK 0xFFFFFC00
-
-target_ulong helper_4xx_tlbre_hi(target_ulong entry)
-{
- ppcemb_tlb_t *tlb;
- target_ulong ret;
- int size;
-
- entry &= PPC4XX_TLB_ENTRY_MASK;
- tlb = &env->tlb.tlbe[entry];
- ret = tlb->EPN;
- if (tlb->prot & PAGE_VALID) {
- ret |= PPC4XX_TLBHI_V;
- }
- size = booke_page_size_to_tlb(tlb->size);
- if (size < PPC4XX_TLBHI_SIZE_MIN || size > PPC4XX_TLBHI_SIZE_MAX) {
- size = PPC4XX_TLBHI_SIZE_DEFAULT;
- }
- ret |= size << PPC4XX_TLBHI_SIZE_SHIFT;
- env->spr[SPR_40x_PID] = tlb->PID;
- return ret;
-}
-
-target_ulong helper_4xx_tlbre_lo(target_ulong entry)
-{
- ppcemb_tlb_t *tlb;
- target_ulong ret;
-
- entry &= PPC4XX_TLB_ENTRY_MASK;
- tlb = &env->tlb.tlbe[entry];
- ret = tlb->RPN;
- if (tlb->prot & PAGE_EXEC) {
- ret |= PPC4XX_TLBLO_EX;
- }
- if (tlb->prot & PAGE_WRITE) {
- ret |= PPC4XX_TLBLO_WR;
- }
- return ret;
-}
-
-void helper_4xx_tlbwe_hi(target_ulong entry, target_ulong val)
-{
- ppcemb_tlb_t *tlb;
- target_ulong page, end;
-
- LOG_SWTLB("%s entry %d val " TARGET_FMT_lx "\n", __func__, (int)entry,
- val);
- entry &= PPC4XX_TLB_ENTRY_MASK;
- tlb = &env->tlb.tlbe[entry];
- /* Invalidate previous TLB (if it's valid) */
- if (tlb->prot & PAGE_VALID) {
- end = tlb->EPN + tlb->size;
- LOG_SWTLB("%s: invalidate old TLB %d start " TARGET_FMT_lx " end "
- TARGET_FMT_lx "\n", __func__, (int)entry, tlb->EPN, end);
- for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) {
- tlb_flush_page(env, page);
- }
- }
- tlb->size = booke_tlb_to_page_size((val >> PPC4XX_TLBHI_SIZE_SHIFT)
- & PPC4XX_TLBHI_SIZE_MASK);
- /* We cannot handle TLB size < TARGET_PAGE_SIZE.
- * If this ever occurs, one should use the ppcemb target instead
- * of the ppc or ppc64 one
- */
- if ((val & PPC4XX_TLBHI_V) && tlb->size < TARGET_PAGE_SIZE) {
- cpu_abort(env, "TLB size " TARGET_FMT_lu " < %u "
- "are not supported (%d)\n",
- tlb->size, TARGET_PAGE_SIZE, (int)((val >> 7) & 0x7));
- }
- tlb->EPN = val & ~(tlb->size - 1);
- if (val & PPC4XX_TLBHI_V) {
- tlb->prot |= PAGE_VALID;
- if (val & PPC4XX_TLBHI_E) {
- /* XXX: TO BE FIXED */
- cpu_abort(env,
- "Little-endian TLB entries are not supported by now\n");
- }
- } else {
- tlb->prot &= ~PAGE_VALID;
- }
- tlb->PID = env->spr[SPR_40x_PID]; /* PID */
- LOG_SWTLB("%s: set up TLB %d RPN " TARGET_FMT_plx " EPN " TARGET_FMT_lx
- " size " TARGET_FMT_lx " prot %c%c%c%c PID %d\n", __func__,
- (int)entry, tlb->RPN, tlb->EPN, tlb->size,
- tlb->prot & PAGE_READ ? 'r' : '-',
- tlb->prot & PAGE_WRITE ? 'w' : '-',
- tlb->prot & PAGE_EXEC ? 'x' : '-',
- tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
- /* Invalidate new TLB (if valid) */
- if (tlb->prot & PAGE_VALID) {
- end = tlb->EPN + tlb->size;
- LOG_SWTLB("%s: invalidate TLB %d start " TARGET_FMT_lx " end "
- TARGET_FMT_lx "\n", __func__, (int)entry, tlb->EPN, end);
- for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) {
- tlb_flush_page(env, page);
- }
- }
-}
-
-void helper_4xx_tlbwe_lo(target_ulong entry, target_ulong val)
-{
- ppcemb_tlb_t *tlb;
-
- LOG_SWTLB("%s entry %i val " TARGET_FMT_lx "\n", __func__, (int)entry,
- val);
- entry &= PPC4XX_TLB_ENTRY_MASK;
- tlb = &env->tlb.tlbe[entry];
- tlb->attr = val & PPC4XX_TLBLO_ATTR_MASK;
- tlb->RPN = val & PPC4XX_TLBLO_RPN_MASK;
- tlb->prot = PAGE_READ;
- if (val & PPC4XX_TLBLO_EX) {
- tlb->prot |= PAGE_EXEC;
- }
- if (val & PPC4XX_TLBLO_WR) {
- tlb->prot |= PAGE_WRITE;
- }
- LOG_SWTLB("%s: set up TLB %d RPN " TARGET_FMT_plx " EPN " TARGET_FMT_lx
- " size " TARGET_FMT_lx " prot %c%c%c%c PID %d\n", __func__,
- (int)entry, tlb->RPN, tlb->EPN, tlb->size,
- tlb->prot & PAGE_READ ? 'r' : '-',
- tlb->prot & PAGE_WRITE ? 'w' : '-',
- tlb->prot & PAGE_EXEC ? 'x' : '-',
- tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
-}
-
-target_ulong helper_4xx_tlbsx(target_ulong address)
-{
- return ppcemb_tlb_search(env, address, env->spr[SPR_40x_PID]);
-}
-
-/* PowerPC 440 TLB management */
-void helper_440_tlbwe(uint32_t word, target_ulong entry, target_ulong value)
-{
- ppcemb_tlb_t *tlb;
- target_ulong EPN, RPN, size;
- int do_flush_tlbs;
-
- LOG_SWTLB("%s word %d entry %d value " TARGET_FMT_lx "\n",
- __func__, word, (int)entry, value);
- do_flush_tlbs = 0;
- entry &= 0x3F;
- tlb = &env->tlb.tlbe[entry];
- switch (word) {
- default:
- /* Just here to please gcc */
- case 0:
- EPN = value & 0xFFFFFC00;
- if ((tlb->prot & PAGE_VALID) && EPN != tlb->EPN) {
- do_flush_tlbs = 1;
- }
- tlb->EPN = EPN;
- size = booke_tlb_to_page_size((value >> 4) & 0xF);
- if ((tlb->prot & PAGE_VALID) && tlb->size < size) {
- do_flush_tlbs = 1;
- }
- tlb->size = size;
- tlb->attr &= ~0x1;
- tlb->attr |= (value >> 8) & 1;
- if (value & 0x200) {
- tlb->prot |= PAGE_VALID;
- } else {
- if (tlb->prot & PAGE_VALID) {
- tlb->prot &= ~PAGE_VALID;
- do_flush_tlbs = 1;
- }
- }
- tlb->PID = env->spr[SPR_440_MMUCR] & 0x000000FF;
- if (do_flush_tlbs) {
- tlb_flush(env, 1);
- }
- break;
- case 1:
- RPN = value & 0xFFFFFC0F;
- if ((tlb->prot & PAGE_VALID) && tlb->RPN != RPN) {
- tlb_flush(env, 1);
- }
- tlb->RPN = RPN;
- break;
- case 2:
- tlb->attr = (tlb->attr & 0x1) | (value & 0x0000FF00);
- tlb->prot = tlb->prot & PAGE_VALID;
- if (value & 0x1) {
- tlb->prot |= PAGE_READ << 4;
- }
- if (value & 0x2) {
- tlb->prot |= PAGE_WRITE << 4;
- }
- if (value & 0x4) {
- tlb->prot |= PAGE_EXEC << 4;
- }
- if (value & 0x8) {
- tlb->prot |= PAGE_READ;
- }
- if (value & 0x10) {
- tlb->prot |= PAGE_WRITE;
- }
- if (value & 0x20) {
- tlb->prot |= PAGE_EXEC;
- }
- break;
- }
-}
-
-target_ulong helper_440_tlbre(uint32_t word, target_ulong entry)
-{
- ppcemb_tlb_t *tlb;
- target_ulong ret;
- int size;
-
- entry &= 0x3F;
- tlb = &env->tlb.tlbe[entry];
- switch (word) {
- default:
- /* Just here to please gcc */
- case 0:
- ret = tlb->EPN;
- size = booke_page_size_to_tlb(tlb->size);
- if (size < 0 || size > 0xF) {
- size = 1;
- }
- ret |= size << 4;
- if (tlb->attr & 0x1) {
- ret |= 0x100;
- }
- if (tlb->prot & PAGE_VALID) {
- ret |= 0x200;
- }
- env->spr[SPR_440_MMUCR] &= ~0x000000FF;
- env->spr[SPR_440_MMUCR] |= tlb->PID;
- break;
- case 1:
- ret = tlb->RPN;
- break;
- case 2:
- ret = tlb->attr & ~0x1;
- if (tlb->prot & (PAGE_READ << 4)) {
- ret |= 0x1;
- }
- if (tlb->prot & (PAGE_WRITE << 4)) {
- ret |= 0x2;
- }
- if (tlb->prot & (PAGE_EXEC << 4)) {
- ret |= 0x4;
- }
- if (tlb->prot & PAGE_READ) {
- ret |= 0x8;
- }
- if (tlb->prot & PAGE_WRITE) {
- ret |= 0x10;
- }
- if (tlb->prot & PAGE_EXEC) {
- ret |= 0x20;
- }
- break;
- }
- return ret;
-}
-
-target_ulong helper_440_tlbsx(target_ulong address)
-{
- return ppcemb_tlb_search(env, address, env->spr[SPR_440_MMUCR] & 0xFF);
-}
-
-/* PowerPC BookE 2.06 TLB management */
-
-static ppcmas_tlb_t *booke206_cur_tlb(CPUPPCState *env)
-{
- uint32_t tlbncfg = 0;
- int esel = (env->spr[SPR_BOOKE_MAS0] & MAS0_ESEL_MASK) >> MAS0_ESEL_SHIFT;
- int ea = (env->spr[SPR_BOOKE_MAS2] & MAS2_EPN_MASK);
- int tlb;
-
- tlb = (env->spr[SPR_BOOKE_MAS0] & MAS0_TLBSEL_MASK) >> MAS0_TLBSEL_SHIFT;
- tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlb];
-
- if ((tlbncfg & TLBnCFG_HES) && (env->spr[SPR_BOOKE_MAS0] & MAS0_HES)) {
- cpu_abort(env, "we don't support HES yet\n");
- }
-
- return booke206_get_tlbm(env, tlb, ea, esel);
-}
-
-void helper_booke_setpid(uint32_t pidn, target_ulong pid)
-{
- env->spr[pidn] = pid;
- /* changing PIDs mean we're in a different address space now */
- tlb_flush(env, 1);
-}
-
-void helper_booke206_tlbwe(void)
-{
- uint32_t tlbncfg, tlbn;
- ppcmas_tlb_t *tlb;
- uint32_t size_tlb, size_ps;
-
- switch (env->spr[SPR_BOOKE_MAS0] & MAS0_WQ_MASK) {
- case MAS0_WQ_ALWAYS:
- /* good to go, write that entry */
- break;
- case MAS0_WQ_COND:
- /* XXX check if reserved */
- if (0) {
- return;
- }
- break;
- case MAS0_WQ_CLR_RSRV:
- /* XXX clear entry */
- return;
- default:
- /* no idea what to do */
- return;
- }
-
- if (((env->spr[SPR_BOOKE_MAS0] & MAS0_ATSEL) == MAS0_ATSEL_LRAT) &&
- !msr_gs) {
- /* XXX we don't support direct LRAT setting yet */
- fprintf(stderr, "cpu: don't support LRAT setting yet\n");
- return;
- }
-
- tlbn = (env->spr[SPR_BOOKE_MAS0] & MAS0_TLBSEL_MASK) >> MAS0_TLBSEL_SHIFT;
- tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlbn];
-
- tlb = booke206_cur_tlb(env);
-
- if (!tlb) {
- helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
- POWERPC_EXCP_INVAL |
- POWERPC_EXCP_INVAL_INVAL);
- }
-
- /* check that we support the targeted size */
- size_tlb = (env->spr[SPR_BOOKE_MAS1] & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
- size_ps = booke206_tlbnps(env, tlbn);
- if ((env->spr[SPR_BOOKE_MAS1] & MAS1_VALID) && (tlbncfg & TLBnCFG_AVAIL) &&
- !(size_ps & (1 << size_tlb))) {
- helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
- POWERPC_EXCP_INVAL |
- POWERPC_EXCP_INVAL_INVAL);
- }
-
- if (msr_gs) {
- cpu_abort(env, "missing HV implementation\n");
- }
- tlb->mas7_3 = ((uint64_t)env->spr[SPR_BOOKE_MAS7] << 32) |
- env->spr[SPR_BOOKE_MAS3];
- tlb->mas1 = env->spr[SPR_BOOKE_MAS1];
-
- /* MAV 1.0 only */
- if (!(tlbncfg & TLBnCFG_AVAIL)) {
- /* force !AVAIL TLB entries to correct page size */
- tlb->mas1 &= ~MAS1_TSIZE_MASK;
- /* XXX can be configured in MMUCSR0 */
- tlb->mas1 |= (tlbncfg & TLBnCFG_MINSIZE) >> 12;
- }
-
- /* XXX needs to change when supporting 64-bit e500 */
- tlb->mas2 = env->spr[SPR_BOOKE_MAS2] & 0xffffffff;
-
- if (!(tlbncfg & TLBnCFG_IPROT)) {
- /* no IPROT supported by TLB */
- tlb->mas1 &= ~MAS1_IPROT;
- }
-
- if (booke206_tlb_to_page_size(env, tlb) == TARGET_PAGE_SIZE) {
- tlb_flush_page(env, tlb->mas2 & MAS2_EPN_MASK);
- } else {
- tlb_flush(env, 1);
- }
-}
-
-static inline void booke206_tlb_to_mas(CPUPPCState *env, ppcmas_tlb_t *tlb)
-{
- int tlbn = booke206_tlbm_to_tlbn(env, tlb);
- int way = booke206_tlbm_to_way(env, tlb);
-
- env->spr[SPR_BOOKE_MAS0] = tlbn << MAS0_TLBSEL_SHIFT;
- env->spr[SPR_BOOKE_MAS0] |= way << MAS0_ESEL_SHIFT;
- env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
-
- env->spr[SPR_BOOKE_MAS1] = tlb->mas1;
- env->spr[SPR_BOOKE_MAS2] = tlb->mas2;
- env->spr[SPR_BOOKE_MAS3] = tlb->mas7_3;
- env->spr[SPR_BOOKE_MAS7] = tlb->mas7_3 >> 32;
-}
-
-void helper_booke206_tlbre(void)
-{
- ppcmas_tlb_t *tlb = NULL;
-
- tlb = booke206_cur_tlb(env);
- if (!tlb) {
- env->spr[SPR_BOOKE_MAS1] = 0;
- } else {
- booke206_tlb_to_mas(env, tlb);
- }
-}
-
-void helper_booke206_tlbsx(target_ulong address)
-{
- ppcmas_tlb_t *tlb = NULL;
- int i, j;
- target_phys_addr_t raddr;
- uint32_t spid, sas;
-
- spid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID_MASK) >> MAS6_SPID_SHIFT;
- sas = env->spr[SPR_BOOKE_MAS6] & MAS6_SAS;
-
- for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
- int ways = booke206_tlb_ways(env, i);
-
- for (j = 0; j < ways; j++) {
- tlb = booke206_get_tlbm(env, i, address, j);
-
- if (!tlb) {
- continue;
- }
-
- if (ppcmas_tlb_check(env, tlb, &raddr, address, spid)) {
- continue;
- }
-
- if (sas != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) {
- continue;
- }
-
- booke206_tlb_to_mas(env, tlb);
- return;
- }
- }
-
- /* no entry found, fill with defaults */
- env->spr[SPR_BOOKE_MAS0] = env->spr[SPR_BOOKE_MAS4] & MAS4_TLBSELD_MASK;
- env->spr[SPR_BOOKE_MAS1] = env->spr[SPR_BOOKE_MAS4] & MAS4_TSIZED_MASK;
- env->spr[SPR_BOOKE_MAS2] = env->spr[SPR_BOOKE_MAS4] & MAS4_WIMGED_MASK;
- env->spr[SPR_BOOKE_MAS3] = 0;
- env->spr[SPR_BOOKE_MAS7] = 0;
-
- if (env->spr[SPR_BOOKE_MAS6] & MAS6_SAS) {
- env->spr[SPR_BOOKE_MAS1] |= MAS1_TS;
- }
-
- env->spr[SPR_BOOKE_MAS1] |= (env->spr[SPR_BOOKE_MAS6] >> 16)
- << MAS1_TID_SHIFT;
-
- /* next victim logic */
- env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_ESEL_SHIFT;
- env->last_way++;
- env->last_way &= booke206_tlb_ways(env, 0) - 1;
- env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
-}
-
-static inline void booke206_invalidate_ea_tlb(CPUPPCState *env, int tlbn,
- uint32_t ea)
-{
- int i;
- int ways = booke206_tlb_ways(env, tlbn);
- target_ulong mask;
-
- for (i = 0; i < ways; i++) {
- ppcmas_tlb_t *tlb = booke206_get_tlbm(env, tlbn, ea, i);
- if (!tlb) {
- continue;
- }
- mask = ~(booke206_tlb_to_page_size(env, tlb) - 1);
- if (((tlb->mas2 & MAS2_EPN_MASK) == (ea & mask)) &&
- !(tlb->mas1 & MAS1_IPROT)) {
- tlb->mas1 &= ~MAS1_VALID;
- }
- }
-}
-
-void helper_booke206_tlbivax(target_ulong address)
-{
- if (address & 0x4) {
- /* flush all entries */
- if (address & 0x8) {
- /* flush all of TLB1 */
- booke206_flush_tlb(env, BOOKE206_FLUSH_TLB1, 1);
- } else {
- /* flush all of TLB0 */
- booke206_flush_tlb(env, BOOKE206_FLUSH_TLB0, 0);
- }
- return;
- }
-
- if (address & 0x8) {
- /* flush TLB1 entries */
- booke206_invalidate_ea_tlb(env, 1, address);
- tlb_flush(env, 1);
- } else {
- /* flush TLB0 entries */
- booke206_invalidate_ea_tlb(env, 0, address);
- tlb_flush_page(env, address & MAS2_EPN_MASK);
- }
-}
-
-void helper_booke206_tlbilx0(target_ulong address)
-{
- /* XXX missing LPID handling */
- booke206_flush_tlb(env, -1, 1);
-}
-
-void helper_booke206_tlbilx1(target_ulong address)
-{
- int i, j;
- int tid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID);
- ppcmas_tlb_t *tlb = env->tlb.tlbm;
- int tlb_size;
-
- /* XXX missing LPID handling */
- for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
- tlb_size = booke206_tlb_size(env, i);
- for (j = 0; j < tlb_size; j++) {
- if (!(tlb[j].mas1 & MAS1_IPROT) &&
- ((tlb[j].mas1 & MAS1_TID_MASK) == tid)) {
- tlb[j].mas1 &= ~MAS1_VALID;
- }
- }
- tlb += booke206_tlb_size(env, i);
- }
- tlb_flush(env, 1);
-}
-
-void helper_booke206_tlbilx3(target_ulong address)
-{
- int i, j;
- ppcmas_tlb_t *tlb;
- int tid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID);
- int pid = tid >> MAS6_SPID_SHIFT;
- int sgs = env->spr[SPR_BOOKE_MAS5] & MAS5_SGS;
- int ind = (env->spr[SPR_BOOKE_MAS6] & MAS6_SIND) ? MAS1_IND : 0;
- /* XXX check for unsupported isize and raise an invalid opcode then */
- int size = env->spr[SPR_BOOKE_MAS6] & MAS6_ISIZE_MASK;
- /* XXX implement MAV2 handling */
- bool mav2 = false;
-
- /* XXX missing LPID handling */
- /* flush by pid and ea */
- for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
- int ways = booke206_tlb_ways(env, i);
-
- for (j = 0; j < ways; j++) {
- tlb = booke206_get_tlbm(env, i, address, j);
- if (!tlb) {
- continue;
- }
- if ((ppcmas_tlb_check(env, tlb, NULL, address, pid) != 0) ||
- (tlb->mas1 & MAS1_IPROT) ||
- ((tlb->mas1 & MAS1_IND) != ind) ||
- ((tlb->mas8 & MAS8_TGS) != sgs)) {
- continue;
- }
- if (mav2 && ((tlb->mas1 & MAS1_TSIZE_MASK) != size)) {
- /* XXX only check when MMUCFG[TWC] || TLBnCFG[HES] */
- continue;
- }
- /* XXX e500mc doesn't match SAS, but other cores might */
- tlb->mas1 &= ~MAS1_VALID;
- }
- }
- tlb_flush(env, 1);
-}
-
-void helper_booke206_tlbflush(uint32_t type)
-{
- int flags = 0;
-
- if (type & 2) {
- flags |= BOOKE206_FLUSH_TLB1;
- }
-
- if (type & 4) {
- flags |= BOOKE206_FLUSH_TLB0;
- }
-
- booke206_flush_tlb(env, flags, 1);
-}
#endif /* !CONFIG_USER_ONLY */
--
1.6.0.2
^ permalink raw reply related [flat|nested] 89+ messages in thread
* [Qemu-devel] [PATCH 11/72] ppc: Avoid AREG0 for MMU etc. helpers
2012-06-23 23:06 [Qemu-devel] [PULL 00/72] ppc patch queue 2012-06-24 Alexander Graf
` (9 preceding siblings ...)
2012-06-23 23:06 ` [Qemu-devel] [PATCH 10/72] ppc: Split MMU etc. helpers from op_helper.c Alexander Graf
@ 2012-06-23 23:06 ` Alexander Graf
2012-06-23 23:06 ` [Qemu-devel] [PATCH 12/72] ppc: Avoid a warning with the next patch Alexander Graf
` (61 subsequent siblings)
72 siblings, 0 replies; 89+ messages in thread
From: Alexander Graf @ 2012-06-23 23:06 UTC (permalink / raw)
To: qemu-devel qemu-devel
Cc: Blue Swirl, qemu-ppc Mailing List, Andreas Färber,
Aurelien Jarno
From: Blue Swirl <blauwirbel@gmail.com>
Add an explicit CPUPPCState parameter instead of relying on AREG0.
Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Andreas Färber <afaerber@suse.de>
Signed-off-by: Alexander Graf <agraf@suse.de>
---
target-ppc/Makefile.objs | 1 -
target-ppc/helper.h | 74 +++++++++++++++++-----------------
target-ppc/mmu_helper.c | 91 ++++++++++++++++++++++---------------------
target-ppc/translate.c | 85 ++++++++++++++++++++++------------------
target-ppc/translate_init.c | 24 ++++++------
5 files changed, 142 insertions(+), 133 deletions(-)
diff --git a/target-ppc/Makefile.objs b/target-ppc/Makefile.objs
index 0f89c2c..71e25b1 100644
--- a/target-ppc/Makefile.objs
+++ b/target-ppc/Makefile.objs
@@ -7,5 +7,4 @@ obj-y += fpu_helper.o
obj-y += int_helper.o
obj-y += mmu_helper.o
-$(obj)/mmu_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
$(obj)/op_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
diff --git a/target-ppc/helper.h b/target-ppc/helper.h
index 7074bad..b1f7ba5 100644
--- a/target-ppc/helper.h
+++ b/target-ppc/helper.h
@@ -324,38 +324,38 @@ DEF_HELPER_3(efdcmpgt, i32, env, i64, i64)
DEF_HELPER_3(efdcmpeq, i32, env, i64, i64)
#if !defined(CONFIG_USER_ONLY)
-DEF_HELPER_1(4xx_tlbre_hi, tl, tl)
-DEF_HELPER_1(4xx_tlbre_lo, tl, tl)
-DEF_HELPER_2(4xx_tlbwe_hi, void, tl, tl)
-DEF_HELPER_2(4xx_tlbwe_lo, void, tl, tl)
-DEF_HELPER_1(4xx_tlbsx, tl, tl)
-DEF_HELPER_2(440_tlbre, tl, i32, tl)
-DEF_HELPER_3(440_tlbwe, void, i32, tl, tl)
-DEF_HELPER_1(440_tlbsx, tl, tl)
-DEF_HELPER_0(booke206_tlbre, void)
-DEF_HELPER_0(booke206_tlbwe, void)
-DEF_HELPER_1(booke206_tlbsx, void, tl)
-DEF_HELPER_1(booke206_tlbivax, void, tl)
-DEF_HELPER_1(booke206_tlbilx0, void, tl)
-DEF_HELPER_1(booke206_tlbilx1, void, tl)
-DEF_HELPER_1(booke206_tlbilx3, void, tl)
-DEF_HELPER_1(booke206_tlbflush, void, i32)
-DEF_HELPER_2(booke_setpid, void, i32, tl)
-DEF_HELPER_1(6xx_tlbd, void, tl)
-DEF_HELPER_1(6xx_tlbi, void, tl)
-DEF_HELPER_1(74xx_tlbd, void, tl)
-DEF_HELPER_1(74xx_tlbi, void, tl)
-DEF_HELPER_FLAGS_0(tlbia, TCG_CALL_CONST, void)
-DEF_HELPER_FLAGS_1(tlbie, TCG_CALL_CONST, void, tl)
+DEF_HELPER_2(4xx_tlbre_hi, tl, env, tl)
+DEF_HELPER_2(4xx_tlbre_lo, tl, env, tl)
+DEF_HELPER_3(4xx_tlbwe_hi, void, env, tl, tl)
+DEF_HELPER_3(4xx_tlbwe_lo, void, env, tl, tl)
+DEF_HELPER_2(4xx_tlbsx, tl, env, tl)
+DEF_HELPER_3(440_tlbre, tl, env, i32, tl)
+DEF_HELPER_4(440_tlbwe, void, env, i32, tl, tl)
+DEF_HELPER_2(440_tlbsx, tl, env, tl)
+DEF_HELPER_1(booke206_tlbre, void, env)
+DEF_HELPER_1(booke206_tlbwe, void, env)
+DEF_HELPER_2(booke206_tlbsx, void, env, tl)
+DEF_HELPER_2(booke206_tlbivax, void, env, tl)
+DEF_HELPER_2(booke206_tlbilx0, void, env, tl)
+DEF_HELPER_2(booke206_tlbilx1, void, env, tl)
+DEF_HELPER_2(booke206_tlbilx3, void, env, tl)
+DEF_HELPER_2(booke206_tlbflush, void, env, i32)
+DEF_HELPER_3(booke_setpid, void, env, i32, tl)
+DEF_HELPER_2(6xx_tlbd, void, env, tl)
+DEF_HELPER_2(6xx_tlbi, void, env, tl)
+DEF_HELPER_2(74xx_tlbd, void, env, tl)
+DEF_HELPER_2(74xx_tlbi, void, env, tl)
+DEF_HELPER_FLAGS_1(tlbia, TCG_CALL_CONST, void, env)
+DEF_HELPER_FLAGS_2(tlbie, TCG_CALL_CONST, void, env, tl)
#if defined(TARGET_PPC64)
-DEF_HELPER_FLAGS_2(store_slb, TCG_CALL_CONST, void, tl, tl)
-DEF_HELPER_1(load_slb_esid, tl, tl)
-DEF_HELPER_1(load_slb_vsid, tl, tl)
-DEF_HELPER_FLAGS_0(slbia, TCG_CALL_CONST, void)
-DEF_HELPER_FLAGS_1(slbie, TCG_CALL_CONST, void, tl)
+DEF_HELPER_FLAGS_3(store_slb, TCG_CALL_CONST, void, env, tl, tl)
+DEF_HELPER_2(load_slb_esid, tl, env, tl)
+DEF_HELPER_2(load_slb_vsid, tl, env, tl)
+DEF_HELPER_FLAGS_1(slbia, TCG_CALL_CONST, void, env)
+DEF_HELPER_FLAGS_2(slbie, TCG_CALL_CONST, void, env, tl)
#endif
-DEF_HELPER_FLAGS_1(load_sr, TCG_CALL_CONST, tl, tl);
-DEF_HELPER_FLAGS_2(store_sr, TCG_CALL_CONST, void, tl, tl)
+DEF_HELPER_FLAGS_2(load_sr, TCG_CALL_CONST, tl, env, tl);
+DEF_HELPER_FLAGS_3(store_sr, TCG_CALL_CONST, void, env, tl, tl)
DEF_HELPER_FLAGS_1(602_mfrom, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl)
DEF_HELPER_1(msgsnd, void, tl)
@@ -365,7 +365,7 @@ DEF_HELPER_2(msgclr, void, env, tl)
DEF_HELPER_4(dlmzb, tl, env, tl, tl, i32)
DEF_HELPER_FLAGS_1(clcs, TCG_CALL_CONST | TCG_CALL_PURE, tl, i32)
#if !defined(CONFIG_USER_ONLY)
-DEF_HELPER_1(rac, tl, tl)
+DEF_HELPER_2(rac, tl, env, tl)
#endif
DEF_HELPER_3(div, tl, env, tl, tl)
DEF_HELPER_3(divo, tl, env, tl, tl)
@@ -405,12 +405,12 @@ DEF_HELPER_1(store_40x_dbcr0, void, tl)
DEF_HELPER_1(store_40x_sler, void, tl)
DEF_HELPER_1(store_booke_tcr, void, tl)
DEF_HELPER_1(store_booke_tsr, void, tl)
-DEF_HELPER_2(store_ibatl, void, i32, tl)
-DEF_HELPER_2(store_ibatu, void, i32, tl)
-DEF_HELPER_2(store_dbatl, void, i32, tl)
-DEF_HELPER_2(store_dbatu, void, i32, tl)
-DEF_HELPER_2(store_601_batl, void, i32, tl)
-DEF_HELPER_2(store_601_batu, void, i32, tl)
+DEF_HELPER_3(store_ibatl, void, env, i32, tl)
+DEF_HELPER_3(store_ibatu, void, env, i32, tl)
+DEF_HELPER_3(store_dbatl, void, env, i32, tl)
+DEF_HELPER_3(store_dbatu, void, env, i32, tl)
+DEF_HELPER_3(store_601_batl, void, env, i32, tl)
+DEF_HELPER_3(store_601_batu, void, env, i32, tl)
#endif
#include "def-helper.h"
diff --git a/target-ppc/mmu_helper.c b/target-ppc/mmu_helper.c
index 81800b6..7bd6230 100644
--- a/target-ppc/mmu_helper.c
+++ b/target-ppc/mmu_helper.c
@@ -17,7 +17,6 @@
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include "cpu.h"
-#include "dyngen-exec.h"
#include "helper.h"
//#define DEBUG_SOFTWARE_TLB
@@ -32,38 +31,38 @@
/* SPR accesses */
#if !defined(CONFIG_USER_ONLY)
-void helper_store_ibatu(uint32_t nr, target_ulong val)
+void helper_store_ibatu(CPUPPCState *env, uint32_t nr, target_ulong val)
{
ppc_store_ibatu(env, nr, val);
}
-void helper_store_ibatl(uint32_t nr, target_ulong val)
+void helper_store_ibatl(CPUPPCState *env, uint32_t nr, target_ulong val)
{
ppc_store_ibatl(env, nr, val);
}
-void helper_store_dbatu(uint32_t nr, target_ulong val)
+void helper_store_dbatu(CPUPPCState *env, uint32_t nr, target_ulong val)
{
ppc_store_dbatu(env, nr, val);
}
-void helper_store_dbatl(uint32_t nr, target_ulong val)
+void helper_store_dbatl(CPUPPCState *env, uint32_t nr, target_ulong val)
{
ppc_store_dbatl(env, nr, val);
}
-void helper_store_601_batl(uint32_t nr, target_ulong val)
+void helper_store_601_batl(CPUPPCState *env, uint32_t nr, target_ulong val)
{
ppc_store_ibatl_601(env, nr, val);
}
-void helper_store_601_batu(uint32_t nr, target_ulong val)
+void helper_store_601_batu(CPUPPCState *env, uint32_t nr, target_ulong val)
{
ppc_store_ibatu_601(env, nr, val);
}
/* Segment registers load and store */
-target_ulong helper_load_sr(target_ulong sr_num)
+target_ulong helper_load_sr(CPUPPCState *env, target_ulong sr_num)
{
#if defined(TARGET_PPC64)
if (env->mmu_model & POWERPC_MMU_64) {
@@ -73,14 +72,14 @@ target_ulong helper_load_sr(target_ulong sr_num)
return env->sr[sr_num];
}
-void helper_store_sr(target_ulong sr_num, target_ulong val)
+void helper_store_sr(CPUPPCState *env, target_ulong sr_num, target_ulong val)
{
ppc_store_sr(env, sr_num, val);
}
/* SLB management */
#if defined(TARGET_PPC64)
-void helper_store_slb(target_ulong rb, target_ulong rs)
+void helper_store_slb(CPUPPCState *env, target_ulong rb, target_ulong rs)
{
if (ppc_store_slb(env, rb, rs) < 0) {
helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
@@ -88,7 +87,7 @@ void helper_store_slb(target_ulong rb, target_ulong rs)
}
}
-target_ulong helper_load_slb_esid(target_ulong rb)
+target_ulong helper_load_slb_esid(CPUPPCState *env, target_ulong rb)
{
target_ulong rt;
@@ -99,7 +98,7 @@ target_ulong helper_load_slb_esid(target_ulong rb)
return rt;
}
-target_ulong helper_load_slb_vsid(target_ulong rb)
+target_ulong helper_load_slb_vsid(CPUPPCState *env, target_ulong rb)
{
target_ulong rt;
@@ -110,12 +109,12 @@ target_ulong helper_load_slb_vsid(target_ulong rb)
return rt;
}
-void helper_slbia(void)
+void helper_slbia(CPUPPCState *env)
{
ppc_slb_invalidate_all(env);
}
-void helper_slbie(target_ulong addr)
+void helper_slbie(CPUPPCState *env, target_ulong addr)
{
ppc_slb_invalidate_one(env, addr);
}
@@ -123,19 +122,19 @@ void helper_slbie(target_ulong addr)
#endif /* defined(TARGET_PPC64) */
/* TLB management */
-void helper_tlbia(void)
+void helper_tlbia(CPUPPCState *env)
{
ppc_tlb_invalidate_all(env);
}
-void helper_tlbie(target_ulong addr)
+void helper_tlbie(CPUPPCState *env, target_ulong addr)
{
ppc_tlb_invalidate_one(env, addr);
}
/* Software driven TLBs management */
/* PowerPC 602/603 software TLB load instructions helpers */
-static void do_6xx_tlb(target_ulong new_EPN, int is_code)
+static void do_6xx_tlb(CPUPPCState *env, target_ulong new_EPN, int is_code)
{
target_ulong RPN, CMP, EPN;
int way;
@@ -158,18 +157,18 @@ static void do_6xx_tlb(target_ulong new_EPN, int is_code)
way, is_code, CMP, RPN);
}
-void helper_6xx_tlbd(target_ulong EPN)
+void helper_6xx_tlbd(CPUPPCState *env, target_ulong EPN)
{
- do_6xx_tlb(EPN, 0);
+ do_6xx_tlb(env, EPN, 0);
}
-void helper_6xx_tlbi(target_ulong EPN)
+void helper_6xx_tlbi(CPUPPCState *env, target_ulong EPN)
{
- do_6xx_tlb(EPN, 1);
+ do_6xx_tlb(env, EPN, 1);
}
/* PowerPC 74xx software TLB load instructions helpers */
-static void do_74xx_tlb(target_ulong new_EPN, int is_code)
+static void do_74xx_tlb(CPUPPCState *env, target_ulong new_EPN, int is_code)
{
target_ulong RPN, CMP, EPN;
int way;
@@ -187,20 +186,20 @@ static void do_74xx_tlb(target_ulong new_EPN, int is_code)
way, is_code, CMP, RPN);
}
-void helper_74xx_tlbd(target_ulong EPN)
+void helper_74xx_tlbd(CPUPPCState *env, target_ulong EPN)
{
- do_74xx_tlb(EPN, 0);
+ do_74xx_tlb(env, EPN, 0);
}
-void helper_74xx_tlbi(target_ulong EPN)
+void helper_74xx_tlbi(CPUPPCState *env, target_ulong EPN)
{
- do_74xx_tlb(EPN, 1);
+ do_74xx_tlb(env, EPN, 1);
}
/*****************************************************************************/
/* PowerPC 601 specific instructions (POWER bridge) */
-target_ulong helper_rac(target_ulong addr)
+target_ulong helper_rac(CPUPPCState *env, target_ulong addr)
{
mmu_ctx_t ctx;
int nb_BATs;
@@ -303,7 +302,7 @@ static inline int booke_page_size_to_tlb(target_ulong page_size)
#define PPC4XX_TLBLO_ATTR_MASK 0x000000FF
#define PPC4XX_TLBLO_RPN_MASK 0xFFFFFC00
-target_ulong helper_4xx_tlbre_hi(target_ulong entry)
+target_ulong helper_4xx_tlbre_hi(CPUPPCState *env, target_ulong entry)
{
ppcemb_tlb_t *tlb;
target_ulong ret;
@@ -324,7 +323,7 @@ target_ulong helper_4xx_tlbre_hi(target_ulong entry)
return ret;
}
-target_ulong helper_4xx_tlbre_lo(target_ulong entry)
+target_ulong helper_4xx_tlbre_lo(CPUPPCState *env, target_ulong entry)
{
ppcemb_tlb_t *tlb;
target_ulong ret;
@@ -341,7 +340,8 @@ target_ulong helper_4xx_tlbre_lo(target_ulong entry)
return ret;
}
-void helper_4xx_tlbwe_hi(target_ulong entry, target_ulong val)
+void helper_4xx_tlbwe_hi(CPUPPCState *env, target_ulong entry,
+ target_ulong val)
{
ppcemb_tlb_t *tlb;
target_ulong page, end;
@@ -400,7 +400,8 @@ void helper_4xx_tlbwe_hi(target_ulong entry, target_ulong val)
}
}
-void helper_4xx_tlbwe_lo(target_ulong entry, target_ulong val)
+void helper_4xx_tlbwe_lo(CPUPPCState *env, target_ulong entry,
+ target_ulong val)
{
ppcemb_tlb_t *tlb;
@@ -426,13 +427,14 @@ void helper_4xx_tlbwe_lo(target_ulong entry, target_ulong val)
tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
}
-target_ulong helper_4xx_tlbsx(target_ulong address)
+target_ulong helper_4xx_tlbsx(CPUPPCState *env, target_ulong address)
{
return ppcemb_tlb_search(env, address, env->spr[SPR_40x_PID]);
}
/* PowerPC 440 TLB management */
-void helper_440_tlbwe(uint32_t word, target_ulong entry, target_ulong value)
+void helper_440_tlbwe(CPUPPCState *env, uint32_t word, target_ulong entry,
+ target_ulong value)
{
ppcemb_tlb_t *tlb;
target_ulong EPN, RPN, size;
@@ -504,7 +506,8 @@ void helper_440_tlbwe(uint32_t word, target_ulong entry, target_ulong value)
}
}
-target_ulong helper_440_tlbre(uint32_t word, target_ulong entry)
+target_ulong helper_440_tlbre(CPUPPCState *env, uint32_t word,
+ target_ulong entry)
{
ppcemb_tlb_t *tlb;
target_ulong ret;
@@ -559,7 +562,7 @@ target_ulong helper_440_tlbre(uint32_t word, target_ulong entry)
return ret;
}
-target_ulong helper_440_tlbsx(target_ulong address)
+target_ulong helper_440_tlbsx(CPUPPCState *env, target_ulong address)
{
return ppcemb_tlb_search(env, address, env->spr[SPR_440_MMUCR] & 0xFF);
}
@@ -583,14 +586,14 @@ static ppcmas_tlb_t *booke206_cur_tlb(CPUPPCState *env)
return booke206_get_tlbm(env, tlb, ea, esel);
}
-void helper_booke_setpid(uint32_t pidn, target_ulong pid)
+void helper_booke_setpid(CPUPPCState *env, uint32_t pidn, target_ulong pid)
{
env->spr[pidn] = pid;
/* changing PIDs mean we're in a different address space now */
tlb_flush(env, 1);
}
-void helper_booke206_tlbwe(void)
+void helper_booke206_tlbwe(CPUPPCState *env)
{
uint32_t tlbncfg, tlbn;
ppcmas_tlb_t *tlb;
@@ -687,7 +690,7 @@ static inline void booke206_tlb_to_mas(CPUPPCState *env, ppcmas_tlb_t *tlb)
env->spr[SPR_BOOKE_MAS7] = tlb->mas7_3 >> 32;
}
-void helper_booke206_tlbre(void)
+void helper_booke206_tlbre(CPUPPCState *env)
{
ppcmas_tlb_t *tlb = NULL;
@@ -699,7 +702,7 @@ void helper_booke206_tlbre(void)
}
}
-void helper_booke206_tlbsx(target_ulong address)
+void helper_booke206_tlbsx(CPUPPCState *env, target_ulong address)
{
ppcmas_tlb_t *tlb = NULL;
int i, j;
@@ -773,7 +776,7 @@ static inline void booke206_invalidate_ea_tlb(CPUPPCState *env, int tlbn,
}
}
-void helper_booke206_tlbivax(target_ulong address)
+void helper_booke206_tlbivax(CPUPPCState *env, target_ulong address)
{
if (address & 0x4) {
/* flush all entries */
@@ -798,13 +801,13 @@ void helper_booke206_tlbivax(target_ulong address)
}
}
-void helper_booke206_tlbilx0(target_ulong address)
+void helper_booke206_tlbilx0(CPUPPCState *env, target_ulong address)
{
/* XXX missing LPID handling */
booke206_flush_tlb(env, -1, 1);
}
-void helper_booke206_tlbilx1(target_ulong address)
+void helper_booke206_tlbilx1(CPUPPCState *env, target_ulong address)
{
int i, j;
int tid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID);
@@ -825,7 +828,7 @@ void helper_booke206_tlbilx1(target_ulong address)
tlb_flush(env, 1);
}
-void helper_booke206_tlbilx3(target_ulong address)
+void helper_booke206_tlbilx3(CPUPPCState *env, target_ulong address)
{
int i, j;
ppcmas_tlb_t *tlb;
@@ -865,7 +868,7 @@ void helper_booke206_tlbilx3(target_ulong address)
tlb_flush(env, 1);
}
-void helper_booke206_tlbflush(uint32_t type)
+void helper_booke206_tlbflush(CPUPPCState *env, uint32_t type)
{
int flags = 0;
diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index eb3cd5a..446f97e 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -4200,7 +4200,7 @@ static void gen_mfsr(DisasContext *ctx)
return;
}
t0 = tcg_const_tl(SR(ctx->opcode));
- gen_helper_load_sr(cpu_gpr[rD(ctx->opcode)], t0);
+ gen_helper_load_sr(cpu_gpr[rD(ctx->opcode)], cpu_env, t0);
tcg_temp_free(t0);
#endif
}
@@ -4219,7 +4219,7 @@ static void gen_mfsrin(DisasContext *ctx)
t0 = tcg_temp_new();
tcg_gen_shri_tl(t0, cpu_gpr[rB(ctx->opcode)], 28);
tcg_gen_andi_tl(t0, t0, 0xF);
- gen_helper_load_sr(cpu_gpr[rD(ctx->opcode)], t0);
+ gen_helper_load_sr(cpu_gpr[rD(ctx->opcode)], cpu_env, t0);
tcg_temp_free(t0);
#endif
}
@@ -4236,7 +4236,7 @@ static void gen_mtsr(DisasContext *ctx)
return;
}
t0 = tcg_const_tl(SR(ctx->opcode));
- gen_helper_store_sr(t0, cpu_gpr[rS(ctx->opcode)]);
+ gen_helper_store_sr(cpu_env, t0, cpu_gpr[rS(ctx->opcode)]);
tcg_temp_free(t0);
#endif
}
@@ -4255,7 +4255,7 @@ static void gen_mtsrin(DisasContext *ctx)
t0 = tcg_temp_new();
tcg_gen_shri_tl(t0, cpu_gpr[rB(ctx->opcode)], 28);
tcg_gen_andi_tl(t0, t0, 0xF);
- gen_helper_store_sr(t0, cpu_gpr[rD(ctx->opcode)]);
+ gen_helper_store_sr(cpu_env, t0, cpu_gpr[rD(ctx->opcode)]);
tcg_temp_free(t0);
#endif
}
@@ -4275,7 +4275,7 @@ static void gen_mfsr_64b(DisasContext *ctx)
return;
}
t0 = tcg_const_tl(SR(ctx->opcode));
- gen_helper_load_sr(cpu_gpr[rD(ctx->opcode)], t0);
+ gen_helper_load_sr(cpu_gpr[rD(ctx->opcode)], cpu_env, t0);
tcg_temp_free(t0);
#endif
}
@@ -4294,7 +4294,7 @@ static void gen_mfsrin_64b(DisasContext *ctx)
t0 = tcg_temp_new();
tcg_gen_shri_tl(t0, cpu_gpr[rB(ctx->opcode)], 28);
tcg_gen_andi_tl(t0, t0, 0xF);
- gen_helper_load_sr(cpu_gpr[rD(ctx->opcode)], t0);
+ gen_helper_load_sr(cpu_gpr[rD(ctx->opcode)], cpu_env, t0);
tcg_temp_free(t0);
#endif
}
@@ -4311,7 +4311,7 @@ static void gen_mtsr_64b(DisasContext *ctx)
return;
}
t0 = tcg_const_tl(SR(ctx->opcode));
- gen_helper_store_sr(t0, cpu_gpr[rS(ctx->opcode)]);
+ gen_helper_store_sr(cpu_env, t0, cpu_gpr[rS(ctx->opcode)]);
tcg_temp_free(t0);
#endif
}
@@ -4330,7 +4330,7 @@ static void gen_mtsrin_64b(DisasContext *ctx)
t0 = tcg_temp_new();
tcg_gen_shri_tl(t0, cpu_gpr[rB(ctx->opcode)], 28);
tcg_gen_andi_tl(t0, t0, 0xF);
- gen_helper_store_sr(t0, cpu_gpr[rS(ctx->opcode)]);
+ gen_helper_store_sr(cpu_env, t0, cpu_gpr[rS(ctx->opcode)]);
tcg_temp_free(t0);
#endif
}
@@ -4345,7 +4345,8 @@ static void gen_slbmte(DisasContext *ctx)
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
return;
}
- gen_helper_store_slb(cpu_gpr[rB(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]);
+ gen_helper_store_slb(cpu_env, cpu_gpr[rB(ctx->opcode)],
+ cpu_gpr[rS(ctx->opcode)]);
#endif
}
@@ -4358,7 +4359,7 @@ static void gen_slbmfee(DisasContext *ctx)
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
return;
}
- gen_helper_load_slb_esid(cpu_gpr[rS(ctx->opcode)],
+ gen_helper_load_slb_esid(cpu_gpr[rS(ctx->opcode)], cpu_env,
cpu_gpr[rB(ctx->opcode)]);
#endif
}
@@ -4372,7 +4373,7 @@ static void gen_slbmfev(DisasContext *ctx)
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
return;
}
- gen_helper_load_slb_vsid(cpu_gpr[rS(ctx->opcode)],
+ gen_helper_load_slb_vsid(cpu_gpr[rS(ctx->opcode)], cpu_env,
cpu_gpr[rB(ctx->opcode)]);
#endif
}
@@ -4391,7 +4392,7 @@ static void gen_tlbia(DisasContext *ctx)
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
return;
}
- gen_helper_tlbia();
+ gen_helper_tlbia(cpu_env);
#endif
}
@@ -4405,7 +4406,7 @@ static void gen_tlbiel(DisasContext *ctx)
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
return;
}
- gen_helper_tlbie(cpu_gpr[rB(ctx->opcode)]);
+ gen_helper_tlbie(cpu_env, cpu_gpr[rB(ctx->opcode)]);
#endif
}
@@ -4423,11 +4424,11 @@ static void gen_tlbie(DisasContext *ctx)
if (!ctx->sf_mode) {
TCGv t0 = tcg_temp_new();
tcg_gen_ext32u_tl(t0, cpu_gpr[rB(ctx->opcode)]);
- gen_helper_tlbie(t0);
+ gen_helper_tlbie(cpu_env, t0);
tcg_temp_free(t0);
} else
#endif
- gen_helper_tlbie(cpu_gpr[rB(ctx->opcode)]);
+ gen_helper_tlbie(cpu_env, cpu_gpr[rB(ctx->opcode)]);
#endif
}
@@ -4459,7 +4460,7 @@ static void gen_slbia(DisasContext *ctx)
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
return;
}
- gen_helper_slbia();
+ gen_helper_slbia(cpu_env);
#endif
}
@@ -4473,7 +4474,7 @@ static void gen_slbie(DisasContext *ctx)
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
return;
}
- gen_helper_slbie(cpu_gpr[rB(ctx->opcode)]);
+ gen_helper_slbie(cpu_env, cpu_gpr[rB(ctx->opcode)]);
#endif
}
#endif
@@ -5194,7 +5195,7 @@ static void gen_tlbld_6xx(DisasContext *ctx)
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
return;
}
- gen_helper_6xx_tlbd(cpu_gpr[rB(ctx->opcode)]);
+ gen_helper_6xx_tlbd(cpu_env, cpu_gpr[rB(ctx->opcode)]);
#endif
}
@@ -5208,7 +5209,7 @@ static void gen_tlbli_6xx(DisasContext *ctx)
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
return;
}
- gen_helper_6xx_tlbi(cpu_gpr[rB(ctx->opcode)]);
+ gen_helper_6xx_tlbi(cpu_env, cpu_gpr[rB(ctx->opcode)]);
#endif
}
@@ -5224,7 +5225,7 @@ static void gen_tlbld_74xx(DisasContext *ctx)
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
return;
}
- gen_helper_74xx_tlbd(cpu_gpr[rB(ctx->opcode)]);
+ gen_helper_74xx_tlbd(cpu_env, cpu_gpr[rB(ctx->opcode)]);
#endif
}
@@ -5238,7 +5239,7 @@ static void gen_tlbli_74xx(DisasContext *ctx)
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
return;
}
- gen_helper_74xx_tlbi(cpu_gpr[rB(ctx->opcode)]);
+ gen_helper_74xx_tlbi(cpu_env, cpu_gpr[rB(ctx->opcode)]);
#endif
}
@@ -5286,7 +5287,7 @@ static void gen_mfsri(DisasContext *ctx)
gen_addr_reg_index(ctx, t0);
tcg_gen_shri_tl(t0, t0, 28);
tcg_gen_andi_tl(t0, t0, 0xF);
- gen_helper_load_sr(cpu_gpr[rd], t0);
+ gen_helper_load_sr(cpu_gpr[rd], cpu_env, t0);
tcg_temp_free(t0);
if (ra != 0 && ra != rd)
tcg_gen_mov_tl(cpu_gpr[ra], cpu_gpr[rd]);
@@ -5305,7 +5306,7 @@ static void gen_rac(DisasContext *ctx)
}
t0 = tcg_temp_new();
gen_addr_reg_index(ctx, t0);
- gen_helper_rac(cpu_gpr[rD(ctx->opcode)], t0);
+ gen_helper_rac(cpu_gpr[rD(ctx->opcode)], cpu_env, t0);
tcg_temp_free(t0);
#endif
}
@@ -5483,7 +5484,7 @@ static void gen_tlbiva(DisasContext *ctx)
}
t0 = tcg_temp_new();
gen_addr_reg_index(ctx, t0);
- gen_helper_tlbie(cpu_gpr[rB(ctx->opcode)]);
+ gen_helper_tlbie(cpu_env, cpu_gpr[rB(ctx->opcode)]);
tcg_temp_free(t0);
#endif
}
@@ -5946,10 +5947,12 @@ static void gen_tlbre_40x(DisasContext *ctx)
}
switch (rB(ctx->opcode)) {
case 0:
- gen_helper_4xx_tlbre_hi(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
+ gen_helper_4xx_tlbre_hi(cpu_gpr[rD(ctx->opcode)], cpu_env,
+ cpu_gpr[rA(ctx->opcode)]);
break;
case 1:
- gen_helper_4xx_tlbre_lo(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
+ gen_helper_4xx_tlbre_lo(cpu_gpr[rD(ctx->opcode)], cpu_env,
+ cpu_gpr[rA(ctx->opcode)]);
break;
default:
gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
@@ -5971,7 +5974,7 @@ static void gen_tlbsx_40x(DisasContext *ctx)
}
t0 = tcg_temp_new();
gen_addr_reg_index(ctx, t0);
- gen_helper_4xx_tlbsx(cpu_gpr[rD(ctx->opcode)], t0);
+ gen_helper_4xx_tlbsx(cpu_gpr[rD(ctx->opcode)], cpu_env, t0);
tcg_temp_free(t0);
if (Rc(ctx->opcode)) {
int l1 = gen_new_label();
@@ -5997,10 +6000,12 @@ static void gen_tlbwe_40x(DisasContext *ctx)
}
switch (rB(ctx->opcode)) {
case 0:
- gen_helper_4xx_tlbwe_hi(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]);
+ gen_helper_4xx_tlbwe_hi(cpu_env, cpu_gpr[rA(ctx->opcode)],
+ cpu_gpr[rS(ctx->opcode)]);
break;
case 1:
- gen_helper_4xx_tlbwe_lo(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]);
+ gen_helper_4xx_tlbwe_lo(cpu_env, cpu_gpr[rA(ctx->opcode)],
+ cpu_gpr[rS(ctx->opcode)]);
break;
default:
gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
@@ -6027,7 +6032,8 @@ static void gen_tlbre_440(DisasContext *ctx)
case 2:
{
TCGv_i32 t0 = tcg_const_i32(rB(ctx->opcode));
- gen_helper_440_tlbre(cpu_gpr[rD(ctx->opcode)], t0, cpu_gpr[rA(ctx->opcode)]);
+ gen_helper_440_tlbre(cpu_gpr[rD(ctx->opcode)], cpu_env,
+ t0, cpu_gpr[rA(ctx->opcode)]);
tcg_temp_free_i32(t0);
}
break;
@@ -6051,7 +6057,7 @@ static void gen_tlbsx_440(DisasContext *ctx)
}
t0 = tcg_temp_new();
gen_addr_reg_index(ctx, t0);
- gen_helper_440_tlbsx(cpu_gpr[rD(ctx->opcode)], t0);
+ gen_helper_440_tlbsx(cpu_gpr[rD(ctx->opcode)], cpu_env, t0);
tcg_temp_free(t0);
if (Rc(ctx->opcode)) {
int l1 = gen_new_label();
@@ -6081,7 +6087,8 @@ static void gen_tlbwe_440(DisasContext *ctx)
case 2:
{
TCGv_i32 t0 = tcg_const_i32(rB(ctx->opcode));
- gen_helper_440_tlbwe(t0, cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]);
+ gen_helper_440_tlbwe(cpu_env, t0, cpu_gpr[rA(ctx->opcode)],
+ cpu_gpr[rS(ctx->opcode)]);
tcg_temp_free_i32(t0);
}
break;
@@ -6105,7 +6112,7 @@ static void gen_tlbre_booke206(DisasContext *ctx)
return;
}
- gen_helper_booke206_tlbre();
+ gen_helper_booke206_tlbre(cpu_env);
#endif
}
@@ -6129,7 +6136,7 @@ static void gen_tlbsx_booke206(DisasContext *ctx)
}
tcg_gen_add_tl(t0, t0, cpu_gpr[rB(ctx->opcode)]);
- gen_helper_booke206_tlbsx(t0);
+ gen_helper_booke206_tlbsx(cpu_env, t0);
#endif
}
@@ -6144,7 +6151,7 @@ static void gen_tlbwe_booke206(DisasContext *ctx)
return;
}
gen_update_nip(ctx, ctx->nip - 4);
- gen_helper_booke206_tlbwe();
+ gen_helper_booke206_tlbwe(cpu_env);
#endif
}
@@ -6162,7 +6169,7 @@ static void gen_tlbivax_booke206(DisasContext *ctx)
t0 = tcg_temp_new();
gen_addr_reg_index(ctx, t0);
- gen_helper_booke206_tlbivax(t0);
+ gen_helper_booke206_tlbivax(cpu_env, t0);
#endif
}
@@ -6182,13 +6189,13 @@ static void gen_tlbilx_booke206(DisasContext *ctx)
switch((ctx->opcode >> 21) & 0x3) {
case 0:
- gen_helper_booke206_tlbilx0(t0);
+ gen_helper_booke206_tlbilx0(cpu_env, t0);
break;
case 1:
- gen_helper_booke206_tlbilx1(t0);
+ gen_helper_booke206_tlbilx1(cpu_env, t0);
break;
case 3:
- gen_helper_booke206_tlbilx3(t0);
+ gen_helper_booke206_tlbilx3(cpu_env, t0);
break;
default:
gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index 6f61175..1e15fd9 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -279,28 +279,28 @@ static void spr_read_ibat_h (void *opaque, int gprn, int sprn)
static void spr_write_ibatu (void *opaque, int sprn, int gprn)
{
TCGv_i32 t0 = tcg_const_i32((sprn - SPR_IBAT0U) / 2);
- gen_helper_store_ibatu(t0, cpu_gpr[gprn]);
+ gen_helper_store_ibatu(cpu_env, t0, cpu_gpr[gprn]);
tcg_temp_free_i32(t0);
}
static void spr_write_ibatu_h (void *opaque, int sprn, int gprn)
{
TCGv_i32 t0 = tcg_const_i32(((sprn - SPR_IBAT4U) / 2) + 4);
- gen_helper_store_ibatu(t0, cpu_gpr[gprn]);
+ gen_helper_store_ibatu(cpu_env, t0, cpu_gpr[gprn]);
tcg_temp_free_i32(t0);
}
static void spr_write_ibatl (void *opaque, int sprn, int gprn)
{
TCGv_i32 t0 = tcg_const_i32((sprn - SPR_IBAT0L) / 2);
- gen_helper_store_ibatl(t0, cpu_gpr[gprn]);
+ gen_helper_store_ibatl(cpu_env, t0, cpu_gpr[gprn]);
tcg_temp_free_i32(t0);
}
static void spr_write_ibatl_h (void *opaque, int sprn, int gprn)
{
TCGv_i32 t0 = tcg_const_i32(((sprn - SPR_IBAT4L) / 2) + 4);
- gen_helper_store_ibatl(t0, cpu_gpr[gprn]);
+ gen_helper_store_ibatl(cpu_env, t0, cpu_gpr[gprn]);
tcg_temp_free_i32(t0);
}
@@ -319,28 +319,28 @@ static void spr_read_dbat_h (void *opaque, int gprn, int sprn)
static void spr_write_dbatu (void *opaque, int sprn, int gprn)
{
TCGv_i32 t0 = tcg_const_i32((sprn - SPR_DBAT0U) / 2);
- gen_helper_store_dbatu(t0, cpu_gpr[gprn]);
+ gen_helper_store_dbatu(cpu_env, t0, cpu_gpr[gprn]);
tcg_temp_free_i32(t0);
}
static void spr_write_dbatu_h (void *opaque, int sprn, int gprn)
{
TCGv_i32 t0 = tcg_const_i32(((sprn - SPR_DBAT4U) / 2) + 4);
- gen_helper_store_dbatu(t0, cpu_gpr[gprn]);
+ gen_helper_store_dbatu(cpu_env, t0, cpu_gpr[gprn]);
tcg_temp_free_i32(t0);
}
static void spr_write_dbatl (void *opaque, int sprn, int gprn)
{
TCGv_i32 t0 = tcg_const_i32((sprn - SPR_DBAT0L) / 2);
- gen_helper_store_dbatl(t0, cpu_gpr[gprn]);
+ gen_helper_store_dbatl(cpu_env, t0, cpu_gpr[gprn]);
tcg_temp_free_i32(t0);
}
static void spr_write_dbatl_h (void *opaque, int sprn, int gprn)
{
TCGv_i32 t0 = tcg_const_i32(((sprn - SPR_DBAT4L) / 2) + 4);
- gen_helper_store_dbatl(t0, cpu_gpr[gprn]);
+ gen_helper_store_dbatl(cpu_env, t0, cpu_gpr[gprn]);
tcg_temp_free_i32(t0);
}
@@ -421,14 +421,14 @@ static void spr_read_601_ubat (void *opaque, int gprn, int sprn)
static void spr_write_601_ubatu (void *opaque, int sprn, int gprn)
{
TCGv_i32 t0 = tcg_const_i32((sprn - SPR_IBAT0U) / 2);
- gen_helper_store_601_batl(t0, cpu_gpr[gprn]);
+ gen_helper_store_601_batl(cpu_env, t0, cpu_gpr[gprn]);
tcg_temp_free_i32(t0);
}
static void spr_write_601_ubatl (void *opaque, int sprn, int gprn)
{
TCGv_i32 t0 = tcg_const_i32((sprn - SPR_IBAT0U) / 2);
- gen_helper_store_601_batu(t0, cpu_gpr[gprn]);
+ gen_helper_store_601_batu(cpu_env, t0, cpu_gpr[gprn]);
tcg_temp_free_i32(t0);
}
#endif
@@ -1371,14 +1371,14 @@ static void spr_write_e500_l1csr0 (void *opaque, int sprn, int gprn)
static void spr_write_booke206_mmucsr0 (void *opaque, int sprn, int gprn)
{
TCGv_i32 t0 = tcg_const_i32(sprn);
- gen_helper_booke206_tlbflush(t0);
+ gen_helper_booke206_tlbflush(cpu_env, t0);
tcg_temp_free_i32(t0);
}
static void spr_write_booke_pid (void *opaque, int sprn, int gprn)
{
TCGv_i32 t0 = tcg_const_i32(sprn);
- gen_helper_booke_setpid(t0, cpu_gpr[gprn]);
+ gen_helper_booke_setpid(cpu_env, t0, cpu_gpr[gprn]);
tcg_temp_free_i32(t0);
}
#endif
--
1.6.0.2
^ permalink raw reply related [flat|nested] 89+ messages in thread
* [Qemu-devel] [PATCH 12/72] ppc: Avoid a warning with the next patch
2012-06-23 23:06 [Qemu-devel] [PULL 00/72] ppc patch queue 2012-06-24 Alexander Graf
` (10 preceding siblings ...)
2012-06-23 23:06 ` [Qemu-devel] [PATCH 11/72] ppc: Avoid AREG0 for MMU etc. helpers Alexander Graf
@ 2012-06-23 23:06 ` Alexander Graf
2012-06-23 23:06 ` [Qemu-devel] [PATCH 13/72] ppc: Move MMU helpers from helper.c to mmu_helper.c Alexander Graf
` (60 subsequent siblings)
72 siblings, 0 replies; 89+ messages in thread
From: Alexander Graf @ 2012-06-23 23:06 UTC (permalink / raw)
To: qemu-devel qemu-devel
Cc: Blue Swirl, qemu-ppc Mailing List, Andreas Färber,
Aurelien Jarno
From: Blue Swirl <blauwirbel@gmail.com>
When the code is moved together by the next patch, compiler
detects a possible uninitialized variable use. Avoid the warning
by initializing the variables.
Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Andreas Färber <afaerber@suse.de>
Signed-off-by: Alexander Graf <agraf@suse.de>
---
target-ppc/mmu_helper.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/target-ppc/mmu_helper.c b/target-ppc/mmu_helper.c
index 7bd6230..e79b8f2 100644
--- a/target-ppc/mmu_helper.c
+++ b/target-ppc/mmu_helper.c
@@ -89,7 +89,7 @@ void helper_store_slb(CPUPPCState *env, target_ulong rb, target_ulong rs)
target_ulong helper_load_slb_esid(CPUPPCState *env, target_ulong rb)
{
- target_ulong rt;
+ target_ulong rt = 0;
if (ppc_load_slb_esid(env, rb, &rt) < 0) {
helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
@@ -100,7 +100,7 @@ target_ulong helper_load_slb_esid(CPUPPCState *env, target_ulong rb)
target_ulong helper_load_slb_vsid(CPUPPCState *env, target_ulong rb)
{
- target_ulong rt;
+ target_ulong rt = 0;
if (ppc_load_slb_vsid(env, rb, &rt) < 0) {
helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
--
1.6.0.2
^ permalink raw reply related [flat|nested] 89+ messages in thread
* [Qemu-devel] [PATCH 13/72] ppc: Move MMU helpers from helper.c to mmu_helper.c
2012-06-23 23:06 [Qemu-devel] [PULL 00/72] ppc patch queue 2012-06-24 Alexander Graf
` (11 preceding siblings ...)
2012-06-23 23:06 ` [Qemu-devel] [PATCH 12/72] ppc: Avoid a warning with the next patch Alexander Graf
@ 2012-06-23 23:06 ` Alexander Graf
2012-06-23 23:06 ` [Qemu-devel] [PATCH 14/72] ppc: Cleanup MMU merge Alexander Graf
` (59 subsequent siblings)
72 siblings, 0 replies; 89+ messages in thread
From: Alexander Graf @ 2012-06-23 23:06 UTC (permalink / raw)
To: qemu-devel qemu-devel
Cc: Blue Swirl, qemu-ppc Mailing List, Andreas Färber,
Aurelien Jarno
From: Blue Swirl <blauwirbel@gmail.com>
Move more MMU helpers from helper.c to mmu_helper.c.
Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Andreas Färber <afaerber@suse.de>
[update to current helper.c state]
Signed-off-by: Alexander Graf <agraf@suse.de>
---
target-ppc/helper.c | 2475 -----------------------------------------------
target-ppc/mmu_helper.c | 2471 ++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 2471 insertions(+), 2475 deletions(-)
diff --git a/target-ppc/helper.c b/target-ppc/helper.c
index 17e72a9..24d109d 100644
--- a/target-ppc/helper.c
+++ b/target-ppc/helper.c
@@ -23,2483 +23,8 @@
#include "kvm_ppc.h"
#include "cpus.h"
-//#define DEBUG_MMU
-//#define DEBUG_BATS
-//#define DEBUG_SLB
-//#define DEBUG_SOFTWARE_TLB
-//#define DUMP_PAGE_TABLES
-//#define FLUSH_ALL_TLBS
-
-#ifdef DEBUG_MMU
-# define LOG_MMU(...) qemu_log(__VA_ARGS__)
-# define LOG_MMU_STATE(env) log_cpu_state((env), 0)
-#else
-# define LOG_MMU(...) do { } while (0)
-# define LOG_MMU_STATE(...) do { } while (0)
-#endif
-
-
-#ifdef DEBUG_SOFTWARE_TLB
-# define LOG_SWTLB(...) qemu_log(__VA_ARGS__)
-#else
-# define LOG_SWTLB(...) do { } while (0)
-#endif
-
-#ifdef DEBUG_BATS
-# define LOG_BATS(...) qemu_log(__VA_ARGS__)
-#else
-# define LOG_BATS(...) do { } while (0)
-#endif
-
-#ifdef DEBUG_SLB
-# define LOG_SLB(...) qemu_log(__VA_ARGS__)
-#else
-# define LOG_SLB(...) do { } while (0)
-#endif
-
-/*****************************************************************************/
-/* PowerPC MMU emulation */
-
-#if defined(CONFIG_USER_ONLY)
-int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw,
- int mmu_idx)
-{
- int exception, error_code;
-
- if (rw == 2) {
- exception = POWERPC_EXCP_ISI;
- error_code = 0x40000000;
- } else {
- exception = POWERPC_EXCP_DSI;
- error_code = 0x40000000;
- if (rw) {
- error_code |= 0x02000000;
- }
- env->spr[SPR_DAR] = address;
- env->spr[SPR_DSISR] = error_code;
- }
- env->exception_index = exception;
- env->error_code = error_code;
-
- return 1;
-}
-
-#else
-/* Common routines used by software and hardware TLBs emulation */
-static inline int pte_is_valid(target_ulong pte0)
-{
- return pte0 & 0x80000000 ? 1 : 0;
-}
-
-static inline void pte_invalidate(target_ulong *pte0)
-{
- *pte0 &= ~0x80000000;
-}
-
-#if defined(TARGET_PPC64)
-static inline int pte64_is_valid(target_ulong pte0)
-{
- return pte0 & 0x0000000000000001ULL ? 1 : 0;
-}
-
-static inline void pte64_invalidate(target_ulong *pte0)
-{
- *pte0 &= ~0x0000000000000001ULL;
-}
-#endif
-
-#define PTE_PTEM_MASK 0x7FFFFFBF
-#define PTE_CHECK_MASK (TARGET_PAGE_MASK | 0x7B)
-#if defined(TARGET_PPC64)
-#define PTE64_PTEM_MASK 0xFFFFFFFFFFFFFF80ULL
-#define PTE64_CHECK_MASK (TARGET_PAGE_MASK | 0x7F)
-#endif
-
-static inline int pp_check(int key, int pp, int nx)
-{
- int access;
-
- /* Compute access rights */
- /* When pp is 3/7, the result is undefined. Set it to noaccess */
- access = 0;
- if (key == 0) {
- switch (pp) {
- case 0x0:
- case 0x1:
- case 0x2:
- access |= PAGE_WRITE;
- /* No break here */
- case 0x3:
- case 0x6:
- access |= PAGE_READ;
- break;
- }
- } else {
- switch (pp) {
- case 0x0:
- case 0x6:
- access = 0;
- break;
- case 0x1:
- case 0x3:
- access = PAGE_READ;
- break;
- case 0x2:
- access = PAGE_READ | PAGE_WRITE;
- break;
- }
- }
- if (nx == 0) {
- access |= PAGE_EXEC;
- }
-
- return access;
-}
-
-static inline int check_prot(int prot, int rw, int access_type)
-{
- int ret;
-
- if (access_type == ACCESS_CODE) {
- if (prot & PAGE_EXEC) {
- ret = 0;
- } else {
- ret = -2;
- }
- } else if (rw) {
- if (prot & PAGE_WRITE) {
- ret = 0;
- } else {
- ret = -2;
- }
- } else {
- if (prot & PAGE_READ) {
- ret = 0;
- } else {
- ret = -2;
- }
- }
-
- return ret;
-}
-
-static inline int pte_check(mmu_ctx_t *ctx, int is_64b, target_ulong pte0,
- target_ulong pte1, int h, int rw, int type)
-{
- target_ulong ptem, mmask;
- int access, ret, pteh, ptev, pp;
-
- ret = -1;
- /* Check validity and table match */
-#if defined(TARGET_PPC64)
- if (is_64b) {
- ptev = pte64_is_valid(pte0);
- pteh = (pte0 >> 1) & 1;
- } else
-#endif
- {
- ptev = pte_is_valid(pte0);
- pteh = (pte0 >> 6) & 1;
- }
- if (ptev && h == pteh) {
- /* Check vsid & api */
-#if defined(TARGET_PPC64)
- if (is_64b) {
- ptem = pte0 & PTE64_PTEM_MASK;
- mmask = PTE64_CHECK_MASK;
- pp = (pte1 & 0x00000003) | ((pte1 >> 61) & 0x00000004);
- ctx->nx = (pte1 >> 2) & 1; /* No execute bit */
- ctx->nx |= (pte1 >> 3) & 1; /* Guarded bit */
- } else
-#endif
- {
- ptem = pte0 & PTE_PTEM_MASK;
- mmask = PTE_CHECK_MASK;
- pp = pte1 & 0x00000003;
- }
- if (ptem == ctx->ptem) {
- if (ctx->raddr != (target_phys_addr_t)-1ULL) {
- /* all matches should have equal RPN, WIMG & PP */
- if ((ctx->raddr & mmask) != (pte1 & mmask)) {
- qemu_log("Bad RPN/WIMG/PP\n");
- return -3;
- }
- }
- /* Compute access rights */
- access = pp_check(ctx->key, pp, ctx->nx);
- /* Keep the matching PTE informations */
- ctx->raddr = pte1;
- ctx->prot = access;
- ret = check_prot(ctx->prot, rw, type);
- if (ret == 0) {
- /* Access granted */
- LOG_MMU("PTE access granted !\n");
- } else {
- /* Access right violation */
- LOG_MMU("PTE access rejected\n");
- }
- }
- }
-
- return ret;
-}
-
-static inline int pte32_check(mmu_ctx_t *ctx, target_ulong pte0,
- target_ulong pte1, int h, int rw, int type)
-{
- return pte_check(ctx, 0, pte0, pte1, h, rw, type);
-}
-
-#if defined(TARGET_PPC64)
-static inline int pte64_check(mmu_ctx_t *ctx, target_ulong pte0,
- target_ulong pte1, int h, int rw, int type)
-{
- return pte_check(ctx, 1, pte0, pte1, h, rw, type);
-}
-#endif
-
-static inline int pte_update_flags(mmu_ctx_t *ctx, target_ulong *pte1p,
- int ret, int rw)
-{
- int store = 0;
-
- /* Update page flags */
- if (!(*pte1p & 0x00000100)) {
- /* Update accessed flag */
- *pte1p |= 0x00000100;
- store = 1;
- }
- if (!(*pte1p & 0x00000080)) {
- if (rw == 1 && ret == 0) {
- /* Update changed flag */
- *pte1p |= 0x00000080;
- store = 1;
- } else {
- /* Force page fault for first write access */
- ctx->prot &= ~PAGE_WRITE;
- }
- }
-
- return store;
-}
-
-/* Software driven TLB helpers */
-static inline int ppc6xx_tlb_getnum(CPUPPCState *env, target_ulong eaddr,
- int way, int is_code)
-{
- int nr;
-
- /* Select TLB num in a way from address */
- nr = (eaddr >> TARGET_PAGE_BITS) & (env->tlb_per_way - 1);
- /* Select TLB way */
- nr += env->tlb_per_way * way;
- /* 6xx have separate TLBs for instructions and data */
- if (is_code && env->id_tlbs == 1) {
- nr += env->nb_tlb;
- }
-
- return nr;
-}
-
-static inline void ppc6xx_tlb_invalidate_all(CPUPPCState *env)
-{
- ppc6xx_tlb_t *tlb;
- int nr, max;
-
- /* LOG_SWTLB("Invalidate all TLBs\n"); */
- /* Invalidate all defined software TLB */
- max = env->nb_tlb;
- if (env->id_tlbs == 1) {
- max *= 2;
- }
- for (nr = 0; nr < max; nr++) {
- tlb = &env->tlb.tlb6[nr];
- pte_invalidate(&tlb->pte0);
- }
- tlb_flush(env, 1);
-}
-
-static inline void ppc6xx_tlb_invalidate_virt2(CPUPPCState *env,
- target_ulong eaddr,
- int is_code, int match_epn)
-{
-#if !defined(FLUSH_ALL_TLBS)
- ppc6xx_tlb_t *tlb;
- int way, nr;
-
- /* Invalidate ITLB + DTLB, all ways */
- for (way = 0; way < env->nb_ways; way++) {
- nr = ppc6xx_tlb_getnum(env, eaddr, way, is_code);
- tlb = &env->tlb.tlb6[nr];
- if (pte_is_valid(tlb->pte0) && (match_epn == 0 || eaddr == tlb->EPN)) {
- LOG_SWTLB("TLB invalidate %d/%d " TARGET_FMT_lx "\n", nr,
- env->nb_tlb, eaddr);
- pte_invalidate(&tlb->pte0);
- tlb_flush_page(env, tlb->EPN);
- }
- }
-#else
- /* XXX: PowerPC specification say this is valid as well */
- ppc6xx_tlb_invalidate_all(env);
-#endif
-}
-
-static inline void ppc6xx_tlb_invalidate_virt(CPUPPCState *env,
- target_ulong eaddr, int is_code)
-{
- ppc6xx_tlb_invalidate_virt2(env, eaddr, is_code, 0);
-}
-
-void ppc6xx_tlb_store(CPUPPCState *env, target_ulong EPN, int way, int is_code,
- target_ulong pte0, target_ulong pte1)
-{
- ppc6xx_tlb_t *tlb;
- int nr;
-
- nr = ppc6xx_tlb_getnum(env, EPN, way, is_code);
- tlb = &env->tlb.tlb6[nr];
- LOG_SWTLB("Set TLB %d/%d EPN " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
- " PTE1 " TARGET_FMT_lx "\n", nr, env->nb_tlb, EPN, pte0, pte1);
- /* Invalidate any pending reference in QEMU for this virtual address */
- ppc6xx_tlb_invalidate_virt2(env, EPN, is_code, 1);
- tlb->pte0 = pte0;
- tlb->pte1 = pte1;
- tlb->EPN = EPN;
- /* Store last way for LRU mechanism */
- env->last_way = way;
-}
-
-static inline int ppc6xx_tlb_check(CPUPPCState *env, mmu_ctx_t *ctx,
- target_ulong eaddr, int rw, int access_type)
-{
- ppc6xx_tlb_t *tlb;
- int nr, best, way;
- int ret;
-
- best = -1;
- ret = -1; /* No TLB found */
- for (way = 0; way < env->nb_ways; way++) {
- nr = ppc6xx_tlb_getnum(env, eaddr, way,
- access_type == ACCESS_CODE ? 1 : 0);
- tlb = &env->tlb.tlb6[nr];
- /* This test "emulates" the PTE index match for hardware TLBs */
- if ((eaddr & TARGET_PAGE_MASK) != tlb->EPN) {
- LOG_SWTLB("TLB %d/%d %s [" TARGET_FMT_lx " " TARGET_FMT_lx
- "] <> " TARGET_FMT_lx "\n", nr, env->nb_tlb,
- pte_is_valid(tlb->pte0) ? "valid" : "inval",
- tlb->EPN, tlb->EPN + TARGET_PAGE_SIZE, eaddr);
- continue;
- }
- LOG_SWTLB("TLB %d/%d %s " TARGET_FMT_lx " <> " TARGET_FMT_lx " "
- TARGET_FMT_lx " %c %c\n", nr, env->nb_tlb,
- pte_is_valid(tlb->pte0) ? "valid" : "inval",
- tlb->EPN, eaddr, tlb->pte1,
- rw ? 'S' : 'L', access_type == ACCESS_CODE ? 'I' : 'D');
- switch (pte32_check(ctx, tlb->pte0, tlb->pte1, 0, rw, access_type)) {
- case -3:
- /* TLB inconsistency */
- return -1;
- case -2:
- /* Access violation */
- ret = -2;
- best = nr;
- break;
- case -1:
- default:
- /* No match */
- break;
- case 0:
- /* access granted */
- /* XXX: we should go on looping to check all TLBs consistency
- * but we can speed-up the whole thing as the
- * result would be undefined if TLBs are not consistent.
- */
- ret = 0;
- best = nr;
- goto done;
- }
- }
- if (best != -1) {
- done:
- LOG_SWTLB("found TLB at addr " TARGET_FMT_plx " prot=%01x ret=%d\n",
- ctx->raddr & TARGET_PAGE_MASK, ctx->prot, ret);
- /* Update page flags */
- pte_update_flags(ctx, &env->tlb.tlb6[best].pte1, ret, rw);
- }
-
- return ret;
-}
-
-/* Perform BAT hit & translation */
-static inline void bat_size_prot(CPUPPCState *env, target_ulong *blp,
- int *validp, int *protp, target_ulong *BATu,
- target_ulong *BATl)
-{
- target_ulong bl;
- int pp, valid, prot;
-
- bl = (*BATu & 0x00001FFC) << 15;
- valid = 0;
- prot = 0;
- if (((msr_pr == 0) && (*BATu & 0x00000002)) ||
- ((msr_pr != 0) && (*BATu & 0x00000001))) {
- valid = 1;
- pp = *BATl & 0x00000003;
- if (pp != 0) {
- prot = PAGE_READ | PAGE_EXEC;
- if (pp == 0x2) {
- prot |= PAGE_WRITE;
- }
- }
- }
- *blp = bl;
- *validp = valid;
- *protp = prot;
-}
-
-static inline void bat_601_size_prot(CPUPPCState *env, target_ulong *blp,
- int *validp, int *protp,
- target_ulong *BATu, target_ulong *BATl)
-{
- target_ulong bl;
- int key, pp, valid, prot;
-
- bl = (*BATl & 0x0000003F) << 17;
- LOG_BATS("b %02x ==> bl " TARGET_FMT_lx " msk " TARGET_FMT_lx "\n",
- (uint8_t)(*BATl & 0x0000003F), bl, ~bl);
- prot = 0;
- valid = (*BATl >> 6) & 1;
- if (valid) {
- pp = *BATu & 0x00000003;
- if (msr_pr == 0) {
- key = (*BATu >> 3) & 1;
- } else {
- key = (*BATu >> 2) & 1;
- }
- prot = pp_check(key, pp, 0);
- }
- *blp = bl;
- *validp = valid;
- *protp = prot;
-}
-
-static inline int get_bat(CPUPPCState *env, mmu_ctx_t *ctx,
- target_ulong virtual, int rw, int type)
-{
- target_ulong *BATlt, *BATut, *BATu, *BATl;
- target_ulong BEPIl, BEPIu, bl;
- int i, valid, prot;
- int ret = -1;
-
- LOG_BATS("%s: %cBAT v " TARGET_FMT_lx "\n", __func__,
- type == ACCESS_CODE ? 'I' : 'D', virtual);
- switch (type) {
- case ACCESS_CODE:
- BATlt = env->IBAT[1];
- BATut = env->IBAT[0];
- break;
- default:
- BATlt = env->DBAT[1];
- BATut = env->DBAT[0];
- break;
- }
- for (i = 0; i < env->nb_BATs; i++) {
- BATu = &BATut[i];
- BATl = &BATlt[i];
- BEPIu = *BATu & 0xF0000000;
- BEPIl = *BATu & 0x0FFE0000;
- if (unlikely(env->mmu_model == POWERPC_MMU_601)) {
- bat_601_size_prot(env, &bl, &valid, &prot, BATu, BATl);
- } else {
- bat_size_prot(env, &bl, &valid, &prot, BATu, BATl);
- }
- LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
- " BATl " TARGET_FMT_lx "\n", __func__,
- type == ACCESS_CODE ? 'I' : 'D', i, virtual, *BATu, *BATl);
- if ((virtual & 0xF0000000) == BEPIu &&
- ((virtual & 0x0FFE0000) & ~bl) == BEPIl) {
- /* BAT matches */
- if (valid != 0) {
- /* Get physical address */
- ctx->raddr = (*BATl & 0xF0000000) |
- ((virtual & 0x0FFE0000 & bl) | (*BATl & 0x0FFE0000)) |
- (virtual & 0x0001F000);
- /* Compute access rights */
- ctx->prot = prot;
- ret = check_prot(ctx->prot, rw, type);
- if (ret == 0) {
- LOG_BATS("BAT %d match: r " TARGET_FMT_plx " prot=%c%c\n",
- i, ctx->raddr, ctx->prot & PAGE_READ ? 'R' : '-',
- ctx->prot & PAGE_WRITE ? 'W' : '-');
- }
- break;
- }
- }
- }
- if (ret < 0) {
-#if defined(DEBUG_BATS)
- if (qemu_log_enabled()) {
- LOG_BATS("no BAT match for " TARGET_FMT_lx ":\n", virtual);
- for (i = 0; i < 4; i++) {
- BATu = &BATut[i];
- BATl = &BATlt[i];
- BEPIu = *BATu & 0xF0000000;
- BEPIl = *BATu & 0x0FFE0000;
- bl = (*BATu & 0x00001FFC) << 15;
- LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
- " BATl " TARGET_FMT_lx "\n\t" TARGET_FMT_lx " "
- TARGET_FMT_lx " " TARGET_FMT_lx "\n",
- __func__, type == ACCESS_CODE ? 'I' : 'D', i, virtual,
- *BATu, *BATl, BEPIu, BEPIl, bl);
- }
- }
-#endif
- }
- /* No hit */
- return ret;
-}
-
-static inline target_phys_addr_t get_pteg_offset(CPUPPCState *env,
- target_phys_addr_t hash,
- int pte_size)
-{
- return (hash * pte_size * 8) & env->htab_mask;
-}
-
-/* PTE table lookup */
-static inline int find_pte2(CPUPPCState *env, mmu_ctx_t *ctx, int is_64b, int h,
- int rw, int type, int target_page_bits)
-{
- target_phys_addr_t pteg_off;
- target_ulong pte0, pte1;
- int i, good = -1;
- int ret, r;
-
- ret = -1; /* No entry found */
- pteg_off = get_pteg_offset(env, ctx->hash[h],
- is_64b ? HASH_PTE_SIZE_64 : HASH_PTE_SIZE_32);
- for (i = 0; i < 8; i++) {
-#if defined(TARGET_PPC64)
- if (is_64b) {
- if (env->external_htab) {
- pte0 = ldq_p(env->external_htab + pteg_off + (i * 16));
- pte1 = ldq_p(env->external_htab + pteg_off + (i * 16) + 8);
- } else {
- pte0 = ldq_phys(env->htab_base + pteg_off + (i * 16));
- pte1 = ldq_phys(env->htab_base + pteg_off + (i * 16) + 8);
- }
-
- r = pte64_check(ctx, pte0, pte1, h, rw, type);
- LOG_MMU("Load pte from " TARGET_FMT_lx " => " TARGET_FMT_lx " "
- TARGET_FMT_lx " %d %d %d " TARGET_FMT_lx "\n",
- pteg_off + (i * 16), pte0, pte1, (int)(pte0 & 1), h,
- (int)((pte0 >> 1) & 1), ctx->ptem);
- } else
-#endif
- {
- if (env->external_htab) {
- pte0 = ldl_p(env->external_htab + pteg_off + (i * 8));
- pte1 = ldl_p(env->external_htab + pteg_off + (i * 8) + 4);
- } else {
- pte0 = ldl_phys(env->htab_base + pteg_off + (i * 8));
- pte1 = ldl_phys(env->htab_base + pteg_off + (i * 8) + 4);
- }
- r = pte32_check(ctx, pte0, pte1, h, rw, type);
- LOG_MMU("Load pte from " TARGET_FMT_lx " => " TARGET_FMT_lx " "
- TARGET_FMT_lx " %d %d %d " TARGET_FMT_lx "\n",
- pteg_off + (i * 8), pte0, pte1, (int)(pte0 >> 31), h,
- (int)((pte0 >> 6) & 1), ctx->ptem);
- }
- switch (r) {
- case -3:
- /* PTE inconsistency */
- return -1;
- case -2:
- /* Access violation */
- ret = -2;
- good = i;
- break;
- case -1:
- default:
- /* No PTE match */
- break;
- case 0:
- /* access granted */
- /* XXX: we should go on looping to check all PTEs consistency
- * but if we can speed-up the whole thing as the
- * result would be undefined if PTEs are not consistent.
- */
- ret = 0;
- good = i;
- goto done;
- }
- }
- if (good != -1) {
- done:
- LOG_MMU("found PTE at addr " TARGET_FMT_lx " prot=%01x ret=%d\n",
- ctx->raddr, ctx->prot, ret);
- /* Update page flags */
- pte1 = ctx->raddr;
- if (pte_update_flags(ctx, &pte1, ret, rw) == 1) {
-#if defined(TARGET_PPC64)
- if (is_64b) {
- if (env->external_htab) {
- stq_p(env->external_htab + pteg_off + (good * 16) + 8,
- pte1);
- } else {
- stq_phys_notdirty(env->htab_base + pteg_off +
- (good * 16) + 8, pte1);
- }
- } else
-#endif
- {
- if (env->external_htab) {
- stl_p(env->external_htab + pteg_off + (good * 8) + 4,
- pte1);
- } else {
- stl_phys_notdirty(env->htab_base + pteg_off +
- (good * 8) + 4, pte1);
- }
- }
- }
- }
-
- /* We have a TLB that saves 4K pages, so let's
- * split a huge page to 4k chunks */
- if (target_page_bits != TARGET_PAGE_BITS) {
- ctx->raddr |= (ctx->eaddr & ((1 << target_page_bits) - 1))
- & TARGET_PAGE_MASK;
- }
- return ret;
-}
-
-static inline int find_pte(CPUPPCState *env, mmu_ctx_t *ctx, int h, int rw,
- int type, int target_page_bits)
-{
-#if defined(TARGET_PPC64)
- if (env->mmu_model & POWERPC_MMU_64) {
- return find_pte2(env, ctx, 1, h, rw, type, target_page_bits);
- }
-#endif
-
- return find_pte2(env, ctx, 0, h, rw, type, target_page_bits);
-}
-
-#if defined(TARGET_PPC64)
-static inline ppc_slb_t *slb_lookup(CPUPPCState *env, target_ulong eaddr)
-{
- uint64_t esid_256M, esid_1T;
- int n;
-
- LOG_SLB("%s: eaddr " TARGET_FMT_lx "\n", __func__, eaddr);
-
- esid_256M = (eaddr & SEGMENT_MASK_256M) | SLB_ESID_V;
- esid_1T = (eaddr & SEGMENT_MASK_1T) | SLB_ESID_V;
-
- for (n = 0; n < env->slb_nr; n++) {
- ppc_slb_t *slb = &env->slb[n];
-
- LOG_SLB("%s: slot %d %016" PRIx64 " %016"
- PRIx64 "\n", __func__, n, slb->esid, slb->vsid);
- /* We check for 1T matches on all MMUs here - if the MMU
- * doesn't have 1T segment support, we will have prevented 1T
- * entries from being inserted in the slbmte code. */
- if (((slb->esid == esid_256M) &&
- ((slb->vsid & SLB_VSID_B) == SLB_VSID_B_256M))
- || ((slb->esid == esid_1T) &&
- ((slb->vsid & SLB_VSID_B) == SLB_VSID_B_1T))) {
- return slb;
- }
- }
-
- return NULL;
-}
-
-void ppc_slb_invalidate_all(CPUPPCState *env)
-{
- int n, do_invalidate;
-
- do_invalidate = 0;
- /* XXX: Warning: slbia never invalidates the first segment */
- for (n = 1; n < env->slb_nr; n++) {
- ppc_slb_t *slb = &env->slb[n];
-
- if (slb->esid & SLB_ESID_V) {
- slb->esid &= ~SLB_ESID_V;
- /* XXX: given the fact that segment size is 256 MB or 1TB,
- * and we still don't have a tlb_flush_mask(env, n, mask)
- * in QEMU, we just invalidate all TLBs
- */
- do_invalidate = 1;
- }
- }
- if (do_invalidate) {
- tlb_flush(env, 1);
- }
-}
-
-void ppc_slb_invalidate_one(CPUPPCState *env, uint64_t T0)
-{
- ppc_slb_t *slb;
-
- slb = slb_lookup(env, T0);
- if (!slb) {
- return;
- }
-
- if (slb->esid & SLB_ESID_V) {
- slb->esid &= ~SLB_ESID_V;
-
- /* XXX: given the fact that segment size is 256 MB or 1TB,
- * and we still don't have a tlb_flush_mask(env, n, mask)
- * in QEMU, we just invalidate all TLBs
- */
- tlb_flush(env, 1);
- }
-}
-
-int ppc_store_slb(CPUPPCState *env, target_ulong rb, target_ulong rs)
-{
- int slot = rb & 0xfff;
- ppc_slb_t *slb = &env->slb[slot];
-
- if (rb & (0x1000 - env->slb_nr)) {
- return -1; /* Reserved bits set or slot too high */
- }
- if (rs & (SLB_VSID_B & ~SLB_VSID_B_1T)) {
- return -1; /* Bad segment size */
- }
- if ((rs & SLB_VSID_B) && !(env->mmu_model & POWERPC_MMU_1TSEG)) {
- return -1; /* 1T segment on MMU that doesn't support it */
- }
-
- /* Mask out the slot number as we store the entry */
- slb->esid = rb & (SLB_ESID_ESID | SLB_ESID_V);
- slb->vsid = rs;
-
- LOG_SLB("%s: %d " TARGET_FMT_lx " - " TARGET_FMT_lx " => %016" PRIx64
- " %016" PRIx64 "\n", __func__, slot, rb, rs,
- slb->esid, slb->vsid);
-
- return 0;
-}
-
-int ppc_load_slb_esid(CPUPPCState *env, target_ulong rb, target_ulong *rt)
-{
- int slot = rb & 0xfff;
- ppc_slb_t *slb = &env->slb[slot];
-
- if (slot >= env->slb_nr) {
- return -1;
- }
-
- *rt = slb->esid;
- return 0;
-}
-
-int ppc_load_slb_vsid(CPUPPCState *env, target_ulong rb, target_ulong *rt)
-{
- int slot = rb & 0xfff;
- ppc_slb_t *slb = &env->slb[slot];
-
- if (slot >= env->slb_nr) {
- return -1;
- }
-
- *rt = slb->vsid;
- return 0;
-}
-#endif /* defined(TARGET_PPC64) */
-
-/* Perform segment based translation */
-static inline int get_segment(CPUPPCState *env, mmu_ctx_t *ctx,
- target_ulong eaddr, int rw, int type)
-{
- target_phys_addr_t hash;
- target_ulong vsid;
- int ds, pr, target_page_bits;
- int ret, ret2;
-
- pr = msr_pr;
- ctx->eaddr = eaddr;
-#if defined(TARGET_PPC64)
- if (env->mmu_model & POWERPC_MMU_64) {
- ppc_slb_t *slb;
- target_ulong pageaddr;
- int segment_bits;
-
- LOG_MMU("Check SLBs\n");
- slb = slb_lookup(env, eaddr);
- if (!slb) {
- return -5;
- }
-
- if (slb->vsid & SLB_VSID_B) {
- vsid = (slb->vsid & SLB_VSID_VSID) >> SLB_VSID_SHIFT_1T;
- segment_bits = 40;
- } else {
- vsid = (slb->vsid & SLB_VSID_VSID) >> SLB_VSID_SHIFT;
- segment_bits = 28;
- }
-
- target_page_bits = (slb->vsid & SLB_VSID_L)
- ? TARGET_PAGE_BITS_16M : TARGET_PAGE_BITS;
- ctx->key = !!(pr ? (slb->vsid & SLB_VSID_KP)
- : (slb->vsid & SLB_VSID_KS));
- ds = 0;
- ctx->nx = !!(slb->vsid & SLB_VSID_N);
-
- pageaddr = eaddr & ((1ULL << segment_bits)
- - (1ULL << target_page_bits));
- if (slb->vsid & SLB_VSID_B) {
- hash = vsid ^ (vsid << 25) ^ (pageaddr >> target_page_bits);
- } else {
- hash = vsid ^ (pageaddr >> target_page_bits);
- }
- /* Only 5 bits of the page index are used in the AVPN */
- ctx->ptem = (slb->vsid & SLB_VSID_PTEM) |
- ((pageaddr >> 16) & ((1ULL << segment_bits) - 0x80));
- } else
-#endif /* defined(TARGET_PPC64) */
- {
- target_ulong sr, pgidx;
-
- sr = env->sr[eaddr >> 28];
- ctx->key = (((sr & 0x20000000) && (pr != 0)) ||
- ((sr & 0x40000000) && (pr == 0))) ? 1 : 0;
- ds = sr & 0x80000000 ? 1 : 0;
- ctx->nx = sr & 0x10000000 ? 1 : 0;
- vsid = sr & 0x00FFFFFF;
- target_page_bits = TARGET_PAGE_BITS;
- LOG_MMU("Check segment v=" TARGET_FMT_lx " %d " TARGET_FMT_lx " nip="
- TARGET_FMT_lx " lr=" TARGET_FMT_lx
- " ir=%d dr=%d pr=%d %d t=%d\n",
- eaddr, (int)(eaddr >> 28), sr, env->nip, env->lr, (int)msr_ir,
- (int)msr_dr, pr != 0 ? 1 : 0, rw, type);
- pgidx = (eaddr & ~SEGMENT_MASK_256M) >> target_page_bits;
- hash = vsid ^ pgidx;
- ctx->ptem = (vsid << 7) | (pgidx >> 10);
- }
- LOG_MMU("pte segment: key=%d ds %d nx %d vsid " TARGET_FMT_lx "\n",
- ctx->key, ds, ctx->nx, vsid);
- ret = -1;
- if (!ds) {
- /* Check if instruction fetch is allowed, if needed */
- if (type != ACCESS_CODE || ctx->nx == 0) {
- /* Page address translation */
- LOG_MMU("htab_base " TARGET_FMT_plx " htab_mask " TARGET_FMT_plx
- " hash " TARGET_FMT_plx "\n",
- env->htab_base, env->htab_mask, hash);
- ctx->hash[0] = hash;
- ctx->hash[1] = ~hash;
-
- /* Initialize real address with an invalid value */
- ctx->raddr = (target_phys_addr_t)-1ULL;
- if (unlikely(env->mmu_model == POWERPC_MMU_SOFT_6xx ||
- env->mmu_model == POWERPC_MMU_SOFT_74xx)) {
- /* Software TLB search */
- ret = ppc6xx_tlb_check(env, ctx, eaddr, rw, type);
- } else {
- LOG_MMU("0 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
- " vsid=" TARGET_FMT_lx " ptem=" TARGET_FMT_lx
- " hash=" TARGET_FMT_plx "\n",
- env->htab_base, env->htab_mask, vsid, ctx->ptem,
- ctx->hash[0]);
- /* Primary table lookup */
- ret = find_pte(env, ctx, 0, rw, type, target_page_bits);
- if (ret < 0) {
- /* Secondary table lookup */
- if (eaddr != 0xEFFFFFFF) {
- LOG_MMU("1 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
- " vsid=" TARGET_FMT_lx " api=" TARGET_FMT_lx
- " hash=" TARGET_FMT_plx "\n", env->htab_base,
- env->htab_mask, vsid, ctx->ptem, ctx->hash[1]);
- }
- ret2 = find_pte(env, ctx, 1, rw, type,
- target_page_bits);
- if (ret2 != -1) {
- ret = ret2;
- }
- }
- }
-#if defined(DUMP_PAGE_TABLES)
- if (qemu_log_enabled()) {
- target_phys_addr_t curaddr;
- uint32_t a0, a1, a2, a3;
-
- qemu_log("Page table: " TARGET_FMT_plx " len " TARGET_FMT_plx
- "\n", sdr, mask + 0x80);
- for (curaddr = sdr; curaddr < (sdr + mask + 0x80);
- curaddr += 16) {
- a0 = ldl_phys(curaddr);
- a1 = ldl_phys(curaddr + 4);
- a2 = ldl_phys(curaddr + 8);
- a3 = ldl_phys(curaddr + 12);
- if (a0 != 0 || a1 != 0 || a2 != 0 || a3 != 0) {
- qemu_log(TARGET_FMT_plx ": %08x %08x %08x %08x\n",
- curaddr, a0, a1, a2, a3);
- }
- }
- }
-#endif
- } else {
- LOG_MMU("No access allowed\n");
- ret = -3;
- }
- } else {
- target_ulong sr;
-
- LOG_MMU("direct store...\n");
- /* Direct-store segment : absolutely *BUGGY* for now */
-
- /* Direct-store implies a 32-bit MMU.
- * Check the Segment Register's bus unit ID (BUID).
- */
- sr = env->sr[eaddr >> 28];
- if ((sr & 0x1FF00000) >> 20 == 0x07f) {
- /* Memory-forced I/O controller interface access */
- /* If T=1 and BUID=x'07F', the 601 performs a memory access
- * to SR[28-31] LA[4-31], bypassing all protection mechanisms.
- */
- ctx->raddr = ((sr & 0xF) << 28) | (eaddr & 0x0FFFFFFF);
- ctx->prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
- return 0;
- }
-
- switch (type) {
- case ACCESS_INT:
- /* Integer load/store : only access allowed */
- break;
- case ACCESS_CODE:
- /* No code fetch is allowed in direct-store areas */
- return -4;
- case ACCESS_FLOAT:
- /* Floating point load/store */
- return -4;
- case ACCESS_RES:
- /* lwarx, ldarx or srwcx. */
- return -4;
- case ACCESS_CACHE:
- /* dcba, dcbt, dcbtst, dcbf, dcbi, dcbst, dcbz, or icbi */
- /* Should make the instruction do no-op.
- * As it already do no-op, it's quite easy :-)
- */
- ctx->raddr = eaddr;
- return 0;
- case ACCESS_EXT:
- /* eciwx or ecowx */
- return -4;
- default:
- qemu_log("ERROR: instruction should not need "
- "address translation\n");
- return -4;
- }
- if ((rw == 1 || ctx->key != 1) && (rw == 0 || ctx->key != 0)) {
- ctx->raddr = eaddr;
- ret = 2;
- } else {
- ret = -2;
- }
- }
-
- return ret;
-}
-
-/* Generic TLB check function for embedded PowerPC implementations */
-int ppcemb_tlb_check(CPUPPCState *env, ppcemb_tlb_t *tlb,
- target_phys_addr_t *raddrp,
- target_ulong address, uint32_t pid, int ext,
- int i)
-{
- target_ulong mask;
-
- /* Check valid flag */
- if (!(tlb->prot & PAGE_VALID)) {
- return -1;
- }
- mask = ~(tlb->size - 1);
- LOG_SWTLB("%s: TLB %d address " TARGET_FMT_lx " PID %u <=> " TARGET_FMT_lx
- " " TARGET_FMT_lx " %u %x\n", __func__, i, address, pid, tlb->EPN,
- mask, (uint32_t)tlb->PID, tlb->prot);
- /* Check PID */
- if (tlb->PID != 0 && tlb->PID != pid) {
- return -1;
- }
- /* Check effective address */
- if ((address & mask) != tlb->EPN) {
- return -1;
- }
- *raddrp = (tlb->RPN & mask) | (address & ~mask);
-#if (TARGET_PHYS_ADDR_BITS >= 36)
- if (ext) {
- /* Extend the physical address to 36 bits */
- *raddrp |= (target_phys_addr_t)(tlb->RPN & 0xF) << 32;
- }
-#endif
-
- return 0;
-}
-
-/* Generic TLB search function for PowerPC embedded implementations */
-int ppcemb_tlb_search(CPUPPCState *env, target_ulong address, uint32_t pid)
-{
- ppcemb_tlb_t *tlb;
- target_phys_addr_t raddr;
- int i, ret;
-
- /* Default return value is no match */
- ret = -1;
- for (i = 0; i < env->nb_tlb; i++) {
- tlb = &env->tlb.tlbe[i];
- if (ppcemb_tlb_check(env, tlb, &raddr, address, pid, 0, i) == 0) {
- ret = i;
- break;
- }
- }
-
- return ret;
-}
-
-/* Helpers specific to PowerPC 40x implementations */
-static inline void ppc4xx_tlb_invalidate_all(CPUPPCState *env)
-{
- ppcemb_tlb_t *tlb;
- int i;
-
- for (i = 0; i < env->nb_tlb; i++) {
- tlb = &env->tlb.tlbe[i];
- tlb->prot &= ~PAGE_VALID;
- }
- tlb_flush(env, 1);
-}
-
-static inline void ppc4xx_tlb_invalidate_virt(CPUPPCState *env,
- target_ulong eaddr, uint32_t pid)
-{
-#if !defined(FLUSH_ALL_TLBS)
- ppcemb_tlb_t *tlb;
- target_phys_addr_t raddr;
- target_ulong page, end;
- int i;
-
- for (i = 0; i < env->nb_tlb; i++) {
- tlb = &env->tlb.tlbe[i];
- if (ppcemb_tlb_check(env, tlb, &raddr, eaddr, pid, 0, i) == 0) {
- end = tlb->EPN + tlb->size;
- for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) {
- tlb_flush_page(env, page);
- }
- tlb->prot &= ~PAGE_VALID;
- break;
- }
- }
-#else
- ppc4xx_tlb_invalidate_all(env);
-#endif
-}
-
-static int mmu40x_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
- target_ulong address, int rw,
- int access_type)
-{
- ppcemb_tlb_t *tlb;
- target_phys_addr_t raddr;
- int i, ret, zsel, zpr, pr;
-
- ret = -1;
- raddr = (target_phys_addr_t)-1ULL;
- pr = msr_pr;
- for (i = 0; i < env->nb_tlb; i++) {
- tlb = &env->tlb.tlbe[i];
- if (ppcemb_tlb_check(env, tlb, &raddr, address,
- env->spr[SPR_40x_PID], 0, i) < 0) {
- continue;
- }
- zsel = (tlb->attr >> 4) & 0xF;
- zpr = (env->spr[SPR_40x_ZPR] >> (30 - (2 * zsel))) & 0x3;
- LOG_SWTLB("%s: TLB %d zsel %d zpr %d rw %d attr %08x\n",
- __func__, i, zsel, zpr, rw, tlb->attr);
- /* Check execute enable bit */
- switch (zpr) {
- case 0x2:
- if (pr != 0) {
- goto check_perms;
- }
- /* No break here */
- case 0x3:
- /* All accesses granted */
- ctx->prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
- ret = 0;
- break;
- case 0x0:
- if (pr != 0) {
- /* Raise Zone protection fault. */
- env->spr[SPR_40x_ESR] = 1 << 22;
- ctx->prot = 0;
- ret = -2;
- break;
- }
- /* No break here */
- case 0x1:
- check_perms:
- /* Check from TLB entry */
- ctx->prot = tlb->prot;
- ret = check_prot(ctx->prot, rw, access_type);
- if (ret == -2) {
- env->spr[SPR_40x_ESR] = 0;
- }
- break;
- }
- if (ret >= 0) {
- ctx->raddr = raddr;
- LOG_SWTLB("%s: access granted " TARGET_FMT_lx " => " TARGET_FMT_plx
- " %d %d\n", __func__, address, ctx->raddr, ctx->prot,
- ret);
- return 0;
- }
- }
- LOG_SWTLB("%s: access refused " TARGET_FMT_lx " => " TARGET_FMT_plx
- " %d %d\n", __func__, address, raddr, ctx->prot, ret);
-
- return ret;
-}
-
-void store_40x_sler(CPUPPCState *env, uint32_t val)
-{
- /* XXX: TO BE FIXED */
- if (val != 0x00000000) {
- cpu_abort(env, "Little-endian regions are not supported by now\n");
- }
- env->spr[SPR_405_SLER] = val;
-}
-
-static inline int mmubooke_check_tlb(CPUPPCState *env, ppcemb_tlb_t *tlb,
- target_phys_addr_t *raddr, int *prot,
- target_ulong address, int rw,
- int access_type, int i)
-{
- int ret, prot2;
-
- if (ppcemb_tlb_check(env, tlb, raddr, address,
- env->spr[SPR_BOOKE_PID],
- !env->nb_pids, i) >= 0) {
- goto found_tlb;
- }
-
- if (env->spr[SPR_BOOKE_PID1] &&
- ppcemb_tlb_check(env, tlb, raddr, address,
- env->spr[SPR_BOOKE_PID1], 0, i) >= 0) {
- goto found_tlb;
- }
-
- if (env->spr[SPR_BOOKE_PID2] &&
- ppcemb_tlb_check(env, tlb, raddr, address,
- env->spr[SPR_BOOKE_PID2], 0, i) >= 0) {
- goto found_tlb;
- }
-
- LOG_SWTLB("%s: TLB entry not found\n", __func__);
- return -1;
-
-found_tlb:
-
- if (msr_pr != 0) {
- prot2 = tlb->prot & 0xF;
- } else {
- prot2 = (tlb->prot >> 4) & 0xF;
- }
-
- /* Check the address space */
- if (access_type == ACCESS_CODE) {
- if (msr_ir != (tlb->attr & 1)) {
- LOG_SWTLB("%s: AS doesn't match\n", __func__);
- return -1;
- }
-
- *prot = prot2;
- if (prot2 & PAGE_EXEC) {
- LOG_SWTLB("%s: good TLB!\n", __func__);
- return 0;
- }
-
- LOG_SWTLB("%s: no PAGE_EXEC: %x\n", __func__, prot2);
- ret = -3;
- } else {
- if (msr_dr != (tlb->attr & 1)) {
- LOG_SWTLB("%s: AS doesn't match\n", __func__);
- return -1;
- }
-
- *prot = prot2;
- if ((!rw && prot2 & PAGE_READ) || (rw && (prot2 & PAGE_WRITE))) {
- LOG_SWTLB("%s: found TLB!\n", __func__);
- return 0;
- }
-
- LOG_SWTLB("%s: PAGE_READ/WRITE doesn't match: %x\n", __func__, prot2);
- ret = -2;
- }
-
- return ret;
-}
-
-static int mmubooke_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
- target_ulong address, int rw,
- int access_type)
-{
- ppcemb_tlb_t *tlb;
- target_phys_addr_t raddr;
- int i, ret;
-
- ret = -1;
- raddr = (target_phys_addr_t)-1ULL;
- for (i = 0; i < env->nb_tlb; i++) {
- tlb = &env->tlb.tlbe[i];
- ret = mmubooke_check_tlb(env, tlb, &raddr, &ctx->prot, address, rw,
- access_type, i);
- if (!ret) {
- break;
- }
- }
-
- if (ret >= 0) {
- ctx->raddr = raddr;
- LOG_SWTLB("%s: access granted " TARGET_FMT_lx " => " TARGET_FMT_plx
- " %d %d\n", __func__, address, ctx->raddr, ctx->prot,
- ret);
- } else {
- LOG_SWTLB("%s: access refused " TARGET_FMT_lx " => " TARGET_FMT_plx
- " %d %d\n", __func__, address, raddr, ctx->prot, ret);
- }
-
- return ret;
-}
-
-void booke206_flush_tlb(CPUPPCState *env, int flags, const int check_iprot)
-{
- int tlb_size;
- int i, j;
- ppcmas_tlb_t *tlb = env->tlb.tlbm;
-
- for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
- if (flags & (1 << i)) {
- tlb_size = booke206_tlb_size(env, i);
- for (j = 0; j < tlb_size; j++) {
- if (!check_iprot || !(tlb[j].mas1 & MAS1_IPROT)) {
- tlb[j].mas1 &= ~MAS1_VALID;
- }
- }
- }
- tlb += booke206_tlb_size(env, i);
- }
-
- tlb_flush(env, 1);
-}
-
-target_phys_addr_t booke206_tlb_to_page_size(CPUPPCState *env,
- ppcmas_tlb_t *tlb)
-{
- int tlbm_size;
-
- tlbm_size = (tlb->mas1 & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
-
- return 1024ULL << tlbm_size;
-}
-
-/* TLB check function for MAS based SoftTLBs */
-int ppcmas_tlb_check(CPUPPCState *env, ppcmas_tlb_t *tlb,
- target_phys_addr_t *raddrp,
- target_ulong address, uint32_t pid)
-{
- target_ulong mask;
- uint32_t tlb_pid;
-
- /* Check valid flag */
- if (!(tlb->mas1 & MAS1_VALID)) {
- return -1;
- }
-
- mask = ~(booke206_tlb_to_page_size(env, tlb) - 1);
- LOG_SWTLB("%s: TLB ADDR=0x" TARGET_FMT_lx " PID=0x%x MAS1=0x%x MAS2=0x%"
- PRIx64 " mask=0x" TARGET_FMT_lx " MAS7_3=0x%" PRIx64 " MAS8=%x\n",
- __func__, address, pid, tlb->mas1, tlb->mas2, mask, tlb->mas7_3,
- tlb->mas8);
-
- /* Check PID */
- tlb_pid = (tlb->mas1 & MAS1_TID_MASK) >> MAS1_TID_SHIFT;
- if (tlb_pid != 0 && tlb_pid != pid) {
- return -1;
- }
-
- /* Check effective address */
- if ((address & mask) != (tlb->mas2 & MAS2_EPN_MASK)) {
- return -1;
- }
-
- if (raddrp) {
- *raddrp = (tlb->mas7_3 & mask) | (address & ~mask);
- }
-
- return 0;
-}
-
-static int mmubooke206_check_tlb(CPUPPCState *env, ppcmas_tlb_t *tlb,
- target_phys_addr_t *raddr, int *prot,
- target_ulong address, int rw,
- int access_type)
-{
- int ret;
- int prot2 = 0;
-
- if (ppcmas_tlb_check(env, tlb, raddr, address,
- env->spr[SPR_BOOKE_PID]) >= 0) {
- goto found_tlb;
- }
-
- if (env->spr[SPR_BOOKE_PID1] &&
- ppcmas_tlb_check(env, tlb, raddr, address,
- env->spr[SPR_BOOKE_PID1]) >= 0) {
- goto found_tlb;
- }
-
- if (env->spr[SPR_BOOKE_PID2] &&
- ppcmas_tlb_check(env, tlb, raddr, address,
- env->spr[SPR_BOOKE_PID2]) >= 0) {
- goto found_tlb;
- }
-
- LOG_SWTLB("%s: TLB entry not found\n", __func__);
- return -1;
-
-found_tlb:
-
- if (msr_pr != 0) {
- if (tlb->mas7_3 & MAS3_UR) {
- prot2 |= PAGE_READ;
- }
- if (tlb->mas7_3 & MAS3_UW) {
- prot2 |= PAGE_WRITE;
- }
- if (tlb->mas7_3 & MAS3_UX) {
- prot2 |= PAGE_EXEC;
- }
- } else {
- if (tlb->mas7_3 & MAS3_SR) {
- prot2 |= PAGE_READ;
- }
- if (tlb->mas7_3 & MAS3_SW) {
- prot2 |= PAGE_WRITE;
- }
- if (tlb->mas7_3 & MAS3_SX) {
- prot2 |= PAGE_EXEC;
- }
- }
-
- /* Check the address space and permissions */
- if (access_type == ACCESS_CODE) {
- if (msr_ir != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) {
- LOG_SWTLB("%s: AS doesn't match\n", __func__);
- return -1;
- }
-
- *prot = prot2;
- if (prot2 & PAGE_EXEC) {
- LOG_SWTLB("%s: good TLB!\n", __func__);
- return 0;
- }
-
- LOG_SWTLB("%s: no PAGE_EXEC: %x\n", __func__, prot2);
- ret = -3;
- } else {
- if (msr_dr != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) {
- LOG_SWTLB("%s: AS doesn't match\n", __func__);
- return -1;
- }
-
- *prot = prot2;
- if ((!rw && prot2 & PAGE_READ) || (rw && (prot2 & PAGE_WRITE))) {
- LOG_SWTLB("%s: found TLB!\n", __func__);
- return 0;
- }
-
- LOG_SWTLB("%s: PAGE_READ/WRITE doesn't match: %x\n", __func__, prot2);
- ret = -2;
- }
-
- return ret;
-}
-
-static int mmubooke206_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
- target_ulong address, int rw,
- int access_type)
-{
- ppcmas_tlb_t *tlb;
- target_phys_addr_t raddr;
- int i, j, ret;
-
- ret = -1;
- raddr = (target_phys_addr_t)-1ULL;
-
- for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
- int ways = booke206_tlb_ways(env, i);
-
- for (j = 0; j < ways; j++) {
- tlb = booke206_get_tlbm(env, i, address, j);
- if (!tlb) {
- continue;
- }
- ret = mmubooke206_check_tlb(env, tlb, &raddr, &ctx->prot, address,
- rw, access_type);
- if (ret != -1) {
- goto found_tlb;
- }
- }
- }
-
-found_tlb:
-
- if (ret >= 0) {
- ctx->raddr = raddr;
- LOG_SWTLB("%s: access granted " TARGET_FMT_lx " => " TARGET_FMT_plx
- " %d %d\n", __func__, address, ctx->raddr, ctx->prot,
- ret);
- } else {
- LOG_SWTLB("%s: access refused " TARGET_FMT_lx " => " TARGET_FMT_plx
- " %d %d\n", __func__, address, raddr, ctx->prot, ret);
- }
-
- return ret;
-}
-
-static const char *book3e_tsize_to_str[32] = {
- "1K", "2K", "4K", "8K", "16K", "32K", "64K", "128K", "256K", "512K",
- "1M", "2M", "4M", "8M", "16M", "32M", "64M", "128M", "256M", "512M",
- "1G", "2G", "4G", "8G", "16G", "32G", "64G", "128G", "256G", "512G",
- "1T", "2T"
-};
-
-static void mmubooke_dump_mmu(FILE *f, fprintf_function cpu_fprintf,
- CPUPPCState *env)
-{
- ppcemb_tlb_t *entry;
- int i;
-
- if (kvm_enabled() && !env->kvm_sw_tlb) {
- cpu_fprintf(f, "Cannot access KVM TLB\n");
- return;
- }
-
- cpu_fprintf(f, "\nTLB:\n");
- cpu_fprintf(f, "Effective Physical Size PID Prot "
- "Attr\n");
-
- entry = &env->tlb.tlbe[0];
- for (i = 0; i < env->nb_tlb; i++, entry++) {
- target_phys_addr_t ea, pa;
- target_ulong mask;
- uint64_t size = (uint64_t)entry->size;
- char size_buf[20];
-
- /* Check valid flag */
- if (!(entry->prot & PAGE_VALID)) {
- continue;
- }
-
- mask = ~(entry->size - 1);
- ea = entry->EPN & mask;
- pa = entry->RPN & mask;
-#if (TARGET_PHYS_ADDR_BITS >= 36)
- /* Extend the physical address to 36 bits */
- pa |= (target_phys_addr_t)(entry->RPN & 0xF) << 32;
-#endif
- size /= 1024;
- if (size >= 1024) {
- snprintf(size_buf, sizeof(size_buf), "%3" PRId64 "M", size / 1024);
- } else {
- snprintf(size_buf, sizeof(size_buf), "%3" PRId64 "k", size);
- }
- cpu_fprintf(f, "0x%016" PRIx64 " 0x%016" PRIx64 " %s %-5u %08x %08x\n",
- (uint64_t)ea, (uint64_t)pa, size_buf, (uint32_t)entry->PID,
- entry->prot, entry->attr);
- }
-
-}
-
-static void mmubooke206_dump_one_tlb(FILE *f, fprintf_function cpu_fprintf,
- CPUPPCState *env, int tlbn, int offset,
- int tlbsize)
-{
- ppcmas_tlb_t *entry;
- int i;
-
- cpu_fprintf(f, "\nTLB%d:\n", tlbn);
- cpu_fprintf(f, "Effective Physical Size TID TS SRWX"
- " URWX WIMGE U0123\n");
-
- entry = &env->tlb.tlbm[offset];
- for (i = 0; i < tlbsize; i++, entry++) {
- target_phys_addr_t ea, pa, size;
- int tsize;
-
- if (!(entry->mas1 & MAS1_VALID)) {
- continue;
- }
-
- tsize = (entry->mas1 & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
- size = 1024ULL << tsize;
- ea = entry->mas2 & ~(size - 1);
- pa = entry->mas7_3 & ~(size - 1);
-
- cpu_fprintf(f, "0x%016" PRIx64 " 0x%016" PRIx64 " %4s %-5u %1u S%c%c%c"
- "U%c%c%c %c%c%c%c%c U%c%c%c%c\n",
- (uint64_t)ea, (uint64_t)pa,
- book3e_tsize_to_str[tsize],
- (entry->mas1 & MAS1_TID_MASK) >> MAS1_TID_SHIFT,
- (entry->mas1 & MAS1_TS) >> MAS1_TS_SHIFT,
- entry->mas7_3 & MAS3_SR ? 'R' : '-',
- entry->mas7_3 & MAS3_SW ? 'W' : '-',
- entry->mas7_3 & MAS3_SX ? 'X' : '-',
- entry->mas7_3 & MAS3_UR ? 'R' : '-',
- entry->mas7_3 & MAS3_UW ? 'W' : '-',
- entry->mas7_3 & MAS3_UX ? 'X' : '-',
- entry->mas2 & MAS2_W ? 'W' : '-',
- entry->mas2 & MAS2_I ? 'I' : '-',
- entry->mas2 & MAS2_M ? 'M' : '-',
- entry->mas2 & MAS2_G ? 'G' : '-',
- entry->mas2 & MAS2_E ? 'E' : '-',
- entry->mas7_3 & MAS3_U0 ? '0' : '-',
- entry->mas7_3 & MAS3_U1 ? '1' : '-',
- entry->mas7_3 & MAS3_U2 ? '2' : '-',
- entry->mas7_3 & MAS3_U3 ? '3' : '-');
- }
-}
-
-static void mmubooke206_dump_mmu(FILE *f, fprintf_function cpu_fprintf,
- CPUPPCState *env)
-{
- int offset = 0;
- int i;
-
- if (kvm_enabled() && !env->kvm_sw_tlb) {
- cpu_fprintf(f, "Cannot access KVM TLB\n");
- return;
- }
-
- for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
- int size = booke206_tlb_size(env, i);
-
- if (size == 0) {
- continue;
- }
-
- mmubooke206_dump_one_tlb(f, cpu_fprintf, env, i, offset, size);
- offset += size;
- }
-}
-
-#if defined(TARGET_PPC64)
-static void mmubooks_dump_mmu(FILE *f, fprintf_function cpu_fprintf,
- CPUPPCState *env)
-{
- int i;
- uint64_t slbe, slbv;
-
- cpu_synchronize_state(env);
-
- cpu_fprintf(f, "SLB\tESID\t\t\tVSID\n");
- for (i = 0; i < env->slb_nr; i++) {
- slbe = env->slb[i].esid;
- slbv = env->slb[i].vsid;
- if (slbe == 0 && slbv == 0) {
- continue;
- }
- cpu_fprintf(f, "%d\t0x%016" PRIx64 "\t0x%016" PRIx64 "\n",
- i, slbe, slbv);
- }
-}
-#endif
-
-void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUPPCState *env)
-{
- switch (env->mmu_model) {
- case POWERPC_MMU_BOOKE:
- mmubooke_dump_mmu(f, cpu_fprintf, env);
- break;
- case POWERPC_MMU_BOOKE206:
- mmubooke206_dump_mmu(f, cpu_fprintf, env);
- break;
-#if defined(TARGET_PPC64)
- case POWERPC_MMU_64B:
- case POWERPC_MMU_2_06:
- mmubooks_dump_mmu(f, cpu_fprintf, env);
- break;
-#endif
- default:
- qemu_log_mask(LOG_UNIMP, "%s: unimplemented\n", __func__);
- }
-}
-
-static inline int check_physical(CPUPPCState *env, mmu_ctx_t *ctx,
- target_ulong eaddr, int rw)
-{
- int in_plb, ret;
-
- ctx->raddr = eaddr;
- ctx->prot = PAGE_READ | PAGE_EXEC;
- ret = 0;
- switch (env->mmu_model) {
- case POWERPC_MMU_32B:
- case POWERPC_MMU_601:
- case POWERPC_MMU_SOFT_6xx:
- case POWERPC_MMU_SOFT_74xx:
- case POWERPC_MMU_SOFT_4xx:
- case POWERPC_MMU_REAL:
- case POWERPC_MMU_BOOKE:
- ctx->prot |= PAGE_WRITE;
- break;
-#if defined(TARGET_PPC64)
- case POWERPC_MMU_620:
- case POWERPC_MMU_64B:
- case POWERPC_MMU_2_06:
- /* Real address are 60 bits long */
- ctx->raddr &= 0x0FFFFFFFFFFFFFFFULL;
- ctx->prot |= PAGE_WRITE;
- break;
-#endif
- case POWERPC_MMU_SOFT_4xx_Z:
- if (unlikely(msr_pe != 0)) {
- /* 403 family add some particular protections,
- * using PBL/PBU registers for accesses with no translation.
- */
- in_plb =
- /* Check PLB validity */
- (env->pb[0] < env->pb[1] &&
- /* and address in plb area */
- eaddr >= env->pb[0] && eaddr < env->pb[1]) ||
- (env->pb[2] < env->pb[3] &&
- eaddr >= env->pb[2] && eaddr < env->pb[3]) ? 1 : 0;
- if (in_plb ^ msr_px) {
- /* Access in protected area */
- if (rw == 1) {
- /* Access is not allowed */
- ret = -2;
- }
- } else {
- /* Read-write access is allowed */
- ctx->prot |= PAGE_WRITE;
- }
- }
- break;
- case POWERPC_MMU_MPC8xx:
- /* XXX: TODO */
- cpu_abort(env, "MPC8xx MMU model is not implemented\n");
- break;
- case POWERPC_MMU_BOOKE206:
- cpu_abort(env, "BookE 2.06 MMU doesn't have physical real mode\n");
- break;
- default:
- cpu_abort(env, "Unknown or invalid MMU model\n");
- return -1;
- }
-
- return ret;
-}
-
-int get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx, target_ulong eaddr,
- int rw, int access_type)
-{
- int ret;
-
-#if 0
- qemu_log("%s\n", __func__);
-#endif
- if ((access_type == ACCESS_CODE && msr_ir == 0) ||
- (access_type != ACCESS_CODE && msr_dr == 0)) {
- if (env->mmu_model == POWERPC_MMU_BOOKE) {
- /* The BookE MMU always performs address translation. The
- IS and DS bits only affect the address space. */
- ret = mmubooke_get_physical_address(env, ctx, eaddr,
- rw, access_type);
- } else if (env->mmu_model == POWERPC_MMU_BOOKE206) {
- ret = mmubooke206_get_physical_address(env, ctx, eaddr, rw,
- access_type);
- } else {
- /* No address translation. */
- ret = check_physical(env, ctx, eaddr, rw);
- }
- } else {
- ret = -1;
- switch (env->mmu_model) {
- case POWERPC_MMU_32B:
- case POWERPC_MMU_601:
- case POWERPC_MMU_SOFT_6xx:
- case POWERPC_MMU_SOFT_74xx:
- /* Try to find a BAT */
- if (env->nb_BATs != 0) {
- ret = get_bat(env, ctx, eaddr, rw, access_type);
- }
-#if defined(TARGET_PPC64)
- case POWERPC_MMU_620:
- case POWERPC_MMU_64B:
- case POWERPC_MMU_2_06:
-#endif
- if (ret < 0) {
- /* We didn't match any BAT entry or don't have BATs */
- ret = get_segment(env, ctx, eaddr, rw, access_type);
- }
- break;
- case POWERPC_MMU_SOFT_4xx:
- case POWERPC_MMU_SOFT_4xx_Z:
- ret = mmu40x_get_physical_address(env, ctx, eaddr,
- rw, access_type);
- break;
- case POWERPC_MMU_BOOKE:
- ret = mmubooke_get_physical_address(env, ctx, eaddr,
- rw, access_type);
- break;
- case POWERPC_MMU_BOOKE206:
- ret = mmubooke206_get_physical_address(env, ctx, eaddr, rw,
- access_type);
- break;
- case POWERPC_MMU_MPC8xx:
- /* XXX: TODO */
- cpu_abort(env, "MPC8xx MMU model is not implemented\n");
- break;
- case POWERPC_MMU_REAL:
- cpu_abort(env, "PowerPC in real mode do not do any translation\n");
- return -1;
- default:
- cpu_abort(env, "Unknown or invalid MMU model\n");
- return -1;
- }
- }
-#if 0
- qemu_log("%s address " TARGET_FMT_lx " => %d " TARGET_FMT_plx "\n",
- __func__, eaddr, ret, ctx->raddr);
-#endif
-
- return ret;
-}
-
-target_phys_addr_t cpu_get_phys_page_debug(CPUPPCState *env, target_ulong addr)
-{
- mmu_ctx_t ctx;
-
- if (unlikely(get_physical_address(env, &ctx, addr, 0, ACCESS_INT) != 0)) {
- return -1;
- }
-
- return ctx.raddr & TARGET_PAGE_MASK;
-}
-
-static void booke206_update_mas_tlb_miss(CPUPPCState *env, target_ulong address,
- int rw)
-{
- env->spr[SPR_BOOKE_MAS0] = env->spr[SPR_BOOKE_MAS4] & MAS4_TLBSELD_MASK;
- env->spr[SPR_BOOKE_MAS1] = env->spr[SPR_BOOKE_MAS4] & MAS4_TSIZED_MASK;
- env->spr[SPR_BOOKE_MAS2] = env->spr[SPR_BOOKE_MAS4] & MAS4_WIMGED_MASK;
- env->spr[SPR_BOOKE_MAS3] = 0;
- env->spr[SPR_BOOKE_MAS6] = 0;
- env->spr[SPR_BOOKE_MAS7] = 0;
-
- /* AS */
- if (((rw == 2) && msr_ir) || ((rw != 2) && msr_dr)) {
- env->spr[SPR_BOOKE_MAS1] |= MAS1_TS;
- env->spr[SPR_BOOKE_MAS6] |= MAS6_SAS;
- }
-
- env->spr[SPR_BOOKE_MAS1] |= MAS1_VALID;
- env->spr[SPR_BOOKE_MAS2] |= address & MAS2_EPN_MASK;
-
- switch (env->spr[SPR_BOOKE_MAS4] & MAS4_TIDSELD_PIDZ) {
- case MAS4_TIDSELD_PID0:
- env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID] << MAS1_TID_SHIFT;
- break;
- case MAS4_TIDSELD_PID1:
- env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID1] << MAS1_TID_SHIFT;
- break;
- case MAS4_TIDSELD_PID2:
- env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID2] << MAS1_TID_SHIFT;
- break;
- }
-
- env->spr[SPR_BOOKE_MAS6] |= env->spr[SPR_BOOKE_PID] << 16;
-
- /* next victim logic */
- env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_ESEL_SHIFT;
- env->last_way++;
- env->last_way &= booke206_tlb_ways(env, 0) - 1;
- env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
-}
-
-/* Perform address translation */
-int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw,
- int mmu_idx)
-{
- mmu_ctx_t ctx;
- int access_type;
- int ret = 0;
-
- if (rw == 2) {
- /* code access */
- rw = 0;
- access_type = ACCESS_CODE;
- } else {
- /* data access */
- access_type = env->access_type;
- }
- ret = get_physical_address(env, &ctx, address, rw, access_type);
- if (ret == 0) {
- tlb_set_page(env, address & TARGET_PAGE_MASK,
- ctx.raddr & TARGET_PAGE_MASK, ctx.prot,
- mmu_idx, TARGET_PAGE_SIZE);
- ret = 0;
- } else if (ret < 0) {
- LOG_MMU_STATE(env);
- if (access_type == ACCESS_CODE) {
- switch (ret) {
- case -1:
- /* No matches in page tables or TLB */
- switch (env->mmu_model) {
- case POWERPC_MMU_SOFT_6xx:
- env->exception_index = POWERPC_EXCP_IFTLB;
- env->error_code = 1 << 18;
- env->spr[SPR_IMISS] = address;
- env->spr[SPR_ICMP] = 0x80000000 | ctx.ptem;
- goto tlb_miss;
- case POWERPC_MMU_SOFT_74xx:
- env->exception_index = POWERPC_EXCP_IFTLB;
- goto tlb_miss_74xx;
- case POWERPC_MMU_SOFT_4xx:
- case POWERPC_MMU_SOFT_4xx_Z:
- env->exception_index = POWERPC_EXCP_ITLB;
- env->error_code = 0;
- env->spr[SPR_40x_DEAR] = address;
- env->spr[SPR_40x_ESR] = 0x00000000;
- break;
- case POWERPC_MMU_32B:
- case POWERPC_MMU_601:
-#if defined(TARGET_PPC64)
- case POWERPC_MMU_620:
- case POWERPC_MMU_64B:
- case POWERPC_MMU_2_06:
-#endif
- env->exception_index = POWERPC_EXCP_ISI;
- env->error_code = 0x40000000;
- break;
- case POWERPC_MMU_BOOKE206:
- booke206_update_mas_tlb_miss(env, address, rw);
- /* fall through */
- case POWERPC_MMU_BOOKE:
- env->exception_index = POWERPC_EXCP_ITLB;
- env->error_code = 0;
- env->spr[SPR_BOOKE_DEAR] = address;
- return -1;
- case POWERPC_MMU_MPC8xx:
- /* XXX: TODO */
- cpu_abort(env, "MPC8xx MMU model is not implemented\n");
- break;
- case POWERPC_MMU_REAL:
- cpu_abort(env, "PowerPC in real mode should never raise "
- "any MMU exceptions\n");
- return -1;
- default:
- cpu_abort(env, "Unknown or invalid MMU model\n");
- return -1;
- }
- break;
- case -2:
- /* Access rights violation */
- env->exception_index = POWERPC_EXCP_ISI;
- env->error_code = 0x08000000;
- break;
- case -3:
- /* No execute protection violation */
- if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
- (env->mmu_model == POWERPC_MMU_BOOKE206)) {
- env->spr[SPR_BOOKE_ESR] = 0x00000000;
- }
- env->exception_index = POWERPC_EXCP_ISI;
- env->error_code = 0x10000000;
- break;
- case -4:
- /* Direct store exception */
- /* No code fetch is allowed in direct-store areas */
- env->exception_index = POWERPC_EXCP_ISI;
- env->error_code = 0x10000000;
- break;
-#if defined(TARGET_PPC64)
- case -5:
- /* No match in segment table */
- if (env->mmu_model == POWERPC_MMU_620) {
- env->exception_index = POWERPC_EXCP_ISI;
- /* XXX: this might be incorrect */
- env->error_code = 0x40000000;
- } else {
- env->exception_index = POWERPC_EXCP_ISEG;
- env->error_code = 0;
- }
- break;
-#endif
- }
- } else {
- switch (ret) {
- case -1:
- /* No matches in page tables or TLB */
- switch (env->mmu_model) {
- case POWERPC_MMU_SOFT_6xx:
- if (rw == 1) {
- env->exception_index = POWERPC_EXCP_DSTLB;
- env->error_code = 1 << 16;
- } else {
- env->exception_index = POWERPC_EXCP_DLTLB;
- env->error_code = 0;
- }
- env->spr[SPR_DMISS] = address;
- env->spr[SPR_DCMP] = 0x80000000 | ctx.ptem;
- tlb_miss:
- env->error_code |= ctx.key << 19;
- env->spr[SPR_HASH1] = env->htab_base +
- get_pteg_offset(env, ctx.hash[0], HASH_PTE_SIZE_32);
- env->spr[SPR_HASH2] = env->htab_base +
- get_pteg_offset(env, ctx.hash[1], HASH_PTE_SIZE_32);
- break;
- case POWERPC_MMU_SOFT_74xx:
- if (rw == 1) {
- env->exception_index = POWERPC_EXCP_DSTLB;
- } else {
- env->exception_index = POWERPC_EXCP_DLTLB;
- }
- tlb_miss_74xx:
- /* Implement LRU algorithm */
- env->error_code = ctx.key << 19;
- env->spr[SPR_TLBMISS] = (address & ~((target_ulong)0x3)) |
- ((env->last_way + 1) & (env->nb_ways - 1));
- env->spr[SPR_PTEHI] = 0x80000000 | ctx.ptem;
- break;
- case POWERPC_MMU_SOFT_4xx:
- case POWERPC_MMU_SOFT_4xx_Z:
- env->exception_index = POWERPC_EXCP_DTLB;
- env->error_code = 0;
- env->spr[SPR_40x_DEAR] = address;
- if (rw) {
- env->spr[SPR_40x_ESR] = 0x00800000;
- } else {
- env->spr[SPR_40x_ESR] = 0x00000000;
- }
- break;
- case POWERPC_MMU_32B:
- case POWERPC_MMU_601:
-#if defined(TARGET_PPC64)
- case POWERPC_MMU_620:
- case POWERPC_MMU_64B:
- case POWERPC_MMU_2_06:
-#endif
- env->exception_index = POWERPC_EXCP_DSI;
- env->error_code = 0;
- env->spr[SPR_DAR] = address;
- if (rw == 1) {
- env->spr[SPR_DSISR] = 0x42000000;
- } else {
- env->spr[SPR_DSISR] = 0x40000000;
- }
- break;
- case POWERPC_MMU_MPC8xx:
- /* XXX: TODO */
- cpu_abort(env, "MPC8xx MMU model is not implemented\n");
- break;
- case POWERPC_MMU_BOOKE206:
- booke206_update_mas_tlb_miss(env, address, rw);
- /* fall through */
- case POWERPC_MMU_BOOKE:
- env->exception_index = POWERPC_EXCP_DTLB;
- env->error_code = 0;
- env->spr[SPR_BOOKE_DEAR] = address;
- env->spr[SPR_BOOKE_ESR] = rw ? ESR_ST : 0;
- return -1;
- case POWERPC_MMU_REAL:
- cpu_abort(env, "PowerPC in real mode should never raise "
- "any MMU exceptions\n");
- return -1;
- default:
- cpu_abort(env, "Unknown or invalid MMU model\n");
- return -1;
- }
- break;
- case -2:
- /* Access rights violation */
- env->exception_index = POWERPC_EXCP_DSI;
- env->error_code = 0;
- if (env->mmu_model == POWERPC_MMU_SOFT_4xx
- || env->mmu_model == POWERPC_MMU_SOFT_4xx_Z) {
- env->spr[SPR_40x_DEAR] = address;
- if (rw) {
- env->spr[SPR_40x_ESR] |= 0x00800000;
- }
- } else if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
- (env->mmu_model == POWERPC_MMU_BOOKE206)) {
- env->spr[SPR_BOOKE_DEAR] = address;
- env->spr[SPR_BOOKE_ESR] = rw ? ESR_ST : 0;
- } else {
- env->spr[SPR_DAR] = address;
- if (rw == 1) {
- env->spr[SPR_DSISR] = 0x0A000000;
- } else {
- env->spr[SPR_DSISR] = 0x08000000;
- }
- }
- break;
- case -4:
- /* Direct store exception */
- switch (access_type) {
- case ACCESS_FLOAT:
- /* Floating point load/store */
- env->exception_index = POWERPC_EXCP_ALIGN;
- env->error_code = POWERPC_EXCP_ALIGN_FP;
- env->spr[SPR_DAR] = address;
- break;
- case ACCESS_RES:
- /* lwarx, ldarx or stwcx. */
- env->exception_index = POWERPC_EXCP_DSI;
- env->error_code = 0;
- env->spr[SPR_DAR] = address;
- if (rw == 1) {
- env->spr[SPR_DSISR] = 0x06000000;
- } else {
- env->spr[SPR_DSISR] = 0x04000000;
- }
- break;
- case ACCESS_EXT:
- /* eciwx or ecowx */
- env->exception_index = POWERPC_EXCP_DSI;
- env->error_code = 0;
- env->spr[SPR_DAR] = address;
- if (rw == 1) {
- env->spr[SPR_DSISR] = 0x06100000;
- } else {
- env->spr[SPR_DSISR] = 0x04100000;
- }
- break;
- default:
- printf("DSI: invalid exception (%d)\n", ret);
- env->exception_index = POWERPC_EXCP_PROGRAM;
- env->error_code =
- POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL;
- env->spr[SPR_DAR] = address;
- break;
- }
- break;
-#if defined(TARGET_PPC64)
- case -5:
- /* No match in segment table */
- if (env->mmu_model == POWERPC_MMU_620) {
- env->exception_index = POWERPC_EXCP_DSI;
- env->error_code = 0;
- env->spr[SPR_DAR] = address;
- /* XXX: this might be incorrect */
- if (rw == 1) {
- env->spr[SPR_DSISR] = 0x42000000;
- } else {
- env->spr[SPR_DSISR] = 0x40000000;
- }
- } else {
- env->exception_index = POWERPC_EXCP_DSEG;
- env->error_code = 0;
- env->spr[SPR_DAR] = address;
- }
- break;
-#endif
- }
- }
-#if 0
- printf("%s: set exception to %d %02x\n", __func__,
- env->exception, env->error_code);
-#endif
- ret = 1;
- }
-
- return ret;
-}
-
-/*****************************************************************************/
-/* BATs management */
-#if !defined(FLUSH_ALL_TLBS)
-static inline void do_invalidate_BAT(CPUPPCState *env, target_ulong BATu,
- target_ulong mask)
-{
- target_ulong base, end, page;
-
- base = BATu & ~0x0001FFFF;
- end = base + mask + 0x00020000;
- LOG_BATS("Flush BAT from " TARGET_FMT_lx " to " TARGET_FMT_lx " ("
- TARGET_FMT_lx ")\n", base, end, mask);
- for (page = base; page != end; page += TARGET_PAGE_SIZE) {
- tlb_flush_page(env, page);
- }
- LOG_BATS("Flush done\n");
-}
-#endif
-
-static inline void dump_store_bat(CPUPPCState *env, char ID, int ul, int nr,
- target_ulong value)
-{
- LOG_BATS("Set %cBAT%d%c to " TARGET_FMT_lx " (" TARGET_FMT_lx ")\n", ID,
- nr, ul == 0 ? 'u' : 'l', value, env->nip);
-}
-
-void ppc_store_ibatu(CPUPPCState *env, int nr, target_ulong value)
-{
- target_ulong mask;
-
- dump_store_bat(env, 'I', 0, nr, value);
- if (env->IBAT[0][nr] != value) {
- mask = (value << 15) & 0x0FFE0000UL;
-#if !defined(FLUSH_ALL_TLBS)
- do_invalidate_BAT(env, env->IBAT[0][nr], mask);
-#endif
- /* When storing valid upper BAT, mask BEPI and BRPN
- * and invalidate all TLBs covered by this BAT
- */
- mask = (value << 15) & 0x0FFE0000UL;
- env->IBAT[0][nr] = (value & 0x00001FFFUL) |
- (value & ~0x0001FFFFUL & ~mask);
- env->IBAT[1][nr] = (env->IBAT[1][nr] & 0x0000007B) |
- (env->IBAT[1][nr] & ~0x0001FFFF & ~mask);
-#if !defined(FLUSH_ALL_TLBS)
- do_invalidate_BAT(env, env->IBAT[0][nr], mask);
-#else
- tlb_flush(env, 1);
-#endif
- }
-}
-
-void ppc_store_ibatl(CPUPPCState *env, int nr, target_ulong value)
-{
- dump_store_bat(env, 'I', 1, nr, value);
- env->IBAT[1][nr] = value;
-}
-
-void ppc_store_dbatu(CPUPPCState *env, int nr, target_ulong value)
-{
- target_ulong mask;
-
- dump_store_bat(env, 'D', 0, nr, value);
- if (env->DBAT[0][nr] != value) {
- /* When storing valid upper BAT, mask BEPI and BRPN
- * and invalidate all TLBs covered by this BAT
- */
- mask = (value << 15) & 0x0FFE0000UL;
-#if !defined(FLUSH_ALL_TLBS)
- do_invalidate_BAT(env, env->DBAT[0][nr], mask);
-#endif
- mask = (value << 15) & 0x0FFE0000UL;
- env->DBAT[0][nr] = (value & 0x00001FFFUL) |
- (value & ~0x0001FFFFUL & ~mask);
- env->DBAT[1][nr] = (env->DBAT[1][nr] & 0x0000007B) |
- (env->DBAT[1][nr] & ~0x0001FFFF & ~mask);
-#if !defined(FLUSH_ALL_TLBS)
- do_invalidate_BAT(env, env->DBAT[0][nr], mask);
-#else
- tlb_flush(env, 1);
-#endif
- }
-}
-
-void ppc_store_dbatl(CPUPPCState *env, int nr, target_ulong value)
-{
- dump_store_bat(env, 'D', 1, nr, value);
- env->DBAT[1][nr] = value;
-}
-
-void ppc_store_ibatu_601(CPUPPCState *env, int nr, target_ulong value)
-{
- target_ulong mask;
-#if defined(FLUSH_ALL_TLBS)
- int do_inval;
-#endif
-
- dump_store_bat(env, 'I', 0, nr, value);
- if (env->IBAT[0][nr] != value) {
-#if defined(FLUSH_ALL_TLBS)
- do_inval = 0;
-#endif
- mask = (env->IBAT[1][nr] << 17) & 0x0FFE0000UL;
- if (env->IBAT[1][nr] & 0x40) {
- /* Invalidate BAT only if it is valid */
-#if !defined(FLUSH_ALL_TLBS)
- do_invalidate_BAT(env, env->IBAT[0][nr], mask);
-#else
- do_inval = 1;
-#endif
- }
- /* When storing valid upper BAT, mask BEPI and BRPN
- * and invalidate all TLBs covered by this BAT
- */
- env->IBAT[0][nr] = (value & 0x00001FFFUL) |
- (value & ~0x0001FFFFUL & ~mask);
- env->DBAT[0][nr] = env->IBAT[0][nr];
- if (env->IBAT[1][nr] & 0x40) {
-#if !defined(FLUSH_ALL_TLBS)
- do_invalidate_BAT(env, env->IBAT[0][nr], mask);
-#else
- do_inval = 1;
-#endif
- }
-#if defined(FLUSH_ALL_TLBS)
- if (do_inval) {
- tlb_flush(env, 1);
- }
-#endif
- }
-}
-
-void ppc_store_ibatl_601(CPUPPCState *env, int nr, target_ulong value)
-{
- target_ulong mask;
-#if defined(FLUSH_ALL_TLBS)
- int do_inval;
-#endif
-
- dump_store_bat(env, 'I', 1, nr, value);
- if (env->IBAT[1][nr] != value) {
-#if defined(FLUSH_ALL_TLBS)
- do_inval = 0;
-#endif
- if (env->IBAT[1][nr] & 0x40) {
-#if !defined(FLUSH_ALL_TLBS)
- mask = (env->IBAT[1][nr] << 17) & 0x0FFE0000UL;
- do_invalidate_BAT(env, env->IBAT[0][nr], mask);
-#else
- do_inval = 1;
-#endif
- }
- if (value & 0x40) {
-#if !defined(FLUSH_ALL_TLBS)
- mask = (value << 17) & 0x0FFE0000UL;
- do_invalidate_BAT(env, env->IBAT[0][nr], mask);
-#else
- do_inval = 1;
-#endif
- }
- env->IBAT[1][nr] = value;
- env->DBAT[1][nr] = value;
-#if defined(FLUSH_ALL_TLBS)
- if (do_inval) {
- tlb_flush(env, 1);
- }
-#endif
- }
-}
-
-/*****************************************************************************/
-/* TLB management */
-void ppc_tlb_invalidate_all(CPUPPCState *env)
-{
- switch (env->mmu_model) {
- case POWERPC_MMU_SOFT_6xx:
- case POWERPC_MMU_SOFT_74xx:
- ppc6xx_tlb_invalidate_all(env);
- break;
- case POWERPC_MMU_SOFT_4xx:
- case POWERPC_MMU_SOFT_4xx_Z:
- ppc4xx_tlb_invalidate_all(env);
- break;
- case POWERPC_MMU_REAL:
- cpu_abort(env, "No TLB for PowerPC 4xx in real mode\n");
- break;
- case POWERPC_MMU_MPC8xx:
- /* XXX: TODO */
- cpu_abort(env, "MPC8xx MMU model is not implemented\n");
- break;
- case POWERPC_MMU_BOOKE:
- tlb_flush(env, 1);
- break;
- case POWERPC_MMU_BOOKE206:
- booke206_flush_tlb(env, -1, 0);
- break;
- case POWERPC_MMU_32B:
- case POWERPC_MMU_601:
-#if defined(TARGET_PPC64)
- case POWERPC_MMU_620:
- case POWERPC_MMU_64B:
- case POWERPC_MMU_2_06:
-#endif /* defined(TARGET_PPC64) */
- tlb_flush(env, 1);
- break;
- default:
- /* XXX: TODO */
- cpu_abort(env, "Unknown MMU model\n");
- break;
- }
-}
-
-void ppc_tlb_invalidate_one(CPUPPCState *env, target_ulong addr)
-{
-#if !defined(FLUSH_ALL_TLBS)
- addr &= TARGET_PAGE_MASK;
- switch (env->mmu_model) {
- case POWERPC_MMU_SOFT_6xx:
- case POWERPC_MMU_SOFT_74xx:
- ppc6xx_tlb_invalidate_virt(env, addr, 0);
- if (env->id_tlbs == 1) {
- ppc6xx_tlb_invalidate_virt(env, addr, 1);
- }
- break;
- case POWERPC_MMU_SOFT_4xx:
- case POWERPC_MMU_SOFT_4xx_Z:
- ppc4xx_tlb_invalidate_virt(env, addr, env->spr[SPR_40x_PID]);
- break;
- case POWERPC_MMU_REAL:
- cpu_abort(env, "No TLB for PowerPC 4xx in real mode\n");
- break;
- case POWERPC_MMU_MPC8xx:
- /* XXX: TODO */
- cpu_abort(env, "MPC8xx MMU model is not implemented\n");
- break;
- case POWERPC_MMU_BOOKE:
- /* XXX: TODO */
- cpu_abort(env, "BookE MMU model is not implemented\n");
- break;
- case POWERPC_MMU_BOOKE206:
- /* XXX: TODO */
- cpu_abort(env, "BookE 2.06 MMU model is not implemented\n");
- break;
- case POWERPC_MMU_32B:
- case POWERPC_MMU_601:
- /* tlbie invalidate TLBs for all segments */
- addr &= ~((target_ulong)-1ULL << 28);
- /* XXX: this case should be optimized,
- * giving a mask to tlb_flush_page
- */
- tlb_flush_page(env, addr | (0x0 << 28));
- tlb_flush_page(env, addr | (0x1 << 28));
- tlb_flush_page(env, addr | (0x2 << 28));
- tlb_flush_page(env, addr | (0x3 << 28));
- tlb_flush_page(env, addr | (0x4 << 28));
- tlb_flush_page(env, addr | (0x5 << 28));
- tlb_flush_page(env, addr | (0x6 << 28));
- tlb_flush_page(env, addr | (0x7 << 28));
- tlb_flush_page(env, addr | (0x8 << 28));
- tlb_flush_page(env, addr | (0x9 << 28));
- tlb_flush_page(env, addr | (0xA << 28));
- tlb_flush_page(env, addr | (0xB << 28));
- tlb_flush_page(env, addr | (0xC << 28));
- tlb_flush_page(env, addr | (0xD << 28));
- tlb_flush_page(env, addr | (0xE << 28));
- tlb_flush_page(env, addr | (0xF << 28));
- break;
-#if defined(TARGET_PPC64)
- case POWERPC_MMU_620:
- case POWERPC_MMU_64B:
- case POWERPC_MMU_2_06:
- /* tlbie invalidate TLBs for all segments */
- /* XXX: given the fact that there are too many segments to invalidate,
- * and we still don't have a tlb_flush_mask(env, n, mask) in QEMU,
- * we just invalidate all TLBs
- */
- tlb_flush(env, 1);
- break;
-#endif /* defined(TARGET_PPC64) */
- default:
- /* XXX: TODO */
- cpu_abort(env, "Unknown MMU model\n");
- break;
- }
-#else
- ppc_tlb_invalidate_all(env);
-#endif
-}
-
/*****************************************************************************/
/* Special registers manipulation */
-#if defined(TARGET_PPC64)
-void ppc_store_asr(CPUPPCState *env, target_ulong value)
-{
- if (env->asr != value) {
- env->asr = value;
- tlb_flush(env, 1);
- }
-}
-#endif
-
-void ppc_store_sdr1(CPUPPCState *env, target_ulong value)
-{
- LOG_MMU("%s: " TARGET_FMT_lx "\n", __func__, value);
- if (env->spr[SPR_SDR1] != value) {
- env->spr[SPR_SDR1] = value;
-#if defined(TARGET_PPC64)
- if (env->mmu_model & POWERPC_MMU_64) {
- target_ulong htabsize = value & SDR_64_HTABSIZE;
-
- if (htabsize > 28) {
- fprintf(stderr, "Invalid HTABSIZE 0x" TARGET_FMT_lx
- " stored in SDR1\n", htabsize);
- htabsize = 28;
- }
- env->htab_mask = (1ULL << (htabsize + 18)) - 1;
- env->htab_base = value & SDR_64_HTABORG;
- } else
-#endif /* defined(TARGET_PPC64) */
- {
- /* FIXME: Should check for valid HTABMASK values */
- env->htab_mask = ((value & SDR_32_HTABMASK) << 16) | 0xFFFF;
- env->htab_base = value & SDR_32_HTABORG;
- }
- tlb_flush(env, 1);
- }
-}
-
-#if defined(TARGET_PPC64)
-target_ulong ppc_load_sr(CPUPPCState *env, int slb_nr)
-{
- /* XXX */
- return 0;
-}
-#endif
-
-void ppc_store_sr(CPUPPCState *env, int srnum, target_ulong value)
-{
- LOG_MMU("%s: reg=%d " TARGET_FMT_lx " " TARGET_FMT_lx "\n", __func__,
- srnum, value, env->sr[srnum]);
-#if defined(TARGET_PPC64)
- if (env->mmu_model & POWERPC_MMU_64) {
- uint64_t rb = 0, rs = 0;
-
- /* ESID = srnum */
- rb |= ((uint32_t)srnum & 0xf) << 28;
- /* Set the valid bit */
- rb |= 1 << 27;
- /* Index = ESID */
- rb |= (uint32_t)srnum;
-
- /* VSID = VSID */
- rs |= (value & 0xfffffff) << 12;
- /* flags = flags */
- rs |= ((value >> 27) & 0xf) << 8;
-
- ppc_store_slb(env, rb, rs);
- } else
-#endif
- if (env->sr[srnum] != value) {
- env->sr[srnum] = value;
-/* Invalidating 256MB of virtual memory in 4kB pages is way longer than
- flusing the whole TLB. */
-#if !defined(FLUSH_ALL_TLBS) && 0
- {
- target_ulong page, end;
- /* Invalidate 256 MB of virtual memory */
- page = (16 << 20) * srnum;
- end = page + (16 << 20);
- for (; page != end; page += TARGET_PAGE_SIZE) {
- tlb_flush_page(env, page);
- }
- }
-#else
- tlb_flush(env, 1);
-#endif
- }
-}
-#endif /* !defined(CONFIG_USER_ONLY) */
/* GDBstub can read and write MSR... */
void ppc_store_msr(CPUPPCState *env, target_ulong value)
diff --git a/target-ppc/mmu_helper.c b/target-ppc/mmu_helper.c
index e79b8f2..1f67451 100644
--- a/target-ppc/mmu_helper.c
+++ b/target-ppc/mmu_helper.c
@@ -18,8 +18,24 @@
*/
#include "cpu.h"
#include "helper.h"
+#include "kvm.h"
+#include "kvm_ppc.h"
+//#define DEBUG_MMU
+//#define DEBUG_BATS
+//#define DEBUG_SLB
//#define DEBUG_SOFTWARE_TLB
+//#define DUMP_PAGE_TABLES
+//#define DEBUG_SOFTWARE_TLB
+//#define FLUSH_ALL_TLBS
+
+#ifdef DEBUG_MMU
+# define LOG_MMU(...) qemu_log(__VA_ARGS__)
+# define LOG_MMU_STATE(env) log_cpu_state((env), 0)
+#else
+# define LOG_MMU(...) do { } while (0)
+# define LOG_MMU_STATE(...) do { } while (0)
+#endif
#ifdef DEBUG_SOFTWARE_TLB
# define LOG_SWTLB(...) qemu_log(__VA_ARGS__)
@@ -27,6 +43,2461 @@
# define LOG_SWTLB(...) do { } while (0)
#endif
+#ifdef DEBUG_BATS
+# define LOG_BATS(...) qemu_log(__VA_ARGS__)
+#else
+# define LOG_BATS(...) do { } while (0)
+#endif
+
+#ifdef DEBUG_SLB
+# define LOG_SLB(...) qemu_log(__VA_ARGS__)
+#else
+# define LOG_SLB(...) do { } while (0)
+#endif
+
+/*****************************************************************************/
+/* PowerPC MMU emulation */
+#if defined(CONFIG_USER_ONLY)
+int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw,
+ int mmu_idx)
+{
+ int exception, error_code;
+
+ if (rw == 2) {
+ exception = POWERPC_EXCP_ISI;
+ error_code = 0x40000000;
+ } else {
+ exception = POWERPC_EXCP_DSI;
+ error_code = 0x40000000;
+ if (rw) {
+ error_code |= 0x02000000;
+ }
+ env->spr[SPR_DAR] = address;
+ env->spr[SPR_DSISR] = error_code;
+ }
+ env->exception_index = exception;
+ env->error_code = error_code;
+
+ return 1;
+}
+
+#else
+/* Common routines used by software and hardware TLBs emulation */
+static inline int pte_is_valid(target_ulong pte0)
+{
+ return pte0 & 0x80000000 ? 1 : 0;
+}
+
+static inline void pte_invalidate(target_ulong *pte0)
+{
+ *pte0 &= ~0x80000000;
+}
+
+#if defined(TARGET_PPC64)
+static inline int pte64_is_valid(target_ulong pte0)
+{
+ return pte0 & 0x0000000000000001ULL ? 1 : 0;
+}
+
+static inline void pte64_invalidate(target_ulong *pte0)
+{
+ *pte0 &= ~0x0000000000000001ULL;
+}
+#endif
+
+#define PTE_PTEM_MASK 0x7FFFFFBF
+#define PTE_CHECK_MASK (TARGET_PAGE_MASK | 0x7B)
+#if defined(TARGET_PPC64)
+#define PTE64_PTEM_MASK 0xFFFFFFFFFFFFFF80ULL
+#define PTE64_CHECK_MASK (TARGET_PAGE_MASK | 0x7F)
+#endif
+
+static inline int pp_check(int key, int pp, int nx)
+{
+ int access;
+
+ /* Compute access rights */
+ /* When pp is 3/7, the result is undefined. Set it to noaccess */
+ access = 0;
+ if (key == 0) {
+ switch (pp) {
+ case 0x0:
+ case 0x1:
+ case 0x2:
+ access |= PAGE_WRITE;
+ /* No break here */
+ case 0x3:
+ case 0x6:
+ access |= PAGE_READ;
+ break;
+ }
+ } else {
+ switch (pp) {
+ case 0x0:
+ case 0x6:
+ access = 0;
+ break;
+ case 0x1:
+ case 0x3:
+ access = PAGE_READ;
+ break;
+ case 0x2:
+ access = PAGE_READ | PAGE_WRITE;
+ break;
+ }
+ }
+ if (nx == 0) {
+ access |= PAGE_EXEC;
+ }
+
+ return access;
+}
+
+static inline int check_prot(int prot, int rw, int access_type)
+{
+ int ret;
+
+ if (access_type == ACCESS_CODE) {
+ if (prot & PAGE_EXEC) {
+ ret = 0;
+ } else {
+ ret = -2;
+ }
+ } else if (rw) {
+ if (prot & PAGE_WRITE) {
+ ret = 0;
+ } else {
+ ret = -2;
+ }
+ } else {
+ if (prot & PAGE_READ) {
+ ret = 0;
+ } else {
+ ret = -2;
+ }
+ }
+
+ return ret;
+}
+
+static inline int pte_check(mmu_ctx_t *ctx, int is_64b, target_ulong pte0,
+ target_ulong pte1, int h, int rw, int type)
+{
+ target_ulong ptem, mmask;
+ int access, ret, pteh, ptev, pp;
+
+ ret = -1;
+ /* Check validity and table match */
+#if defined(TARGET_PPC64)
+ if (is_64b) {
+ ptev = pte64_is_valid(pte0);
+ pteh = (pte0 >> 1) & 1;
+ } else
+#endif
+ {
+ ptev = pte_is_valid(pte0);
+ pteh = (pte0 >> 6) & 1;
+ }
+ if (ptev && h == pteh) {
+ /* Check vsid & api */
+#if defined(TARGET_PPC64)
+ if (is_64b) {
+ ptem = pte0 & PTE64_PTEM_MASK;
+ mmask = PTE64_CHECK_MASK;
+ pp = (pte1 & 0x00000003) | ((pte1 >> 61) & 0x00000004);
+ ctx->nx = (pte1 >> 2) & 1; /* No execute bit */
+ ctx->nx |= (pte1 >> 3) & 1; /* Guarded bit */
+ } else
+#endif
+ {
+ ptem = pte0 & PTE_PTEM_MASK;
+ mmask = PTE_CHECK_MASK;
+ pp = pte1 & 0x00000003;
+ }
+ if (ptem == ctx->ptem) {
+ if (ctx->raddr != (target_phys_addr_t)-1ULL) {
+ /* all matches should have equal RPN, WIMG & PP */
+ if ((ctx->raddr & mmask) != (pte1 & mmask)) {
+ qemu_log("Bad RPN/WIMG/PP\n");
+ return -3;
+ }
+ }
+ /* Compute access rights */
+ access = pp_check(ctx->key, pp, ctx->nx);
+ /* Keep the matching PTE informations */
+ ctx->raddr = pte1;
+ ctx->prot = access;
+ ret = check_prot(ctx->prot, rw, type);
+ if (ret == 0) {
+ /* Access granted */
+ LOG_MMU("PTE access granted !\n");
+ } else {
+ /* Access right violation */
+ LOG_MMU("PTE access rejected\n");
+ }
+ }
+ }
+
+ return ret;
+}
+
+static inline int pte32_check(mmu_ctx_t *ctx, target_ulong pte0,
+ target_ulong pte1, int h, int rw, int type)
+{
+ return pte_check(ctx, 0, pte0, pte1, h, rw, type);
+}
+
+#if defined(TARGET_PPC64)
+static inline int pte64_check(mmu_ctx_t *ctx, target_ulong pte0,
+ target_ulong pte1, int h, int rw, int type)
+{
+ return pte_check(ctx, 1, pte0, pte1, h, rw, type);
+}
+#endif
+
+static inline int pte_update_flags(mmu_ctx_t *ctx, target_ulong *pte1p,
+ int ret, int rw)
+{
+ int store = 0;
+
+ /* Update page flags */
+ if (!(*pte1p & 0x00000100)) {
+ /* Update accessed flag */
+ *pte1p |= 0x00000100;
+ store = 1;
+ }
+ if (!(*pte1p & 0x00000080)) {
+ if (rw == 1 && ret == 0) {
+ /* Update changed flag */
+ *pte1p |= 0x00000080;
+ store = 1;
+ } else {
+ /* Force page fault for first write access */
+ ctx->prot &= ~PAGE_WRITE;
+ }
+ }
+
+ return store;
+}
+
+/* Software driven TLB helpers */
+static inline int ppc6xx_tlb_getnum(CPUPPCState *env, target_ulong eaddr,
+ int way, int is_code)
+{
+ int nr;
+
+ /* Select TLB num in a way from address */
+ nr = (eaddr >> TARGET_PAGE_BITS) & (env->tlb_per_way - 1);
+ /* Select TLB way */
+ nr += env->tlb_per_way * way;
+ /* 6xx have separate TLBs for instructions and data */
+ if (is_code && env->id_tlbs == 1) {
+ nr += env->nb_tlb;
+ }
+
+ return nr;
+}
+
+static inline void ppc6xx_tlb_invalidate_all(CPUPPCState *env)
+{
+ ppc6xx_tlb_t *tlb;
+ int nr, max;
+
+ /* LOG_SWTLB("Invalidate all TLBs\n"); */
+ /* Invalidate all defined software TLB */
+ max = env->nb_tlb;
+ if (env->id_tlbs == 1) {
+ max *= 2;
+ }
+ for (nr = 0; nr < max; nr++) {
+ tlb = &env->tlb.tlb6[nr];
+ pte_invalidate(&tlb->pte0);
+ }
+ tlb_flush(env, 1);
+}
+
+static inline void ppc6xx_tlb_invalidate_virt2(CPUPPCState *env,
+ target_ulong eaddr,
+ int is_code, int match_epn)
+{
+#if !defined(FLUSH_ALL_TLBS)
+ ppc6xx_tlb_t *tlb;
+ int way, nr;
+
+ /* Invalidate ITLB + DTLB, all ways */
+ for (way = 0; way < env->nb_ways; way++) {
+ nr = ppc6xx_tlb_getnum(env, eaddr, way, is_code);
+ tlb = &env->tlb.tlb6[nr];
+ if (pte_is_valid(tlb->pte0) && (match_epn == 0 || eaddr == tlb->EPN)) {
+ LOG_SWTLB("TLB invalidate %d/%d " TARGET_FMT_lx "\n", nr,
+ env->nb_tlb, eaddr);
+ pte_invalidate(&tlb->pte0);
+ tlb_flush_page(env, tlb->EPN);
+ }
+ }
+#else
+ /* XXX: PowerPC specification say this is valid as well */
+ ppc6xx_tlb_invalidate_all(env);
+#endif
+}
+
+static inline void ppc6xx_tlb_invalidate_virt(CPUPPCState *env,
+ target_ulong eaddr, int is_code)
+{
+ ppc6xx_tlb_invalidate_virt2(env, eaddr, is_code, 0);
+}
+
+void ppc6xx_tlb_store(CPUPPCState *env, target_ulong EPN, int way, int is_code,
+ target_ulong pte0, target_ulong pte1)
+{
+ ppc6xx_tlb_t *tlb;
+ int nr;
+
+ nr = ppc6xx_tlb_getnum(env, EPN, way, is_code);
+ tlb = &env->tlb.tlb6[nr];
+ LOG_SWTLB("Set TLB %d/%d EPN " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
+ " PTE1 " TARGET_FMT_lx "\n", nr, env->nb_tlb, EPN, pte0, pte1);
+ /* Invalidate any pending reference in QEMU for this virtual address */
+ ppc6xx_tlb_invalidate_virt2(env, EPN, is_code, 1);
+ tlb->pte0 = pte0;
+ tlb->pte1 = pte1;
+ tlb->EPN = EPN;
+ /* Store last way for LRU mechanism */
+ env->last_way = way;
+}
+
+static inline int ppc6xx_tlb_check(CPUPPCState *env, mmu_ctx_t *ctx,
+ target_ulong eaddr, int rw, int access_type)
+{
+ ppc6xx_tlb_t *tlb;
+ int nr, best, way;
+ int ret;
+
+ best = -1;
+ ret = -1; /* No TLB found */
+ for (way = 0; way < env->nb_ways; way++) {
+ nr = ppc6xx_tlb_getnum(env, eaddr, way,
+ access_type == ACCESS_CODE ? 1 : 0);
+ tlb = &env->tlb.tlb6[nr];
+ /* This test "emulates" the PTE index match for hardware TLBs */
+ if ((eaddr & TARGET_PAGE_MASK) != tlb->EPN) {
+ LOG_SWTLB("TLB %d/%d %s [" TARGET_FMT_lx " " TARGET_FMT_lx
+ "] <> " TARGET_FMT_lx "\n", nr, env->nb_tlb,
+ pte_is_valid(tlb->pte0) ? "valid" : "inval",
+ tlb->EPN, tlb->EPN + TARGET_PAGE_SIZE, eaddr);
+ continue;
+ }
+ LOG_SWTLB("TLB %d/%d %s " TARGET_FMT_lx " <> " TARGET_FMT_lx " "
+ TARGET_FMT_lx " %c %c\n", nr, env->nb_tlb,
+ pte_is_valid(tlb->pte0) ? "valid" : "inval",
+ tlb->EPN, eaddr, tlb->pte1,
+ rw ? 'S' : 'L', access_type == ACCESS_CODE ? 'I' : 'D');
+ switch (pte32_check(ctx, tlb->pte0, tlb->pte1, 0, rw, access_type)) {
+ case -3:
+ /* TLB inconsistency */
+ return -1;
+ case -2:
+ /* Access violation */
+ ret = -2;
+ best = nr;
+ break;
+ case -1:
+ default:
+ /* No match */
+ break;
+ case 0:
+ /* access granted */
+ /* XXX: we should go on looping to check all TLBs consistency
+ * but we can speed-up the whole thing as the
+ * result would be undefined if TLBs are not consistent.
+ */
+ ret = 0;
+ best = nr;
+ goto done;
+ }
+ }
+ if (best != -1) {
+ done:
+ LOG_SWTLB("found TLB at addr " TARGET_FMT_plx " prot=%01x ret=%d\n",
+ ctx->raddr & TARGET_PAGE_MASK, ctx->prot, ret);
+ /* Update page flags */
+ pte_update_flags(ctx, &env->tlb.tlb6[best].pte1, ret, rw);
+ }
+
+ return ret;
+}
+
+/* Perform BAT hit & translation */
+static inline void bat_size_prot(CPUPPCState *env, target_ulong *blp,
+ int *validp, int *protp, target_ulong *BATu,
+ target_ulong *BATl)
+{
+ target_ulong bl;
+ int pp, valid, prot;
+
+ bl = (*BATu & 0x00001FFC) << 15;
+ valid = 0;
+ prot = 0;
+ if (((msr_pr == 0) && (*BATu & 0x00000002)) ||
+ ((msr_pr != 0) && (*BATu & 0x00000001))) {
+ valid = 1;
+ pp = *BATl & 0x00000003;
+ if (pp != 0) {
+ prot = PAGE_READ | PAGE_EXEC;
+ if (pp == 0x2) {
+ prot |= PAGE_WRITE;
+ }
+ }
+ }
+ *blp = bl;
+ *validp = valid;
+ *protp = prot;
+}
+
+static inline void bat_601_size_prot(CPUPPCState *env, target_ulong *blp,
+ int *validp, int *protp,
+ target_ulong *BATu, target_ulong *BATl)
+{
+ target_ulong bl;
+ int key, pp, valid, prot;
+
+ bl = (*BATl & 0x0000003F) << 17;
+ LOG_BATS("b %02x ==> bl " TARGET_FMT_lx " msk " TARGET_FMT_lx "\n",
+ (uint8_t)(*BATl & 0x0000003F), bl, ~bl);
+ prot = 0;
+ valid = (*BATl >> 6) & 1;
+ if (valid) {
+ pp = *BATu & 0x00000003;
+ if (msr_pr == 0) {
+ key = (*BATu >> 3) & 1;
+ } else {
+ key = (*BATu >> 2) & 1;
+ }
+ prot = pp_check(key, pp, 0);
+ }
+ *blp = bl;
+ *validp = valid;
+ *protp = prot;
+}
+
+static inline int get_bat(CPUPPCState *env, mmu_ctx_t *ctx,
+ target_ulong virtual, int rw, int type)
+{
+ target_ulong *BATlt, *BATut, *BATu, *BATl;
+ target_ulong BEPIl, BEPIu, bl;
+ int i, valid, prot;
+ int ret = -1;
+
+ LOG_BATS("%s: %cBAT v " TARGET_FMT_lx "\n", __func__,
+ type == ACCESS_CODE ? 'I' : 'D', virtual);
+ switch (type) {
+ case ACCESS_CODE:
+ BATlt = env->IBAT[1];
+ BATut = env->IBAT[0];
+ break;
+ default:
+ BATlt = env->DBAT[1];
+ BATut = env->DBAT[0];
+ break;
+ }
+ for (i = 0; i < env->nb_BATs; i++) {
+ BATu = &BATut[i];
+ BATl = &BATlt[i];
+ BEPIu = *BATu & 0xF0000000;
+ BEPIl = *BATu & 0x0FFE0000;
+ if (unlikely(env->mmu_model == POWERPC_MMU_601)) {
+ bat_601_size_prot(env, &bl, &valid, &prot, BATu, BATl);
+ } else {
+ bat_size_prot(env, &bl, &valid, &prot, BATu, BATl);
+ }
+ LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
+ " BATl " TARGET_FMT_lx "\n", __func__,
+ type == ACCESS_CODE ? 'I' : 'D', i, virtual, *BATu, *BATl);
+ if ((virtual & 0xF0000000) == BEPIu &&
+ ((virtual & 0x0FFE0000) & ~bl) == BEPIl) {
+ /* BAT matches */
+ if (valid != 0) {
+ /* Get physical address */
+ ctx->raddr = (*BATl & 0xF0000000) |
+ ((virtual & 0x0FFE0000 & bl) | (*BATl & 0x0FFE0000)) |
+ (virtual & 0x0001F000);
+ /* Compute access rights */
+ ctx->prot = prot;
+ ret = check_prot(ctx->prot, rw, type);
+ if (ret == 0) {
+ LOG_BATS("BAT %d match: r " TARGET_FMT_plx " prot=%c%c\n",
+ i, ctx->raddr, ctx->prot & PAGE_READ ? 'R' : '-',
+ ctx->prot & PAGE_WRITE ? 'W' : '-');
+ }
+ break;
+ }
+ }
+ }
+ if (ret < 0) {
+#if defined(DEBUG_BATS)
+ if (qemu_log_enabled()) {
+ LOG_BATS("no BAT match for " TARGET_FMT_lx ":\n", virtual);
+ for (i = 0; i < 4; i++) {
+ BATu = &BATut[i];
+ BATl = &BATlt[i];
+ BEPIu = *BATu & 0xF0000000;
+ BEPIl = *BATu & 0x0FFE0000;
+ bl = (*BATu & 0x00001FFC) << 15;
+ LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
+ " BATl " TARGET_FMT_lx "\n\t" TARGET_FMT_lx " "
+ TARGET_FMT_lx " " TARGET_FMT_lx "\n",
+ __func__, type == ACCESS_CODE ? 'I' : 'D', i, virtual,
+ *BATu, *BATl, BEPIu, BEPIl, bl);
+ }
+ }
+#endif
+ }
+ /* No hit */
+ return ret;
+}
+
+static inline target_phys_addr_t get_pteg_offset(CPUPPCState *env,
+ target_phys_addr_t hash,
+ int pte_size)
+{
+ return (hash * pte_size * 8) & env->htab_mask;
+}
+
+/* PTE table lookup */
+static inline int find_pte2(CPUPPCState *env, mmu_ctx_t *ctx, int is_64b, int h,
+ int rw, int type, int target_page_bits)
+{
+ target_phys_addr_t pteg_off;
+ target_ulong pte0, pte1;
+ int i, good = -1;
+ int ret, r;
+
+ ret = -1; /* No entry found */
+ pteg_off = get_pteg_offset(env, ctx->hash[h],
+ is_64b ? HASH_PTE_SIZE_64 : HASH_PTE_SIZE_32);
+ for (i = 0; i < 8; i++) {
+#if defined(TARGET_PPC64)
+ if (is_64b) {
+ if (env->external_htab) {
+ pte0 = ldq_p(env->external_htab + pteg_off + (i * 16));
+ pte1 = ldq_p(env->external_htab + pteg_off + (i * 16) + 8);
+ } else {
+ pte0 = ldq_phys(env->htab_base + pteg_off + (i * 16));
+ pte1 = ldq_phys(env->htab_base + pteg_off + (i * 16) + 8);
+ }
+
+ r = pte64_check(ctx, pte0, pte1, h, rw, type);
+ LOG_MMU("Load pte from " TARGET_FMT_lx " => " TARGET_FMT_lx " "
+ TARGET_FMT_lx " %d %d %d " TARGET_FMT_lx "\n",
+ pteg_off + (i * 16), pte0, pte1, (int)(pte0 & 1), h,
+ (int)((pte0 >> 1) & 1), ctx->ptem);
+ } else
+#endif
+ {
+ if (env->external_htab) {
+ pte0 = ldl_p(env->external_htab + pteg_off + (i * 8));
+ pte1 = ldl_p(env->external_htab + pteg_off + (i * 8) + 4);
+ } else {
+ pte0 = ldl_phys(env->htab_base + pteg_off + (i * 8));
+ pte1 = ldl_phys(env->htab_base + pteg_off + (i * 8) + 4);
+ }
+ r = pte32_check(ctx, pte0, pte1, h, rw, type);
+ LOG_MMU("Load pte from " TARGET_FMT_lx " => " TARGET_FMT_lx " "
+ TARGET_FMT_lx " %d %d %d " TARGET_FMT_lx "\n",
+ pteg_off + (i * 8), pte0, pte1, (int)(pte0 >> 31), h,
+ (int)((pte0 >> 6) & 1), ctx->ptem);
+ }
+ switch (r) {
+ case -3:
+ /* PTE inconsistency */
+ return -1;
+ case -2:
+ /* Access violation */
+ ret = -2;
+ good = i;
+ break;
+ case -1:
+ default:
+ /* No PTE match */
+ break;
+ case 0:
+ /* access granted */
+ /* XXX: we should go on looping to check all PTEs consistency
+ * but if we can speed-up the whole thing as the
+ * result would be undefined if PTEs are not consistent.
+ */
+ ret = 0;
+ good = i;
+ goto done;
+ }
+ }
+ if (good != -1) {
+ done:
+ LOG_MMU("found PTE at addr " TARGET_FMT_lx " prot=%01x ret=%d\n",
+ ctx->raddr, ctx->prot, ret);
+ /* Update page flags */
+ pte1 = ctx->raddr;
+ if (pte_update_flags(ctx, &pte1, ret, rw) == 1) {
+#if defined(TARGET_PPC64)
+ if (is_64b) {
+ if (env->external_htab) {
+ stq_p(env->external_htab + pteg_off + (good * 16) + 8,
+ pte1);
+ } else {
+ stq_phys_notdirty(env->htab_base + pteg_off +
+ (good * 16) + 8, pte1);
+ }
+ } else
+#endif
+ {
+ if (env->external_htab) {
+ stl_p(env->external_htab + pteg_off + (good * 8) + 4,
+ pte1);
+ } else {
+ stl_phys_notdirty(env->htab_base + pteg_off +
+ (good * 8) + 4, pte1);
+ }
+ }
+ }
+ }
+
+ /* We have a TLB that saves 4K pages, so let's
+ * split a huge page to 4k chunks */
+ if (target_page_bits != TARGET_PAGE_BITS) {
+ ctx->raddr |= (ctx->eaddr & ((1 << target_page_bits) - 1))
+ & TARGET_PAGE_MASK;
+ }
+ return ret;
+}
+
+static inline int find_pte(CPUPPCState *env, mmu_ctx_t *ctx, int h, int rw,
+ int type, int target_page_bits)
+{
+#if defined(TARGET_PPC64)
+ if (env->mmu_model & POWERPC_MMU_64) {
+ return find_pte2(env, ctx, 1, h, rw, type, target_page_bits);
+ }
+#endif
+
+ return find_pte2(env, ctx, 0, h, rw, type, target_page_bits);
+}
+
+#if defined(TARGET_PPC64)
+static inline ppc_slb_t *slb_lookup(CPUPPCState *env, target_ulong eaddr)
+{
+ uint64_t esid_256M, esid_1T;
+ int n;
+
+ LOG_SLB("%s: eaddr " TARGET_FMT_lx "\n", __func__, eaddr);
+
+ esid_256M = (eaddr & SEGMENT_MASK_256M) | SLB_ESID_V;
+ esid_1T = (eaddr & SEGMENT_MASK_1T) | SLB_ESID_V;
+
+ for (n = 0; n < env->slb_nr; n++) {
+ ppc_slb_t *slb = &env->slb[n];
+
+ LOG_SLB("%s: slot %d %016" PRIx64 " %016"
+ PRIx64 "\n", __func__, n, slb->esid, slb->vsid);
+ /* We check for 1T matches on all MMUs here - if the MMU
+ * doesn't have 1T segment support, we will have prevented 1T
+ * entries from being inserted in the slbmte code. */
+ if (((slb->esid == esid_256M) &&
+ ((slb->vsid & SLB_VSID_B) == SLB_VSID_B_256M))
+ || ((slb->esid == esid_1T) &&
+ ((slb->vsid & SLB_VSID_B) == SLB_VSID_B_1T))) {
+ return slb;
+ }
+ }
+
+ return NULL;
+}
+
+void ppc_slb_invalidate_all(CPUPPCState *env)
+{
+ int n, do_invalidate;
+
+ do_invalidate = 0;
+ /* XXX: Warning: slbia never invalidates the first segment */
+ for (n = 1; n < env->slb_nr; n++) {
+ ppc_slb_t *slb = &env->slb[n];
+
+ if (slb->esid & SLB_ESID_V) {
+ slb->esid &= ~SLB_ESID_V;
+ /* XXX: given the fact that segment size is 256 MB or 1TB,
+ * and we still don't have a tlb_flush_mask(env, n, mask)
+ * in QEMU, we just invalidate all TLBs
+ */
+ do_invalidate = 1;
+ }
+ }
+ if (do_invalidate) {
+ tlb_flush(env, 1);
+ }
+}
+
+void ppc_slb_invalidate_one(CPUPPCState *env, uint64_t T0)
+{
+ ppc_slb_t *slb;
+
+ slb = slb_lookup(env, T0);
+ if (!slb) {
+ return;
+ }
+
+ if (slb->esid & SLB_ESID_V) {
+ slb->esid &= ~SLB_ESID_V;
+
+ /* XXX: given the fact that segment size is 256 MB or 1TB,
+ * and we still don't have a tlb_flush_mask(env, n, mask)
+ * in QEMU, we just invalidate all TLBs
+ */
+ tlb_flush(env, 1);
+ }
+}
+
+int ppc_store_slb(CPUPPCState *env, target_ulong rb, target_ulong rs)
+{
+ int slot = rb & 0xfff;
+ ppc_slb_t *slb = &env->slb[slot];
+
+ if (rb & (0x1000 - env->slb_nr)) {
+ return -1; /* Reserved bits set or slot too high */
+ }
+ if (rs & (SLB_VSID_B & ~SLB_VSID_B_1T)) {
+ return -1; /* Bad segment size */
+ }
+ if ((rs & SLB_VSID_B) && !(env->mmu_model & POWERPC_MMU_1TSEG)) {
+ return -1; /* 1T segment on MMU that doesn't support it */
+ }
+
+ /* Mask out the slot number as we store the entry */
+ slb->esid = rb & (SLB_ESID_ESID | SLB_ESID_V);
+ slb->vsid = rs;
+
+ LOG_SLB("%s: %d " TARGET_FMT_lx " - " TARGET_FMT_lx " => %016" PRIx64
+ " %016" PRIx64 "\n", __func__, slot, rb, rs,
+ slb->esid, slb->vsid);
+
+ return 0;
+}
+
+int ppc_load_slb_esid(CPUPPCState *env, target_ulong rb, target_ulong *rt)
+{
+ int slot = rb & 0xfff;
+ ppc_slb_t *slb = &env->slb[slot];
+
+ if (slot >= env->slb_nr) {
+ return -1;
+ }
+
+ *rt = slb->esid;
+ return 0;
+}
+
+int ppc_load_slb_vsid(CPUPPCState *env, target_ulong rb, target_ulong *rt)
+{
+ int slot = rb & 0xfff;
+ ppc_slb_t *slb = &env->slb[slot];
+
+ if (slot >= env->slb_nr) {
+ return -1;
+ }
+
+ *rt = slb->vsid;
+ return 0;
+}
+#endif /* defined(TARGET_PPC64) */
+
+/* Perform segment based translation */
+static inline int get_segment(CPUPPCState *env, mmu_ctx_t *ctx,
+ target_ulong eaddr, int rw, int type)
+{
+ target_phys_addr_t hash;
+ target_ulong vsid;
+ int ds, pr, target_page_bits;
+ int ret, ret2;
+
+ pr = msr_pr;
+ ctx->eaddr = eaddr;
+#if defined(TARGET_PPC64)
+ if (env->mmu_model & POWERPC_MMU_64) {
+ ppc_slb_t *slb;
+ target_ulong pageaddr;
+ int segment_bits;
+
+ LOG_MMU("Check SLBs\n");
+ slb = slb_lookup(env, eaddr);
+ if (!slb) {
+ return -5;
+ }
+
+ if (slb->vsid & SLB_VSID_B) {
+ vsid = (slb->vsid & SLB_VSID_VSID) >> SLB_VSID_SHIFT_1T;
+ segment_bits = 40;
+ } else {
+ vsid = (slb->vsid & SLB_VSID_VSID) >> SLB_VSID_SHIFT;
+ segment_bits = 28;
+ }
+
+ target_page_bits = (slb->vsid & SLB_VSID_L)
+ ? TARGET_PAGE_BITS_16M : TARGET_PAGE_BITS;
+ ctx->key = !!(pr ? (slb->vsid & SLB_VSID_KP)
+ : (slb->vsid & SLB_VSID_KS));
+ ds = 0;
+ ctx->nx = !!(slb->vsid & SLB_VSID_N);
+
+ pageaddr = eaddr & ((1ULL << segment_bits)
+ - (1ULL << target_page_bits));
+ if (slb->vsid & SLB_VSID_B) {
+ hash = vsid ^ (vsid << 25) ^ (pageaddr >> target_page_bits);
+ } else {
+ hash = vsid ^ (pageaddr >> target_page_bits);
+ }
+ /* Only 5 bits of the page index are used in the AVPN */
+ ctx->ptem = (slb->vsid & SLB_VSID_PTEM) |
+ ((pageaddr >> 16) & ((1ULL << segment_bits) - 0x80));
+ } else
+#endif /* defined(TARGET_PPC64) */
+ {
+ target_ulong sr, pgidx;
+
+ sr = env->sr[eaddr >> 28];
+ ctx->key = (((sr & 0x20000000) && (pr != 0)) ||
+ ((sr & 0x40000000) && (pr == 0))) ? 1 : 0;
+ ds = sr & 0x80000000 ? 1 : 0;
+ ctx->nx = sr & 0x10000000 ? 1 : 0;
+ vsid = sr & 0x00FFFFFF;
+ target_page_bits = TARGET_PAGE_BITS;
+ LOG_MMU("Check segment v=" TARGET_FMT_lx " %d " TARGET_FMT_lx " nip="
+ TARGET_FMT_lx " lr=" TARGET_FMT_lx
+ " ir=%d dr=%d pr=%d %d t=%d\n",
+ eaddr, (int)(eaddr >> 28), sr, env->nip, env->lr, (int)msr_ir,
+ (int)msr_dr, pr != 0 ? 1 : 0, rw, type);
+ pgidx = (eaddr & ~SEGMENT_MASK_256M) >> target_page_bits;
+ hash = vsid ^ pgidx;
+ ctx->ptem = (vsid << 7) | (pgidx >> 10);
+ }
+ LOG_MMU("pte segment: key=%d ds %d nx %d vsid " TARGET_FMT_lx "\n",
+ ctx->key, ds, ctx->nx, vsid);
+ ret = -1;
+ if (!ds) {
+ /* Check if instruction fetch is allowed, if needed */
+ if (type != ACCESS_CODE || ctx->nx == 0) {
+ /* Page address translation */
+ LOG_MMU("htab_base " TARGET_FMT_plx " htab_mask " TARGET_FMT_plx
+ " hash " TARGET_FMT_plx "\n",
+ env->htab_base, env->htab_mask, hash);
+ ctx->hash[0] = hash;
+ ctx->hash[1] = ~hash;
+
+ /* Initialize real address with an invalid value */
+ ctx->raddr = (target_phys_addr_t)-1ULL;
+ if (unlikely(env->mmu_model == POWERPC_MMU_SOFT_6xx ||
+ env->mmu_model == POWERPC_MMU_SOFT_74xx)) {
+ /* Software TLB search */
+ ret = ppc6xx_tlb_check(env, ctx, eaddr, rw, type);
+ } else {
+ LOG_MMU("0 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
+ " vsid=" TARGET_FMT_lx " ptem=" TARGET_FMT_lx
+ " hash=" TARGET_FMT_plx "\n",
+ env->htab_base, env->htab_mask, vsid, ctx->ptem,
+ ctx->hash[0]);
+ /* Primary table lookup */
+ ret = find_pte(env, ctx, 0, rw, type, target_page_bits);
+ if (ret < 0) {
+ /* Secondary table lookup */
+ if (eaddr != 0xEFFFFFFF) {
+ LOG_MMU("1 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
+ " vsid=" TARGET_FMT_lx " api=" TARGET_FMT_lx
+ " hash=" TARGET_FMT_plx "\n", env->htab_base,
+ env->htab_mask, vsid, ctx->ptem, ctx->hash[1]);
+ }
+ ret2 = find_pte(env, ctx, 1, rw, type,
+ target_page_bits);
+ if (ret2 != -1) {
+ ret = ret2;
+ }
+ }
+ }
+#if defined(DUMP_PAGE_TABLES)
+ if (qemu_log_enabled()) {
+ target_phys_addr_t curaddr;
+ uint32_t a0, a1, a2, a3;
+
+ qemu_log("Page table: " TARGET_FMT_plx " len " TARGET_FMT_plx
+ "\n", sdr, mask + 0x80);
+ for (curaddr = sdr; curaddr < (sdr + mask + 0x80);
+ curaddr += 16) {
+ a0 = ldl_phys(curaddr);
+ a1 = ldl_phys(curaddr + 4);
+ a2 = ldl_phys(curaddr + 8);
+ a3 = ldl_phys(curaddr + 12);
+ if (a0 != 0 || a1 != 0 || a2 != 0 || a3 != 0) {
+ qemu_log(TARGET_FMT_plx ": %08x %08x %08x %08x\n",
+ curaddr, a0, a1, a2, a3);
+ }
+ }
+ }
+#endif
+ } else {
+ LOG_MMU("No access allowed\n");
+ ret = -3;
+ }
+ } else {
+ target_ulong sr;
+
+ LOG_MMU("direct store...\n");
+ /* Direct-store segment : absolutely *BUGGY* for now */
+
+ /* Direct-store implies a 32-bit MMU.
+ * Check the Segment Register's bus unit ID (BUID).
+ */
+ sr = env->sr[eaddr >> 28];
+ if ((sr & 0x1FF00000) >> 20 == 0x07f) {
+ /* Memory-forced I/O controller interface access */
+ /* If T=1 and BUID=x'07F', the 601 performs a memory access
+ * to SR[28-31] LA[4-31], bypassing all protection mechanisms.
+ */
+ ctx->raddr = ((sr & 0xF) << 28) | (eaddr & 0x0FFFFFFF);
+ ctx->prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
+ return 0;
+ }
+
+ switch (type) {
+ case ACCESS_INT:
+ /* Integer load/store : only access allowed */
+ break;
+ case ACCESS_CODE:
+ /* No code fetch is allowed in direct-store areas */
+ return -4;
+ case ACCESS_FLOAT:
+ /* Floating point load/store */
+ return -4;
+ case ACCESS_RES:
+ /* lwarx, ldarx or srwcx. */
+ return -4;
+ case ACCESS_CACHE:
+ /* dcba, dcbt, dcbtst, dcbf, dcbi, dcbst, dcbz, or icbi */
+ /* Should make the instruction do no-op.
+ * As it already do no-op, it's quite easy :-)
+ */
+ ctx->raddr = eaddr;
+ return 0;
+ case ACCESS_EXT:
+ /* eciwx or ecowx */
+ return -4;
+ default:
+ qemu_log("ERROR: instruction should not need "
+ "address translation\n");
+ return -4;
+ }
+ if ((rw == 1 || ctx->key != 1) && (rw == 0 || ctx->key != 0)) {
+ ctx->raddr = eaddr;
+ ret = 2;
+ } else {
+ ret = -2;
+ }
+ }
+
+ return ret;
+}
+
+/* Generic TLB check function for embedded PowerPC implementations */
+int ppcemb_tlb_check(CPUPPCState *env, ppcemb_tlb_t *tlb,
+ target_phys_addr_t *raddrp,
+ target_ulong address, uint32_t pid, int ext,
+ int i)
+{
+ target_ulong mask;
+
+ /* Check valid flag */
+ if (!(tlb->prot & PAGE_VALID)) {
+ return -1;
+ }
+ mask = ~(tlb->size - 1);
+ LOG_SWTLB("%s: TLB %d address " TARGET_FMT_lx " PID %u <=> " TARGET_FMT_lx
+ " " TARGET_FMT_lx " %u %x\n", __func__, i, address, pid, tlb->EPN,
+ mask, (uint32_t)tlb->PID, tlb->prot);
+ /* Check PID */
+ if (tlb->PID != 0 && tlb->PID != pid) {
+ return -1;
+ }
+ /* Check effective address */
+ if ((address & mask) != tlb->EPN) {
+ return -1;
+ }
+ *raddrp = (tlb->RPN & mask) | (address & ~mask);
+#if (TARGET_PHYS_ADDR_BITS >= 36)
+ if (ext) {
+ /* Extend the physical address to 36 bits */
+ *raddrp |= (target_phys_addr_t)(tlb->RPN & 0xF) << 32;
+ }
+#endif
+
+ return 0;
+}
+
+/* Generic TLB search function for PowerPC embedded implementations */
+int ppcemb_tlb_search(CPUPPCState *env, target_ulong address, uint32_t pid)
+{
+ ppcemb_tlb_t *tlb;
+ target_phys_addr_t raddr;
+ int i, ret;
+
+ /* Default return value is no match */
+ ret = -1;
+ for (i = 0; i < env->nb_tlb; i++) {
+ tlb = &env->tlb.tlbe[i];
+ if (ppcemb_tlb_check(env, tlb, &raddr, address, pid, 0, i) == 0) {
+ ret = i;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+/* Helpers specific to PowerPC 40x implementations */
+static inline void ppc4xx_tlb_invalidate_all(CPUPPCState *env)
+{
+ ppcemb_tlb_t *tlb;
+ int i;
+
+ for (i = 0; i < env->nb_tlb; i++) {
+ tlb = &env->tlb.tlbe[i];
+ tlb->prot &= ~PAGE_VALID;
+ }
+ tlb_flush(env, 1);
+}
+
+static inline void ppc4xx_tlb_invalidate_virt(CPUPPCState *env,
+ target_ulong eaddr, uint32_t pid)
+{
+#if !defined(FLUSH_ALL_TLBS)
+ ppcemb_tlb_t *tlb;
+ target_phys_addr_t raddr;
+ target_ulong page, end;
+ int i;
+
+ for (i = 0; i < env->nb_tlb; i++) {
+ tlb = &env->tlb.tlbe[i];
+ if (ppcemb_tlb_check(env, tlb, &raddr, eaddr, pid, 0, i) == 0) {
+ end = tlb->EPN + tlb->size;
+ for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) {
+ tlb_flush_page(env, page);
+ }
+ tlb->prot &= ~PAGE_VALID;
+ break;
+ }
+ }
+#else
+ ppc4xx_tlb_invalidate_all(env);
+#endif
+}
+
+static int mmu40x_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
+ target_ulong address, int rw,
+ int access_type)
+{
+ ppcemb_tlb_t *tlb;
+ target_phys_addr_t raddr;
+ int i, ret, zsel, zpr, pr;
+
+ ret = -1;
+ raddr = (target_phys_addr_t)-1ULL;
+ pr = msr_pr;
+ for (i = 0; i < env->nb_tlb; i++) {
+ tlb = &env->tlb.tlbe[i];
+ if (ppcemb_tlb_check(env, tlb, &raddr, address,
+ env->spr[SPR_40x_PID], 0, i) < 0) {
+ continue;
+ }
+ zsel = (tlb->attr >> 4) & 0xF;
+ zpr = (env->spr[SPR_40x_ZPR] >> (30 - (2 * zsel))) & 0x3;
+ LOG_SWTLB("%s: TLB %d zsel %d zpr %d rw %d attr %08x\n",
+ __func__, i, zsel, zpr, rw, tlb->attr);
+ /* Check execute enable bit */
+ switch (zpr) {
+ case 0x2:
+ if (pr != 0) {
+ goto check_perms;
+ }
+ /* No break here */
+ case 0x3:
+ /* All accesses granted */
+ ctx->prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
+ ret = 0;
+ break;
+ case 0x0:
+ if (pr != 0) {
+ /* Raise Zone protection fault. */
+ env->spr[SPR_40x_ESR] = 1 << 22;
+ ctx->prot = 0;
+ ret = -2;
+ break;
+ }
+ /* No break here */
+ case 0x1:
+ check_perms:
+ /* Check from TLB entry */
+ ctx->prot = tlb->prot;
+ ret = check_prot(ctx->prot, rw, access_type);
+ if (ret == -2) {
+ env->spr[SPR_40x_ESR] = 0;
+ }
+ break;
+ }
+ if (ret >= 0) {
+ ctx->raddr = raddr;
+ LOG_SWTLB("%s: access granted " TARGET_FMT_lx " => " TARGET_FMT_plx
+ " %d %d\n", __func__, address, ctx->raddr, ctx->prot,
+ ret);
+ return 0;
+ }
+ }
+ LOG_SWTLB("%s: access refused " TARGET_FMT_lx " => " TARGET_FMT_plx
+ " %d %d\n", __func__, address, raddr, ctx->prot, ret);
+
+ return ret;
+}
+
+void store_40x_sler(CPUPPCState *env, uint32_t val)
+{
+ /* XXX: TO BE FIXED */
+ if (val != 0x00000000) {
+ cpu_abort(env, "Little-endian regions are not supported by now\n");
+ }
+ env->spr[SPR_405_SLER] = val;
+}
+
+static inline int mmubooke_check_tlb(CPUPPCState *env, ppcemb_tlb_t *tlb,
+ target_phys_addr_t *raddr, int *prot,
+ target_ulong address, int rw,
+ int access_type, int i)
+{
+ int ret, prot2;
+
+ if (ppcemb_tlb_check(env, tlb, raddr, address,
+ env->spr[SPR_BOOKE_PID],
+ !env->nb_pids, i) >= 0) {
+ goto found_tlb;
+ }
+
+ if (env->spr[SPR_BOOKE_PID1] &&
+ ppcemb_tlb_check(env, tlb, raddr, address,
+ env->spr[SPR_BOOKE_PID1], 0, i) >= 0) {
+ goto found_tlb;
+ }
+
+ if (env->spr[SPR_BOOKE_PID2] &&
+ ppcemb_tlb_check(env, tlb, raddr, address,
+ env->spr[SPR_BOOKE_PID2], 0, i) >= 0) {
+ goto found_tlb;
+ }
+
+ LOG_SWTLB("%s: TLB entry not found\n", __func__);
+ return -1;
+
+found_tlb:
+
+ if (msr_pr != 0) {
+ prot2 = tlb->prot & 0xF;
+ } else {
+ prot2 = (tlb->prot >> 4) & 0xF;
+ }
+
+ /* Check the address space */
+ if (access_type == ACCESS_CODE) {
+ if (msr_ir != (tlb->attr & 1)) {
+ LOG_SWTLB("%s: AS doesn't match\n", __func__);
+ return -1;
+ }
+
+ *prot = prot2;
+ if (prot2 & PAGE_EXEC) {
+ LOG_SWTLB("%s: good TLB!\n", __func__);
+ return 0;
+ }
+
+ LOG_SWTLB("%s: no PAGE_EXEC: %x\n", __func__, prot2);
+ ret = -3;
+ } else {
+ if (msr_dr != (tlb->attr & 1)) {
+ LOG_SWTLB("%s: AS doesn't match\n", __func__);
+ return -1;
+ }
+
+ *prot = prot2;
+ if ((!rw && prot2 & PAGE_READ) || (rw && (prot2 & PAGE_WRITE))) {
+ LOG_SWTLB("%s: found TLB!\n", __func__);
+ return 0;
+ }
+
+ LOG_SWTLB("%s: PAGE_READ/WRITE doesn't match: %x\n", __func__, prot2);
+ ret = -2;
+ }
+
+ return ret;
+}
+
+static int mmubooke_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
+ target_ulong address, int rw,
+ int access_type)
+{
+ ppcemb_tlb_t *tlb;
+ target_phys_addr_t raddr;
+ int i, ret;
+
+ ret = -1;
+ raddr = (target_phys_addr_t)-1ULL;
+ for (i = 0; i < env->nb_tlb; i++) {
+ tlb = &env->tlb.tlbe[i];
+ ret = mmubooke_check_tlb(env, tlb, &raddr, &ctx->prot, address, rw,
+ access_type, i);
+ if (!ret) {
+ break;
+ }
+ }
+
+ if (ret >= 0) {
+ ctx->raddr = raddr;
+ LOG_SWTLB("%s: access granted " TARGET_FMT_lx " => " TARGET_FMT_plx
+ " %d %d\n", __func__, address, ctx->raddr, ctx->prot,
+ ret);
+ } else {
+ LOG_SWTLB("%s: access refused " TARGET_FMT_lx " => " TARGET_FMT_plx
+ " %d %d\n", __func__, address, raddr, ctx->prot, ret);
+ }
+
+ return ret;
+}
+
+void booke206_flush_tlb(CPUPPCState *env, int flags, const int check_iprot)
+{
+ int tlb_size;
+ int i, j;
+ ppcmas_tlb_t *tlb = env->tlb.tlbm;
+
+ for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
+ if (flags & (1 << i)) {
+ tlb_size = booke206_tlb_size(env, i);
+ for (j = 0; j < tlb_size; j++) {
+ if (!check_iprot || !(tlb[j].mas1 & MAS1_IPROT)) {
+ tlb[j].mas1 &= ~MAS1_VALID;
+ }
+ }
+ }
+ tlb += booke206_tlb_size(env, i);
+ }
+
+ tlb_flush(env, 1);
+}
+
+target_phys_addr_t booke206_tlb_to_page_size(CPUPPCState *env,
+ ppcmas_tlb_t *tlb)
+{
+ int tlbm_size;
+
+ tlbm_size = (tlb->mas1 & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
+
+ return 1024ULL << tlbm_size;
+}
+
+/* TLB check function for MAS based SoftTLBs */
+int ppcmas_tlb_check(CPUPPCState *env, ppcmas_tlb_t *tlb,
+ target_phys_addr_t *raddrp,
+ target_ulong address, uint32_t pid)
+{
+ target_ulong mask;
+ uint32_t tlb_pid;
+
+ /* Check valid flag */
+ if (!(tlb->mas1 & MAS1_VALID)) {
+ return -1;
+ }
+
+ mask = ~(booke206_tlb_to_page_size(env, tlb) - 1);
+ LOG_SWTLB("%s: TLB ADDR=0x" TARGET_FMT_lx " PID=0x%x MAS1=0x%x MAS2=0x%"
+ PRIx64 " mask=0x" TARGET_FMT_lx " MAS7_3=0x%" PRIx64 " MAS8=%x\n",
+ __func__, address, pid, tlb->mas1, tlb->mas2, mask, tlb->mas7_3,
+ tlb->mas8);
+
+ /* Check PID */
+ tlb_pid = (tlb->mas1 & MAS1_TID_MASK) >> MAS1_TID_SHIFT;
+ if (tlb_pid != 0 && tlb_pid != pid) {
+ return -1;
+ }
+
+ /* Check effective address */
+ if ((address & mask) != (tlb->mas2 & MAS2_EPN_MASK)) {
+ return -1;
+ }
+
+ if (raddrp) {
+ *raddrp = (tlb->mas7_3 & mask) | (address & ~mask);
+ }
+
+ return 0;
+}
+
+static int mmubooke206_check_tlb(CPUPPCState *env, ppcmas_tlb_t *tlb,
+ target_phys_addr_t *raddr, int *prot,
+ target_ulong address, int rw,
+ int access_type)
+{
+ int ret;
+ int prot2 = 0;
+
+ if (ppcmas_tlb_check(env, tlb, raddr, address,
+ env->spr[SPR_BOOKE_PID]) >= 0) {
+ goto found_tlb;
+ }
+
+ if (env->spr[SPR_BOOKE_PID1] &&
+ ppcmas_tlb_check(env, tlb, raddr, address,
+ env->spr[SPR_BOOKE_PID1]) >= 0) {
+ goto found_tlb;
+ }
+
+ if (env->spr[SPR_BOOKE_PID2] &&
+ ppcmas_tlb_check(env, tlb, raddr, address,
+ env->spr[SPR_BOOKE_PID2]) >= 0) {
+ goto found_tlb;
+ }
+
+ LOG_SWTLB("%s: TLB entry not found\n", __func__);
+ return -1;
+
+found_tlb:
+
+ if (msr_pr != 0) {
+ if (tlb->mas7_3 & MAS3_UR) {
+ prot2 |= PAGE_READ;
+ }
+ if (tlb->mas7_3 & MAS3_UW) {
+ prot2 |= PAGE_WRITE;
+ }
+ if (tlb->mas7_3 & MAS3_UX) {
+ prot2 |= PAGE_EXEC;
+ }
+ } else {
+ if (tlb->mas7_3 & MAS3_SR) {
+ prot2 |= PAGE_READ;
+ }
+ if (tlb->mas7_3 & MAS3_SW) {
+ prot2 |= PAGE_WRITE;
+ }
+ if (tlb->mas7_3 & MAS3_SX) {
+ prot2 |= PAGE_EXEC;
+ }
+ }
+
+ /* Check the address space and permissions */
+ if (access_type == ACCESS_CODE) {
+ if (msr_ir != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) {
+ LOG_SWTLB("%s: AS doesn't match\n", __func__);
+ return -1;
+ }
+
+ *prot = prot2;
+ if (prot2 & PAGE_EXEC) {
+ LOG_SWTLB("%s: good TLB!\n", __func__);
+ return 0;
+ }
+
+ LOG_SWTLB("%s: no PAGE_EXEC: %x\n", __func__, prot2);
+ ret = -3;
+ } else {
+ if (msr_dr != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) {
+ LOG_SWTLB("%s: AS doesn't match\n", __func__);
+ return -1;
+ }
+
+ *prot = prot2;
+ if ((!rw && prot2 & PAGE_READ) || (rw && (prot2 & PAGE_WRITE))) {
+ LOG_SWTLB("%s: found TLB!\n", __func__);
+ return 0;
+ }
+
+ LOG_SWTLB("%s: PAGE_READ/WRITE doesn't match: %x\n", __func__, prot2);
+ ret = -2;
+ }
+
+ return ret;
+}
+
+static int mmubooke206_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
+ target_ulong address, int rw,
+ int access_type)
+{
+ ppcmas_tlb_t *tlb;
+ target_phys_addr_t raddr;
+ int i, j, ret;
+
+ ret = -1;
+ raddr = (target_phys_addr_t)-1ULL;
+
+ for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
+ int ways = booke206_tlb_ways(env, i);
+
+ for (j = 0; j < ways; j++) {
+ tlb = booke206_get_tlbm(env, i, address, j);
+ if (!tlb) {
+ continue;
+ }
+ ret = mmubooke206_check_tlb(env, tlb, &raddr, &ctx->prot, address,
+ rw, access_type);
+ if (ret != -1) {
+ goto found_tlb;
+ }
+ }
+ }
+
+found_tlb:
+
+ if (ret >= 0) {
+ ctx->raddr = raddr;
+ LOG_SWTLB("%s: access granted " TARGET_FMT_lx " => " TARGET_FMT_plx
+ " %d %d\n", __func__, address, ctx->raddr, ctx->prot,
+ ret);
+ } else {
+ LOG_SWTLB("%s: access refused " TARGET_FMT_lx " => " TARGET_FMT_plx
+ " %d %d\n", __func__, address, raddr, ctx->prot, ret);
+ }
+
+ return ret;
+}
+
+static const char *book3e_tsize_to_str[32] = {
+ "1K", "2K", "4K", "8K", "16K", "32K", "64K", "128K", "256K", "512K",
+ "1M", "2M", "4M", "8M", "16M", "32M", "64M", "128M", "256M", "512M",
+ "1G", "2G", "4G", "8G", "16G", "32G", "64G", "128G", "256G", "512G",
+ "1T", "2T"
+};
+
+static void mmubooke_dump_mmu(FILE *f, fprintf_function cpu_fprintf,
+ CPUPPCState *env)
+{
+ ppcemb_tlb_t *entry;
+ int i;
+
+ if (kvm_enabled() && !env->kvm_sw_tlb) {
+ cpu_fprintf(f, "Cannot access KVM TLB\n");
+ return;
+ }
+
+ cpu_fprintf(f, "\nTLB:\n");
+ cpu_fprintf(f, "Effective Physical Size PID Prot "
+ "Attr\n");
+
+ entry = &env->tlb.tlbe[0];
+ for (i = 0; i < env->nb_tlb; i++, entry++) {
+ target_phys_addr_t ea, pa;
+ target_ulong mask;
+ uint64_t size = (uint64_t)entry->size;
+ char size_buf[20];
+
+ /* Check valid flag */
+ if (!(entry->prot & PAGE_VALID)) {
+ continue;
+ }
+
+ mask = ~(entry->size - 1);
+ ea = entry->EPN & mask;
+ pa = entry->RPN & mask;
+#if (TARGET_PHYS_ADDR_BITS >= 36)
+ /* Extend the physical address to 36 bits */
+ pa |= (target_phys_addr_t)(entry->RPN & 0xF) << 32;
+#endif
+ size /= 1024;
+ if (size >= 1024) {
+ snprintf(size_buf, sizeof(size_buf), "%3" PRId64 "M", size / 1024);
+ } else {
+ snprintf(size_buf, sizeof(size_buf), "%3" PRId64 "k", size);
+ }
+ cpu_fprintf(f, "0x%016" PRIx64 " 0x%016" PRIx64 " %s %-5u %08x %08x\n",
+ (uint64_t)ea, (uint64_t)pa, size_buf, (uint32_t)entry->PID,
+ entry->prot, entry->attr);
+ }
+
+}
+
+static void mmubooke206_dump_one_tlb(FILE *f, fprintf_function cpu_fprintf,
+ CPUPPCState *env, int tlbn, int offset,
+ int tlbsize)
+{
+ ppcmas_tlb_t *entry;
+ int i;
+
+ cpu_fprintf(f, "\nTLB%d:\n", tlbn);
+ cpu_fprintf(f, "Effective Physical Size TID TS SRWX"
+ " URWX WIMGE U0123\n");
+
+ entry = &env->tlb.tlbm[offset];
+ for (i = 0; i < tlbsize; i++, entry++) {
+ target_phys_addr_t ea, pa, size;
+ int tsize;
+
+ if (!(entry->mas1 & MAS1_VALID)) {
+ continue;
+ }
+
+ tsize = (entry->mas1 & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
+ size = 1024ULL << tsize;
+ ea = entry->mas2 & ~(size - 1);
+ pa = entry->mas7_3 & ~(size - 1);
+
+ cpu_fprintf(f, "0x%016" PRIx64 " 0x%016" PRIx64 " %4s %-5u %1u S%c%c%c"
+ "U%c%c%c %c%c%c%c%c U%c%c%c%c\n",
+ (uint64_t)ea, (uint64_t)pa,
+ book3e_tsize_to_str[tsize],
+ (entry->mas1 & MAS1_TID_MASK) >> MAS1_TID_SHIFT,
+ (entry->mas1 & MAS1_TS) >> MAS1_TS_SHIFT,
+ entry->mas7_3 & MAS3_SR ? 'R' : '-',
+ entry->mas7_3 & MAS3_SW ? 'W' : '-',
+ entry->mas7_3 & MAS3_SX ? 'X' : '-',
+ entry->mas7_3 & MAS3_UR ? 'R' : '-',
+ entry->mas7_3 & MAS3_UW ? 'W' : '-',
+ entry->mas7_3 & MAS3_UX ? 'X' : '-',
+ entry->mas2 & MAS2_W ? 'W' : '-',
+ entry->mas2 & MAS2_I ? 'I' : '-',
+ entry->mas2 & MAS2_M ? 'M' : '-',
+ entry->mas2 & MAS2_G ? 'G' : '-',
+ entry->mas2 & MAS2_E ? 'E' : '-',
+ entry->mas7_3 & MAS3_U0 ? '0' : '-',
+ entry->mas7_3 & MAS3_U1 ? '1' : '-',
+ entry->mas7_3 & MAS3_U2 ? '2' : '-',
+ entry->mas7_3 & MAS3_U3 ? '3' : '-');
+ }
+}
+
+static void mmubooke206_dump_mmu(FILE *f, fprintf_function cpu_fprintf,
+ CPUPPCState *env)
+{
+ int offset = 0;
+ int i;
+
+ if (kvm_enabled() && !env->kvm_sw_tlb) {
+ cpu_fprintf(f, "Cannot access KVM TLB\n");
+ return;
+ }
+
+ for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
+ int size = booke206_tlb_size(env, i);
+
+ if (size == 0) {
+ continue;
+ }
+
+ mmubooke206_dump_one_tlb(f, cpu_fprintf, env, i, offset, size);
+ offset += size;
+ }
+}
+
+#if defined(TARGET_PPC64)
+static void mmubooks_dump_mmu(FILE *f, fprintf_function cpu_fprintf,
+ CPUPPCState *env)
+{
+ int i;
+ uint64_t slbe, slbv;
+
+ cpu_synchronize_state(env);
+
+ cpu_fprintf(f, "SLB\tESID\t\t\tVSID\n");
+ for (i = 0; i < env->slb_nr; i++) {
+ slbe = env->slb[i].esid;
+ slbv = env->slb[i].vsid;
+ if (slbe == 0 && slbv == 0) {
+ continue;
+ }
+ cpu_fprintf(f, "%d\t0x%016" PRIx64 "\t0x%016" PRIx64 "\n",
+ i, slbe, slbv);
+ }
+}
+#endif
+
+void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUPPCState *env)
+{
+ switch (env->mmu_model) {
+ case POWERPC_MMU_BOOKE:
+ mmubooke_dump_mmu(f, cpu_fprintf, env);
+ break;
+ case POWERPC_MMU_BOOKE206:
+ mmubooke206_dump_mmu(f, cpu_fprintf, env);
+ break;
+#if defined(TARGET_PPC64)
+ case POWERPC_MMU_64B:
+ case POWERPC_MMU_2_06:
+ mmubooks_dump_mmu(f, cpu_fprintf, env);
+ break;
+#endif
+ default:
+ qemu_log_mask(LOG_UNIMP, "%s: unimplemented\n", __func__);
+ }
+}
+
+static inline int check_physical(CPUPPCState *env, mmu_ctx_t *ctx,
+ target_ulong eaddr, int rw)
+{
+ int in_plb, ret;
+
+ ctx->raddr = eaddr;
+ ctx->prot = PAGE_READ | PAGE_EXEC;
+ ret = 0;
+ switch (env->mmu_model) {
+ case POWERPC_MMU_32B:
+ case POWERPC_MMU_601:
+ case POWERPC_MMU_SOFT_6xx:
+ case POWERPC_MMU_SOFT_74xx:
+ case POWERPC_MMU_SOFT_4xx:
+ case POWERPC_MMU_REAL:
+ case POWERPC_MMU_BOOKE:
+ ctx->prot |= PAGE_WRITE;
+ break;
+#if defined(TARGET_PPC64)
+ case POWERPC_MMU_620:
+ case POWERPC_MMU_64B:
+ case POWERPC_MMU_2_06:
+ /* Real address are 60 bits long */
+ ctx->raddr &= 0x0FFFFFFFFFFFFFFFULL;
+ ctx->prot |= PAGE_WRITE;
+ break;
+#endif
+ case POWERPC_MMU_SOFT_4xx_Z:
+ if (unlikely(msr_pe != 0)) {
+ /* 403 family add some particular protections,
+ * using PBL/PBU registers for accesses with no translation.
+ */
+ in_plb =
+ /* Check PLB validity */
+ (env->pb[0] < env->pb[1] &&
+ /* and address in plb area */
+ eaddr >= env->pb[0] && eaddr < env->pb[1]) ||
+ (env->pb[2] < env->pb[3] &&
+ eaddr >= env->pb[2] && eaddr < env->pb[3]) ? 1 : 0;
+ if (in_plb ^ msr_px) {
+ /* Access in protected area */
+ if (rw == 1) {
+ /* Access is not allowed */
+ ret = -2;
+ }
+ } else {
+ /* Read-write access is allowed */
+ ctx->prot |= PAGE_WRITE;
+ }
+ }
+ break;
+ case POWERPC_MMU_MPC8xx:
+ /* XXX: TODO */
+ cpu_abort(env, "MPC8xx MMU model is not implemented\n");
+ break;
+ case POWERPC_MMU_BOOKE206:
+ cpu_abort(env, "BookE 2.06 MMU doesn't have physical real mode\n");
+ break;
+ default:
+ cpu_abort(env, "Unknown or invalid MMU model\n");
+ return -1;
+ }
+
+ return ret;
+}
+
+int get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx, target_ulong eaddr,
+ int rw, int access_type)
+{
+ int ret;
+
+#if 0
+ qemu_log("%s\n", __func__);
+#endif
+ if ((access_type == ACCESS_CODE && msr_ir == 0) ||
+ (access_type != ACCESS_CODE && msr_dr == 0)) {
+ if (env->mmu_model == POWERPC_MMU_BOOKE) {
+ /* The BookE MMU always performs address translation. The
+ IS and DS bits only affect the address space. */
+ ret = mmubooke_get_physical_address(env, ctx, eaddr,
+ rw, access_type);
+ } else if (env->mmu_model == POWERPC_MMU_BOOKE206) {
+ ret = mmubooke206_get_physical_address(env, ctx, eaddr, rw,
+ access_type);
+ } else {
+ /* No address translation. */
+ ret = check_physical(env, ctx, eaddr, rw);
+ }
+ } else {
+ ret = -1;
+ switch (env->mmu_model) {
+ case POWERPC_MMU_32B:
+ case POWERPC_MMU_601:
+ case POWERPC_MMU_SOFT_6xx:
+ case POWERPC_MMU_SOFT_74xx:
+ /* Try to find a BAT */
+ if (env->nb_BATs != 0) {
+ ret = get_bat(env, ctx, eaddr, rw, access_type);
+ }
+#if defined(TARGET_PPC64)
+ case POWERPC_MMU_620:
+ case POWERPC_MMU_64B:
+ case POWERPC_MMU_2_06:
+#endif
+ if (ret < 0) {
+ /* We didn't match any BAT entry or don't have BATs */
+ ret = get_segment(env, ctx, eaddr, rw, access_type);
+ }
+ break;
+ case POWERPC_MMU_SOFT_4xx:
+ case POWERPC_MMU_SOFT_4xx_Z:
+ ret = mmu40x_get_physical_address(env, ctx, eaddr,
+ rw, access_type);
+ break;
+ case POWERPC_MMU_BOOKE:
+ ret = mmubooke_get_physical_address(env, ctx, eaddr,
+ rw, access_type);
+ break;
+ case POWERPC_MMU_BOOKE206:
+ ret = mmubooke206_get_physical_address(env, ctx, eaddr, rw,
+ access_type);
+ break;
+ case POWERPC_MMU_MPC8xx:
+ /* XXX: TODO */
+ cpu_abort(env, "MPC8xx MMU model is not implemented\n");
+ break;
+ case POWERPC_MMU_REAL:
+ cpu_abort(env, "PowerPC in real mode do not do any translation\n");
+ return -1;
+ default:
+ cpu_abort(env, "Unknown or invalid MMU model\n");
+ return -1;
+ }
+ }
+#if 0
+ qemu_log("%s address " TARGET_FMT_lx " => %d " TARGET_FMT_plx "\n",
+ __func__, eaddr, ret, ctx->raddr);
+#endif
+
+ return ret;
+}
+
+target_phys_addr_t cpu_get_phys_page_debug(CPUPPCState *env, target_ulong addr)
+{
+ mmu_ctx_t ctx;
+
+ if (unlikely(get_physical_address(env, &ctx, addr, 0, ACCESS_INT) != 0)) {
+ return -1;
+ }
+
+ return ctx.raddr & TARGET_PAGE_MASK;
+}
+
+static void booke206_update_mas_tlb_miss(CPUPPCState *env, target_ulong address,
+ int rw)
+{
+ env->spr[SPR_BOOKE_MAS0] = env->spr[SPR_BOOKE_MAS4] & MAS4_TLBSELD_MASK;
+ env->spr[SPR_BOOKE_MAS1] = env->spr[SPR_BOOKE_MAS4] & MAS4_TSIZED_MASK;
+ env->spr[SPR_BOOKE_MAS2] = env->spr[SPR_BOOKE_MAS4] & MAS4_WIMGED_MASK;
+ env->spr[SPR_BOOKE_MAS3] = 0;
+ env->spr[SPR_BOOKE_MAS6] = 0;
+ env->spr[SPR_BOOKE_MAS7] = 0;
+
+ /* AS */
+ if (((rw == 2) && msr_ir) || ((rw != 2) && msr_dr)) {
+ env->spr[SPR_BOOKE_MAS1] |= MAS1_TS;
+ env->spr[SPR_BOOKE_MAS6] |= MAS6_SAS;
+ }
+
+ env->spr[SPR_BOOKE_MAS1] |= MAS1_VALID;
+ env->spr[SPR_BOOKE_MAS2] |= address & MAS2_EPN_MASK;
+
+ switch (env->spr[SPR_BOOKE_MAS4] & MAS4_TIDSELD_PIDZ) {
+ case MAS4_TIDSELD_PID0:
+ env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID] << MAS1_TID_SHIFT;
+ break;
+ case MAS4_TIDSELD_PID1:
+ env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID1] << MAS1_TID_SHIFT;
+ break;
+ case MAS4_TIDSELD_PID2:
+ env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID2] << MAS1_TID_SHIFT;
+ break;
+ }
+
+ env->spr[SPR_BOOKE_MAS6] |= env->spr[SPR_BOOKE_PID] << 16;
+
+ /* next victim logic */
+ env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_ESEL_SHIFT;
+ env->last_way++;
+ env->last_way &= booke206_tlb_ways(env, 0) - 1;
+ env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
+}
+
+/* Perform address translation */
+int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw,
+ int mmu_idx)
+{
+ mmu_ctx_t ctx;
+ int access_type;
+ int ret = 0;
+
+ if (rw == 2) {
+ /* code access */
+ rw = 0;
+ access_type = ACCESS_CODE;
+ } else {
+ /* data access */
+ access_type = env->access_type;
+ }
+ ret = get_physical_address(env, &ctx, address, rw, access_type);
+ if (ret == 0) {
+ tlb_set_page(env, address & TARGET_PAGE_MASK,
+ ctx.raddr & TARGET_PAGE_MASK, ctx.prot,
+ mmu_idx, TARGET_PAGE_SIZE);
+ ret = 0;
+ } else if (ret < 0) {
+ LOG_MMU_STATE(env);
+ if (access_type == ACCESS_CODE) {
+ switch (ret) {
+ case -1:
+ /* No matches in page tables or TLB */
+ switch (env->mmu_model) {
+ case POWERPC_MMU_SOFT_6xx:
+ env->exception_index = POWERPC_EXCP_IFTLB;
+ env->error_code = 1 << 18;
+ env->spr[SPR_IMISS] = address;
+ env->spr[SPR_ICMP] = 0x80000000 | ctx.ptem;
+ goto tlb_miss;
+ case POWERPC_MMU_SOFT_74xx:
+ env->exception_index = POWERPC_EXCP_IFTLB;
+ goto tlb_miss_74xx;
+ case POWERPC_MMU_SOFT_4xx:
+ case POWERPC_MMU_SOFT_4xx_Z:
+ env->exception_index = POWERPC_EXCP_ITLB;
+ env->error_code = 0;
+ env->spr[SPR_40x_DEAR] = address;
+ env->spr[SPR_40x_ESR] = 0x00000000;
+ break;
+ case POWERPC_MMU_32B:
+ case POWERPC_MMU_601:
+#if defined(TARGET_PPC64)
+ case POWERPC_MMU_620:
+ case POWERPC_MMU_64B:
+ case POWERPC_MMU_2_06:
+#endif
+ env->exception_index = POWERPC_EXCP_ISI;
+ env->error_code = 0x40000000;
+ break;
+ case POWERPC_MMU_BOOKE206:
+ booke206_update_mas_tlb_miss(env, address, rw);
+ /* fall through */
+ case POWERPC_MMU_BOOKE:
+ env->exception_index = POWERPC_EXCP_ITLB;
+ env->error_code = 0;
+ env->spr[SPR_BOOKE_DEAR] = address;
+ return -1;
+ case POWERPC_MMU_MPC8xx:
+ /* XXX: TODO */
+ cpu_abort(env, "MPC8xx MMU model is not implemented\n");
+ break;
+ case POWERPC_MMU_REAL:
+ cpu_abort(env, "PowerPC in real mode should never raise "
+ "any MMU exceptions\n");
+ return -1;
+ default:
+ cpu_abort(env, "Unknown or invalid MMU model\n");
+ return -1;
+ }
+ break;
+ case -2:
+ /* Access rights violation */
+ env->exception_index = POWERPC_EXCP_ISI;
+ env->error_code = 0x08000000;
+ break;
+ case -3:
+ /* No execute protection violation */
+ if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
+ (env->mmu_model == POWERPC_MMU_BOOKE206)) {
+ env->spr[SPR_BOOKE_ESR] = 0x00000000;
+ }
+ env->exception_index = POWERPC_EXCP_ISI;
+ env->error_code = 0x10000000;
+ break;
+ case -4:
+ /* Direct store exception */
+ /* No code fetch is allowed in direct-store areas */
+ env->exception_index = POWERPC_EXCP_ISI;
+ env->error_code = 0x10000000;
+ break;
+#if defined(TARGET_PPC64)
+ case -5:
+ /* No match in segment table */
+ if (env->mmu_model == POWERPC_MMU_620) {
+ env->exception_index = POWERPC_EXCP_ISI;
+ /* XXX: this might be incorrect */
+ env->error_code = 0x40000000;
+ } else {
+ env->exception_index = POWERPC_EXCP_ISEG;
+ env->error_code = 0;
+ }
+ break;
+#endif
+ }
+ } else {
+ switch (ret) {
+ case -1:
+ /* No matches in page tables or TLB */
+ switch (env->mmu_model) {
+ case POWERPC_MMU_SOFT_6xx:
+ if (rw == 1) {
+ env->exception_index = POWERPC_EXCP_DSTLB;
+ env->error_code = 1 << 16;
+ } else {
+ env->exception_index = POWERPC_EXCP_DLTLB;
+ env->error_code = 0;
+ }
+ env->spr[SPR_DMISS] = address;
+ env->spr[SPR_DCMP] = 0x80000000 | ctx.ptem;
+ tlb_miss:
+ env->error_code |= ctx.key << 19;
+ env->spr[SPR_HASH1] = env->htab_base +
+ get_pteg_offset(env, ctx.hash[0], HASH_PTE_SIZE_32);
+ env->spr[SPR_HASH2] = env->htab_base +
+ get_pteg_offset(env, ctx.hash[1], HASH_PTE_SIZE_32);
+ break;
+ case POWERPC_MMU_SOFT_74xx:
+ if (rw == 1) {
+ env->exception_index = POWERPC_EXCP_DSTLB;
+ } else {
+ env->exception_index = POWERPC_EXCP_DLTLB;
+ }
+ tlb_miss_74xx:
+ /* Implement LRU algorithm */
+ env->error_code = ctx.key << 19;
+ env->spr[SPR_TLBMISS] = (address & ~((target_ulong)0x3)) |
+ ((env->last_way + 1) & (env->nb_ways - 1));
+ env->spr[SPR_PTEHI] = 0x80000000 | ctx.ptem;
+ break;
+ case POWERPC_MMU_SOFT_4xx:
+ case POWERPC_MMU_SOFT_4xx_Z:
+ env->exception_index = POWERPC_EXCP_DTLB;
+ env->error_code = 0;
+ env->spr[SPR_40x_DEAR] = address;
+ if (rw) {
+ env->spr[SPR_40x_ESR] = 0x00800000;
+ } else {
+ env->spr[SPR_40x_ESR] = 0x00000000;
+ }
+ break;
+ case POWERPC_MMU_32B:
+ case POWERPC_MMU_601:
+#if defined(TARGET_PPC64)
+ case POWERPC_MMU_620:
+ case POWERPC_MMU_64B:
+ case POWERPC_MMU_2_06:
+#endif
+ env->exception_index = POWERPC_EXCP_DSI;
+ env->error_code = 0;
+ env->spr[SPR_DAR] = address;
+ if (rw == 1) {
+ env->spr[SPR_DSISR] = 0x42000000;
+ } else {
+ env->spr[SPR_DSISR] = 0x40000000;
+ }
+ break;
+ case POWERPC_MMU_MPC8xx:
+ /* XXX: TODO */
+ cpu_abort(env, "MPC8xx MMU model is not implemented\n");
+ break;
+ case POWERPC_MMU_BOOKE206:
+ booke206_update_mas_tlb_miss(env, address, rw);
+ /* fall through */
+ case POWERPC_MMU_BOOKE:
+ env->exception_index = POWERPC_EXCP_DTLB;
+ env->error_code = 0;
+ env->spr[SPR_BOOKE_DEAR] = address;
+ env->spr[SPR_BOOKE_ESR] = rw ? ESR_ST : 0;
+ return -1;
+ case POWERPC_MMU_REAL:
+ cpu_abort(env, "PowerPC in real mode should never raise "
+ "any MMU exceptions\n");
+ return -1;
+ default:
+ cpu_abort(env, "Unknown or invalid MMU model\n");
+ return -1;
+ }
+ break;
+ case -2:
+ /* Access rights violation */
+ env->exception_index = POWERPC_EXCP_DSI;
+ env->error_code = 0;
+ if (env->mmu_model == POWERPC_MMU_SOFT_4xx
+ || env->mmu_model == POWERPC_MMU_SOFT_4xx_Z) {
+ env->spr[SPR_40x_DEAR] = address;
+ if (rw) {
+ env->spr[SPR_40x_ESR] |= 0x00800000;
+ }
+ } else if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
+ (env->mmu_model == POWERPC_MMU_BOOKE206)) {
+ env->spr[SPR_BOOKE_DEAR] = address;
+ env->spr[SPR_BOOKE_ESR] = rw ? ESR_ST : 0;
+ } else {
+ env->spr[SPR_DAR] = address;
+ if (rw == 1) {
+ env->spr[SPR_DSISR] = 0x0A000000;
+ } else {
+ env->spr[SPR_DSISR] = 0x08000000;
+ }
+ }
+ break;
+ case -4:
+ /* Direct store exception */
+ switch (access_type) {
+ case ACCESS_FLOAT:
+ /* Floating point load/store */
+ env->exception_index = POWERPC_EXCP_ALIGN;
+ env->error_code = POWERPC_EXCP_ALIGN_FP;
+ env->spr[SPR_DAR] = address;
+ break;
+ case ACCESS_RES:
+ /* lwarx, ldarx or stwcx. */
+ env->exception_index = POWERPC_EXCP_DSI;
+ env->error_code = 0;
+ env->spr[SPR_DAR] = address;
+ if (rw == 1) {
+ env->spr[SPR_DSISR] = 0x06000000;
+ } else {
+ env->spr[SPR_DSISR] = 0x04000000;
+ }
+ break;
+ case ACCESS_EXT:
+ /* eciwx or ecowx */
+ env->exception_index = POWERPC_EXCP_DSI;
+ env->error_code = 0;
+ env->spr[SPR_DAR] = address;
+ if (rw == 1) {
+ env->spr[SPR_DSISR] = 0x06100000;
+ } else {
+ env->spr[SPR_DSISR] = 0x04100000;
+ }
+ break;
+ default:
+ printf("DSI: invalid exception (%d)\n", ret);
+ env->exception_index = POWERPC_EXCP_PROGRAM;
+ env->error_code =
+ POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL;
+ env->spr[SPR_DAR] = address;
+ break;
+ }
+ break;
+#if defined(TARGET_PPC64)
+ case -5:
+ /* No match in segment table */
+ if (env->mmu_model == POWERPC_MMU_620) {
+ env->exception_index = POWERPC_EXCP_DSI;
+ env->error_code = 0;
+ env->spr[SPR_DAR] = address;
+ /* XXX: this might be incorrect */
+ if (rw == 1) {
+ env->spr[SPR_DSISR] = 0x42000000;
+ } else {
+ env->spr[SPR_DSISR] = 0x40000000;
+ }
+ } else {
+ env->exception_index = POWERPC_EXCP_DSEG;
+ env->error_code = 0;
+ env->spr[SPR_DAR] = address;
+ }
+ break;
+#endif
+ }
+ }
+#if 0
+ printf("%s: set exception to %d %02x\n", __func__,
+ env->exception, env->error_code);
+#endif
+ ret = 1;
+ }
+
+ return ret;
+}
+
+/*****************************************************************************/
+/* BATs management */
+#if !defined(FLUSH_ALL_TLBS)
+static inline void do_invalidate_BAT(CPUPPCState *env, target_ulong BATu,
+ target_ulong mask)
+{
+ target_ulong base, end, page;
+
+ base = BATu & ~0x0001FFFF;
+ end = base + mask + 0x00020000;
+ LOG_BATS("Flush BAT from " TARGET_FMT_lx " to " TARGET_FMT_lx " ("
+ TARGET_FMT_lx ")\n", base, end, mask);
+ for (page = base; page != end; page += TARGET_PAGE_SIZE) {
+ tlb_flush_page(env, page);
+ }
+ LOG_BATS("Flush done\n");
+}
+#endif
+
+static inline void dump_store_bat(CPUPPCState *env, char ID, int ul, int nr,
+ target_ulong value)
+{
+ LOG_BATS("Set %cBAT%d%c to " TARGET_FMT_lx " (" TARGET_FMT_lx ")\n", ID,
+ nr, ul == 0 ? 'u' : 'l', value, env->nip);
+}
+
+void ppc_store_ibatu(CPUPPCState *env, int nr, target_ulong value)
+{
+ target_ulong mask;
+
+ dump_store_bat(env, 'I', 0, nr, value);
+ if (env->IBAT[0][nr] != value) {
+ mask = (value << 15) & 0x0FFE0000UL;
+#if !defined(FLUSH_ALL_TLBS)
+ do_invalidate_BAT(env, env->IBAT[0][nr], mask);
+#endif
+ /* When storing valid upper BAT, mask BEPI and BRPN
+ * and invalidate all TLBs covered by this BAT
+ */
+ mask = (value << 15) & 0x0FFE0000UL;
+ env->IBAT[0][nr] = (value & 0x00001FFFUL) |
+ (value & ~0x0001FFFFUL & ~mask);
+ env->IBAT[1][nr] = (env->IBAT[1][nr] & 0x0000007B) |
+ (env->IBAT[1][nr] & ~0x0001FFFF & ~mask);
+#if !defined(FLUSH_ALL_TLBS)
+ do_invalidate_BAT(env, env->IBAT[0][nr], mask);
+#else
+ tlb_flush(env, 1);
+#endif
+ }
+}
+
+void ppc_store_ibatl(CPUPPCState *env, int nr, target_ulong value)
+{
+ dump_store_bat(env, 'I', 1, nr, value);
+ env->IBAT[1][nr] = value;
+}
+
+void ppc_store_dbatu(CPUPPCState *env, int nr, target_ulong value)
+{
+ target_ulong mask;
+
+ dump_store_bat(env, 'D', 0, nr, value);
+ if (env->DBAT[0][nr] != value) {
+ /* When storing valid upper BAT, mask BEPI and BRPN
+ * and invalidate all TLBs covered by this BAT
+ */
+ mask = (value << 15) & 0x0FFE0000UL;
+#if !defined(FLUSH_ALL_TLBS)
+ do_invalidate_BAT(env, env->DBAT[0][nr], mask);
+#endif
+ mask = (value << 15) & 0x0FFE0000UL;
+ env->DBAT[0][nr] = (value & 0x00001FFFUL) |
+ (value & ~0x0001FFFFUL & ~mask);
+ env->DBAT[1][nr] = (env->DBAT[1][nr] & 0x0000007B) |
+ (env->DBAT[1][nr] & ~0x0001FFFF & ~mask);
+#if !defined(FLUSH_ALL_TLBS)
+ do_invalidate_BAT(env, env->DBAT[0][nr], mask);
+#else
+ tlb_flush(env, 1);
+#endif
+ }
+}
+
+void ppc_store_dbatl(CPUPPCState *env, int nr, target_ulong value)
+{
+ dump_store_bat(env, 'D', 1, nr, value);
+ env->DBAT[1][nr] = value;
+}
+
+void ppc_store_ibatu_601(CPUPPCState *env, int nr, target_ulong value)
+{
+ target_ulong mask;
+#if defined(FLUSH_ALL_TLBS)
+ int do_inval;
+#endif
+
+ dump_store_bat(env, 'I', 0, nr, value);
+ if (env->IBAT[0][nr] != value) {
+#if defined(FLUSH_ALL_TLBS)
+ do_inval = 0;
+#endif
+ mask = (env->IBAT[1][nr] << 17) & 0x0FFE0000UL;
+ if (env->IBAT[1][nr] & 0x40) {
+ /* Invalidate BAT only if it is valid */
+#if !defined(FLUSH_ALL_TLBS)
+ do_invalidate_BAT(env, env->IBAT[0][nr], mask);
+#else
+ do_inval = 1;
+#endif
+ }
+ /* When storing valid upper BAT, mask BEPI and BRPN
+ * and invalidate all TLBs covered by this BAT
+ */
+ env->IBAT[0][nr] = (value & 0x00001FFFUL) |
+ (value & ~0x0001FFFFUL & ~mask);
+ env->DBAT[0][nr] = env->IBAT[0][nr];
+ if (env->IBAT[1][nr] & 0x40) {
+#if !defined(FLUSH_ALL_TLBS)
+ do_invalidate_BAT(env, env->IBAT[0][nr], mask);
+#else
+ do_inval = 1;
+#endif
+ }
+#if defined(FLUSH_ALL_TLBS)
+ if (do_inval) {
+ tlb_flush(env, 1);
+ }
+#endif
+ }
+}
+
+void ppc_store_ibatl_601(CPUPPCState *env, int nr, target_ulong value)
+{
+ target_ulong mask;
+#if defined(FLUSH_ALL_TLBS)
+ int do_inval;
+#endif
+
+ dump_store_bat(env, 'I', 1, nr, value);
+ if (env->IBAT[1][nr] != value) {
+#if defined(FLUSH_ALL_TLBS)
+ do_inval = 0;
+#endif
+ if (env->IBAT[1][nr] & 0x40) {
+#if !defined(FLUSH_ALL_TLBS)
+ mask = (env->IBAT[1][nr] << 17) & 0x0FFE0000UL;
+ do_invalidate_BAT(env, env->IBAT[0][nr], mask);
+#else
+ do_inval = 1;
+#endif
+ }
+ if (value & 0x40) {
+#if !defined(FLUSH_ALL_TLBS)
+ mask = (value << 17) & 0x0FFE0000UL;
+ do_invalidate_BAT(env, env->IBAT[0][nr], mask);
+#else
+ do_inval = 1;
+#endif
+ }
+ env->IBAT[1][nr] = value;
+ env->DBAT[1][nr] = value;
+#if defined(FLUSH_ALL_TLBS)
+ if (do_inval) {
+ tlb_flush(env, 1);
+ }
+#endif
+ }
+}
+
+/*****************************************************************************/
+/* TLB management */
+void ppc_tlb_invalidate_all(CPUPPCState *env)
+{
+ switch (env->mmu_model) {
+ case POWERPC_MMU_SOFT_6xx:
+ case POWERPC_MMU_SOFT_74xx:
+ ppc6xx_tlb_invalidate_all(env);
+ break;
+ case POWERPC_MMU_SOFT_4xx:
+ case POWERPC_MMU_SOFT_4xx_Z:
+ ppc4xx_tlb_invalidate_all(env);
+ break;
+ case POWERPC_MMU_REAL:
+ cpu_abort(env, "No TLB for PowerPC 4xx in real mode\n");
+ break;
+ case POWERPC_MMU_MPC8xx:
+ /* XXX: TODO */
+ cpu_abort(env, "MPC8xx MMU model is not implemented\n");
+ break;
+ case POWERPC_MMU_BOOKE:
+ tlb_flush(env, 1);
+ break;
+ case POWERPC_MMU_BOOKE206:
+ booke206_flush_tlb(env, -1, 0);
+ break;
+ case POWERPC_MMU_32B:
+ case POWERPC_MMU_601:
+#if defined(TARGET_PPC64)
+ case POWERPC_MMU_620:
+ case POWERPC_MMU_64B:
+ case POWERPC_MMU_2_06:
+#endif /* defined(TARGET_PPC64) */
+ tlb_flush(env, 1);
+ break;
+ default:
+ /* XXX: TODO */
+ cpu_abort(env, "Unknown MMU model\n");
+ break;
+ }
+}
+
+void ppc_tlb_invalidate_one(CPUPPCState *env, target_ulong addr)
+{
+#if !defined(FLUSH_ALL_TLBS)
+ addr &= TARGET_PAGE_MASK;
+ switch (env->mmu_model) {
+ case POWERPC_MMU_SOFT_6xx:
+ case POWERPC_MMU_SOFT_74xx:
+ ppc6xx_tlb_invalidate_virt(env, addr, 0);
+ if (env->id_tlbs == 1) {
+ ppc6xx_tlb_invalidate_virt(env, addr, 1);
+ }
+ break;
+ case POWERPC_MMU_SOFT_4xx:
+ case POWERPC_MMU_SOFT_4xx_Z:
+ ppc4xx_tlb_invalidate_virt(env, addr, env->spr[SPR_40x_PID]);
+ break;
+ case POWERPC_MMU_REAL:
+ cpu_abort(env, "No TLB for PowerPC 4xx in real mode\n");
+ break;
+ case POWERPC_MMU_MPC8xx:
+ /* XXX: TODO */
+ cpu_abort(env, "MPC8xx MMU model is not implemented\n");
+ break;
+ case POWERPC_MMU_BOOKE:
+ /* XXX: TODO */
+ cpu_abort(env, "BookE MMU model is not implemented\n");
+ break;
+ case POWERPC_MMU_BOOKE206:
+ /* XXX: TODO */
+ cpu_abort(env, "BookE 2.06 MMU model is not implemented\n");
+ break;
+ case POWERPC_MMU_32B:
+ case POWERPC_MMU_601:
+ /* tlbie invalidate TLBs for all segments */
+ addr &= ~((target_ulong)-1ULL << 28);
+ /* XXX: this case should be optimized,
+ * giving a mask to tlb_flush_page
+ */
+ tlb_flush_page(env, addr | (0x0 << 28));
+ tlb_flush_page(env, addr | (0x1 << 28));
+ tlb_flush_page(env, addr | (0x2 << 28));
+ tlb_flush_page(env, addr | (0x3 << 28));
+ tlb_flush_page(env, addr | (0x4 << 28));
+ tlb_flush_page(env, addr | (0x5 << 28));
+ tlb_flush_page(env, addr | (0x6 << 28));
+ tlb_flush_page(env, addr | (0x7 << 28));
+ tlb_flush_page(env, addr | (0x8 << 28));
+ tlb_flush_page(env, addr | (0x9 << 28));
+ tlb_flush_page(env, addr | (0xA << 28));
+ tlb_flush_page(env, addr | (0xB << 28));
+ tlb_flush_page(env, addr | (0xC << 28));
+ tlb_flush_page(env, addr | (0xD << 28));
+ tlb_flush_page(env, addr | (0xE << 28));
+ tlb_flush_page(env, addr | (0xF << 28));
+ break;
+#if defined(TARGET_PPC64)
+ case POWERPC_MMU_620:
+ case POWERPC_MMU_64B:
+ case POWERPC_MMU_2_06:
+ /* tlbie invalidate TLBs for all segments */
+ /* XXX: given the fact that there are too many segments to invalidate,
+ * and we still don't have a tlb_flush_mask(env, n, mask) in QEMU,
+ * we just invalidate all TLBs
+ */
+ tlb_flush(env, 1);
+ break;
+#endif /* defined(TARGET_PPC64) */
+ default:
+ /* XXX: TODO */
+ cpu_abort(env, "Unknown MMU model\n");
+ break;
+ }
+#else
+ ppc_tlb_invalidate_all(env);
+#endif
+}
+
+/*****************************************************************************/
+/* Special registers manipulation */
+#if defined(TARGET_PPC64)
+void ppc_store_asr(CPUPPCState *env, target_ulong value)
+{
+ if (env->asr != value) {
+ env->asr = value;
+ tlb_flush(env, 1);
+ }
+}
+#endif
+
+void ppc_store_sdr1(CPUPPCState *env, target_ulong value)
+{
+ LOG_MMU("%s: " TARGET_FMT_lx "\n", __func__, value);
+ if (env->spr[SPR_SDR1] != value) {
+ env->spr[SPR_SDR1] = value;
+#if defined(TARGET_PPC64)
+ if (env->mmu_model & POWERPC_MMU_64) {
+ target_ulong htabsize = value & SDR_64_HTABSIZE;
+
+ if (htabsize > 28) {
+ fprintf(stderr, "Invalid HTABSIZE 0x" TARGET_FMT_lx
+ " stored in SDR1\n", htabsize);
+ htabsize = 28;
+ }
+ env->htab_mask = (1ULL << (htabsize + 18)) - 1;
+ env->htab_base = value & SDR_64_HTABORG;
+ } else
+#endif /* defined(TARGET_PPC64) */
+ {
+ /* FIXME: Should check for valid HTABMASK values */
+ env->htab_mask = ((value & SDR_32_HTABMASK) << 16) | 0xFFFF;
+ env->htab_base = value & SDR_32_HTABORG;
+ }
+ tlb_flush(env, 1);
+ }
+}
+
+#if defined(TARGET_PPC64)
+target_ulong ppc_load_sr(CPUPPCState *env, int slb_nr)
+{
+ /* XXX */
+ return 0;
+}
+#endif
+
+void ppc_store_sr(CPUPPCState *env, int srnum, target_ulong value)
+{
+ LOG_MMU("%s: reg=%d " TARGET_FMT_lx " " TARGET_FMT_lx "\n", __func__,
+ srnum, value, env->sr[srnum]);
+#if defined(TARGET_PPC64)
+ if (env->mmu_model & POWERPC_MMU_64) {
+ uint64_t rb = 0, rs = 0;
+
+ /* ESID = srnum */
+ rb |= ((uint32_t)srnum & 0xf) << 28;
+ /* Set the valid bit */
+ rb |= 1 << 27;
+ /* Index = ESID */
+ rb |= (uint32_t)srnum;
+
+ /* VSID = VSID */
+ rs |= (value & 0xfffffff) << 12;
+ /* flags = flags */
+ rs |= ((value >> 27) & 0xf) << 8;
+
+ ppc_store_slb(env, rb, rs);
+ } else
+#endif
+ if (env->sr[srnum] != value) {
+ env->sr[srnum] = value;
+/* Invalidating 256MB of virtual memory in 4kB pages is way longer than
+ flusing the whole TLB. */
+#if !defined(FLUSH_ALL_TLBS) && 0
+ {
+ target_ulong page, end;
+ /* Invalidate 256 MB of virtual memory */
+ page = (16 << 20) * srnum;
+ end = page + (16 << 20);
+ for (; page != end; page += TARGET_PAGE_SIZE) {
+ tlb_flush_page(env, page);
+ }
+ }
+#else
+ tlb_flush(env, 1);
+#endif
+ }
+}
+#endif /* !defined(CONFIG_USER_ONLY) */
+
/*****************************************************************************/
/* SPR accesses */
--
1.6.0.2
^ permalink raw reply related [flat|nested] 89+ messages in thread
* [Qemu-devel] [PATCH 14/72] ppc: Cleanup MMU merge
2012-06-23 23:06 [Qemu-devel] [PULL 00/72] ppc patch queue 2012-06-24 Alexander Graf
` (12 preceding siblings ...)
2012-06-23 23:06 ` [Qemu-devel] [PATCH 13/72] ppc: Move MMU helpers from helper.c to mmu_helper.c Alexander Graf
@ 2012-06-23 23:06 ` Alexander Graf
2012-06-23 23:06 ` [Qemu-devel] [PATCH 15/72] ppc: Split off timebase helpers Alexander Graf
` (58 subsequent siblings)
72 siblings, 0 replies; 89+ messages in thread
From: Alexander Graf @ 2012-06-23 23:06 UTC (permalink / raw)
To: qemu-devel qemu-devel
Cc: Blue Swirl, qemu-ppc Mailing List, Andreas Färber,
Aurelien Jarno
From: Blue Swirl <blauwirbel@gmail.com>
Remove useless wrappers. In some cases 'int' parameters are
changed to uint32_t.
Make internal functions static.
Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
[agraf: fix kvm compilation]
Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Andreas Färber <afaerber@suse.de>
Signed-off-by: Alexander Graf <agraf@suse.de>
---
target-ppc/cpu.h | 21 --------
target-ppc/mmu_helper.c | 120 ++++++++++++++---------------------------------
2 files changed, 35 insertions(+), 106 deletions(-)
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index 32cfcef..9b157f0 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -1118,24 +1118,11 @@ void do_interrupt (CPUPPCState *env);
void ppc_hw_interrupt (CPUPPCState *env);
#if !defined(CONFIG_USER_ONLY)
-void ppc6xx_tlb_store (CPUPPCState *env, target_ulong EPN, int way, int is_code,
- target_ulong pte0, target_ulong pte1);
-void ppc_store_ibatu (CPUPPCState *env, int nr, target_ulong value);
-void ppc_store_ibatl (CPUPPCState *env, int nr, target_ulong value);
-void ppc_store_dbatu (CPUPPCState *env, int nr, target_ulong value);
-void ppc_store_dbatl (CPUPPCState *env, int nr, target_ulong value);
-void ppc_store_ibatu_601 (CPUPPCState *env, int nr, target_ulong value);
-void ppc_store_ibatl_601 (CPUPPCState *env, int nr, target_ulong value);
void ppc_store_sdr1 (CPUPPCState *env, target_ulong value);
#if defined(TARGET_PPC64)
void ppc_store_asr (CPUPPCState *env, target_ulong value);
-target_ulong ppc_load_slb (CPUPPCState *env, int slb_nr);
-target_ulong ppc_load_sr (CPUPPCState *env, int sr_nr);
int ppc_store_slb (CPUPPCState *env, target_ulong rb, target_ulong rs);
-int ppc_load_slb_esid (CPUPPCState *env, target_ulong rb, target_ulong *rt);
-int ppc_load_slb_vsid (CPUPPCState *env, target_ulong rb, target_ulong *rt);
#endif /* defined(TARGET_PPC64) */
-void ppc_store_sr (CPUPPCState *env, int srnum, target_ulong value);
#endif /* !defined(CONFIG_USER_ONLY) */
void ppc_store_msr (CPUPPCState *env, target_ulong value);
@@ -1174,19 +1161,11 @@ void store_booke_tcr (CPUPPCState *env, target_ulong val);
void store_booke_tsr (CPUPPCState *env, target_ulong val);
void booke206_flush_tlb(CPUPPCState *env, int flags, const int check_iprot);
target_phys_addr_t booke206_tlb_to_page_size(CPUPPCState *env, ppcmas_tlb_t *tlb);
-int ppcemb_tlb_check(CPUPPCState *env, ppcemb_tlb_t *tlb,
- target_phys_addr_t *raddrp, target_ulong address,
- uint32_t pid, int ext, int i);
int ppcmas_tlb_check(CPUPPCState *env, ppcmas_tlb_t *tlb,
target_phys_addr_t *raddrp, target_ulong address,
uint32_t pid);
void ppc_tlb_invalidate_all (CPUPPCState *env);
void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr);
-#if defined(TARGET_PPC64)
-void ppc_slb_invalidate_all (CPUPPCState *env);
-void ppc_slb_invalidate_one (CPUPPCState *env, uint64_t T0);
-#endif
-int ppcemb_tlb_search (CPUPPCState *env, target_ulong address, uint32_t pid);
#endif
#endif
diff --git a/target-ppc/mmu_helper.c b/target-ppc/mmu_helper.c
index 1f67451..d65d290 100644
--- a/target-ppc/mmu_helper.c
+++ b/target-ppc/mmu_helper.c
@@ -347,8 +347,8 @@ static inline void ppc6xx_tlb_invalidate_virt(CPUPPCState *env,
ppc6xx_tlb_invalidate_virt2(env, eaddr, is_code, 0);
}
-void ppc6xx_tlb_store(CPUPPCState *env, target_ulong EPN, int way, int is_code,
- target_ulong pte0, target_ulong pte1)
+static void ppc6xx_tlb_store(CPUPPCState *env, target_ulong EPN, int way,
+ int is_code, target_ulong pte0, target_ulong pte1)
{
ppc6xx_tlb_t *tlb;
int nr;
@@ -712,7 +712,10 @@ static inline ppc_slb_t *slb_lookup(CPUPPCState *env, target_ulong eaddr)
return NULL;
}
-void ppc_slb_invalidate_all(CPUPPCState *env)
+/*****************************************************************************/
+/* SPR accesses */
+
+void helper_slbia(CPUPPCState *env)
{
int n, do_invalidate;
@@ -735,11 +738,11 @@ void ppc_slb_invalidate_all(CPUPPCState *env)
}
}
-void ppc_slb_invalidate_one(CPUPPCState *env, uint64_t T0)
+void helper_slbie(CPUPPCState *env, target_ulong addr)
{
ppc_slb_t *slb;
- slb = slb_lookup(env, T0);
+ slb = slb_lookup(env, addr);
if (!slb) {
return;
}
@@ -781,7 +784,8 @@ int ppc_store_slb(CPUPPCState *env, target_ulong rb, target_ulong rs)
return 0;
}
-int ppc_load_slb_esid(CPUPPCState *env, target_ulong rb, target_ulong *rt)
+static int ppc_load_slb_esid(CPUPPCState *env, target_ulong rb,
+ target_ulong *rt)
{
int slot = rb & 0xfff;
ppc_slb_t *slb = &env->slb[slot];
@@ -794,7 +798,8 @@ int ppc_load_slb_esid(CPUPPCState *env, target_ulong rb, target_ulong *rt)
return 0;
}
-int ppc_load_slb_vsid(CPUPPCState *env, target_ulong rb, target_ulong *rt)
+static int ppc_load_slb_vsid(CPUPPCState *env, target_ulong rb,
+ target_ulong *rt)
{
int slot = rb & 0xfff;
ppc_slb_t *slb = &env->slb[slot];
@@ -1003,10 +1008,10 @@ static inline int get_segment(CPUPPCState *env, mmu_ctx_t *ctx,
}
/* Generic TLB check function for embedded PowerPC implementations */
-int ppcemb_tlb_check(CPUPPCState *env, ppcemb_tlb_t *tlb,
- target_phys_addr_t *raddrp,
- target_ulong address, uint32_t pid, int ext,
- int i)
+static int ppcemb_tlb_check(CPUPPCState *env, ppcemb_tlb_t *tlb,
+ target_phys_addr_t *raddrp,
+ target_ulong address, uint32_t pid, int ext,
+ int i)
{
target_ulong mask;
@@ -1038,7 +1043,8 @@ int ppcemb_tlb_check(CPUPPCState *env, ppcemb_tlb_t *tlb,
}
/* Generic TLB search function for PowerPC embedded implementations */
-int ppcemb_tlb_search(CPUPPCState *env, target_ulong address, uint32_t pid)
+static int ppcemb_tlb_search(CPUPPCState *env, target_ulong address,
+ uint32_t pid)
{
ppcemb_tlb_t *tlb;
target_phys_addr_t raddr;
@@ -2144,7 +2150,7 @@ static inline void dump_store_bat(CPUPPCState *env, char ID, int ul, int nr,
nr, ul == 0 ? 'u' : 'l', value, env->nip);
}
-void ppc_store_ibatu(CPUPPCState *env, int nr, target_ulong value)
+void helper_store_ibatu(CPUPPCState *env, uint32_t nr, target_ulong value)
{
target_ulong mask;
@@ -2170,13 +2176,13 @@ void ppc_store_ibatu(CPUPPCState *env, int nr, target_ulong value)
}
}
-void ppc_store_ibatl(CPUPPCState *env, int nr, target_ulong value)
+void helper_store_ibatl(CPUPPCState *env, uint32_t nr, target_ulong value)
{
dump_store_bat(env, 'I', 1, nr, value);
env->IBAT[1][nr] = value;
}
-void ppc_store_dbatu(CPUPPCState *env, int nr, target_ulong value)
+void helper_store_dbatu(CPUPPCState *env, uint32_t nr, target_ulong value)
{
target_ulong mask;
@@ -2202,13 +2208,13 @@ void ppc_store_dbatu(CPUPPCState *env, int nr, target_ulong value)
}
}
-void ppc_store_dbatl(CPUPPCState *env, int nr, target_ulong value)
+void helper_store_dbatl(CPUPPCState *env, uint32_t nr, target_ulong value)
{
dump_store_bat(env, 'D', 1, nr, value);
env->DBAT[1][nr] = value;
}
-void ppc_store_ibatu_601(CPUPPCState *env, int nr, target_ulong value)
+void helper_store_601_batu(CPUPPCState *env, uint32_t nr, target_ulong value)
{
target_ulong mask;
#if defined(FLUSH_ALL_TLBS)
@@ -2250,7 +2256,7 @@ void ppc_store_ibatu_601(CPUPPCState *env, int nr, target_ulong value)
}
}
-void ppc_store_ibatl_601(CPUPPCState *env, int nr, target_ulong value)
+void helper_store_601_batl(CPUPPCState *env, uint32_t nr, target_ulong value)
{
target_ulong mask;
#if defined(FLUSH_ALL_TLBS)
@@ -2446,18 +2452,22 @@ void ppc_store_sdr1(CPUPPCState *env, target_ulong value)
}
}
-#if defined(TARGET_PPC64)
-target_ulong ppc_load_sr(CPUPPCState *env, int slb_nr)
+/* Segment registers load and store */
+target_ulong helper_load_sr(CPUPPCState *env, target_ulong sr_num)
{
- /* XXX */
- return 0;
-}
+#if defined(TARGET_PPC64)
+ if (env->mmu_model & POWERPC_MMU_64) {
+ /* XXX */
+ return 0;
+ }
#endif
+ return env->sr[sr_num];
+}
-void ppc_store_sr(CPUPPCState *env, int srnum, target_ulong value)
+void helper_store_sr(CPUPPCState *env, target_ulong srnum, target_ulong value)
{
LOG_MMU("%s: reg=%d " TARGET_FMT_lx " " TARGET_FMT_lx "\n", __func__,
- srnum, value, env->sr[srnum]);
+ (int)srnum, value, env->sr[srnum]);
#if defined(TARGET_PPC64)
if (env->mmu_model & POWERPC_MMU_64) {
uint64_t rb = 0, rs = 0;
@@ -2498,56 +2508,7 @@ void ppc_store_sr(CPUPPCState *env, int srnum, target_ulong value)
}
#endif /* !defined(CONFIG_USER_ONLY) */
-/*****************************************************************************/
-/* SPR accesses */
-
#if !defined(CONFIG_USER_ONLY)
-void helper_store_ibatu(CPUPPCState *env, uint32_t nr, target_ulong val)
-{
- ppc_store_ibatu(env, nr, val);
-}
-
-void helper_store_ibatl(CPUPPCState *env, uint32_t nr, target_ulong val)
-{
- ppc_store_ibatl(env, nr, val);
-}
-
-void helper_store_dbatu(CPUPPCState *env, uint32_t nr, target_ulong val)
-{
- ppc_store_dbatu(env, nr, val);
-}
-
-void helper_store_dbatl(CPUPPCState *env, uint32_t nr, target_ulong val)
-{
- ppc_store_dbatl(env, nr, val);
-}
-
-void helper_store_601_batl(CPUPPCState *env, uint32_t nr, target_ulong val)
-{
- ppc_store_ibatl_601(env, nr, val);
-}
-
-void helper_store_601_batu(CPUPPCState *env, uint32_t nr, target_ulong val)
-{
- ppc_store_ibatu_601(env, nr, val);
-}
-
-/* Segment registers load and store */
-target_ulong helper_load_sr(CPUPPCState *env, target_ulong sr_num)
-{
-#if defined(TARGET_PPC64)
- if (env->mmu_model & POWERPC_MMU_64) {
- return ppc_load_sr(env, sr_num);
- }
-#endif
- return env->sr[sr_num];
-}
-
-void helper_store_sr(CPUPPCState *env, target_ulong sr_num, target_ulong val)
-{
- ppc_store_sr(env, sr_num, val);
-}
-
/* SLB management */
#if defined(TARGET_PPC64)
void helper_store_slb(CPUPPCState *env, target_ulong rb, target_ulong rs)
@@ -2579,17 +2540,6 @@ target_ulong helper_load_slb_vsid(CPUPPCState *env, target_ulong rb)
}
return rt;
}
-
-void helper_slbia(CPUPPCState *env)
-{
- ppc_slb_invalidate_all(env);
-}
-
-void helper_slbie(CPUPPCState *env, target_ulong addr)
-{
- ppc_slb_invalidate_one(env, addr);
-}
-
#endif /* defined(TARGET_PPC64) */
/* TLB management */
--
1.6.0.2
^ permalink raw reply related [flat|nested] 89+ messages in thread
* [Qemu-devel] [PATCH 15/72] ppc: Split off timebase helpers
2012-06-23 23:06 [Qemu-devel] [PULL 00/72] ppc patch queue 2012-06-24 Alexander Graf
` (13 preceding siblings ...)
2012-06-23 23:06 ` [Qemu-devel] [PATCH 14/72] ppc: Cleanup MMU merge Alexander Graf
@ 2012-06-23 23:06 ` Alexander Graf
2012-06-23 23:06 ` [Qemu-devel] [PATCH 16/72] ppc: Avoid AREG0 for " Alexander Graf
` (57 subsequent siblings)
72 siblings, 0 replies; 89+ messages in thread
From: Alexander Graf @ 2012-06-23 23:06 UTC (permalink / raw)
To: qemu-devel qemu-devel
Cc: Blue Swirl, qemu-ppc Mailing List, Andreas Färber,
Aurelien Jarno
From: Blue Swirl <blauwirbel@gmail.com>
Move decrementer and timebase helpers to a dedicated file.
Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Andreas Färber <afaerber@suse.de>
Signed-off-by: Alexander Graf <agraf@suse.de>
---
target-ppc/Makefile.objs | 2 +
target-ppc/op_helper.c | 135 -----------------------------------
target-ppc/timebase_helper.c | 160 ++++++++++++++++++++++++++++++++++++++++++
3 files changed, 162 insertions(+), 135 deletions(-)
create mode 100644 target-ppc/timebase_helper.c
diff --git a/target-ppc/Makefile.objs b/target-ppc/Makefile.objs
index 71e25b1..19dc744 100644
--- a/target-ppc/Makefile.objs
+++ b/target-ppc/Makefile.objs
@@ -6,5 +6,7 @@ obj-y += excp_helper.o
obj-y += fpu_helper.o
obj-y += int_helper.o
obj-y += mmu_helper.o
+obj-y += timebase_helper.o
+$(obj)/timebase_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
$(obj)/op_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c
index c854c71..0929906 100644
--- a/target-ppc/op_helper.c
+++ b/target-ppc/op_helper.c
@@ -43,44 +43,6 @@ void helper_store_dump_spr(uint32_t sprn)
qemu_log("Write SPR %d %03x <= " TARGET_FMT_lx "\n", sprn, sprn,
env->spr[sprn]);
}
-
-target_ulong helper_load_tbl(void)
-{
- return (target_ulong)cpu_ppc_load_tbl(env);
-}
-
-target_ulong helper_load_tbu(void)
-{
- return cpu_ppc_load_tbu(env);
-}
-
-target_ulong helper_load_atbl(void)
-{
- return (target_ulong)cpu_ppc_load_atbl(env);
-}
-
-target_ulong helper_load_atbu(void)
-{
- return cpu_ppc_load_atbu(env);
-}
-
-#if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY)
-target_ulong helper_load_purr(void)
-{
- return (target_ulong)cpu_ppc_load_purr(env);
-}
-#endif
-
-target_ulong helper_load_601_rtcl(void)
-{
- return cpu_ppc601_load_rtcl(env);
-}
-
-target_ulong helper_load_601_rtcu(void)
-{
- return cpu_ppc601_load_rtcu(env);
-}
-
#if !defined(CONFIG_USER_ONLY)
#if defined(TARGET_PPC64)
void helper_store_asr(target_ulong val)
@@ -94,46 +56,6 @@ void helper_store_sdr1(target_ulong val)
ppc_store_sdr1(env, val);
}
-void helper_store_tbl(target_ulong val)
-{
- cpu_ppc_store_tbl(env, val);
-}
-
-void helper_store_tbu(target_ulong val)
-{
- cpu_ppc_store_tbu(env, val);
-}
-
-void helper_store_atbl(target_ulong val)
-{
- cpu_ppc_store_atbl(env, val);
-}
-
-void helper_store_atbu(target_ulong val)
-{
- cpu_ppc_store_atbu(env, val);
-}
-
-void helper_store_601_rtcl(target_ulong val)
-{
- cpu_ppc601_store_rtcl(env, val);
-}
-
-void helper_store_601_rtcu(target_ulong val)
-{
- cpu_ppc601_store_rtcu(env, val);
-}
-
-target_ulong helper_load_decr(void)
-{
- return cpu_ppc_load_decr(env);
-}
-
-void helper_store_decr(target_ulong val)
-{
- cpu_ppc_store_decr(env, val);
-}
-
void helper_store_hid0_601(target_ulong val)
{
target_ulong hid0;
@@ -160,16 +82,6 @@ void helper_store_403_pbr(uint32_t num, target_ulong value)
}
}
-target_ulong helper_load_40x_pit(void)
-{
- return load_40x_pit(env);
-}
-
-void helper_store_40x_pit(target_ulong val)
-{
- store_40x_pit(env, val);
-}
-
void helper_store_40x_dbcr0(target_ulong val)
{
store_40x_dbcr0(env, val);
@@ -179,16 +91,6 @@ void helper_store_40x_sler(target_ulong val)
{
store_40x_sler(env, val);
}
-
-void helper_store_booke_tcr(target_ulong val)
-{
- store_booke_tcr(env, val);
-}
-
-void helper_store_booke_tsr(target_ulong val)
-{
- store_booke_tsr(env, val);
-}
#endif
/*****************************************************************************/
@@ -381,43 +283,6 @@ target_ulong helper_clcs(uint32_t arg)
}
/*****************************************************************************/
-/* Embedded PowerPC specific helpers */
-
-/* XXX: to be improved to check access rights when in user-mode */
-target_ulong helper_load_dcr(target_ulong dcrn)
-{
- uint32_t val = 0;
-
- if (unlikely(env->dcr_env == NULL)) {
- qemu_log("No DCR environment\n");
- helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
- POWERPC_EXCP_INVAL |
- POWERPC_EXCP_INVAL_INVAL);
- } else if (unlikely(ppc_dcr_read(env->dcr_env,
- (uint32_t)dcrn, &val) != 0)) {
- qemu_log("DCR read error %d %03x\n", (uint32_t)dcrn, (uint32_t)dcrn);
- helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
- POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG);
- }
- return val;
-}
-
-void helper_store_dcr(target_ulong dcrn, target_ulong val)
-{
- if (unlikely(env->dcr_env == NULL)) {
- qemu_log("No DCR environment\n");
- helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
- POWERPC_EXCP_INVAL |
- POWERPC_EXCP_INVAL_INVAL);
- } else if (unlikely(ppc_dcr_write(env->dcr_env, (uint32_t)dcrn,
- (uint32_t)val) != 0)) {
- qemu_log("DCR write error %d %03x\n", (uint32_t)dcrn, (uint32_t)dcrn);
- helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
- POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG);
- }
-}
-
-/*****************************************************************************/
/* Altivec extension helpers */
#if defined(HOST_WORDS_BIGENDIAN)
#define HI_IDX 0
diff --git a/target-ppc/timebase_helper.c b/target-ppc/timebase_helper.c
new file mode 100644
index 0000000..23f5cfa
--- /dev/null
+++ b/target-ppc/timebase_helper.c
@@ -0,0 +1,160 @@
+/*
+ * PowerPC emulation helpers for QEMU.
+ *
+ * Copyright (c) 2003-2007 Jocelyn Mayer
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "cpu.h"
+#include "dyngen-exec.h"
+#include "helper.h"
+
+/*****************************************************************************/
+/* SPR accesses */
+
+target_ulong helper_load_tbl(void)
+{
+ return (target_ulong)cpu_ppc_load_tbl(env);
+}
+
+target_ulong helper_load_tbu(void)
+{
+ return cpu_ppc_load_tbu(env);
+}
+
+target_ulong helper_load_atbl(void)
+{
+ return (target_ulong)cpu_ppc_load_atbl(env);
+}
+
+target_ulong helper_load_atbu(void)
+{
+ return cpu_ppc_load_atbu(env);
+}
+
+#if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY)
+target_ulong helper_load_purr(void)
+{
+ return (target_ulong)cpu_ppc_load_purr(env);
+}
+#endif
+
+target_ulong helper_load_601_rtcl(void)
+{
+ return cpu_ppc601_load_rtcl(env);
+}
+
+target_ulong helper_load_601_rtcu(void)
+{
+ return cpu_ppc601_load_rtcu(env);
+}
+
+#if !defined(CONFIG_USER_ONLY)
+void helper_store_tbl(target_ulong val)
+{
+ cpu_ppc_store_tbl(env, val);
+}
+
+void helper_store_tbu(target_ulong val)
+{
+ cpu_ppc_store_tbu(env, val);
+}
+
+void helper_store_atbl(target_ulong val)
+{
+ cpu_ppc_store_atbl(env, val);
+}
+
+void helper_store_atbu(target_ulong val)
+{
+ cpu_ppc_store_atbu(env, val);
+}
+
+void helper_store_601_rtcl(target_ulong val)
+{
+ cpu_ppc601_store_rtcl(env, val);
+}
+
+void helper_store_601_rtcu(target_ulong val)
+{
+ cpu_ppc601_store_rtcu(env, val);
+}
+
+target_ulong helper_load_decr(void)
+{
+ return cpu_ppc_load_decr(env);
+}
+
+void helper_store_decr(target_ulong val)
+{
+ cpu_ppc_store_decr(env, val);
+}
+
+target_ulong helper_load_40x_pit(void)
+{
+ return load_40x_pit(env);
+}
+
+void helper_store_40x_pit(target_ulong val)
+{
+ store_40x_pit(env, val);
+}
+
+void helper_store_booke_tcr(target_ulong val)
+{
+ store_booke_tcr(env, val);
+}
+
+void helper_store_booke_tsr(target_ulong val)
+{
+ store_booke_tsr(env, val);
+}
+#endif
+
+/*****************************************************************************/
+/* Embedded PowerPC specific helpers */
+
+/* XXX: to be improved to check access rights when in user-mode */
+target_ulong helper_load_dcr(target_ulong dcrn)
+{
+ uint32_t val = 0;
+
+ if (unlikely(env->dcr_env == NULL)) {
+ qemu_log("No DCR environment\n");
+ helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
+ POWERPC_EXCP_INVAL |
+ POWERPC_EXCP_INVAL_INVAL);
+ } else if (unlikely(ppc_dcr_read(env->dcr_env,
+ (uint32_t)dcrn, &val) != 0)) {
+ qemu_log("DCR read error %d %03x\n", (uint32_t)dcrn, (uint32_t)dcrn);
+ helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
+ POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG);
+ }
+ return val;
+}
+
+void helper_store_dcr(target_ulong dcrn, target_ulong val)
+{
+ if (unlikely(env->dcr_env == NULL)) {
+ qemu_log("No DCR environment\n");
+ helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
+ POWERPC_EXCP_INVAL |
+ POWERPC_EXCP_INVAL_INVAL);
+ } else if (unlikely(ppc_dcr_write(env->dcr_env, (uint32_t)dcrn,
+ (uint32_t)val) != 0)) {
+ qemu_log("DCR write error %d %03x\n", (uint32_t)dcrn, (uint32_t)dcrn);
+ helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
+ POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG);
+ }
+}
--
1.6.0.2
^ permalink raw reply related [flat|nested] 89+ messages in thread
* [Qemu-devel] [PATCH 16/72] ppc: Avoid AREG0 for timebase helpers
2012-06-23 23:06 [Qemu-devel] [PULL 00/72] ppc patch queue 2012-06-24 Alexander Graf
` (14 preceding siblings ...)
2012-06-23 23:06 ` [Qemu-devel] [PATCH 15/72] ppc: Split off timebase helpers Alexander Graf
@ 2012-06-23 23:06 ` Alexander Graf
2012-06-23 23:06 ` [Qemu-devel] [PATCH 17/72] ppc: Split off misc helpers Alexander Graf
` (56 subsequent siblings)
72 siblings, 0 replies; 89+ messages in thread
From: Alexander Graf @ 2012-06-23 23:06 UTC (permalink / raw)
To: qemu-devel qemu-devel
Cc: Blue Swirl, qemu-ppc Mailing List, Andreas Färber,
Aurelien Jarno
From: Blue Swirl <blauwirbel@gmail.com>
Add an explicit CPUPPCState parameter instead of relying on AREG0.
Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Andreas Färber <afaerber@suse.de>
Signed-off-by: Alexander Graf <agraf@suse.de>
---
target-ppc/Makefile.objs | 1 -
target-ppc/helper.h | 42 ++++++++++++++++++++--------------------
target-ppc/timebase_helper.c | 43 ++++++++++++++++++++---------------------
target-ppc/translate.c | 16 +++++++++-----
target-ppc/translate_init.c | 38 ++++++++++++++++++------------------
5 files changed, 71 insertions(+), 69 deletions(-)
diff --git a/target-ppc/Makefile.objs b/target-ppc/Makefile.objs
index 19dc744..4a88641 100644
--- a/target-ppc/Makefile.objs
+++ b/target-ppc/Makefile.objs
@@ -8,5 +8,4 @@ obj-y += int_helper.o
obj-y += mmu_helper.o
obj-y += timebase_helper.o
-$(obj)/timebase_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
$(obj)/op_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
diff --git a/target-ppc/helper.h b/target-ppc/helper.h
index b1f7ba5..81fc40e 100644
--- a/target-ppc/helper.h
+++ b/target-ppc/helper.h
@@ -372,39 +372,39 @@ DEF_HELPER_3(divo, tl, env, tl, tl)
DEF_HELPER_3(divs, tl, env, tl, tl)
DEF_HELPER_3(divso, tl, env, tl, tl)
-DEF_HELPER_1(load_dcr, tl, tl);
-DEF_HELPER_2(store_dcr, void, tl, tl)
+DEF_HELPER_2(load_dcr, tl, env, tl);
+DEF_HELPER_3(store_dcr, void, env, tl, tl)
DEF_HELPER_1(load_dump_spr, void, i32)
DEF_HELPER_1(store_dump_spr, void, i32)
-DEF_HELPER_0(load_tbl, tl)
-DEF_HELPER_0(load_tbu, tl)
-DEF_HELPER_0(load_atbl, tl)
-DEF_HELPER_0(load_atbu, tl)
-DEF_HELPER_0(load_601_rtcl, tl)
-DEF_HELPER_0(load_601_rtcu, tl)
+DEF_HELPER_1(load_tbl, tl, env)
+DEF_HELPER_1(load_tbu, tl, env)
+DEF_HELPER_1(load_atbl, tl, env)
+DEF_HELPER_1(load_atbu, tl, env)
+DEF_HELPER_1(load_601_rtcl, tl, env)
+DEF_HELPER_1(load_601_rtcu, tl, env)
#if !defined(CONFIG_USER_ONLY)
#if defined(TARGET_PPC64)
DEF_HELPER_1(store_asr, void, tl)
-DEF_HELPER_0(load_purr, tl)
+DEF_HELPER_1(load_purr, tl, env)
#endif
DEF_HELPER_1(store_sdr1, void, tl)
-DEF_HELPER_1(store_tbl, void, tl)
-DEF_HELPER_1(store_tbu, void, tl)
-DEF_HELPER_1(store_atbl, void, tl)
-DEF_HELPER_1(store_atbu, void, tl)
-DEF_HELPER_1(store_601_rtcl, void, tl)
-DEF_HELPER_1(store_601_rtcu, void, tl)
-DEF_HELPER_0(load_decr, tl)
-DEF_HELPER_1(store_decr, void, tl)
+DEF_HELPER_2(store_tbl, void, env, tl)
+DEF_HELPER_2(store_tbu, void, env, tl)
+DEF_HELPER_2(store_atbl, void, env, tl)
+DEF_HELPER_2(store_atbu, void, env, tl)
+DEF_HELPER_2(store_601_rtcl, void, env, tl)
+DEF_HELPER_2(store_601_rtcu, void, env, tl)
+DEF_HELPER_1(load_decr, tl, env)
+DEF_HELPER_2(store_decr, void, env, tl)
DEF_HELPER_1(store_hid0_601, void, tl)
DEF_HELPER_2(store_403_pbr, void, i32, tl)
-DEF_HELPER_0(load_40x_pit, tl)
-DEF_HELPER_1(store_40x_pit, void, tl)
+DEF_HELPER_1(load_40x_pit, tl, env)
+DEF_HELPER_2(store_40x_pit, void, env, tl)
DEF_HELPER_1(store_40x_dbcr0, void, tl)
DEF_HELPER_1(store_40x_sler, void, tl)
-DEF_HELPER_1(store_booke_tcr, void, tl)
-DEF_HELPER_1(store_booke_tsr, void, tl)
+DEF_HELPER_2(store_booke_tcr, void, env, tl)
+DEF_HELPER_2(store_booke_tsr, void, env, tl)
DEF_HELPER_3(store_ibatl, void, env, i32, tl)
DEF_HELPER_3(store_ibatu, void, env, i32, tl)
DEF_HELPER_3(store_dbatl, void, env, i32, tl)
diff --git a/target-ppc/timebase_helper.c b/target-ppc/timebase_helper.c
index 23f5cfa..fad738a 100644
--- a/target-ppc/timebase_helper.c
+++ b/target-ppc/timebase_helper.c
@@ -17,106 +17,105 @@
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include "cpu.h"
-#include "dyngen-exec.h"
#include "helper.h"
/*****************************************************************************/
/* SPR accesses */
-target_ulong helper_load_tbl(void)
+target_ulong helper_load_tbl(CPUPPCState *env)
{
return (target_ulong)cpu_ppc_load_tbl(env);
}
-target_ulong helper_load_tbu(void)
+target_ulong helper_load_tbu(CPUPPCState *env)
{
return cpu_ppc_load_tbu(env);
}
-target_ulong helper_load_atbl(void)
+target_ulong helper_load_atbl(CPUPPCState *env)
{
return (target_ulong)cpu_ppc_load_atbl(env);
}
-target_ulong helper_load_atbu(void)
+target_ulong helper_load_atbu(CPUPPCState *env)
{
return cpu_ppc_load_atbu(env);
}
#if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY)
-target_ulong helper_load_purr(void)
+target_ulong helper_load_purr(CPUPPCState *env)
{
return (target_ulong)cpu_ppc_load_purr(env);
}
#endif
-target_ulong helper_load_601_rtcl(void)
+target_ulong helper_load_601_rtcl(CPUPPCState *env)
{
return cpu_ppc601_load_rtcl(env);
}
-target_ulong helper_load_601_rtcu(void)
+target_ulong helper_load_601_rtcu(CPUPPCState *env)
{
return cpu_ppc601_load_rtcu(env);
}
#if !defined(CONFIG_USER_ONLY)
-void helper_store_tbl(target_ulong val)
+void helper_store_tbl(CPUPPCState *env, target_ulong val)
{
cpu_ppc_store_tbl(env, val);
}
-void helper_store_tbu(target_ulong val)
+void helper_store_tbu(CPUPPCState *env, target_ulong val)
{
cpu_ppc_store_tbu(env, val);
}
-void helper_store_atbl(target_ulong val)
+void helper_store_atbl(CPUPPCState *env, target_ulong val)
{
cpu_ppc_store_atbl(env, val);
}
-void helper_store_atbu(target_ulong val)
+void helper_store_atbu(CPUPPCState *env, target_ulong val)
{
cpu_ppc_store_atbu(env, val);
}
-void helper_store_601_rtcl(target_ulong val)
+void helper_store_601_rtcl(CPUPPCState *env, target_ulong val)
{
cpu_ppc601_store_rtcl(env, val);
}
-void helper_store_601_rtcu(target_ulong val)
+void helper_store_601_rtcu(CPUPPCState *env, target_ulong val)
{
cpu_ppc601_store_rtcu(env, val);
}
-target_ulong helper_load_decr(void)
+target_ulong helper_load_decr(CPUPPCState *env)
{
return cpu_ppc_load_decr(env);
}
-void helper_store_decr(target_ulong val)
+void helper_store_decr(CPUPPCState *env, target_ulong val)
{
cpu_ppc_store_decr(env, val);
}
-target_ulong helper_load_40x_pit(void)
+target_ulong helper_load_40x_pit(CPUPPCState *env)
{
return load_40x_pit(env);
}
-void helper_store_40x_pit(target_ulong val)
+void helper_store_40x_pit(CPUPPCState *env, target_ulong val)
{
store_40x_pit(env, val);
}
-void helper_store_booke_tcr(target_ulong val)
+void helper_store_booke_tcr(CPUPPCState *env, target_ulong val)
{
store_booke_tcr(env, val);
}
-void helper_store_booke_tsr(target_ulong val)
+void helper_store_booke_tsr(CPUPPCState *env, target_ulong val)
{
store_booke_tsr(env, val);
}
@@ -126,7 +125,7 @@ void helper_store_booke_tsr(target_ulong val)
/* Embedded PowerPC specific helpers */
/* XXX: to be improved to check access rights when in user-mode */
-target_ulong helper_load_dcr(target_ulong dcrn)
+target_ulong helper_load_dcr(CPUPPCState *env, target_ulong dcrn)
{
uint32_t val = 0;
@@ -144,7 +143,7 @@ target_ulong helper_load_dcr(target_ulong dcrn)
return val;
}
-void helper_store_dcr(target_ulong dcrn, target_ulong val)
+void helper_store_dcr(CPUPPCState *env, target_ulong dcrn, target_ulong val)
{
if (unlikely(env->dcr_env == NULL)) {
qemu_log("No DCR environment\n");
diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index 446f97e..5eec4b0 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -5717,7 +5717,7 @@ static void gen_mfdcr(DisasContext *ctx)
/* NIP cannot be restored if the memory exception comes from an helper */
gen_update_nip(ctx, ctx->nip - 4);
dcrn = tcg_const_tl(SPR(ctx->opcode));
- gen_helper_load_dcr(cpu_gpr[rD(ctx->opcode)], dcrn);
+ gen_helper_load_dcr(cpu_gpr[rD(ctx->opcode)], cpu_env, dcrn);
tcg_temp_free(dcrn);
#endif
}
@@ -5736,7 +5736,7 @@ static void gen_mtdcr(DisasContext *ctx)
/* NIP cannot be restored if the memory exception comes from an helper */
gen_update_nip(ctx, ctx->nip - 4);
dcrn = tcg_const_tl(SPR(ctx->opcode));
- gen_helper_store_dcr(dcrn, cpu_gpr[rS(ctx->opcode)]);
+ gen_helper_store_dcr(cpu_env, dcrn, cpu_gpr[rS(ctx->opcode)]);
tcg_temp_free(dcrn);
#endif
}
@@ -5754,7 +5754,8 @@ static void gen_mfdcrx(DisasContext *ctx)
}
/* NIP cannot be restored if the memory exception comes from an helper */
gen_update_nip(ctx, ctx->nip - 4);
- gen_helper_load_dcr(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
+ gen_helper_load_dcr(cpu_gpr[rD(ctx->opcode)], cpu_env,
+ cpu_gpr[rA(ctx->opcode)]);
/* Note: Rc update flag set leads to undefined state of Rc0 */
#endif
}
@@ -5772,7 +5773,8 @@ static void gen_mtdcrx(DisasContext *ctx)
}
/* NIP cannot be restored if the memory exception comes from an helper */
gen_update_nip(ctx, ctx->nip - 4);
- gen_helper_store_dcr(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]);
+ gen_helper_store_dcr(cpu_env, cpu_gpr[rA(ctx->opcode)],
+ cpu_gpr[rS(ctx->opcode)]);
/* Note: Rc update flag set leads to undefined state of Rc0 */
#endif
}
@@ -5782,7 +5784,8 @@ static void gen_mfdcrux(DisasContext *ctx)
{
/* NIP cannot be restored if the memory exception comes from an helper */
gen_update_nip(ctx, ctx->nip - 4);
- gen_helper_load_dcr(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
+ gen_helper_load_dcr(cpu_gpr[rD(ctx->opcode)], cpu_env,
+ cpu_gpr[rA(ctx->opcode)]);
/* Note: Rc update flag set leads to undefined state of Rc0 */
}
@@ -5791,7 +5794,8 @@ static void gen_mtdcrux(DisasContext *ctx)
{
/* NIP cannot be restored if the memory exception comes from an helper */
gen_update_nip(ctx, ctx->nip - 4);
- gen_helper_store_dcr(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]);
+ gen_helper_store_dcr(cpu_gpr[rA(ctx->opcode)], cpu_env,
+ cpu_gpr[rS(ctx->opcode)]);
/* Note: Rc update flag set leads to undefined state of Rc0 */
}
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index 1e15fd9..f3a8aa5 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -159,7 +159,7 @@ static void spr_read_decr (void *opaque, int gprn, int sprn)
if (use_icount) {
gen_io_start();
}
- gen_helper_load_decr(cpu_gpr[gprn]);
+ gen_helper_load_decr(cpu_gpr[gprn], cpu_env);
if (use_icount) {
gen_io_end();
gen_stop_exception(opaque);
@@ -171,7 +171,7 @@ static void spr_write_decr (void *opaque, int sprn, int gprn)
if (use_icount) {
gen_io_start();
}
- gen_helper_store_decr(cpu_gpr[gprn]);
+ gen_helper_store_decr(cpu_env, cpu_gpr[gprn]);
if (use_icount) {
gen_io_end();
gen_stop_exception(opaque);
@@ -186,7 +186,7 @@ static void spr_read_tbl (void *opaque, int gprn, int sprn)
if (use_icount) {
gen_io_start();
}
- gen_helper_load_tbl(cpu_gpr[gprn]);
+ gen_helper_load_tbl(cpu_gpr[gprn], cpu_env);
if (use_icount) {
gen_io_end();
gen_stop_exception(opaque);
@@ -198,7 +198,7 @@ static void spr_read_tbu (void *opaque, int gprn, int sprn)
if (use_icount) {
gen_io_start();
}
- gen_helper_load_tbu(cpu_gpr[gprn]);
+ gen_helper_load_tbu(cpu_gpr[gprn], cpu_env);
if (use_icount) {
gen_io_end();
gen_stop_exception(opaque);
@@ -208,13 +208,13 @@ static void spr_read_tbu (void *opaque, int gprn, int sprn)
__attribute__ (( unused ))
static void spr_read_atbl (void *opaque, int gprn, int sprn)
{
- gen_helper_load_atbl(cpu_gpr[gprn]);
+ gen_helper_load_atbl(cpu_gpr[gprn], cpu_env);
}
__attribute__ (( unused ))
static void spr_read_atbu (void *opaque, int gprn, int sprn)
{
- gen_helper_load_atbu(cpu_gpr[gprn]);
+ gen_helper_load_atbu(cpu_gpr[gprn], cpu_env);
}
#if !defined(CONFIG_USER_ONLY)
@@ -223,7 +223,7 @@ static void spr_write_tbl (void *opaque, int sprn, int gprn)
if (use_icount) {
gen_io_start();
}
- gen_helper_store_tbl(cpu_gpr[gprn]);
+ gen_helper_store_tbl(cpu_env, cpu_gpr[gprn]);
if (use_icount) {
gen_io_end();
gen_stop_exception(opaque);
@@ -235,7 +235,7 @@ static void spr_write_tbu (void *opaque, int sprn, int gprn)
if (use_icount) {
gen_io_start();
}
- gen_helper_store_tbu(cpu_gpr[gprn]);
+ gen_helper_store_tbu(cpu_env, cpu_gpr[gprn]);
if (use_icount) {
gen_io_end();
gen_stop_exception(opaque);
@@ -245,20 +245,20 @@ static void spr_write_tbu (void *opaque, int sprn, int gprn)
__attribute__ (( unused ))
static void spr_write_atbl (void *opaque, int sprn, int gprn)
{
- gen_helper_store_atbl(cpu_gpr[gprn]);
+ gen_helper_store_atbl(cpu_env, cpu_gpr[gprn]);
}
__attribute__ (( unused ))
static void spr_write_atbu (void *opaque, int sprn, int gprn)
{
- gen_helper_store_atbu(cpu_gpr[gprn]);
+ gen_helper_store_atbu(cpu_env, cpu_gpr[gprn]);
}
#if defined(TARGET_PPC64)
__attribute__ (( unused ))
static void spr_read_purr (void *opaque, int gprn, int sprn)
{
- gen_helper_load_purr(cpu_gpr[gprn]);
+ gen_helper_load_purr(cpu_gpr[gprn], cpu_env);
}
#endif
#endif
@@ -382,23 +382,23 @@ static void spr_write_asr (void *opaque, int sprn, int gprn)
/* RTC */
static void spr_read_601_rtcl (void *opaque, int gprn, int sprn)
{
- gen_helper_load_601_rtcl(cpu_gpr[gprn]);
+ gen_helper_load_601_rtcl(cpu_gpr[gprn], cpu_env);
}
static void spr_read_601_rtcu (void *opaque, int gprn, int sprn)
{
- gen_helper_load_601_rtcu(cpu_gpr[gprn]);
+ gen_helper_load_601_rtcu(cpu_gpr[gprn], cpu_env);
}
#if !defined(CONFIG_USER_ONLY)
static void spr_write_601_rtcu (void *opaque, int sprn, int gprn)
{
- gen_helper_store_601_rtcu(cpu_gpr[gprn]);
+ gen_helper_store_601_rtcu(cpu_env, cpu_gpr[gprn]);
}
static void spr_write_601_rtcl (void *opaque, int sprn, int gprn)
{
- gen_helper_store_601_rtcl(cpu_gpr[gprn]);
+ gen_helper_store_601_rtcl(cpu_env, cpu_gpr[gprn]);
}
static void spr_write_hid0_601 (void *opaque, int sprn, int gprn)
@@ -437,12 +437,12 @@ static void spr_write_601_ubatl (void *opaque, int sprn, int gprn)
#if !defined(CONFIG_USER_ONLY)
static void spr_read_40x_pit (void *opaque, int gprn, int sprn)
{
- gen_helper_load_40x_pit(cpu_gpr[gprn]);
+ gen_helper_load_40x_pit(cpu_gpr[gprn], cpu_env);
}
static void spr_write_40x_pit (void *opaque, int sprn, int gprn)
{
- gen_helper_store_40x_pit(cpu_gpr[gprn]);
+ gen_helper_store_40x_pit(cpu_env, cpu_gpr[gprn]);
}
static void spr_write_40x_dbcr0 (void *opaque, int sprn, int gprn)
@@ -461,12 +461,12 @@ static void spr_write_40x_sler (void *opaque, int sprn, int gprn)
static void spr_write_booke_tcr (void *opaque, int sprn, int gprn)
{
- gen_helper_store_booke_tcr(cpu_gpr[gprn]);
+ gen_helper_store_booke_tcr(cpu_env, cpu_gpr[gprn]);
}
static void spr_write_booke_tsr (void *opaque, int sprn, int gprn)
{
- gen_helper_store_booke_tsr(cpu_gpr[gprn]);
+ gen_helper_store_booke_tsr(cpu_env, cpu_gpr[gprn]);
}
#endif
--
1.6.0.2
^ permalink raw reply related [flat|nested] 89+ messages in thread
* [Qemu-devel] [PATCH 17/72] ppc: Split off misc helpers
2012-06-23 23:06 [Qemu-devel] [PULL 00/72] ppc patch queue 2012-06-24 Alexander Graf
` (15 preceding siblings ...)
2012-06-23 23:06 ` [Qemu-devel] [PATCH 16/72] ppc: Avoid AREG0 for " Alexander Graf
@ 2012-06-23 23:06 ` Alexander Graf
2012-06-23 23:06 ` [Qemu-devel] [PATCH 18/72] ppc: Avoid AREG0 for " Alexander Graf
` (55 subsequent siblings)
72 siblings, 0 replies; 89+ messages in thread
From: Alexander Graf @ 2012-06-23 23:06 UTC (permalink / raw)
To: qemu-devel qemu-devel
Cc: Blue Swirl, qemu-ppc Mailing List, Andreas Färber,
Aurelien Jarno
From: Blue Swirl <blauwirbel@gmail.com>
Move misc helpers from op_helper.c to misc_helpers.c.
Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Andreas Färber <afaerber@suse.de>
Signed-off-by: Alexander Graf <agraf@suse.de>
---
target-ppc/Makefile.objs | 2 +
target-ppc/misc_helper.c | 116 ++++++++++++++++++++++++++++++++++++++++++++++
target-ppc/op_helper.c | 94 -------------------------------------
3 files changed, 118 insertions(+), 94 deletions(-)
create mode 100644 target-ppc/misc_helper.c
diff --git a/target-ppc/Makefile.objs b/target-ppc/Makefile.objs
index 4a88641..3a444eb 100644
--- a/target-ppc/Makefile.objs
+++ b/target-ppc/Makefile.objs
@@ -7,5 +7,7 @@ obj-y += fpu_helper.o
obj-y += int_helper.o
obj-y += mmu_helper.o
obj-y += timebase_helper.o
+obj-y += misc_helper.o
+$(obj)/misc_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
$(obj)/op_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
diff --git a/target-ppc/misc_helper.c b/target-ppc/misc_helper.c
new file mode 100644
index 0000000..67eab08
--- /dev/null
+++ b/target-ppc/misc_helper.c
@@ -0,0 +1,116 @@
+/*
+ * Miscellaneous PowerPC emulation helpers for QEMU.
+ *
+ * Copyright (c) 2003-2007 Jocelyn Mayer
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "cpu.h"
+#include "dyngen-exec.h"
+#include "helper.h"
+
+#include "helper_regs.h"
+
+/*****************************************************************************/
+/* SPR accesses */
+void helper_load_dump_spr(uint32_t sprn)
+{
+ qemu_log("Read SPR %d %03x => " TARGET_FMT_lx "\n", sprn, sprn,
+ env->spr[sprn]);
+}
+
+void helper_store_dump_spr(uint32_t sprn)
+{
+ qemu_log("Write SPR %d %03x <= " TARGET_FMT_lx "\n", sprn, sprn,
+ env->spr[sprn]);
+}
+#if !defined(CONFIG_USER_ONLY)
+#if defined(TARGET_PPC64)
+void helper_store_asr(target_ulong val)
+{
+ ppc_store_asr(env, val);
+}
+#endif
+
+void helper_store_sdr1(target_ulong val)
+{
+ ppc_store_sdr1(env, val);
+}
+
+void helper_store_hid0_601(target_ulong val)
+{
+ target_ulong hid0;
+
+ hid0 = env->spr[SPR_HID0];
+ if ((val ^ hid0) & 0x00000008) {
+ /* Change current endianness */
+ env->hflags &= ~(1 << MSR_LE);
+ env->hflags_nmsr &= ~(1 << MSR_LE);
+ env->hflags_nmsr |= (1 << MSR_LE) & (((val >> 3) & 1) << MSR_LE);
+ env->hflags |= env->hflags_nmsr;
+ qemu_log("%s: set endianness to %c => " TARGET_FMT_lx "\n", __func__,
+ val & 0x8 ? 'l' : 'b', env->hflags);
+ }
+ env->spr[SPR_HID0] = (uint32_t)val;
+}
+
+void helper_store_403_pbr(uint32_t num, target_ulong value)
+{
+ if (likely(env->pb[num] != value)) {
+ env->pb[num] = value;
+ /* Should be optimized */
+ tlb_flush(env, 1);
+ }
+}
+
+void helper_store_40x_dbcr0(target_ulong val)
+{
+ store_40x_dbcr0(env, val);
+}
+
+void helper_store_40x_sler(target_ulong val)
+{
+ store_40x_sler(env, val);
+}
+#endif
+/*****************************************************************************/
+/* PowerPC 601 specific instructions (POWER bridge) */
+
+target_ulong helper_clcs(uint32_t arg)
+{
+ switch (arg) {
+ case 0x0CUL:
+ /* Instruction cache line size */
+ return env->icache_line_size;
+ break;
+ case 0x0DUL:
+ /* Data cache line size */
+ return env->dcache_line_size;
+ break;
+ case 0x0EUL:
+ /* Minimum cache line size */
+ return (env->icache_line_size < env->dcache_line_size) ?
+ env->icache_line_size : env->dcache_line_size;
+ break;
+ case 0x0FUL:
+ /* Maximum cache line size */
+ return (env->icache_line_size > env->dcache_line_size) ?
+ env->icache_line_size : env->dcache_line_size;
+ break;
+ default:
+ /* Undefined */
+ return 0;
+ break;
+ }
+}
diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c
index 0929906..cd1a533 100644
--- a/target-ppc/op_helper.c
+++ b/target-ppc/op_helper.c
@@ -31,69 +31,6 @@
//#define DEBUG_OP
/*****************************************************************************/
-/* SPR accesses */
-void helper_load_dump_spr(uint32_t sprn)
-{
- qemu_log("Read SPR %d %03x => " TARGET_FMT_lx "\n", sprn, sprn,
- env->spr[sprn]);
-}
-
-void helper_store_dump_spr(uint32_t sprn)
-{
- qemu_log("Write SPR %d %03x <= " TARGET_FMT_lx "\n", sprn, sprn,
- env->spr[sprn]);
-}
-#if !defined(CONFIG_USER_ONLY)
-#if defined(TARGET_PPC64)
-void helper_store_asr(target_ulong val)
-{
- ppc_store_asr(env, val);
-}
-#endif
-
-void helper_store_sdr1(target_ulong val)
-{
- ppc_store_sdr1(env, val);
-}
-
-void helper_store_hid0_601(target_ulong val)
-{
- target_ulong hid0;
-
- hid0 = env->spr[SPR_HID0];
- if ((val ^ hid0) & 0x00000008) {
- /* Change current endianness */
- env->hflags &= ~(1 << MSR_LE);
- env->hflags_nmsr &= ~(1 << MSR_LE);
- env->hflags_nmsr |= (1 << MSR_LE) & (((val >> 3) & 1) << MSR_LE);
- env->hflags |= env->hflags_nmsr;
- qemu_log("%s: set endianness to %c => " TARGET_FMT_lx "\n", __func__,
- val & 0x8 ? 'l' : 'b', env->hflags);
- }
- env->spr[SPR_HID0] = (uint32_t)val;
-}
-
-void helper_store_403_pbr(uint32_t num, target_ulong value)
-{
- if (likely(env->pb[num] != value)) {
- env->pb[num] = value;
- /* Should be optimized */
- tlb_flush(env, 1);
- }
-}
-
-void helper_store_40x_dbcr0(target_ulong val)
-{
- store_40x_dbcr0(env, val);
-}
-
-void helper_store_40x_sler(target_ulong val)
-{
- store_40x_sler(env, val);
-}
-#endif
-
-/*****************************************************************************/
/* Memory load and stores */
static inline target_ulong addr_add(target_ulong addr, target_long arg)
@@ -252,37 +189,6 @@ target_ulong helper_lscbx(target_ulong addr, uint32_t reg, uint32_t ra,
}
/*****************************************************************************/
-/* PowerPC 601 specific instructions (POWER bridge) */
-
-target_ulong helper_clcs(uint32_t arg)
-{
- switch (arg) {
- case 0x0CUL:
- /* Instruction cache line size */
- return env->icache_line_size;
- break;
- case 0x0DUL:
- /* Data cache line size */
- return env->dcache_line_size;
- break;
- case 0x0EUL:
- /* Minimum cache line size */
- return (env->icache_line_size < env->dcache_line_size) ?
- env->icache_line_size : env->dcache_line_size;
- break;
- case 0x0FUL:
- /* Maximum cache line size */
- return (env->icache_line_size > env->dcache_line_size) ?
- env->icache_line_size : env->dcache_line_size;
- break;
- default:
- /* Undefined */
- return 0;
- break;
- }
-}
-
-/*****************************************************************************/
/* Altivec extension helpers */
#if defined(HOST_WORDS_BIGENDIAN)
#define HI_IDX 0
--
1.6.0.2
^ permalink raw reply related [flat|nested] 89+ messages in thread
* [Qemu-devel] [PATCH 18/72] ppc: Avoid AREG0 for misc helpers
2012-06-23 23:06 [Qemu-devel] [PULL 00/72] ppc patch queue 2012-06-24 Alexander Graf
` (16 preceding siblings ...)
2012-06-23 23:06 ` [Qemu-devel] [PATCH 17/72] ppc: Split off misc helpers Alexander Graf
@ 2012-06-23 23:06 ` Alexander Graf
2012-06-23 23:06 ` [Qemu-devel] [PATCH 19/72] ppc: Move misc helpers from helper.c to misc_helper.c Alexander Graf
` (54 subsequent siblings)
72 siblings, 0 replies; 89+ messages in thread
From: Alexander Graf @ 2012-06-23 23:06 UTC (permalink / raw)
To: qemu-devel qemu-devel
Cc: Blue Swirl, qemu-ppc Mailing List, Andreas Färber,
Aurelien Jarno
From: Blue Swirl <blauwirbel@gmail.com>
Add an explicit CPUPPCState parameter instead of relying on AREG0.
Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Andreas Färber <afaerber@suse.de>
Signed-off-by: Alexander Graf <agraf@suse.de>
---
target-ppc/Makefile.objs | 1 -
target-ppc/helper.h | 18 +++++++++---------
target-ppc/misc_helper.c | 19 +++++++++----------
target-ppc/translate.c | 2 +-
target-ppc/translate_init.c | 12 ++++++------
5 files changed, 25 insertions(+), 27 deletions(-)
diff --git a/target-ppc/Makefile.objs b/target-ppc/Makefile.objs
index 3a444eb..8d4d16b 100644
--- a/target-ppc/Makefile.objs
+++ b/target-ppc/Makefile.objs
@@ -9,5 +9,4 @@ obj-y += mmu_helper.o
obj-y += timebase_helper.o
obj-y += misc_helper.o
-$(obj)/misc_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
$(obj)/op_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
diff --git a/target-ppc/helper.h b/target-ppc/helper.h
index 81fc40e..b7a157e 100644
--- a/target-ppc/helper.h
+++ b/target-ppc/helper.h
@@ -363,7 +363,7 @@ DEF_HELPER_2(msgclr, void, env, tl)
#endif
DEF_HELPER_4(dlmzb, tl, env, tl, tl, i32)
-DEF_HELPER_FLAGS_1(clcs, TCG_CALL_CONST | TCG_CALL_PURE, tl, i32)
+DEF_HELPER_FLAGS_2(clcs, TCG_CALL_CONST | TCG_CALL_PURE, tl, env, i32)
#if !defined(CONFIG_USER_ONLY)
DEF_HELPER_2(rac, tl, env, tl)
#endif
@@ -375,8 +375,8 @@ DEF_HELPER_3(divso, tl, env, tl, tl)
DEF_HELPER_2(load_dcr, tl, env, tl);
DEF_HELPER_3(store_dcr, void, env, tl, tl)
-DEF_HELPER_1(load_dump_spr, void, i32)
-DEF_HELPER_1(store_dump_spr, void, i32)
+DEF_HELPER_2(load_dump_spr, void, env, i32)
+DEF_HELPER_2(store_dump_spr, void, env, i32)
DEF_HELPER_1(load_tbl, tl, env)
DEF_HELPER_1(load_tbu, tl, env)
DEF_HELPER_1(load_atbl, tl, env)
@@ -385,10 +385,10 @@ DEF_HELPER_1(load_601_rtcl, tl, env)
DEF_HELPER_1(load_601_rtcu, tl, env)
#if !defined(CONFIG_USER_ONLY)
#if defined(TARGET_PPC64)
-DEF_HELPER_1(store_asr, void, tl)
+DEF_HELPER_2(store_asr, void, env, tl)
DEF_HELPER_1(load_purr, tl, env)
#endif
-DEF_HELPER_1(store_sdr1, void, tl)
+DEF_HELPER_2(store_sdr1, void, env, tl)
DEF_HELPER_2(store_tbl, void, env, tl)
DEF_HELPER_2(store_tbu, void, env, tl)
DEF_HELPER_2(store_atbl, void, env, tl)
@@ -397,12 +397,12 @@ DEF_HELPER_2(store_601_rtcl, void, env, tl)
DEF_HELPER_2(store_601_rtcu, void, env, tl)
DEF_HELPER_1(load_decr, tl, env)
DEF_HELPER_2(store_decr, void, env, tl)
-DEF_HELPER_1(store_hid0_601, void, tl)
-DEF_HELPER_2(store_403_pbr, void, i32, tl)
+DEF_HELPER_2(store_hid0_601, void, env, tl)
+DEF_HELPER_3(store_403_pbr, void, env, i32, tl)
DEF_HELPER_1(load_40x_pit, tl, env)
DEF_HELPER_2(store_40x_pit, void, env, tl)
-DEF_HELPER_1(store_40x_dbcr0, void, tl)
-DEF_HELPER_1(store_40x_sler, void, tl)
+DEF_HELPER_2(store_40x_dbcr0, void, env, tl)
+DEF_HELPER_2(store_40x_sler, void, env, tl)
DEF_HELPER_2(store_booke_tcr, void, env, tl)
DEF_HELPER_2(store_booke_tsr, void, env, tl)
DEF_HELPER_3(store_ibatl, void, env, i32, tl)
diff --git a/target-ppc/misc_helper.c b/target-ppc/misc_helper.c
index 67eab08..b194d19 100644
--- a/target-ppc/misc_helper.c
+++ b/target-ppc/misc_helper.c
@@ -17,38 +17,37 @@
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include "cpu.h"
-#include "dyngen-exec.h"
#include "helper.h"
#include "helper_regs.h"
/*****************************************************************************/
/* SPR accesses */
-void helper_load_dump_spr(uint32_t sprn)
+void helper_load_dump_spr(CPUPPCState *env, uint32_t sprn)
{
qemu_log("Read SPR %d %03x => " TARGET_FMT_lx "\n", sprn, sprn,
env->spr[sprn]);
}
-void helper_store_dump_spr(uint32_t sprn)
+void helper_store_dump_spr(CPUPPCState *env, uint32_t sprn)
{
qemu_log("Write SPR %d %03x <= " TARGET_FMT_lx "\n", sprn, sprn,
env->spr[sprn]);
}
#if !defined(CONFIG_USER_ONLY)
#if defined(TARGET_PPC64)
-void helper_store_asr(target_ulong val)
+void helper_store_asr(CPUPPCState *env, target_ulong val)
{
ppc_store_asr(env, val);
}
#endif
-void helper_store_sdr1(target_ulong val)
+void helper_store_sdr1(CPUPPCState *env, target_ulong val)
{
ppc_store_sdr1(env, val);
}
-void helper_store_hid0_601(target_ulong val)
+void helper_store_hid0_601(CPUPPCState *env, target_ulong val)
{
target_ulong hid0;
@@ -65,7 +64,7 @@ void helper_store_hid0_601(target_ulong val)
env->spr[SPR_HID0] = (uint32_t)val;
}
-void helper_store_403_pbr(uint32_t num, target_ulong value)
+void helper_store_403_pbr(CPUPPCState *env, uint32_t num, target_ulong value)
{
if (likely(env->pb[num] != value)) {
env->pb[num] = value;
@@ -74,12 +73,12 @@ void helper_store_403_pbr(uint32_t num, target_ulong value)
}
}
-void helper_store_40x_dbcr0(target_ulong val)
+void helper_store_40x_dbcr0(CPUPPCState *env, target_ulong val)
{
store_40x_dbcr0(env, val);
}
-void helper_store_40x_sler(target_ulong val)
+void helper_store_40x_sler(CPUPPCState *env, target_ulong val)
{
store_40x_sler(env, val);
}
@@ -87,7 +86,7 @@ void helper_store_40x_sler(target_ulong val)
/*****************************************************************************/
/* PowerPC 601 specific instructions (POWER bridge) */
-target_ulong helper_clcs(uint32_t arg)
+target_ulong helper_clcs(CPUPPCState *env, uint32_t arg)
{
switch (arg) {
case 0x0CUL:
diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index 5eec4b0..bcc9933 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -4551,7 +4551,7 @@ static void gen_abso(DisasContext *ctx)
static void gen_clcs(DisasContext *ctx)
{
TCGv_i32 t0 = tcg_const_i32(rA(ctx->opcode));
- gen_helper_clcs(cpu_gpr[rD(ctx->opcode)], t0);
+ gen_helper_clcs(cpu_gpr[rD(ctx->opcode)], cpu_env, t0);
tcg_temp_free_i32(t0);
/* Rc=1 sets CR0 to an undefined state */
}
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index f3a8aa5..f6ac589 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -347,7 +347,7 @@ static void spr_write_dbatl_h (void *opaque, int sprn, int gprn)
/* SDR1 */
static void spr_write_sdr1 (void *opaque, int sprn, int gprn)
{
- gen_helper_store_sdr1(cpu_gpr[gprn]);
+ gen_helper_store_sdr1(cpu_env, cpu_gpr[gprn]);
}
/* 64 bits PowerPC specific SPRs */
@@ -373,7 +373,7 @@ static void spr_read_asr (void *opaque, int gprn, int sprn)
static void spr_write_asr (void *opaque, int sprn, int gprn)
{
- gen_helper_store_asr(cpu_gpr[gprn]);
+ gen_helper_store_asr(cpu_env, cpu_gpr[gprn]);
}
#endif
#endif
@@ -405,7 +405,7 @@ static void spr_write_hid0_601 (void *opaque, int sprn, int gprn)
{
DisasContext *ctx = opaque;
- gen_helper_store_hid0_601(cpu_gpr[gprn]);
+ gen_helper_store_hid0_601(cpu_env, cpu_gpr[gprn]);
/* Must stop the translation as endianness may have changed */
gen_stop_exception(ctx);
}
@@ -449,14 +449,14 @@ static void spr_write_40x_dbcr0 (void *opaque, int sprn, int gprn)
{
DisasContext *ctx = opaque;
- gen_helper_store_40x_dbcr0(cpu_gpr[gprn]);
+ gen_helper_store_40x_dbcr0(cpu_env, cpu_gpr[gprn]);
/* We must stop translation as we may have rebooted */
gen_stop_exception(ctx);
}
static void spr_write_40x_sler (void *opaque, int sprn, int gprn)
{
- gen_helper_store_40x_sler(cpu_gpr[gprn]);
+ gen_helper_store_40x_sler(cpu_env, cpu_gpr[gprn]);
}
static void spr_write_booke_tcr (void *opaque, int sprn, int gprn)
@@ -481,7 +481,7 @@ static void spr_read_403_pbr (void *opaque, int gprn, int sprn)
static void spr_write_403_pbr (void *opaque, int sprn, int gprn)
{
TCGv_i32 t0 = tcg_const_i32(sprn - SPR_403_PBL1);
- gen_helper_store_403_pbr(t0, cpu_gpr[gprn]);
+ gen_helper_store_403_pbr(cpu_env, t0, cpu_gpr[gprn]);
tcg_temp_free_i32(t0);
}
--
1.6.0.2
^ permalink raw reply related [flat|nested] 89+ messages in thread
* [Qemu-devel] [PATCH 19/72] ppc: Move misc helpers from helper.c to misc_helper.c
2012-06-23 23:06 [Qemu-devel] [PULL 00/72] ppc patch queue 2012-06-24 Alexander Graf
` (17 preceding siblings ...)
2012-06-23 23:06 ` [Qemu-devel] [PATCH 18/72] ppc: Avoid AREG0 for " Alexander Graf
@ 2012-06-23 23:06 ` Alexander Graf
2012-06-23 23:06 ` [Qemu-devel] [PATCH 20/72] ppc: Move load and store helpers, switch to AREG0 free mode Alexander Graf
` (53 subsequent siblings)
72 siblings, 0 replies; 89+ messages in thread
From: Alexander Graf @ 2012-06-23 23:06 UTC (permalink / raw)
To: qemu-devel qemu-devel
Cc: Blue Swirl, qemu-ppc Mailing List, Andreas Färber,
Aurelien Jarno
From: Blue Swirl <blauwirbel@gmail.com>
Move more misc helpers from helper.c to misc_helper.c.
Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Andreas Färber <afaerber@suse.de>
Signed-off-by: Alexander Graf <agraf@suse.de>
---
target-ppc/helper.c | 9 ---------
target-ppc/misc_helper.c | 9 +++++++++
2 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/target-ppc/helper.c b/target-ppc/helper.c
index 24d109d..48b19a7 100644
--- a/target-ppc/helper.c
+++ b/target-ppc/helper.c
@@ -23,15 +23,6 @@
#include "kvm_ppc.h"
#include "cpus.h"
-/*****************************************************************************/
-/* Special registers manipulation */
-
-/* GDBstub can read and write MSR... */
-void ppc_store_msr(CPUPPCState *env, target_ulong value)
-{
- hreg_store_msr(env, value, 0);
-}
-
PowerPCCPU *cpu_ppc_init(const char *cpu_model)
{
PowerPCCPU *cpu;
diff --git a/target-ppc/misc_helper.c b/target-ppc/misc_helper.c
index b194d19..26edcca 100644
--- a/target-ppc/misc_helper.c
+++ b/target-ppc/misc_helper.c
@@ -113,3 +113,12 @@ target_ulong helper_clcs(CPUPPCState *env, uint32_t arg)
break;
}
}
+
+/*****************************************************************************/
+/* Special registers manipulation */
+
+/* GDBstub can read and write MSR... */
+void ppc_store_msr(CPUPPCState *env, target_ulong value)
+{
+ hreg_store_msr(env, value, 0);
+}
--
1.6.0.2
^ permalink raw reply related [flat|nested] 89+ messages in thread
* [Qemu-devel] [PATCH 20/72] ppc: Move load and store helpers, switch to AREG0 free mode
2012-06-23 23:06 [Qemu-devel] [PULL 00/72] ppc patch queue 2012-06-24 Alexander Graf
` (18 preceding siblings ...)
2012-06-23 23:06 ` [Qemu-devel] [PATCH 19/72] ppc: Move misc helpers from helper.c to misc_helper.c Alexander Graf
@ 2012-06-23 23:06 ` Alexander Graf
2012-06-23 23:06 ` [Qemu-devel] [PATCH 21/72] ppc: Add missing break Alexander Graf
` (52 subsequent siblings)
72 siblings, 0 replies; 89+ messages in thread
From: Alexander Graf @ 2012-06-23 23:06 UTC (permalink / raw)
To: qemu-devel qemu-devel
Cc: Blue Swirl, qemu-ppc Mailing List, Andreas Färber,
Aurelien Jarno
From: Blue Swirl <blauwirbel@gmail.com>
Add an explicit CPUPPCState parameter instead of relying on AREG0
and rename op_helper.c (which only contains load and store helpers)
to mem_helper.c. Remove AREG0 swapping in
tlb_fill().
Switch to AREG0 free mode. Use cpu_ld{l,uw}_code in translation
and interrupt handling, cpu_{ld,st}{l,uw}_data in loads and stores.
Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Andreas Färber <afaerber@suse.de>
Signed-off-by: Alexander Graf <agraf@suse.de>
---
configure | 2 +-
cpu-all.h | 9 +++
target-ppc/Makefile.objs | 7 +-
target-ppc/excp_helper.c | 3 +-
target-ppc/helper.h | 30 ++++----
target-ppc/{op_helper.c => mem_helper.c} | 109 +++++++++++++++---------------
target-ppc/translate.c | 30 ++++----
7 files changed, 100 insertions(+), 90 deletions(-)
rename target-ppc/{op_helper.c => mem_helper.c} (68%)
diff --git a/configure b/configure
index b68c0ca..6128ba7 100755
--- a/configure
+++ b/configure
@@ -3679,7 +3679,7 @@ symlink "$source_path/Makefile.target" "$target_dir/Makefile"
case "$target_arch2" in
- alpha | sparc* | xtensa*)
+ alpha | sparc* | xtensa* | ppc*)
echo "CONFIG_TCG_PASS_AREG0=y" >> $config_target_mak
;;
esac
diff --git a/cpu-all.h b/cpu-all.h
index 50c8b62..9dc249a 100644
--- a/cpu-all.h
+++ b/cpu-all.h
@@ -291,6 +291,15 @@ extern unsigned long reserved_va;
#define stfl_kernel(p, v) stfl_raw(p, v)
#define stfq_kernel(p, vt) stfq_raw(p, v)
+#ifdef CONFIG_TCG_PASS_AREG0
+#define cpu_ldub_data(env, addr) ldub_raw(addr)
+#define cpu_lduw_data(env, addr) lduw_raw(addr)
+#define cpu_ldl_data(env, addr) ldl_raw(addr)
+
+#define cpu_stb_data(env, addr, data) stb_raw(addr, data)
+#define cpu_stw_data(env, addr, data) stw_raw(addr, data)
+#define cpu_stl_data(env, addr, data) stl_raw(addr, data)
+#endif
#endif /* defined(CONFIG_USER_ONLY) */
/* page related stuff */
diff --git a/target-ppc/Makefile.objs b/target-ppc/Makefile.objs
index 8d4d16b..6c11ef8 100644
--- a/target-ppc/Makefile.objs
+++ b/target-ppc/Makefile.objs
@@ -1,12 +1,11 @@
-obj-y += translate.o op_helper.o helper.o
+obj-y += translate.o helper.o
obj-$(CONFIG_SOFTMMU) += machine.o
obj-$(CONFIG_KVM) += kvm.o kvm_ppc.o
-obj-y += op_helper.o helper.o
+obj-y += helper.o
obj-y += excp_helper.o
obj-y += fpu_helper.o
obj-y += int_helper.o
obj-y += mmu_helper.o
obj-y += timebase_helper.o
obj-y += misc_helper.o
-
-$(obj)/op_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
+obj-y += mem_helper.o
diff --git a/target-ppc/excp_helper.c b/target-ppc/excp_helper.c
index 7fa7a59..c7762b9 100644
--- a/target-ppc/excp_helper.c
+++ b/target-ppc/excp_helper.c
@@ -179,7 +179,8 @@ static inline void powerpc_excp(CPUPPCState *env, int excp_model, int excp)
}
/* XXX: this is false */
/* Get rS/rD and rA from faulting opcode */
- env->spr[SPR_DSISR] |= (ldl_code((env->nip - 4)) & 0x03FF0000) >> 16;
+ env->spr[SPR_DSISR] |= (cpu_ldl_code(env, (env->nip - 4))
+ & 0x03FF0000) >> 16;
goto store_current;
case POWERPC_EXCP_PROGRAM: /* Program exception */
switch (env->error_code & ~0xF) {
diff --git a/target-ppc/helper.h b/target-ppc/helper.h
index b7a157e..ddab97b 100644
--- a/target-ppc/helper.h
+++ b/target-ppc/helper.h
@@ -20,15 +20,15 @@ DEF_HELPER_1(hrfid, void, env)
#endif
#endif
-DEF_HELPER_2(lmw, void, tl, i32)
-DEF_HELPER_2(stmw, void, tl, i32)
-DEF_HELPER_3(lsw, void, tl, i32, i32)
-DEF_HELPER_4(lswx, void, tl, i32, i32, i32)
-DEF_HELPER_3(stsw, void, tl, i32, i32)
-DEF_HELPER_1(dcbz, void, tl)
-DEF_HELPER_1(dcbz_970, void, tl)
-DEF_HELPER_1(icbi, void, tl)
-DEF_HELPER_4(lscbx, tl, tl, i32, i32, i32)
+DEF_HELPER_3(lmw, void, env, tl, i32)
+DEF_HELPER_3(stmw, void, env, tl, i32)
+DEF_HELPER_4(lsw, void, env, tl, i32, i32)
+DEF_HELPER_5(lswx, void, env, tl, i32, i32, i32)
+DEF_HELPER_4(stsw, void, env, tl, i32, i32)
+DEF_HELPER_2(dcbz, void, env, tl)
+DEF_HELPER_2(dcbz_970, void, env, tl)
+DEF_HELPER_2(icbi, void, env, tl)
+DEF_HELPER_5(lscbx, tl, env, tl, i32, i32, i32)
#if defined(TARGET_PPC64)
DEF_HELPER_FLAGS_2(mulhd, TCG_CALL_CONST | TCG_CALL_PURE, i64, i64, i64)
@@ -226,12 +226,12 @@ DEF_HELPER_5(vmsumshm, void, env, avr, avr, avr, avr)
DEF_HELPER_5(vmsumshs, void, env, avr, avr, avr, avr)
DEF_HELPER_4(vmladduhm, void, avr, avr, avr, avr)
DEF_HELPER_2(mtvscr, void, env, avr);
-DEF_HELPER_2(lvebx, void, avr, tl)
-DEF_HELPER_2(lvehx, void, avr, tl)
-DEF_HELPER_2(lvewx, void, avr, tl)
-DEF_HELPER_2(stvebx, void, avr, tl)
-DEF_HELPER_2(stvehx, void, avr, tl)
-DEF_HELPER_2(stvewx, void, avr, tl)
+DEF_HELPER_3(lvebx, void, env, avr, tl)
+DEF_HELPER_3(lvehx, void, env, avr, tl)
+DEF_HELPER_3(lvewx, void, env, avr, tl)
+DEF_HELPER_3(stvebx, void, env, avr, tl)
+DEF_HELPER_3(stvehx, void, env, avr, tl)
+DEF_HELPER_3(stvewx, void, env, avr, tl)
DEF_HELPER_4(vsumsws, void, env, avr, avr, avr)
DEF_HELPER_4(vsum2sws, void, env, avr, avr, avr)
DEF_HELPER_4(vsum4sbs, void, env, avr, avr, avr)
diff --git a/target-ppc/op_helper.c b/target-ppc/mem_helper.c
similarity index 68%
rename from target-ppc/op_helper.c
rename to target-ppc/mem_helper.c
index cd1a533..ebcd7b2 100644
--- a/target-ppc/op_helper.c
+++ b/target-ppc/mem_helper.c
@@ -1,5 +1,5 @@
/*
- * PowerPC emulation helpers for QEMU.
+ * PowerPC memory access emulation helpers for QEMU.
*
* Copyright (c) 2003-2007 Jocelyn Mayer
*
@@ -16,9 +16,7 @@
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
-#include <string.h>
#include "cpu.h"
-#include "dyngen-exec.h"
#include "host-utils.h"
#include "helper.h"
@@ -33,7 +31,8 @@
/*****************************************************************************/
/* Memory load and stores */
-static inline target_ulong addr_add(target_ulong addr, target_long arg)
+static inline target_ulong addr_add(CPUPPCState *env, target_ulong addr,
+ target_long arg)
{
#if defined(TARGET_PPC64)
if (!msr_sf) {
@@ -45,44 +44,44 @@ static inline target_ulong addr_add(target_ulong addr, target_long arg)
}
}
-void helper_lmw(target_ulong addr, uint32_t reg)
+void helper_lmw(CPUPPCState *env, target_ulong addr, uint32_t reg)
{
for (; reg < 32; reg++) {
if (msr_le) {
- env->gpr[reg] = bswap32(ldl(addr));
+ env->gpr[reg] = bswap32(cpu_ldl_data(env, addr));
} else {
- env->gpr[reg] = ldl(addr);
+ env->gpr[reg] = cpu_ldl_data(env, addr);
}
- addr = addr_add(addr, 4);
+ addr = addr_add(env, addr, 4);
}
}
-void helper_stmw(target_ulong addr, uint32_t reg)
+void helper_stmw(CPUPPCState *env, target_ulong addr, uint32_t reg)
{
for (; reg < 32; reg++) {
if (msr_le) {
- stl(addr, bswap32((uint32_t)env->gpr[reg]));
+ cpu_stl_data(env, addr, bswap32((uint32_t)env->gpr[reg]));
} else {
- stl(addr, (uint32_t)env->gpr[reg]);
+ cpu_stl_data(env, addr, (uint32_t)env->gpr[reg]);
}
- addr = addr_add(addr, 4);
+ addr = addr_add(env, addr, 4);
}
}
-void helper_lsw(target_ulong addr, uint32_t nb, uint32_t reg)
+void helper_lsw(CPUPPCState *env, target_ulong addr, uint32_t nb, uint32_t reg)
{
int sh;
for (; nb > 3; nb -= 4) {
- env->gpr[reg] = ldl(addr);
+ env->gpr[reg] = cpu_ldl_data(env, addr);
reg = (reg + 1) % 32;
- addr = addr_add(addr, 4);
+ addr = addr_add(env, addr, 4);
}
if (unlikely(nb > 0)) {
env->gpr[reg] = 0;
for (sh = 24; nb > 0; nb--, sh -= 8) {
- env->gpr[reg] |= ldub(addr) << sh;
- addr = addr_add(addr, 1);
+ env->gpr[reg] |= cpu_ldub_data(env, addr) << sh;
+ addr = addr_add(env, addr, 1);
}
}
}
@@ -91,7 +90,8 @@ void helper_lsw(target_ulong addr, uint32_t nb, uint32_t reg)
* In an other hand, IBM says this is valid, but rA won't be loaded.
* For now, I'll follow the spec...
*/
-void helper_lswx(target_ulong addr, uint32_t reg, uint32_t ra, uint32_t rb)
+void helper_lswx(CPUPPCState *env, target_ulong addr, uint32_t reg,
+ uint32_t ra, uint32_t rb)
{
if (likely(xer_bc != 0)) {
if (unlikely((ra != 0 && reg < ra && (reg + xer_bc) > ra) ||
@@ -100,56 +100,57 @@ void helper_lswx(target_ulong addr, uint32_t reg, uint32_t ra, uint32_t rb)
POWERPC_EXCP_INVAL |
POWERPC_EXCP_INVAL_LSWX);
} else {
- helper_lsw(addr, xer_bc, reg);
+ helper_lsw(env, addr, xer_bc, reg);
}
}
}
-void helper_stsw(target_ulong addr, uint32_t nb, uint32_t reg)
+void helper_stsw(CPUPPCState *env, target_ulong addr, uint32_t nb,
+ uint32_t reg)
{
int sh;
for (; nb > 3; nb -= 4) {
- stl(addr, env->gpr[reg]);
+ cpu_stl_data(env, addr, env->gpr[reg]);
reg = (reg + 1) % 32;
- addr = addr_add(addr, 4);
+ addr = addr_add(env, addr, 4);
}
if (unlikely(nb > 0)) {
for (sh = 24; nb > 0; nb--, sh -= 8) {
- stb(addr, (env->gpr[reg] >> sh) & 0xFF);
- addr = addr_add(addr, 1);
+ cpu_stb_data(env, addr, (env->gpr[reg] >> sh) & 0xFF);
+ addr = addr_add(env, addr, 1);
}
}
}
-static void do_dcbz(target_ulong addr, int dcache_line_size)
+static void do_dcbz(CPUPPCState *env, target_ulong addr, int dcache_line_size)
{
int i;
addr &= ~(dcache_line_size - 1);
for (i = 0; i < dcache_line_size; i += 4) {
- stl(addr + i, 0);
+ cpu_stl_data(env, addr + i, 0);
}
if (env->reserve_addr == addr) {
env->reserve_addr = (target_ulong)-1ULL;
}
}
-void helper_dcbz(target_ulong addr)
+void helper_dcbz(CPUPPCState *env, target_ulong addr)
{
- do_dcbz(addr, env->dcache_line_size);
+ do_dcbz(env, addr, env->dcache_line_size);
}
-void helper_dcbz_970(target_ulong addr)
+void helper_dcbz_970(CPUPPCState *env, target_ulong addr)
{
if (((env->spr[SPR_970_HID5] >> 7) & 0x3) == 1) {
- do_dcbz(addr, 32);
+ do_dcbz(env, addr, 32);
} else {
- do_dcbz(addr, env->dcache_line_size);
+ do_dcbz(env, addr, env->dcache_line_size);
}
}
-void helper_icbi(target_ulong addr)
+void helper_icbi(CPUPPCState *env, target_ulong addr)
{
addr &= ~(env->dcache_line_size - 1);
/* Invalidate one cache line :
@@ -157,19 +158,19 @@ void helper_icbi(target_ulong addr)
* (not a fetch) by the MMU. To be sure it will be so,
* do the load "by hand".
*/
- ldl(addr);
+ cpu_ldl_data(env, addr);
}
/* XXX: to be tested */
-target_ulong helper_lscbx(target_ulong addr, uint32_t reg, uint32_t ra,
- uint32_t rb)
+target_ulong helper_lscbx(CPUPPCState *env, target_ulong addr, uint32_t reg,
+ uint32_t ra, uint32_t rb)
{
int i, c, d;
d = 24;
for (i = 0; i < xer_bc; i++) {
- c = ldub(addr);
- addr = addr_add(addr, 1);
+ c = cpu_ldub_data(env, addr);
+ addr = addr_add(env, addr, 1);
/* ra (if not 0) and rb are never modified */
if (likely(reg != rb && (ra == 0 || reg != ra))) {
env->gpr[reg] = (env->gpr[reg] & ~(0xFF << d)) | (c << d);
@@ -199,7 +200,8 @@ target_ulong helper_lscbx(target_ulong addr, uint32_t reg, uint32_t ra,
#endif
#define LVE(name, access, swap, element) \
- void helper_##name(ppc_avr_t *r, target_ulong addr) \
+ void helper_##name(CPUPPCState *env, ppc_avr_t *r, \
+ target_ulong addr) \
{ \
size_t n_elems = ARRAY_SIZE(r->element); \
int adjust = HI_IDX*(n_elems - 1); \
@@ -208,21 +210,22 @@ target_ulong helper_lscbx(target_ulong addr, uint32_t reg, uint32_t ra,
\
if (msr_le) { \
r->element[LO_IDX ? index : (adjust - index)] = \
- swap(access(addr)); \
+ swap(access(env, addr)); \
} else { \
r->element[LO_IDX ? index : (adjust - index)] = \
- access(addr); \
+ access(env, addr); \
} \
}
#define I(x) (x)
-LVE(lvebx, ldub, I, u8)
-LVE(lvehx, lduw, bswap16, u16)
-LVE(lvewx, ldl, bswap32, u32)
+LVE(lvebx, cpu_ldub_data, I, u8)
+LVE(lvehx, cpu_lduw_data, bswap16, u16)
+LVE(lvewx, cpu_ldl_data, bswap32, u32)
#undef I
#undef LVE
#define STVE(name, access, swap, element) \
- void helper_##name(ppc_avr_t *r, target_ulong addr) \
+ void helper_##name(CPUPPCState *env, ppc_avr_t *r, \
+ target_ulong addr) \
{ \
size_t n_elems = ARRAY_SIZE(r->element); \
int adjust = HI_IDX * (n_elems - 1); \
@@ -230,15 +233,17 @@ LVE(lvewx, ldl, bswap32, u32)
int index = (addr & 0xf) >> sh; \
\
if (msr_le) { \
- access(addr, swap(r->element[LO_IDX ? index : (adjust - index)])); \
+ access(env, addr, swap(r->element[LO_IDX ? index : \
+ (adjust - index)])); \
} else { \
- access(addr, r->element[LO_IDX ? index : (adjust - index)]); \
+ access(env, addr, r->element[LO_IDX ? index : \
+ (adjust - index)]); \
} \
}
#define I(x) (x)
-STVE(stvebx, stb, I, u8)
-STVE(stvehx, stw, bswap16, u16)
-STVE(stvewx, stl, bswap32, u32)
+STVE(stvebx, cpu_stb_data, I, u8)
+STVE(stvehx, cpu_stw_data, bswap16, u16)
+STVE(stvewx, cpu_stl_data, bswap32, u32)
#undef I
#undef LVE
@@ -267,15 +272,12 @@ STVE(stvewx, stl, bswap32, u32)
NULL, it means that the function was called in C code (i.e. not
from generated code or from helper.c) */
/* XXX: fix it to restore all registers */
-void tlb_fill(CPUPPCState *env1, target_ulong addr, int is_write, int mmu_idx,
+void tlb_fill(CPUPPCState *env, target_ulong addr, int is_write, int mmu_idx,
uintptr_t retaddr)
{
TranslationBlock *tb;
- CPUPPCState *saved_env;
int ret;
- saved_env = env;
- env = env1;
ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, mmu_idx);
if (unlikely(ret != 0)) {
if (likely(retaddr)) {
@@ -289,6 +291,5 @@ void tlb_fill(CPUPPCState *env1, target_ulong addr, int is_write, int mmu_idx,
}
helper_raise_exception_err(env, env->exception_index, env->error_code);
}
- env = saved_env;
}
#endif /* !CONFIG_USER_ONLY */
diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index bcc9933..9103fd5 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -2989,7 +2989,7 @@ static void gen_lmw(DisasContext *ctx)
t0 = tcg_temp_new();
t1 = tcg_const_i32(rD(ctx->opcode));
gen_addr_imm_index(ctx, t0, 0);
- gen_helper_lmw(t0, t1);
+ gen_helper_lmw(cpu_env, t0, t1);
tcg_temp_free(t0);
tcg_temp_free_i32(t1);
}
@@ -3005,7 +3005,7 @@ static void gen_stmw(DisasContext *ctx)
t0 = tcg_temp_new();
t1 = tcg_const_i32(rS(ctx->opcode));
gen_addr_imm_index(ctx, t0, 0);
- gen_helper_stmw(t0, t1);
+ gen_helper_stmw(cpu_env, t0, t1);
tcg_temp_free(t0);
tcg_temp_free_i32(t1);
}
@@ -3043,7 +3043,7 @@ static void gen_lswi(DisasContext *ctx)
gen_addr_register(ctx, t0);
t1 = tcg_const_i32(nb);
t2 = tcg_const_i32(start);
- gen_helper_lsw(t0, t1, t2);
+ gen_helper_lsw(cpu_env, t0, t1, t2);
tcg_temp_free(t0);
tcg_temp_free_i32(t1);
tcg_temp_free_i32(t2);
@@ -3062,7 +3062,7 @@ static void gen_lswx(DisasContext *ctx)
t1 = tcg_const_i32(rD(ctx->opcode));
t2 = tcg_const_i32(rA(ctx->opcode));
t3 = tcg_const_i32(rB(ctx->opcode));
- gen_helper_lswx(t0, t1, t2, t3);
+ gen_helper_lswx(cpu_env, t0, t1, t2, t3);
tcg_temp_free(t0);
tcg_temp_free_i32(t1);
tcg_temp_free_i32(t2);
@@ -3084,7 +3084,7 @@ static void gen_stswi(DisasContext *ctx)
nb = 32;
t1 = tcg_const_i32(nb);
t2 = tcg_const_i32(rS(ctx->opcode));
- gen_helper_stsw(t0, t1, t2);
+ gen_helper_stsw(cpu_env, t0, t1, t2);
tcg_temp_free(t0);
tcg_temp_free_i32(t1);
tcg_temp_free_i32(t2);
@@ -3104,7 +3104,7 @@ static void gen_stswx(DisasContext *ctx)
tcg_gen_trunc_tl_i32(t1, cpu_xer);
tcg_gen_andi_i32(t1, t1, 0x7F);
t2 = tcg_const_i32(rS(ctx->opcode));
- gen_helper_stsw(t0, t1, t2);
+ gen_helper_stsw(cpu_env, t0, t1, t2);
tcg_temp_free(t0);
tcg_temp_free_i32(t1);
tcg_temp_free_i32(t2);
@@ -4116,7 +4116,7 @@ static void gen_dcbz(DisasContext *ctx)
gen_update_nip(ctx, ctx->nip - 4);
t0 = tcg_temp_new();
gen_addr_reg_index(ctx, t0);
- gen_helper_dcbz(t0);
+ gen_helper_dcbz(cpu_env, t0);
tcg_temp_free(t0);
}
@@ -4129,9 +4129,9 @@ static void gen_dcbz_970(DisasContext *ctx)
t0 = tcg_temp_new();
gen_addr_reg_index(ctx, t0);
if (ctx->opcode & 0x00200000)
- gen_helper_dcbz(t0);
+ gen_helper_dcbz(cpu_env, t0);
else
- gen_helper_dcbz_970(t0);
+ gen_helper_dcbz_970(cpu_env, t0);
tcg_temp_free(t0);
}
@@ -4171,7 +4171,7 @@ static void gen_icbi(DisasContext *ctx)
gen_update_nip(ctx, ctx->nip - 4);
t0 = tcg_temp_new();
gen_addr_reg_index(ctx, t0);
- gen_helper_icbi(t0);
+ gen_helper_icbi(cpu_env, t0);
tcg_temp_free(t0);
}
@@ -4663,7 +4663,7 @@ static void gen_lscbx(DisasContext *ctx)
gen_addr_reg_index(ctx, t0);
/* NIP cannot be restored if the memory exception comes from an helper */
gen_update_nip(ctx, ctx->nip - 4);
- gen_helper_lscbx(t0, t0, t1, t2, t3);
+ gen_helper_lscbx(t0, cpu_env, t0, t1, t2, t3);
tcg_temp_free_i32(t1);
tcg_temp_free_i32(t2);
tcg_temp_free_i32(t3);
@@ -6387,7 +6387,7 @@ static void gen_lve##name(DisasContext *ctx) \
EA = tcg_temp_new(); \
gen_addr_reg_index(ctx, EA); \
rs = gen_avr_ptr(rS(ctx->opcode)); \
- gen_helper_lve##name (rs, EA); \
+ gen_helper_lve##name(cpu_env, rs, EA); \
tcg_temp_free(EA); \
tcg_temp_free_ptr(rs); \
}
@@ -6405,7 +6405,7 @@ static void gen_stve##name(DisasContext *ctx) \
EA = tcg_temp_new(); \
gen_addr_reg_index(ctx, EA); \
rs = gen_avr_ptr(rS(ctx->opcode)); \
- gen_helper_stve##name (rs, EA); \
+ gen_helper_stve##name(cpu_env, rs, EA); \
tcg_temp_free(EA); \
tcg_temp_free_ptr(rs); \
}
@@ -9683,9 +9683,9 @@ static inline void gen_intermediate_code_internal(CPUPPCState *env,
if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO))
gen_io_start();
if (unlikely(ctx.le_mode)) {
- ctx.opcode = bswap32(ldl_code(ctx.nip));
+ ctx.opcode = bswap32(cpu_ldl_code(env, ctx.nip));
} else {
- ctx.opcode = ldl_code(ctx.nip);
+ ctx.opcode = cpu_ldl_code(env, ctx.nip);
}
LOG_DISAS("translate opcode %08x (%02x %02x %02x) (%s)\n",
ctx.opcode, opc1(ctx.opcode), opc2(ctx.opcode),
--
1.6.0.2
^ permalink raw reply related [flat|nested] 89+ messages in thread
* [Qemu-devel] [PATCH 21/72] ppc: Add missing break
2012-06-23 23:06 [Qemu-devel] [PULL 00/72] ppc patch queue 2012-06-24 Alexander Graf
` (19 preceding siblings ...)
2012-06-23 23:06 ` [Qemu-devel] [PATCH 20/72] ppc: Move load and store helpers, switch to AREG0 free mode Alexander Graf
@ 2012-06-23 23:06 ` Alexander Graf
2012-06-23 23:06 ` [Qemu-devel] [PATCH 22/72] ppc: Make hbrev table const Alexander Graf
` (51 subsequent siblings)
72 siblings, 0 replies; 89+ messages in thread
From: Alexander Graf @ 2012-06-23 23:06 UTC (permalink / raw)
To: qemu-devel qemu-devel
Cc: Blue Swirl, qemu-ppc Mailing List, Andreas Färber,
Aurelien Jarno
From: Blue Swirl <blauwirbel@gmail.com>
Add obviously missing 'break' statement.
Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Andreas Färber <afaerber@suse.de>
Signed-off-by: Alexander Graf <agraf@suse.de>
---
target-ppc/fpu_helper.c | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/target-ppc/fpu_helper.c b/target-ppc/fpu_helper.c
index d90636f..9d67926 100644
--- a/target-ppc/fpu_helper.c
+++ b/target-ppc/fpu_helper.c
@@ -310,6 +310,7 @@ void helper_fpscr_setbit(CPUPPCState *env, uint32_t bit)
if (fpscr_ve) {
goto raise_ve;
}
+ break;
case FPSCR_OX:
env->fpscr |= 1 << FPSCR_FX;
if (fpscr_oe) {
--
1.6.0.2
^ permalink raw reply related [flat|nested] 89+ messages in thread
* [Qemu-devel] [PATCH 22/72] ppc: Make hbrev table const
2012-06-23 23:06 [Qemu-devel] [PULL 00/72] ppc patch queue 2012-06-24 Alexander Graf
` (20 preceding siblings ...)
2012-06-23 23:06 ` [Qemu-devel] [PATCH 21/72] ppc: Add missing break Alexander Graf
@ 2012-06-23 23:06 ` Alexander Graf
2012-06-23 23:06 ` [Qemu-devel] [PATCH 23/72] PPC: mpc8544ds: Span initial TLB entry over as much RAM as we need Alexander Graf
` (50 subsequent siblings)
72 siblings, 0 replies; 89+ messages in thread
From: Alexander Graf @ 2012-06-23 23:06 UTC (permalink / raw)
To: qemu-devel qemu-devel
Cc: Blue Swirl, qemu-ppc Mailing List, Andreas Färber,
Aurelien Jarno
From: Blue Swirl <blauwirbel@gmail.com>
Lookup table 'hbrev' is never written to, so add a 'const' qualifier.
Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Andreas Färber <afaerber@suse.de>
Signed-off-by: Alexander Graf <agraf@suse.de>
---
target-ppc/int_helper.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/target-ppc/int_helper.c b/target-ppc/int_helper.c
index 3173f11..f638b2a 100644
--- a/target-ppc/int_helper.c
+++ b/target-ppc/int_helper.c
@@ -1484,7 +1484,7 @@ VUPK(lsh, s32, s16, UPKLO)
/*****************************************************************************/
/* SPE extension helpers */
/* Use a table to make this quicker */
-static uint8_t hbrev[16] = {
+static const uint8_t hbrev[16] = {
0x0, 0x8, 0x4, 0xC, 0x2, 0xA, 0x6, 0xE,
0x1, 0x9, 0x5, 0xD, 0x3, 0xB, 0x7, 0xF,
};
--
1.6.0.2
^ permalink raw reply related [flat|nested] 89+ messages in thread
* [Qemu-devel] [PATCH 23/72] PPC: mpc8544ds: Span initial TLB entry over as much RAM as we need
2012-06-23 23:06 [Qemu-devel] [PULL 00/72] ppc patch queue 2012-06-24 Alexander Graf
` (21 preceding siblings ...)
2012-06-23 23:06 ` [Qemu-devel] [PATCH 22/72] ppc: Make hbrev table const Alexander Graf
@ 2012-06-23 23:06 ` Alexander Graf
2012-06-23 23:06 ` [Qemu-devel] [PATCH 24/72] Avoid segfault in cpu_dump_state Alexander Graf
` (49 subsequent siblings)
72 siblings, 0 replies; 89+ messages in thread
From: Alexander Graf @ 2012-06-23 23:06 UTC (permalink / raw)
To: qemu-devel qemu-devel; +Cc: Blue Swirl, qemu-ppc Mailing List, Aurelien Jarno
The initial TLB entry is supposed to help us run the guest -kernel payload.
This means the guest needs to be able to access its own memory, the initrd
memory and the device tree.
So far we only statically reserved a TLB entry from [0;256M[. This patch
fixes it to span from [0;dt_end[, allowing the guest payload to access
everything initially.
Reported-by: Stuart Yoder <stuart.yoder@freescale.com>
Signed-off-by: Alexander Graf <agraf@suse.de>
---
hw/ppce500_mpc8544ds.c | 41 +++++++++++++++++++++++++++--------------
1 files changed, 27 insertions(+), 14 deletions(-)
diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c
index 3eb8a23..b1a0b8c 100644
--- a/hw/ppce500_mpc8544ds.c
+++ b/hw/ppce500_mpc8544ds.c
@@ -31,6 +31,7 @@
#include "elf.h"
#include "sysbus.h"
#include "exec-memory.h"
+#include "host-utils.h"
#define BINARY_DEVICE_TREE_FILE "mpc8544ds.dtb"
#define UIMAGE_LOAD_BASE 0
@@ -55,6 +56,7 @@
struct boot_info
{
uint32_t dt_base;
+ uint32_t dt_size;
uint32_t entry;
};
@@ -164,7 +166,11 @@ static int mpc8544_load_device_tree(CPUPPCState *env,
}
ret = rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr);
+ if (ret < 0) {
+ goto out;
+ }
g_free(fdt);
+ ret = fdt_size;
out:
#endif
@@ -172,23 +178,27 @@ out:
return ret;
}
-/* Create -kernel TLB entries for BookE, linearly spanning 256MB. */
+/* Create -kernel TLB entries for BookE. */
static inline target_phys_addr_t booke206_page_size_to_tlb(uint64_t size)
{
- return ffs(size >> 10) - 1;
+ return 63 - clz64(size >> 10);
}
-static void mmubooke_create_initial_mapping(CPUPPCState *env,
- target_ulong va,
- target_phys_addr_t pa)
+static void mmubooke_create_initial_mapping(CPUPPCState *env)
{
+ struct boot_info *bi = env->load_info;
ppcmas_tlb_t *tlb = booke206_get_tlbm(env, 1, 0, 0);
- target_phys_addr_t size;
-
- size = (booke206_page_size_to_tlb(256 * 1024 * 1024) << MAS1_TSIZE_SHIFT);
+ target_phys_addr_t size, dt_end;
+ int ps;
+
+ /* Our initial TLB entry needs to cover everything from 0 to
+ the device tree top */
+ dt_end = bi->dt_base + bi->dt_size;
+ ps = booke206_page_size_to_tlb(dt_end) + 1;
+ size = (ps << MAS1_TSIZE_SHIFT);
tlb->mas1 = MAS1_VALID | size;
- tlb->mas2 = va & TARGET_PAGE_MASK;
- tlb->mas7_3 = pa & TARGET_PAGE_MASK;
+ tlb->mas2 = 0;
+ tlb->mas7_3 = 0;
tlb->mas7_3 |= MAS3_UR | MAS3_UW | MAS3_UX | MAS3_SR | MAS3_SW | MAS3_SX;
env->tlb_dirty = true;
@@ -220,7 +230,7 @@ static void mpc8544ds_cpu_reset(void *opaque)
env->gpr[1] = (16<<20) - 8;
env->gpr[3] = bi->dt_base;
env->nip = bi->entry;
- mmubooke_create_initial_mapping(env, 0, 0);
+ mmubooke_create_initial_mapping(env);
}
static void mpc8544ds_init(ram_addr_t ram_size,
@@ -379,13 +389,15 @@ static void mpc8544ds_init(ram_addr_t ram_size,
/* If we're loading a kernel directly, we must load the device tree too. */
if (kernel_filename) {
struct boot_info *boot_info;
+ int dt_size;
#ifndef CONFIG_FDT
cpu_abort(env, "Compiled without FDT support - can't load kernel\n");
#endif
- dt_base = (kernel_size + DTC_LOAD_PAD) & ~DTC_PAD_MASK;
- if (mpc8544_load_device_tree(env, dt_base, ram_size,
- initrd_base, initrd_size, kernel_cmdline) < 0) {
+ dt_base = (loadaddr + kernel_size + DTC_LOAD_PAD) & ~DTC_PAD_MASK;
+ dt_size = mpc8544_load_device_tree(env, dt_base, ram_size, initrd_base,
+ initrd_size, kernel_cmdline);
+ if (dt_size < 0) {
fprintf(stderr, "couldn't load device tree\n");
exit(1);
}
@@ -393,6 +405,7 @@ static void mpc8544ds_init(ram_addr_t ram_size,
boot_info = env->load_info;
boot_info->entry = entry;
boot_info->dt_base = dt_base;
+ boot_info->dt_size = dt_size;
}
if (kvm_enabled()) {
--
1.6.0.2
^ permalink raw reply related [flat|nested] 89+ messages in thread
* [Qemu-devel] [PATCH 24/72] Avoid segfault in cpu_dump_state
2012-06-23 23:06 [Qemu-devel] [PULL 00/72] ppc patch queue 2012-06-24 Alexander Graf
` (22 preceding siblings ...)
2012-06-23 23:06 ` [Qemu-devel] [PATCH 23/72] PPC: mpc8544ds: Span initial TLB entry over as much RAM as we need Alexander Graf
@ 2012-06-23 23:06 ` Alexander Graf
2012-06-23 23:06 ` [Qemu-devel] [PATCH 25/72] booke_206_tlbwe: Discard invalid bits in MAS2 Alexander Graf
` (48 subsequent siblings)
72 siblings, 0 replies; 89+ messages in thread
From: Alexander Graf @ 2012-06-23 23:06 UTC (permalink / raw)
To: qemu-devel qemu-devel
Cc: Blue Swirl, qemu-ppc Mailing List, Fabien Chouteau,
Aurelien Jarno
From: Fabien Chouteau <chouteau@adacore.com>
Do not call cpu_dump_state if logfile is NULL.
Signed-off-by: Fabien Chouteau <chouteau@adacore.com>
[agraf: adjust to inline functions]
Signed-off-by: Alexander Graf <agraf@suse.de>
---
qemu-log.h | 4 +++-
1 files changed, 3 insertions(+), 1 deletions(-)
diff --git a/qemu-log.h b/qemu-log.h
index 40f8b7b..2ed19d1 100644
--- a/qemu-log.h
+++ b/qemu-log.h
@@ -69,7 +69,9 @@ void GCC_FMT_ATTR(2, 3) qemu_log_mask(int mask, const char *fmt, ...);
/* cpu_dump_state() logging functions: */
static inline void log_cpu_state(CPUArchState *env1, int flags)
{
- cpu_dump_state(env1, qemu_logfile, fprintf, flags);
+ if (qemu_log_enabled()) {
+ cpu_dump_state(env1, qemu_logfile, fprintf, flags);
+ }
}
static inline void log_cpu_state_mask(int mask, CPUArchState *env1, int flags)
--
1.6.0.2
^ permalink raw reply related [flat|nested] 89+ messages in thread
* [Qemu-devel] [PATCH 25/72] booke_206_tlbwe: Discard invalid bits in MAS2
2012-06-23 23:06 [Qemu-devel] [PULL 00/72] ppc patch queue 2012-06-24 Alexander Graf
` (23 preceding siblings ...)
2012-06-23 23:06 ` [Qemu-devel] [PATCH 24/72] Avoid segfault in cpu_dump_state Alexander Graf
@ 2012-06-23 23:06 ` Alexander Graf
2012-06-23 23:06 ` [Qemu-devel] [PATCH 26/72] ppc64: Rudimentary Support for extra page sizes on server CPUs Alexander Graf
` (47 subsequent siblings)
72 siblings, 0 replies; 89+ messages in thread
From: Alexander Graf @ 2012-06-23 23:06 UTC (permalink / raw)
To: qemu-devel qemu-devel
Cc: Blue Swirl, qemu-ppc Mailing List, Fabien Chouteau,
Aurelien Jarno
From: Fabien Chouteau <chouteau@adacore.com>
The size of EPN field in MAS2 depends on page size. This patch adds a
mask to discard invalid bits in EPN field.
Definition of EPN field from e500v2 RM:
EPN Effective page number: Depending on page size, only the bits
associated with a page boundary are valid. Bits that represent offsets
within a page are ignored and should be cleared.
There is a similar (but more complicated) definition in PowerISA V2.06.
Signed-off-by: Fabien Chouteau <chouteau@adacore.com>
Signed-off-by: Alexander Graf <agraf@suse.de>
---
target-ppc/mmu_helper.c | 17 +++++++++++++++--
1 files changed, 15 insertions(+), 2 deletions(-)
diff --git a/target-ppc/mmu_helper.c b/target-ppc/mmu_helper.c
index d65d290..c4e79d9 100644
--- a/target-ppc/mmu_helper.c
+++ b/target-ppc/mmu_helper.c
@@ -3019,6 +3019,8 @@ void helper_booke206_tlbwe(CPUPPCState *env)
uint32_t tlbncfg, tlbn;
ppcmas_tlb_t *tlb;
uint32_t size_tlb, size_ps;
+ target_ulong mask;
+
switch (env->spr[SPR_BOOKE_MAS0] & MAS0_WQ_MASK) {
case MAS0_WQ_ALWAYS:
@@ -3081,8 +3083,19 @@ void helper_booke206_tlbwe(CPUPPCState *env)
tlb->mas1 |= (tlbncfg & TLBnCFG_MINSIZE) >> 12;
}
- /* XXX needs to change when supporting 64-bit e500 */
- tlb->mas2 = env->spr[SPR_BOOKE_MAS2] & 0xffffffff;
+ /* Make a mask from TLB size to discard invalid bits in EPN field */
+ mask = ~(booke206_tlb_to_page_size(env, tlb) - 1);
+ /* Add a mask for page attributes */
+ mask |= MAS2_ACM | MAS2_VLE | MAS2_W | MAS2_I | MAS2_M | MAS2_G | MAS2_E;
+
+ if (!msr_cm) {
+ /* Executing a tlbwe instruction in 32-bit mode will set
+ * bits 0:31 of the TLB EPN field to zero.
+ */
+ mask &= 0xffffffff;
+ }
+
+ tlb->mas2 = env->spr[SPR_BOOKE_MAS2] & mask;
if (!(tlbncfg & TLBnCFG_IPROT)) {
/* no IPROT supported by TLB */
--
1.6.0.2
^ permalink raw reply related [flat|nested] 89+ messages in thread
* [Qemu-devel] [PATCH 26/72] ppc64: Rudimentary Support for extra page sizes on server CPUs
2012-06-23 23:06 [Qemu-devel] [PULL 00/72] ppc patch queue 2012-06-24 Alexander Graf
` (24 preceding siblings ...)
2012-06-23 23:06 ` [Qemu-devel] [PATCH 25/72] booke_206_tlbwe: Discard invalid bits in MAS2 Alexander Graf
@ 2012-06-23 23:06 ` Alexander Graf
2012-06-23 23:06 ` [Qemu-devel] [PATCH 27/72] pseries: Correctly create ibm, segment-page-sizes property Alexander Graf
` (46 subsequent siblings)
72 siblings, 0 replies; 89+ messages in thread
From: Alexander Graf @ 2012-06-23 23:06 UTC (permalink / raw)
To: qemu-devel qemu-devel
Cc: Blue Swirl, qemu-ppc Mailing List, Aurelien Jarno, David Gibson
From: Benjamin Herrenschmidt <benh@kernel.crashing.org>
More recent Power server chips (i.e. based on the 64 bit hash MMU)
support more than just the traditional 4k and 16M page sizes. This
can get quite complicated, because which page sizes are supported,
which combinations are supported within an MMU segment and how these
page sizes are encoded both in the SLB entry and the hash PTE can vary
depending on the CPU model (they are not specified by the
architecture). In addition the firmware or hypervisor may not permit
use of certain page sizes, for various reasons. Whether various page
sizes are supported on KVM, for example, depends on whether the PR or
HV variant of KVM is in use, and on the page size of the memory
backing the guest's RAM.
This patch adds information to the CPUState and cpu defs to describe
the supported page sizes and encodings. Since TCG does not yet
support any extended page sizes, we just set this to NULL in the
static CPU definitions, expanding this to the default 4k and 16M page
sizes when we initialize the cpu state. When using KVM, however, we
instead determine available page sizes using the new
KVM_PPC_GET_SMMU_INFO call. For old kernels without that call, we use
some defaults, with some guesswork which should do the right thing for
existing HV and PR implementations. The fallback might not be correct
for future versions, but that's ok, because they'll have
KVM_PPC_GET_SMMU_INFO.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Alexander Graf <agraf@suse.de>
---
target-ppc/cpu.h | 31 +++++++
target-ppc/kvm.c | 208 +++++++++++++++++++++++++++++++++++++++++++
target-ppc/kvm_ppc.h | 5 +
target-ppc/mmu_helper.c | 7 ++
target-ppc/translate_init.c | 21 +++++
5 files changed, 272 insertions(+), 0 deletions(-)
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index 9b157f0..67e699c 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -119,6 +119,8 @@ enum powerpc_mmu_t {
POWERPC_MMU_620 = POWERPC_MMU_64 | 0x00000002,
/* Architecture 2.06 variant */
POWERPC_MMU_2_06 = POWERPC_MMU_64 | POWERPC_MMU_1TSEG | 0x00000003,
+ /* Architecture 2.06 "degraded" (no 1T segments) */
+ POWERPC_MMU_2_06d = POWERPC_MMU_64 | 0x00000003,
#endif /* defined(TARGET_PPC64) */
};
@@ -874,6 +876,29 @@ enum {
#define DBELL_PIRTAG_MASK 0x3fff
/*****************************************************************************/
+/* Segment page size information, used by recent hash MMUs
+ * The format of this structure mirrors kvm_ppc_smmu_info
+ */
+
+#define PPC_PAGE_SIZES_MAX_SZ 8
+
+struct ppc_one_page_size {
+ uint32_t page_shift; /* Page shift (or 0) */
+ uint32_t pte_enc; /* Encoding in the HPTE (>>12) */
+};
+
+struct ppc_one_seg_page_size {
+ uint32_t page_shift; /* Base page shift of segment (or 0) */
+ uint32_t slb_enc; /* SLB encoding for BookS */
+ struct ppc_one_page_size enc[PPC_PAGE_SIZES_MAX_SZ];
+};
+
+struct ppc_segment_page_sizes {
+ struct ppc_one_seg_page_size sps[PPC_PAGE_SIZES_MAX_SZ];
+};
+
+
+/*****************************************************************************/
/* The whole PowerPC CPU context */
#define NB_MMU_MODES 3
@@ -889,6 +914,9 @@ struct ppc_def_t {
powerpc_input_t bus_model;
uint32_t flags;
int bfd_mach;
+#if defined(TARGET_PPC64)
+ const struct ppc_segment_page_sizes *sps;
+#endif
void (*init_proc)(CPUPPCState *env);
int (*check_pow)(CPUPPCState *env);
};
@@ -1012,6 +1040,9 @@ struct CPUPPCState {
uint32_t flags;
uint64_t insns_flags;
uint64_t insns_flags2;
+#if defined(TARGET_PPC64)
+ struct ppc_segment_page_sizes sps;
+#endif
#if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY)
target_phys_addr_t vpa;
diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c
index c09cc39..b6ef72d 100644
--- a/target-ppc/kvm.c
+++ b/target-ppc/kvm.c
@@ -18,6 +18,7 @@
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
+#include <sys/vfs.h>
#include <linux/kvm.h>
@@ -167,10 +168,217 @@ static int kvm_booke206_tlb_init(CPUPPCState *env)
return 0;
}
+
+#if defined(TARGET_PPC64)
+static void kvm_get_fallback_smmu_info(CPUPPCState *env,
+ struct kvm_ppc_smmu_info *info)
+{
+ memset(info, 0, sizeof(*info));
+
+ /* We don't have the new KVM_PPC_GET_SMMU_INFO ioctl, so
+ * need to "guess" what the supported page sizes are.
+ *
+ * For that to work we make a few assumptions:
+ *
+ * - If KVM_CAP_PPC_GET_PVINFO is supported we are running "PR"
+ * KVM which only supports 4K and 16M pages, but supports them
+ * regardless of the backing store characteritics. We also don't
+ * support 1T segments.
+ *
+ * This is safe as if HV KVM ever supports that capability or PR
+ * KVM grows supports for more page/segment sizes, those versions
+ * will have implemented KVM_CAP_PPC_GET_SMMU_INFO and thus we
+ * will not hit this fallback
+ *
+ * - Else we are running HV KVM. This means we only support page
+ * sizes that fit in the backing store. Additionally we only
+ * advertize 64K pages if the processor is ARCH 2.06 and we assume
+ * P7 encodings for the SLB and hash table. Here too, we assume
+ * support for any newer processor will mean a kernel that
+ * implements KVM_CAP_PPC_GET_SMMU_INFO and thus doesn't hit
+ * this fallback.
+ */
+ if (kvm_check_extension(env->kvm_state, KVM_CAP_PPC_GET_PVINFO)) {
+ /* No flags */
+ info->flags = 0;
+ info->slb_size = 64;
+
+ /* Standard 4k base page size segment */
+ info->sps[0].page_shift = 12;
+ info->sps[0].slb_enc = 0;
+ info->sps[0].enc[0].page_shift = 12;
+ info->sps[0].enc[0].pte_enc = 0;
+
+ /* Standard 16M large page size segment */
+ info->sps[1].page_shift = 24;
+ info->sps[1].slb_enc = SLB_VSID_L;
+ info->sps[1].enc[0].page_shift = 24;
+ info->sps[1].enc[0].pte_enc = 0;
+ } else {
+ int i = 0;
+
+ /* HV KVM has backing store size restrictions */
+ info->flags = KVM_PPC_PAGE_SIZES_REAL;
+
+ if (env->mmu_model & POWERPC_MMU_1TSEG) {
+ info->flags |= KVM_PPC_1T_SEGMENTS;
+ }
+
+ if (env->mmu_model == POWERPC_MMU_2_06) {
+ info->slb_size = 32;
+ } else {
+ info->slb_size = 64;
+ }
+
+ /* Standard 4k base page size segment */
+ info->sps[i].page_shift = 12;
+ info->sps[i].slb_enc = 0;
+ info->sps[i].enc[0].page_shift = 12;
+ info->sps[i].enc[0].pte_enc = 0;
+ i++;
+
+ /* 64K on MMU 2.06 */
+ if (env->mmu_model == POWERPC_MMU_2_06) {
+ info->sps[i].page_shift = 16;
+ info->sps[i].slb_enc = 0x110;
+ info->sps[i].enc[0].page_shift = 16;
+ info->sps[i].enc[0].pte_enc = 1;
+ i++;
+ }
+
+ /* Standard 16M large page size segment */
+ info->sps[i].page_shift = 24;
+ info->sps[i].slb_enc = SLB_VSID_L;
+ info->sps[i].enc[0].page_shift = 24;
+ info->sps[i].enc[0].pte_enc = 0;
+ }
+}
+
+static void kvm_get_smmu_info(CPUPPCState *env, struct kvm_ppc_smmu_info *info)
+{
+ int ret;
+
+ if (kvm_check_extension(env->kvm_state, KVM_CAP_PPC_GET_SMMU_INFO)) {
+ ret = kvm_vm_ioctl(env->kvm_state, KVM_PPC_GET_SMMU_INFO, info);
+ if (ret == 0) {
+ return;
+ }
+ }
+
+ kvm_get_fallback_smmu_info(env, info);
+}
+
+static long getrampagesize(void)
+{
+ struct statfs fs;
+ int ret;
+
+ if (!mem_path) {
+ /* guest RAM is backed by normal anonymous pages */
+ return getpagesize();
+ }
+
+ do {
+ ret = statfs(mem_path, &fs);
+ } while (ret != 0 && errno == EINTR);
+
+ if (ret != 0) {
+ fprintf(stderr, "Couldn't statfs() memory path: %s\n",
+ strerror(errno));
+ exit(1);
+ }
+
+#define HUGETLBFS_MAGIC 0x958458f6
+
+ if (fs.f_type != HUGETLBFS_MAGIC) {
+ /* Explicit mempath, but it's ordinary pages */
+ return getpagesize();
+ }
+
+ /* It's hugepage, return the huge page size */
+ return fs.f_bsize;
+}
+
+static bool kvm_valid_page_size(uint32_t flags, long rampgsize, uint32_t shift)
+{
+ if (!(flags & KVM_PPC_PAGE_SIZES_REAL)) {
+ return true;
+ }
+
+ return (1ul << shift) <= rampgsize;
+}
+
+static void kvm_fixup_page_sizes(CPUPPCState *env)
+{
+ static struct kvm_ppc_smmu_info smmu_info;
+ static bool has_smmu_info;
+ long rampagesize;
+ int iq, ik, jq, jk;
+
+ /* We only handle page sizes for 64-bit server guests for now */
+ if (!(env->mmu_model & POWERPC_MMU_64)) {
+ return;
+ }
+
+ /* Collect MMU info from kernel if not already */
+ if (!has_smmu_info) {
+ kvm_get_smmu_info(env, &smmu_info);
+ has_smmu_info = true;
+ }
+
+ rampagesize = getrampagesize();
+
+ /* Convert to QEMU form */
+ memset(&env->sps, 0, sizeof(env->sps));
+
+ for (ik = iq = 0; ik < KVM_PPC_PAGE_SIZES_MAX_SZ; ik++) {
+ struct ppc_one_seg_page_size *qsps = &env->sps.sps[iq];
+ struct kvm_ppc_one_seg_page_size *ksps = &smmu_info.sps[ik];
+
+ if (!kvm_valid_page_size(smmu_info.flags, rampagesize,
+ ksps->page_shift)) {
+ continue;
+ }
+ qsps->page_shift = ksps->page_shift;
+ qsps->slb_enc = ksps->slb_enc;
+ for (jk = jq = 0; jk < KVM_PPC_PAGE_SIZES_MAX_SZ; jk++) {
+ if (!kvm_valid_page_size(smmu_info.flags, rampagesize,
+ ksps->enc[jk].page_shift)) {
+ continue;
+ }
+ qsps->enc[jq].page_shift = ksps->enc[jk].page_shift;
+ qsps->enc[jq].pte_enc = ksps->enc[jk].pte_enc;
+ if (++jq >= PPC_PAGE_SIZES_MAX_SZ) {
+ break;
+ }
+ }
+ if (++iq >= PPC_PAGE_SIZES_MAX_SZ) {
+ break;
+ }
+ }
+ env->slb_nr = smmu_info.slb_size;
+ if (smmu_info.flags & KVM_PPC_1T_SEGMENTS) {
+ env->mmu_model |= POWERPC_MMU_1TSEG;
+ } else {
+ env->mmu_model &= ~POWERPC_MMU_1TSEG;
+ }
+}
+#else /* defined (TARGET_PPC64) */
+
+static inline void kvm_fixup_page_sizes(CPUPPCState *env)
+{
+}
+
+#endif /* !defined (TARGET_PPC64) */
+
int kvm_arch_init_vcpu(CPUPPCState *cenv)
{
int ret;
+ /* Gather server mmu info from KVM and update the CPU state */
+ kvm_fixup_page_sizes(cenv);
+
+ /* Synchronize sregs with kvm */
ret = kvm_arch_sync_sregs(cenv);
if (ret) {
return ret;
diff --git a/target-ppc/kvm_ppc.h b/target-ppc/kvm_ppc.h
index 34ecad3..e2f8703 100644
--- a/target-ppc/kvm_ppc.h
+++ b/target-ppc/kvm_ppc.h
@@ -58,6 +58,11 @@ static inline int kvmppc_get_hypercall(CPUPPCState *env, uint8_t *buf, int buf_l
return -1;
}
+static inline int kvmppc_read_segment_page_sizes(uint32_t *prop, int maxcells)
+{
+ return -1;
+}
+
static inline int kvmppc_set_interrupt(CPUPPCState *env, int irq, int level)
{
return -1;
diff --git a/target-ppc/mmu_helper.c b/target-ppc/mmu_helper.c
index c4e79d9..d2664ac 100644
--- a/target-ppc/mmu_helper.c
+++ b/target-ppc/mmu_helper.c
@@ -1634,6 +1634,7 @@ void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUPPCState *env)
#if defined(TARGET_PPC64)
case POWERPC_MMU_64B:
case POWERPC_MMU_2_06:
+ case POWERPC_MMU_2_06d:
mmubooks_dump_mmu(f, cpu_fprintf, env);
break;
#endif
@@ -1664,6 +1665,7 @@ static inline int check_physical(CPUPPCState *env, mmu_ctx_t *ctx,
case POWERPC_MMU_620:
case POWERPC_MMU_64B:
case POWERPC_MMU_2_06:
+ case POWERPC_MMU_2_06d:
/* Real address are 60 bits long */
ctx->raddr &= 0x0FFFFFFFFFFFFFFFULL;
ctx->prot |= PAGE_WRITE;
@@ -1745,6 +1747,7 @@ int get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx, target_ulong eaddr,
case POWERPC_MMU_620:
case POWERPC_MMU_64B:
case POWERPC_MMU_2_06:
+ case POWERPC_MMU_2_06d:
#endif
if (ret < 0) {
/* We didn't match any BAT entry or don't have BATs */
@@ -1886,6 +1889,7 @@ int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw,
case POWERPC_MMU_620:
case POWERPC_MMU_64B:
case POWERPC_MMU_2_06:
+ case POWERPC_MMU_2_06d:
#endif
env->exception_index = POWERPC_EXCP_ISI;
env->error_code = 0x40000000;
@@ -1997,6 +2001,7 @@ int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw,
case POWERPC_MMU_620:
case POWERPC_MMU_64B:
case POWERPC_MMU_2_06:
+ case POWERPC_MMU_2_06d:
#endif
env->exception_index = POWERPC_EXCP_DSI;
env->error_code = 0;
@@ -2326,6 +2331,7 @@ void ppc_tlb_invalidate_all(CPUPPCState *env)
case POWERPC_MMU_620:
case POWERPC_MMU_64B:
case POWERPC_MMU_2_06:
+ case POWERPC_MMU_2_06d:
#endif /* defined(TARGET_PPC64) */
tlb_flush(env, 1);
break;
@@ -2395,6 +2401,7 @@ void ppc_tlb_invalidate_one(CPUPPCState *env, target_ulong addr)
case POWERPC_MMU_620:
case POWERPC_MMU_64B:
case POWERPC_MMU_2_06:
+ case POWERPC_MMU_2_06d:
/* tlbie invalidate TLBs for all segments */
/* XXX: given the fact that there are too many segments to invalidate,
* and we still don't have a tlb_flush_mask(env, n, mask) in QEMU,
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index f6ac589..57027a2 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -9928,6 +9928,27 @@ int cpu_ppc_register_internal (CPUPPCState *env, const ppc_def_t *def)
env->bfd_mach = def->bfd_mach;
env->check_pow = def->check_pow;
+#if defined(TARGET_PPC64)
+ if (def->sps)
+ env->sps = *def->sps;
+ else if (env->mmu_model & POWERPC_MMU_64) {
+ /* Use default sets of page sizes */
+ static const struct ppc_segment_page_sizes defsps = {
+ .sps = {
+ { .page_shift = 12, /* 4K */
+ .slb_enc = 0,
+ .enc = { { .page_shift = 12, .pte_enc = 0 } }
+ },
+ { .page_shift = 24, /* 16M */
+ .slb_enc = 0x100,
+ .enc = { { .page_shift = 24, .pte_enc = 0 } }
+ },
+ },
+ };
+ env->sps = defsps;
+ }
+#endif /* defined(TARGET_PPC64) */
+
if (kvm_enabled()) {
if (kvmppc_fixup_cpu(env) != 0) {
fprintf(stderr, "Unable to virtualize selected CPU with KVM\n");
--
1.6.0.2
^ permalink raw reply related [flat|nested] 89+ messages in thread
* [Qemu-devel] [PATCH 27/72] pseries: Correctly create ibm, segment-page-sizes property
2012-06-23 23:06 [Qemu-devel] [PULL 00/72] ppc patch queue 2012-06-24 Alexander Graf
` (25 preceding siblings ...)
2012-06-23 23:06 ` [Qemu-devel] [PATCH 26/72] ppc64: Rudimentary Support for extra page sizes on server CPUs Alexander Graf
@ 2012-06-23 23:06 ` Alexander Graf
2012-06-23 23:06 ` [Qemu-devel] [PATCH 28/72] spapr_vscsi: Error handling fixes Alexander Graf
` (45 subsequent siblings)
72 siblings, 0 replies; 89+ messages in thread
From: Alexander Graf @ 2012-06-23 23:06 UTC (permalink / raw)
To: qemu-devel qemu-devel
Cc: Blue Swirl, qemu-ppc Mailing List, Nishanth Aravamudan,
Aurelien Jarno, David Gibson
From: Benjamin Herrenschmidt <benh@kernel.crashing.org>
The core tcg/kvm code for ppc64 now has at least the outline
capability to support pagesizes beyond the standard 4k and 16MB. The
CPUState is initialized with information advertising the available
pagesizes and their correct encodings, and under the right KVM setup
this will be populated with page sizes beyond the standard.
Obviously guests can't use the extra page sizes unless they know
they're present. For the pseries machine, at least, there is a
defined method for conveying exactly this information, the
"ibm-segment-page-sizes" property in the guest device tree.
This patch generates this property using the supported page size
information that's already in the CPUState.
Signed-off-by: Nishanth Aravamudan <nacc@us.ibm.com>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Alexander Graf <agraf@suse.de>
---
hw/spapr.c | 43 +++++++++++++++++++++++++++++++++++++++++++
1 files changed, 43 insertions(+), 0 deletions(-)
diff --git a/hw/spapr.c b/hw/spapr.c
index d0bddbc..1b01d64 100644
--- a/hw/spapr.c
+++ b/hw/spapr.c
@@ -146,6 +146,40 @@ static int spapr_set_associativity(void *fdt, sPAPREnvironment *spapr)
return ret;
}
+
+static size_t create_page_sizes_prop(CPUPPCState *env, uint32_t *prop,
+ size_t maxsize)
+{
+ size_t maxcells = maxsize / sizeof(uint32_t);
+ int i, j, count;
+ uint32_t *p = prop;
+
+ for (i = 0; i < PPC_PAGE_SIZES_MAX_SZ; i++) {
+ struct ppc_one_seg_page_size *sps = &env->sps.sps[i];
+
+ if (!sps->page_shift) {
+ break;
+ }
+ for (count = 0; count < PPC_PAGE_SIZES_MAX_SZ; count++) {
+ if (sps->enc[count].page_shift == 0) {
+ break;
+ }
+ }
+ if ((p - prop) >= (maxcells - 3 - count * 2)) {
+ break;
+ }
+ *(p++) = cpu_to_be32(sps->page_shift);
+ *(p++) = cpu_to_be32(sps->slb_enc);
+ *(p++) = cpu_to_be32(count);
+ for (j = 0; j < count; j++) {
+ *(p++) = cpu_to_be32(sps->enc[j].page_shift);
+ *(p++) = cpu_to_be32(sps->enc[j].pte_enc);
+ }
+ }
+
+ return (p - prop) * sizeof(uint32_t);
+}
+
static void *spapr_create_fdt_skel(const char *cpu_model,
target_phys_addr_t rma_size,
target_phys_addr_t initrd_base,
@@ -298,6 +332,8 @@ static void *spapr_create_fdt_skel(const char *cpu_model,
0xffffffff, 0xffffffff};
uint32_t tbfreq = kvm_enabled() ? kvmppc_get_tbfreq() : TIMEBASE_FREQ;
uint32_t cpufreq = kvm_enabled() ? kvmppc_get_clockfreq() : 1000000000;
+ uint32_t page_sizes_prop[64];
+ size_t page_sizes_prop_size;
if ((index % smt) != 0) {
continue;
@@ -362,6 +398,13 @@ static void *spapr_create_fdt_skel(const char *cpu_model,
_FDT((fdt_property_cell(fdt, "ibm,dfp", 1)));
}
+ page_sizes_prop_size = create_page_sizes_prop(env, page_sizes_prop,
+ sizeof(page_sizes_prop));
+ if (page_sizes_prop_size) {
+ _FDT((fdt_property(fdt, "ibm,segment-page-sizes",
+ page_sizes_prop, page_sizes_prop_size)));
+ }
+
_FDT((fdt_end_node(fdt)));
}
--
1.6.0.2
^ permalink raw reply related [flat|nested] 89+ messages in thread
* [Qemu-devel] [PATCH 28/72] spapr_vscsi: Error handling fixes
2012-06-23 23:06 [Qemu-devel] [PULL 00/72] ppc patch queue 2012-06-24 Alexander Graf
` (26 preceding siblings ...)
2012-06-23 23:06 ` [Qemu-devel] [PATCH 27/72] pseries: Correctly create ibm, segment-page-sizes property Alexander Graf
@ 2012-06-23 23:06 ` Alexander Graf
2012-06-23 23:06 ` [Qemu-devel] [PATCH 29/72] spapr: Add "memop" hypercall Alexander Graf
` (44 subsequent siblings)
72 siblings, 0 replies; 89+ messages in thread
From: Alexander Graf @ 2012-06-23 23:06 UTC (permalink / raw)
To: qemu-devel qemu-devel; +Cc: Blue Swirl, qemu-ppc Mailing List, Aurelien Jarno
From: Benjamin Herrenschmidt <benh@kernel.crashing.org>
We were incorrectly g_free'ing an object that isn't allocated
in one error path and failed to release it completely in another
This fixes qemu crashes with some cases of IO errors.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Alexander Graf <agraf@suse.de>
---
hw/spapr_vscsi.c | 4 +++-
1 files changed, 3 insertions(+), 1 deletions(-)
diff --git a/hw/spapr_vscsi.c b/hw/spapr_vscsi.c
index 037867a..2f09616 100644
--- a/hw/spapr_vscsi.c
+++ b/hw/spapr_vscsi.c
@@ -800,6 +800,7 @@ static void vscsi_got_payload(VSCSIState *s, vscsi_crq *crq)
if (crq->s.IU_length > sizeof(union viosrp_iu)) {
fprintf(stderr, "VSCSI: SRP IU too long (%d bytes) !\n",
crq->s.IU_length);
+ vscsi_put_req(req);
return;
}
@@ -807,7 +808,8 @@ static void vscsi_got_payload(VSCSIState *s, vscsi_crq *crq)
if (spapr_tce_dma_read(&s->vdev, crq->s.IU_data_ptr, &req->iu,
crq->s.IU_length)) {
fprintf(stderr, "vscsi_got_payload: DMA read failure !\n");
- g_free(req);
+ vscsi_put_req(req);
+ return;
}
memcpy(&req->crq, crq, sizeof(vscsi_crq));
--
1.6.0.2
^ permalink raw reply related [flat|nested] 89+ messages in thread
* [Qemu-devel] [PATCH 29/72] spapr: Add "memop" hypercall
2012-06-23 23:06 [Qemu-devel] [PULL 00/72] ppc patch queue 2012-06-24 Alexander Graf
` (27 preceding siblings ...)
2012-06-23 23:06 ` [Qemu-devel] [PATCH 28/72] spapr_vscsi: Error handling fixes Alexander Graf
@ 2012-06-23 23:06 ` Alexander Graf
2012-06-23 23:06 ` [Qemu-devel] [PATCH 30/72] raw-posix: Fix build without is_allocated support Alexander Graf
` (43 subsequent siblings)
72 siblings, 0 replies; 89+ messages in thread
From: Alexander Graf @ 2012-06-23 23:06 UTC (permalink / raw)
To: qemu-devel qemu-devel; +Cc: Blue Swirl, qemu-ppc Mailing List, Aurelien Jarno
From: Benjamin Herrenschmidt <benh@kernel.crashing.org>
This adds a qemu-specific hypervisor call to the pseries machine
which allows to do what amounts to memmove, memcpy and xor over
regions of physical memory such as the framebuffer.
This is the simplest way to get usable framebuffer speed from
SLOF since the framebuffer isn't mapped in the VRMA and so would
otherwise require an hcall per 8 bytes access.
The performance is still not great but usable, and can be improved
with a more complex implementation of the hcall itself if needed.
This also adds some documentation for the qemu-specific hypercalls
that we add to PAPR along with a new qemu,hypertas-functions property
that mirrors ibm,hypertas-functions and provides some discoverability
for the new calls.
Note: I chose note to advertise H_RTAS to the guest via that mechanism.
This is done on purpose, the guest uses the normal RTAS interfaces
provided by qemu (including SLOF) which internally calls H_RTAS.
We might in the future implement part (or even all) of RTAS inside the
guest like IBM's firmware does and replace H_RTAS with some finer grained
set of private hypercalls.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Alexander Graf <agraf@suse.de>
---
docs/specs/ppc-spapr-hcalls.txt | 78 +++++++++++++++++++++++++++++++++++++++
hw/spapr.c | 3 +
hw/spapr.h | 3 +-
hw/spapr_hcall.c | 68 ++++++++++++++++++++++++++++++++++
4 files changed, 151 insertions(+), 1 deletions(-)
create mode 100644 docs/specs/ppc-spapr-hcalls.txt
diff --git a/docs/specs/ppc-spapr-hcalls.txt b/docs/specs/ppc-spapr-hcalls.txt
new file mode 100644
index 0000000..52ba8d4
--- /dev/null
+++ b/docs/specs/ppc-spapr-hcalls.txt
@@ -0,0 +1,78 @@
+When used with the "pseries" machine type, QEMU-system-ppc64 implements
+a set of hypervisor calls using a subset of the server "PAPR" specification
+(IBM internal at this point), which is also what IBM's proprietary hypervisor
+adheres too.
+
+The subset is selected based on the requirements of Linux as a guest.
+
+In addition to those calls, we have added our own private hypervisor
+calls which are mostly used as a private interface between the firmware
+running in the guest and QEMU.
+
+All those hypercalls start at hcall number 0xf000 which correspond
+to a implementation specific range in PAPR.
+
+- H_RTAS (0xf000)
+
+RTAS is a set of runtime services generally provided by the firmware
+inside the guest to the operating system. It predates the existence
+of hypervisors (it was originally an extension to Open Firmware) and
+is still used by PAPR to provide various services that aren't performance
+sensitive.
+
+We currently implement the RTAS services in QEMU itself. The actual RTAS
+"firmware" blob in the guest is a small stub of a few instructions which
+calls our private H_RTAS hypervisor call to pass the RTAS calls to QEMU.
+
+Arguments:
+
+ r3 : H_RTAS (0xf000)
+ r4 : Guest physical address of RTAS parameter block
+
+Returns:
+
+ H_SUCCESS : Successully called the RTAS function (RTAS result
+ will have been stored in the parameter block)
+ H_PARAMETER : Unknown token
+
+- H_LOGICAL_MEMOP (0xf001)
+
+When the guest runs in "real mode" (in powerpc lingua this means
+with MMU disabled, ie guest effective == guest physical), it only
+has access to a subset of memory and no IOs.
+
+PAPR provides a set of hypervisor calls to perform cachable or
+non-cachable accesses to any guest physical addresses that the
+guest can use in order to access IO devices while in real mode.
+
+This is typically used by the firmware running in the guest.
+
+However, doing a hypercall for each access is extremely inefficient
+(even more so when running KVM) when accessing the frame buffer. In
+that case, things like scrolling become unusably slow.
+
+This hypercall allows the guest to request a "memory op" to be applied
+to memory. The supported memory ops at this point are to copy a range
+of memory (supports overlap of source and destination) and XOR which
+is used by our SLOF firmware to invert the screen.
+
+Arguments:
+
+ r3: H_LOGICAL_MEMOP (0xf001)
+ r4: Guest physical address of destination
+ r5: Guest physical address of source
+ r6: Individual element size
+ 0 = 1 byte
+ 1 = 2 bytes
+ 2 = 4 bytes
+ 3 = 8 bytes
+ r7: Number of elements
+ r8: Operation
+ 0 = copy
+ 1 = xor
+
+Returns:
+
+ H_SUCCESS : Success
+ H_PARAMETER : Invalid argument
+
diff --git a/hw/spapr.c b/hw/spapr.c
index 1b01d64..09a23ff 100644
--- a/hw/spapr.c
+++ b/hw/spapr.c
@@ -197,6 +197,7 @@ static void *spapr_create_fdt_skel(const char *cpu_model,
uint32_t pft_size_prop[] = {0, cpu_to_be32(hash_shift)};
char hypertas_prop[] = "hcall-pft\0hcall-term\0hcall-dabr\0hcall-interrupt"
"\0hcall-tce\0hcall-vio\0hcall-splpar\0hcall-bulk";
+ char qemu_hypertas_prop[] = "hcall-memop1";
uint32_t interrupt_server_ranges_prop[] = {0, cpu_to_be32(smp_cpus)};
int i;
char *modelname;
@@ -417,6 +418,8 @@ static void *spapr_create_fdt_skel(const char *cpu_model,
_FDT((fdt_property(fdt, "ibm,hypertas-functions", hypertas_prop,
sizeof(hypertas_prop))));
+ _FDT((fdt_property(fdt, "qemu,hypertas-functions", qemu_hypertas_prop,
+ sizeof(qemu_hypertas_prop))));
_FDT((fdt_property(fdt, "ibm,associativity-reference-points",
refpoints, sizeof(refpoints))));
diff --git a/hw/spapr.h b/hw/spapr.h
index 654a7a8..c75172e 100644
--- a/hw/spapr.h
+++ b/hw/spapr.h
@@ -264,7 +264,8 @@ typedef struct sPAPREnvironment {
*/
#define KVMPPC_HCALL_BASE 0xf000
#define KVMPPC_H_RTAS (KVMPPC_HCALL_BASE + 0x0)
-#define KVMPPC_HCALL_MAX KVMPPC_H_RTAS
+#define KVMPPC_H_LOGICAL_MEMOP (KVMPPC_HCALL_BASE + 0x1)
+#define KVMPPC_HCALL_MAX KVMPPC_H_LOGICAL_MEMOP
extern sPAPREnvironment *spapr;
diff --git a/hw/spapr_hcall.c b/hw/spapr_hcall.c
index 94bb504..a5990a9 100644
--- a/hw/spapr_hcall.c
+++ b/hw/spapr_hcall.c
@@ -608,6 +608,73 @@ static target_ulong h_logical_store(CPUPPCState *env, sPAPREnvironment *spapr,
return H_PARAMETER;
}
+static target_ulong h_logical_memop(CPUPPCState *env, sPAPREnvironment *spapr,
+ target_ulong opcode, target_ulong *args)
+{
+ target_ulong dst = args[0]; /* Destination address */
+ target_ulong src = args[1]; /* Source address */
+ target_ulong esize = args[2]; /* Element size (0=1,1=2,2=4,3=8) */
+ target_ulong count = args[3]; /* Element count */
+ target_ulong op = args[4]; /* 0 = copy, 1 = invert */
+ uint64_t tmp;
+ unsigned int mask = (1 << esize) - 1;
+ int step = 1 << esize;
+
+ if (count > 0x80000000) {
+ return H_PARAMETER;
+ }
+
+ if ((dst & mask) || (src & mask) || (op > 1)) {
+ return H_PARAMETER;
+ }
+
+ if (dst >= src && dst < (src + (count << esize))) {
+ dst = dst + ((count - 1) << esize);
+ src = src + ((count - 1) << esize);
+ step = -step;
+ }
+
+ while (count--) {
+ switch (esize) {
+ case 0:
+ tmp = ldub_phys(src);
+ break;
+ case 1:
+ tmp = lduw_phys(src);
+ break;
+ case 2:
+ tmp = ldl_phys(src);
+ break;
+ case 3:
+ tmp = ldq_phys(src);
+ break;
+ default:
+ return H_PARAMETER;
+ }
+ if (op == 1) {
+ tmp = ~tmp;
+ }
+ switch (esize) {
+ case 0:
+ stb_phys(dst, tmp);
+ break;
+ case 1:
+ stw_phys(dst, tmp);
+ break;
+ case 2:
+ stl_phys(dst, tmp);
+ break;
+ case 3:
+ stq_phys(dst, tmp);
+ break;
+ }
+ dst = dst + step;
+ src = src + step;
+ }
+
+ return H_SUCCESS;
+}
+
static target_ulong h_logical_icbi(CPUPPCState *env, sPAPREnvironment *spapr,
target_ulong opcode, target_ulong *args)
{
@@ -700,6 +767,7 @@ static void hypercall_register_types(void)
spapr_register_hypercall(H_LOGICAL_CACHE_STORE, h_logical_store);
spapr_register_hypercall(H_LOGICAL_ICBI, h_logical_icbi);
spapr_register_hypercall(H_LOGICAL_DCBF, h_logical_dcbf);
+ spapr_register_hypercall(KVMPPC_H_LOGICAL_MEMOP, h_logical_memop);
/* qemu/KVM-PPC specific hcalls */
spapr_register_hypercall(KVMPPC_H_RTAS, h_rtas);
--
1.6.0.2
^ permalink raw reply related [flat|nested] 89+ messages in thread
* [Qemu-devel] [PATCH 30/72] raw-posix: Fix build without is_allocated support
2012-06-23 23:06 [Qemu-devel] [PULL 00/72] ppc patch queue 2012-06-24 Alexander Graf
` (28 preceding siblings ...)
2012-06-23 23:06 ` [Qemu-devel] [PATCH 29/72] spapr: Add "memop" hypercall Alexander Graf
@ 2012-06-23 23:06 ` Alexander Graf
2012-06-23 23:06 ` [Qemu-devel] [PATCH 31/72] dt: allow add_subnode to create root subnodes Alexander Graf
` (42 subsequent siblings)
72 siblings, 0 replies; 89+ messages in thread
From: Alexander Graf @ 2012-06-23 23:06 UTC (permalink / raw)
To: qemu-devel qemu-devel
Cc: Blue Swirl, Kevin Wolf, qemu-ppc Mailing List, Aurelien Jarno
From: Kevin Wolf <kwolf@redhat.com>
Move the declaration of s into the #ifdef sections that actually make
use of it.
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Alexander Graf <agraf@suse.de>
---
block/raw-posix.c | 9 ++++++++-
1 files changed, 8 insertions(+), 1 deletions(-)
diff --git a/block/raw-posix.c b/block/raw-posix.c
index bf7700a..0dce089 100644
--- a/block/raw-posix.c
+++ b/block/raw-posix.c
@@ -606,7 +606,6 @@ static int coroutine_fn raw_co_is_allocated(BlockDriverState *bs,
int64_t sector_num,
int nb_sectors, int *pnum)
{
- BDRVRawState *s = bs->opaque;
off_t start, data, hole;
int ret;
@@ -616,11 +615,15 @@ static int coroutine_fn raw_co_is_allocated(BlockDriverState *bs,
}
start = sector_num * BDRV_SECTOR_SIZE;
+
#ifdef CONFIG_FIEMAP
+
+ BDRVRawState *s = bs->opaque;
struct {
struct fiemap fm;
struct fiemap_extent fe;
} f;
+
f.fm.fm_start = start;
f.fm.fm_length = (int64_t)nb_sectors * BDRV_SECTOR_SIZE;
f.fm.fm_flags = 0;
@@ -643,7 +646,11 @@ static int coroutine_fn raw_co_is_allocated(BlockDriverState *bs,
data = f.fe.fe_logical;
hole = f.fe.fe_logical + f.fe.fe_length;
}
+
#elif defined SEEK_HOLE && defined SEEK_DATA
+
+ BDRVRawState *s = bs->opaque;
+
hole = lseek(s->fd, start, SEEK_HOLE);
if (hole == -1) {
/* -ENXIO indicates that sector_num was past the end of the file.
--
1.6.0.2
^ permalink raw reply related [flat|nested] 89+ messages in thread
* [Qemu-devel] [PATCH 31/72] dt: allow add_subnode to create root subnodes
2012-06-23 23:06 [Qemu-devel] [PULL 00/72] ppc patch queue 2012-06-24 Alexander Graf
` (29 preceding siblings ...)
2012-06-23 23:06 ` [Qemu-devel] [PATCH 30/72] raw-posix: Fix build without is_allocated support Alexander Graf
@ 2012-06-23 23:06 ` Alexander Graf
2012-06-23 23:06 ` [Qemu-devel] [PATCH 32/72] dt: add helpers for multi-cell adds Alexander Graf
` (41 subsequent siblings)
72 siblings, 0 replies; 89+ messages in thread
From: Alexander Graf @ 2012-06-23 23:06 UTC (permalink / raw)
To: qemu-devel qemu-devel; +Cc: Blue Swirl, qemu-ppc Mailing List, Aurelien Jarno
Our subnode creation helper can't handle creation of root subnodes,
like "/memory". Fix this by allowing the parent node to be an empty
string, indicating the root node.
Signed-off-by: Alexander Graf <agraf@suse.de>
Reviewed-by: Peter Crosthwaite <peter.crosthwaite@petalogix.com>
---
device_tree.c | 7 ++++++-
1 files changed, 6 insertions(+), 1 deletions(-)
diff --git a/device_tree.c b/device_tree.c
index 86a694c..94a239e 100644
--- a/device_tree.c
+++ b/device_tree.c
@@ -151,6 +151,7 @@ int qemu_devtree_add_subnode(void *fdt, const char *name)
char *dupname = g_strdup(name);
char *basename = strrchr(dupname, '/');
int retval;
+ int parent = 0;
if (!basename) {
g_free(dupname);
@@ -160,7 +161,11 @@ int qemu_devtree_add_subnode(void *fdt, const char *name)
basename[0] = '\0';
basename++;
- retval = fdt_add_subnode(fdt, findnode_nofail(fdt, dupname), basename);
+ if (dupname[0]) {
+ parent = findnode_nofail(fdt, dupname);
+ }
+
+ retval = fdt_add_subnode(fdt, parent, basename);
if (retval < 0) {
fprintf(stderr, "FDT: Failed to create subnode %s: %s\n", name,
fdt_strerror(retval));
--
1.6.0.2
^ permalink raw reply related [flat|nested] 89+ messages in thread
* [Qemu-devel] [PATCH 32/72] dt: add helpers for multi-cell adds
2012-06-23 23:06 [Qemu-devel] [PULL 00/72] ppc patch queue 2012-06-24 Alexander Graf
` (30 preceding siblings ...)
2012-06-23 23:06 ` [Qemu-devel] [PATCH 31/72] dt: allow add_subnode to create root subnodes Alexander Graf
@ 2012-06-23 23:06 ` Alexander Graf
2012-06-23 23:06 ` [Qemu-devel] [PATCH 33/72] dt: add helper for phandle references Alexander Graf
` (40 subsequent siblings)
72 siblings, 0 replies; 89+ messages in thread
From: Alexander Graf @ 2012-06-23 23:06 UTC (permalink / raw)
To: qemu-devel qemu-devel; +Cc: Blue Swirl, qemu-ppc Mailing List, Aurelien Jarno
We have device tree helpers that allow us to create single cell (u32)
wide properties. However, when creating properties that contain an array of
cells, we need to jump through hoops, manually passing in an array with
converted endianness.
To ease the pain of this, create a generic macro helper that allows us
to pass the cells as arguments.
Signed-off-by: Alexander Graf <agraf@suse.de>
Reviewed-by: Peter Crosthwaite <peter.crosthwaite@petalogix.com>
---
device_tree.h | 12 ++++++++++++
1 files changed, 12 insertions(+), 0 deletions(-)
diff --git a/device_tree.h b/device_tree.h
index 4378685..1e671e2 100644
--- a/device_tree.h
+++ b/device_tree.h
@@ -25,4 +25,16 @@ int qemu_devtree_setprop_string(void *fdt, const char *node_path,
int qemu_devtree_nop_node(void *fdt, const char *node_path);
int qemu_devtree_add_subnode(void *fdt, const char *name);
+#define qemu_devtree_setprop_cells(fdt, node_path, property, ...) \
+ do { \
+ uint32_t qdt_tmp[] = { __VA_ARGS__ }; \
+ int i; \
+ \
+ for (i = 0; i < ARRAY_SIZE(qdt_tmp); i++) { \
+ qdt_tmp[i] = cpu_to_be32(qdt_tmp[i]); \
+ } \
+ qemu_devtree_setprop(fdt, node_path, property, qdt_tmp, \
+ sizeof(qdt_tmp)); \
+ } while (0)
+
#endif /* __DEVICE_TREE_H__ */
--
1.6.0.2
^ permalink raw reply related [flat|nested] 89+ messages in thread
* [Qemu-devel] [PATCH 33/72] dt: add helper for phandle references
2012-06-23 23:06 [Qemu-devel] [PULL 00/72] ppc patch queue 2012-06-24 Alexander Graf
` (31 preceding siblings ...)
2012-06-23 23:06 ` [Qemu-devel] [PATCH 32/72] dt: add helpers for multi-cell adds Alexander Graf
@ 2012-06-23 23:06 ` Alexander Graf
2012-06-23 23:06 ` [Qemu-devel] [PATCH 34/72] dt: temporarily disable subtree creation failure check Alexander Graf
` (39 subsequent siblings)
72 siblings, 0 replies; 89+ messages in thread
From: Alexander Graf @ 2012-06-23 23:06 UTC (permalink / raw)
To: qemu-devel qemu-devel; +Cc: Blue Swirl, qemu-ppc Mailing List, Aurelien Jarno
Phandles are the fancy device tree name for "pointer to another node".
To create a phandle property, we most likely want to reference to the
node we're pointing to by its path. So create a helper that allows
us to do so.
Signed-off-by: Alexander Graf <agraf@suse.de>
Reviewed-by: Peter Crosthwaite <peter.crosthwaite@petalogix.com>
---
device_tree.c | 8 ++++++++
device_tree.h | 3 +++
2 files changed, 11 insertions(+), 0 deletions(-)
diff --git a/device_tree.c b/device_tree.c
index 94a239e..2905f9a 100644
--- a/device_tree.c
+++ b/device_tree.c
@@ -132,6 +132,14 @@ int qemu_devtree_setprop_string(void *fdt, const char *node_path,
return r;
}
+int qemu_devtree_setprop_phandle(void *fdt, const char *node_path,
+ const char *property,
+ const char *target_node_path)
+{
+ uint32_t phandle = fdt_get_phandle(fdt, findnode_nofail(fdt, target_node_path));
+ return qemu_devtree_setprop_cell(fdt, node_path, property, phandle);
+}
+
int qemu_devtree_nop_node(void *fdt, const char *node_path)
{
int r;
diff --git a/device_tree.h b/device_tree.h
index 1e671e2..754bd2b 100644
--- a/device_tree.h
+++ b/device_tree.h
@@ -22,6 +22,9 @@ int qemu_devtree_setprop_cell(void *fdt, const char *node_path,
const char *property, uint32_t val);
int qemu_devtree_setprop_string(void *fdt, const char *node_path,
const char *property, const char *string);
+int qemu_devtree_setprop_phandle(void *fdt, const char *node_path,
+ const char *property,
+ const char *target_node_path);
int qemu_devtree_nop_node(void *fdt, const char *node_path);
int qemu_devtree_add_subnode(void *fdt, const char *name);
--
1.6.0.2
^ permalink raw reply related [flat|nested] 89+ messages in thread
* [Qemu-devel] [PATCH 34/72] dt: temporarily disable subtree creation failure check
2012-06-23 23:06 [Qemu-devel] [PULL 00/72] ppc patch queue 2012-06-24 Alexander Graf
` (32 preceding siblings ...)
2012-06-23 23:06 ` [Qemu-devel] [PATCH 33/72] dt: add helper for phandle references Alexander Graf
@ 2012-06-23 23:06 ` Alexander Graf
2012-06-23 23:06 ` [Qemu-devel] [PATCH 35/72] dt: add helper for phandle enumeration Alexander Graf
` (38 subsequent siblings)
72 siblings, 0 replies; 89+ messages in thread
From: Alexander Graf @ 2012-06-23 23:06 UTC (permalink / raw)
To: qemu-devel qemu-devel; +Cc: Blue Swirl, qemu-ppc Mailing List, Aurelien Jarno
Usually we want to know when creating a subtree fails. However, while
introducing this patch set we have to modify the device tree and some
times have the code to create a subtree in both the binary tree and
the dynamically created tree.
So ignore failures about this for now and enable them once we got rid
of the binary device tree.
Signed-off-by: Alexander Graf <agraf@suse.de>
---
device_tree.c | 2 ++
1 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/device_tree.c b/device_tree.c
index 2905f9a..967c97a 100644
--- a/device_tree.c
+++ b/device_tree.c
@@ -174,11 +174,13 @@ int qemu_devtree_add_subnode(void *fdt, const char *name)
}
retval = fdt_add_subnode(fdt, parent, basename);
+#if 0
if (retval < 0) {
fprintf(stderr, "FDT: Failed to create subnode %s: %s\n", name,
fdt_strerror(retval));
exit(1);
}
+#endif
g_free(dupname);
return retval;
--
1.6.0.2
^ permalink raw reply related [flat|nested] 89+ messages in thread
* [Qemu-devel] [PATCH 35/72] dt: add helper for phandle enumeration
2012-06-23 23:06 [Qemu-devel] [PULL 00/72] ppc patch queue 2012-06-24 Alexander Graf
` (33 preceding siblings ...)
2012-06-23 23:06 ` [Qemu-devel] [PATCH 34/72] dt: temporarily disable subtree creation failure check Alexander Graf
@ 2012-06-23 23:06 ` Alexander Graf
2012-06-23 23:07 ` [Qemu-devel] [PATCH 36/72] dt: add helper for empty dt creation Alexander Graf
` (37 subsequent siblings)
72 siblings, 0 replies; 89+ messages in thread
From: Alexander Graf @ 2012-06-23 23:06 UTC (permalink / raw)
To: qemu-devel qemu-devel; +Cc: Blue Swirl, qemu-ppc Mailing List, Aurelien Jarno
This patch adds a helper to search for a node's phandle by its path. This
is especially useful when the phandle is part of an array, not just a single
cell in which case qemu_devtree_setprop_phandle would be the easy choice.
Signed-off-by: Alexander Graf <agraf@suse.de>
Reviewed-by: Peter Crosthwaite <peter.crosthwaite@petalogix.com>
---
device_tree.c | 16 +++++++++++++++-
device_tree.h | 1 +
2 files changed, 16 insertions(+), 1 deletions(-)
diff --git a/device_tree.c b/device_tree.c
index 967c97a..2f127b7 100644
--- a/device_tree.c
+++ b/device_tree.c
@@ -132,11 +132,25 @@ int qemu_devtree_setprop_string(void *fdt, const char *node_path,
return r;
}
+uint32_t qemu_devtree_get_phandle(void *fdt, const char *path)
+{
+ uint32_t r;
+
+ r = fdt_get_phandle(fdt, findnode_nofail(fdt, path));
+ if (r <= 0) {
+ fprintf(stderr, "%s: Couldn't get phandle for %s: %s\n", __func__,
+ path, fdt_strerror(r));
+ exit(1);
+ }
+
+ return r;
+}
+
int qemu_devtree_setprop_phandle(void *fdt, const char *node_path,
const char *property,
const char *target_node_path)
{
- uint32_t phandle = fdt_get_phandle(fdt, findnode_nofail(fdt, target_node_path));
+ uint32_t phandle = qemu_devtree_get_phandle(fdt, target_node_path);
return qemu_devtree_setprop_cell(fdt, node_path, property, phandle);
}
diff --git a/device_tree.h b/device_tree.h
index 754bd2b..36fc9db 100644
--- a/device_tree.h
+++ b/device_tree.h
@@ -25,6 +25,7 @@ int qemu_devtree_setprop_string(void *fdt, const char *node_path,
int qemu_devtree_setprop_phandle(void *fdt, const char *node_path,
const char *property,
const char *target_node_path);
+uint32_t qemu_devtree_get_phandle(void *fdt, const char *path);
int qemu_devtree_nop_node(void *fdt, const char *node_path);
int qemu_devtree_add_subnode(void *fdt, const char *name);
--
1.6.0.2
^ permalink raw reply related [flat|nested] 89+ messages in thread
* [Qemu-devel] [PATCH 36/72] dt: add helper for empty dt creation
2012-06-23 23:06 [Qemu-devel] [PULL 00/72] ppc patch queue 2012-06-24 Alexander Graf
` (34 preceding siblings ...)
2012-06-23 23:06 ` [Qemu-devel] [PATCH 35/72] dt: add helper for phandle enumeration Alexander Graf
@ 2012-06-23 23:07 ` Alexander Graf
2012-06-23 23:07 ` [Qemu-devel] [PATCH 37/72] dt: add helper for phandle allocation Alexander Graf
` (36 subsequent siblings)
72 siblings, 0 replies; 89+ messages in thread
From: Alexander Graf @ 2012-06-23 23:07 UTC (permalink / raw)
To: qemu-devel qemu-devel; +Cc: Blue Swirl, qemu-ppc Mailing List, Aurelien Jarno
We want to get rid of the concept of loading an external device tree and instead
generate our own. However, to do this we need to also create a device tree
template programatically.
This patch adds a helper to create an empty device tree in memory.
Signed-off-by: Alexander Graf <agraf@suse.de>
Reviewed-by: Peter Crosthwaite <peter.crosthwaite@petalogix.com>
---
device_tree.c | 37 +++++++++++++++++++++++++++++++++++++
device_tree.h | 1 +
2 files changed, 38 insertions(+), 0 deletions(-)
diff --git a/device_tree.c b/device_tree.c
index 2f127b7..d037896 100644
--- a/device_tree.c
+++ b/device_tree.c
@@ -25,6 +25,43 @@
#include <libfdt.h>
+#define FDT_MAX_SIZE 0x10000
+
+void *create_device_tree(int *sizep)
+{
+ void *fdt;
+ int ret;
+
+ *sizep = FDT_MAX_SIZE;
+ fdt = g_malloc0(FDT_MAX_SIZE);
+ ret = fdt_create(fdt, FDT_MAX_SIZE);
+ if (ret < 0) {
+ goto fail;
+ }
+ ret = fdt_begin_node(fdt, "");
+ if (ret < 0) {
+ goto fail;
+ }
+ ret = fdt_end_node(fdt);
+ if (ret < 0) {
+ goto fail;
+ }
+ ret = fdt_finish(fdt);
+ if (ret < 0) {
+ goto fail;
+ }
+ ret = fdt_open_into(fdt, fdt, *sizep);
+ if (ret) {
+ fprintf(stderr, "Unable to copy device tree in memory\n");
+ exit(1);
+ }
+
+ return fdt;
+fail:
+ fprintf(stderr, "%s Couldn't create dt: %s\n", __func__, fdt_strerror(ret));
+ exit(1);
+}
+
void *load_device_tree(const char *filename_path, int *sizep)
{
int dt_size;
diff --git a/device_tree.h b/device_tree.h
index 36fc9db..5f76f40 100644
--- a/device_tree.h
+++ b/device_tree.h
@@ -14,6 +14,7 @@
#ifndef __DEVICE_TREE_H__
#define __DEVICE_TREE_H__
+void *create_device_tree(int *sizep);
void *load_device_tree(const char *filename_path, int *sizep);
int qemu_devtree_setprop(void *fdt, const char *node_path,
--
1.6.0.2
^ permalink raw reply related [flat|nested] 89+ messages in thread
* [Qemu-devel] [PATCH 37/72] dt: add helper for phandle allocation
2012-06-23 23:06 [Qemu-devel] [PULL 00/72] ppc patch queue 2012-06-24 Alexander Graf
` (35 preceding siblings ...)
2012-06-23 23:07 ` [Qemu-devel] [PATCH 36/72] dt: add helper for empty dt creation Alexander Graf
@ 2012-06-23 23:07 ` Alexander Graf
2012-06-23 23:07 ` [Qemu-devel] [PATCH 38/72] dt: add helper for 64bit cell adds Alexander Graf
` (35 subsequent siblings)
72 siblings, 0 replies; 89+ messages in thread
From: Alexander Graf @ 2012-06-23 23:07 UTC (permalink / raw)
To: qemu-devel qemu-devel; +Cc: Blue Swirl, qemu-ppc Mailing List, Aurelien Jarno
Phandle references work by having 2 pieces:
- a "phandle" 1-cell property in the device tree node
- a reference to the same value in a property we want to point
to the other node
To generate the 1-cell property, we need an allocation mechanism that
gives us a unique number space. This patch adds an allocator for these
properties.
Signed-off-by: Alexander Graf <agraf@suse.de>
---
device_tree.c | 7 +++++++
device_tree.h | 1 +
2 files changed, 8 insertions(+), 0 deletions(-)
diff --git a/device_tree.c b/device_tree.c
index d037896..7541274 100644
--- a/device_tree.c
+++ b/device_tree.c
@@ -191,6 +191,13 @@ int qemu_devtree_setprop_phandle(void *fdt, const char *node_path,
return qemu_devtree_setprop_cell(fdt, node_path, property, phandle);
}
+uint32_t qemu_devtree_alloc_phandle(void *fdt)
+{
+ static int phandle = 0x8000;
+
+ return phandle++;
+}
+
int qemu_devtree_nop_node(void *fdt, const char *node_path)
{
int r;
diff --git a/device_tree.h b/device_tree.h
index 5f76f40..97af345 100644
--- a/device_tree.h
+++ b/device_tree.h
@@ -27,6 +27,7 @@ int qemu_devtree_setprop_phandle(void *fdt, const char *node_path,
const char *property,
const char *target_node_path);
uint32_t qemu_devtree_get_phandle(void *fdt, const char *path);
+uint32_t qemu_devtree_alloc_phandle(void *fdt);
int qemu_devtree_nop_node(void *fdt, const char *node_path);
int qemu_devtree_add_subnode(void *fdt, const char *name);
--
1.6.0.2
^ permalink raw reply related [flat|nested] 89+ messages in thread
* [Qemu-devel] [PATCH 38/72] dt: add helper for 64bit cell adds
2012-06-23 23:06 [Qemu-devel] [PULL 00/72] ppc patch queue 2012-06-24 Alexander Graf
` (36 preceding siblings ...)
2012-06-23 23:07 ` [Qemu-devel] [PATCH 37/72] dt: add helper for phandle allocation Alexander Graf
@ 2012-06-23 23:07 ` Alexander Graf
2012-06-23 23:07 ` [Qemu-devel] [PATCH 39/72] PPC: e500: require libfdt Alexander Graf
` (34 subsequent siblings)
72 siblings, 0 replies; 89+ messages in thread
From: Alexander Graf @ 2012-06-23 23:07 UTC (permalink / raw)
To: qemu-devel qemu-devel; +Cc: Blue Swirl, qemu-ppc Mailing List, Aurelien Jarno
Some times in the device tree, we find an array of 2 u32 cells that
really are a single u64 value. This patch adds a helper to make the
creation of these easy.
Signed-off-by: Alexander Graf <agraf@suse.de>
Reviewed-by: Peter Crosthwaite <peter.crosthwaite@petalogix.com>
---
device_tree.c | 7 +++++++
device_tree.h | 2 ++
2 files changed, 9 insertions(+), 0 deletions(-)
diff --git a/device_tree.c b/device_tree.c
index 7541274..c8d68c2 100644
--- a/device_tree.c
+++ b/device_tree.c
@@ -154,6 +154,13 @@ int qemu_devtree_setprop_cell(void *fdt, const char *node_path,
return r;
}
+int qemu_devtree_setprop_u64(void *fdt, const char *node_path,
+ const char *property, uint64_t val)
+{
+ val = cpu_to_be64(val);
+ return qemu_devtree_setprop(fdt, node_path, property, &val, sizeof(val));
+}
+
int qemu_devtree_setprop_string(void *fdt, const char *node_path,
const char *property, const char *string)
{
diff --git a/device_tree.h b/device_tree.h
index 97af345..4898d95 100644
--- a/device_tree.h
+++ b/device_tree.h
@@ -21,6 +21,8 @@ int qemu_devtree_setprop(void *fdt, const char *node_path,
const char *property, void *val_array, int size);
int qemu_devtree_setprop_cell(void *fdt, const char *node_path,
const char *property, uint32_t val);
+int qemu_devtree_setprop_u64(void *fdt, const char *node_path,
+ const char *property, uint64_t val);
int qemu_devtree_setprop_string(void *fdt, const char *node_path,
const char *property, const char *string);
int qemu_devtree_setprop_phandle(void *fdt, const char *node_path,
--
1.6.0.2
^ permalink raw reply related [flat|nested] 89+ messages in thread
* [Qemu-devel] [PATCH 39/72] PPC: e500: require libfdt
2012-06-23 23:06 [Qemu-devel] [PULL 00/72] ppc patch queue 2012-06-24 Alexander Graf
` (37 preceding siblings ...)
2012-06-23 23:07 ` [Qemu-devel] [PATCH 38/72] dt: add helper for 64bit cell adds Alexander Graf
@ 2012-06-23 23:07 ` Alexander Graf
2012-06-23 23:07 ` [Qemu-devel] [PATCH 40/72] PPC: e500: dt: create memory node dynamically Alexander Graf
` (33 subsequent siblings)
72 siblings, 0 replies; 89+ messages in thread
From: Alexander Graf @ 2012-06-23 23:07 UTC (permalink / raw)
To: qemu-devel qemu-devel; +Cc: Blue Swirl, qemu-ppc Mailing List, Aurelien Jarno
Now that we're moving all of the device tree generation from an external
pre-execution generated blob to runtime generation using libfdt, we absolutely
must have libfdt around.
This requirement was there before already, as the only way to not require libfdt
with e500 was to not use -kernel, which was the only way to boot the mpc8544ds
machine. This patch only manifests said requirement in the build system.
Signed-off-by: Alexander Graf <agraf@suse.de>
---
hw/ppc/Makefile.objs | 2 +-
hw/ppce500_mpc8544ds.c | 5 -----
2 files changed, 1 insertions(+), 6 deletions(-)
diff --git a/hw/ppc/Makefile.objs b/hw/ppc/Makefile.objs
index 44a1e8c..d18dbaf 100644
--- a/hw/ppc/Makefile.objs
+++ b/hw/ppc/Makefile.objs
@@ -15,7 +15,7 @@ obj-$(CONFIG_PSERIES) += spapr_pci.o pci-hotplug.o
obj-y += ppc4xx_devs.o ppc4xx_pci.o ppc405_uc.o ppc405_boards.o
obj-y += ppc440_bamboo.o
# PowerPC E500 boards
-obj-y += ppce500_mpc8544ds.o mpc8544_guts.o ppce500_spin.o
+obj-$(CONFIG_FDT) += ppce500_mpc8544ds.o mpc8544_guts.o ppce500_spin.o
# PowerPC 440 Xilinx ML507 reference board.
obj-y += virtex_ml507.o
# PowerPC OpenPIC
diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c
index b1a0b8c..506ddf3 100644
--- a/hw/ppce500_mpc8544ds.c
+++ b/hw/ppce500_mpc8544ds.c
@@ -68,7 +68,6 @@ static int mpc8544_load_device_tree(CPUPPCState *env,
const char *kernel_cmdline)
{
int ret = -1;
-#ifdef CONFIG_FDT
uint32_t mem_reg_property[] = {0, cpu_to_be32(ramsize)};
char *filename;
int fdt_size;
@@ -173,7 +172,6 @@ static int mpc8544_load_device_tree(CPUPPCState *env,
ret = fdt_size;
out:
-#endif
return ret;
}
@@ -391,9 +389,6 @@ static void mpc8544ds_init(ram_addr_t ram_size,
struct boot_info *boot_info;
int dt_size;
-#ifndef CONFIG_FDT
- cpu_abort(env, "Compiled without FDT support - can't load kernel\n");
-#endif
dt_base = (loadaddr + kernel_size + DTC_LOAD_PAD) & ~DTC_PAD_MASK;
dt_size = mpc8544_load_device_tree(env, dt_base, ram_size, initrd_base,
initrd_size, kernel_cmdline);
--
1.6.0.2
^ permalink raw reply related [flat|nested] 89+ messages in thread
* [Qemu-devel] [PATCH 40/72] PPC: e500: dt: create memory node dynamically
2012-06-23 23:06 [Qemu-devel] [PULL 00/72] ppc patch queue 2012-06-24 Alexander Graf
` (38 preceding siblings ...)
2012-06-23 23:07 ` [Qemu-devel] [PATCH 39/72] PPC: e500: require libfdt Alexander Graf
@ 2012-06-23 23:07 ` Alexander Graf
2012-06-23 23:07 ` [Qemu-devel] [PATCH 41/72] PPC: e500: dt: create /cpus " Alexander Graf
` (32 subsequent siblings)
72 siblings, 0 replies; 89+ messages in thread
From: Alexander Graf @ 2012-06-23 23:07 UTC (permalink / raw)
To: qemu-devel qemu-devel; +Cc: Blue Swirl, qemu-ppc Mailing List, Aurelien Jarno
Signed-off-by: Alexander Graf <agraf@suse.de>
---
hw/ppce500_mpc8544ds.c | 8 ++++----
pc-bios/mpc8544ds.dtb | Bin 2028 -> 1972 bytes
pc-bios/mpc8544ds.dts | 5 -----
3 files changed, 4 insertions(+), 9 deletions(-)
diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c
index 506ddf3..3ec9013 100644
--- a/hw/ppce500_mpc8544ds.c
+++ b/hw/ppce500_mpc8544ds.c
@@ -88,10 +88,10 @@ static int mpc8544_load_device_tree(CPUPPCState *env,
}
/* Manipulate device tree in memory. */
- ret = qemu_devtree_setprop(fdt, "/memory", "reg", mem_reg_property,
- sizeof(mem_reg_property));
- if (ret < 0)
- fprintf(stderr, "couldn't set /memory/reg\n");
+ qemu_devtree_add_subnode(fdt, "/memory");
+ qemu_devtree_setprop_string(fdt, "/memory", "device_type", "memory");
+ qemu_devtree_setprop(fdt, "/memory", "reg", mem_reg_property,
+ sizeof(mem_reg_property));
if (initrd_size) {
ret = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-start",
diff --git a/pc-bios/mpc8544ds.dtb b/pc-bios/mpc8544ds.dtb
index c6d302153c7407d5d0127be29b0c35f80e47f8fb..db9fb701f246e058bca4c2fe9546c9f2493a57b1 100644
GIT binary patch
delta 104
zcmaFEzlC4m0`I@K3=HgB7#J8V7#P@QOcW4jOxUQQ!8o~tF`dzO@&`t7#*oPzOxY|U
z3=FQ5xtSd&?_lx=2{E?=$qCHM8ACQ(uxw`psb#GO3gxhE;!Mm-Pc3FBN==`v&VCdC
D8)_c+
delta 159
zcmdnO|At@S0`I@K3=HgV7#J8V7#P?tOcW4joUu_ugHb0pH8;Pg5-85VzzoFfK<tPn
z#sL)b1!9KDE{w&Jfgsic5Fr2}z`DRHCSPF8X7rtG!!#L4USMhmk`c_y8GSdgY-eN)
coV<gz8Yp7Iwuv(}ouMc(FFmz*@_V+U0H2g3&j0`b
diff --git a/pc-bios/mpc8544ds.dts b/pc-bios/mpc8544ds.dts
index 7eb3160..f46e9ed 100644
--- a/pc-bios/mpc8544ds.dts
+++ b/pc-bios/mpc8544ds.dts
@@ -27,11 +27,6 @@
#size-cells = <0>;
};
- memory {
- device_type = "memory";
- reg = <0x0 0x0>; // Filled by U-Boot
- };
-
soc8544@e0000000 {
#address-cells = <1>;
#size-cells = <1>;
--
1.6.0.2
^ permalink raw reply related [flat|nested] 89+ messages in thread
* [Qemu-devel] [PATCH 41/72] PPC: e500: dt: create /cpus node dynamically
2012-06-23 23:06 [Qemu-devel] [PULL 00/72] ppc patch queue 2012-06-24 Alexander Graf
` (39 preceding siblings ...)
2012-06-23 23:07 ` [Qemu-devel] [PATCH 40/72] PPC: e500: dt: create memory node dynamically Alexander Graf
@ 2012-06-23 23:07 ` Alexander Graf
2012-06-23 23:07 ` [Qemu-devel] [PATCH 42/72] PPC: e500: dt: create /hypervisor " Alexander Graf
` (31 subsequent siblings)
72 siblings, 0 replies; 89+ messages in thread
From: Alexander Graf @ 2012-06-23 23:07 UTC (permalink / raw)
To: qemu-devel qemu-devel; +Cc: Blue Swirl, qemu-ppc Mailing List, Aurelien Jarno
Signed-off-by: Alexander Graf <agraf@suse.de>
---
hw/ppce500_mpc8544ds.c | 5 +++++
pc-bios/mpc8544ds.dtb | Bin 1972 -> 1924 bytes
pc-bios/mpc8544ds.dts | 5 -----
3 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c
index 3ec9013..c046206 100644
--- a/hw/ppce500_mpc8544ds.c
+++ b/hw/ppce500_mpc8544ds.c
@@ -125,6 +125,11 @@ static int mpc8544_load_device_tree(CPUPPCState *env,
hypercall, sizeof(hypercall));
}
+ /* Create CPU nodes */
+ qemu_devtree_add_subnode(fdt, "/cpus");
+ qemu_devtree_setprop_cell(fdt, "/cpus", "#address-cells", 1);
+ qemu_devtree_setprop_cell(fdt, "/cpus", "#size-cells", 0);
+
/* We need to generate the cpu nodes in reverse order, so Linux can pick
the first node as boot node and be happy */
for (i = smp_cpus - 1; i >= 0; i--) {
diff --git a/pc-bios/mpc8544ds.dtb b/pc-bios/mpc8544ds.dtb
index db9fb701f246e058bca4c2fe9546c9f2493a57b1..a85b93c1e6e66c318c3f0c1910abae78f4b78f5e 100644
GIT binary patch
delta 34
qcmdnO-@-3&f%o5A1_t&P1_lNT1_ri_i2~w`1`{=YYz|;dVFLiG$q8rx
delta 43
zcmZqS-@-3&f%o5A1_t&m3=9kw3=C{DCJKl%CQQ`$!IE51T0Gf+QF*gCV=fy28+Z(E
diff --git a/pc-bios/mpc8544ds.dts b/pc-bios/mpc8544ds.dts
index f46e9ed..1fcb865 100644
--- a/pc-bios/mpc8544ds.dts
+++ b/pc-bios/mpc8544ds.dts
@@ -22,11 +22,6 @@
pci0 = &pci0;
};
- cpus {
- #address-cells = <1>;
- #size-cells = <0>;
- };
-
soc8544@e0000000 {
#address-cells = <1>;
#size-cells = <1>;
--
1.6.0.2
^ permalink raw reply related [flat|nested] 89+ messages in thread
* [Qemu-devel] [PATCH 42/72] PPC: e500: dt: create /hypervisor node dynamically
2012-06-23 23:06 [Qemu-devel] [PULL 00/72] ppc patch queue 2012-06-24 Alexander Graf
` (40 preceding siblings ...)
2012-06-23 23:07 ` [Qemu-devel] [PATCH 41/72] PPC: e500: dt: create /cpus " Alexander Graf
@ 2012-06-23 23:07 ` Alexander Graf
2012-06-23 23:07 ` [Qemu-devel] [PATCH 43/72] PPC: e500: dt: create / " Alexander Graf
` (30 subsequent siblings)
72 siblings, 0 replies; 89+ messages in thread
From: Alexander Graf @ 2012-06-23 23:07 UTC (permalink / raw)
To: qemu-devel qemu-devel; +Cc: Blue Swirl, qemu-ppc Mailing List, Aurelien Jarno
Signed-off-by: Alexander Graf <agraf@suse.de>
---
hw/ppce500_mpc8544ds.c | 1 +
pc-bios/mpc8544ds.dtb | Bin 1924 -> 1904 bytes
pc-bios/mpc8544ds.dts | 3 ---
3 files changed, 1 insertions(+), 3 deletions(-)
diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c
index c046206..54e7ec7 100644
--- a/hw/ppce500_mpc8544ds.c
+++ b/hw/ppce500_mpc8544ds.c
@@ -118,6 +118,7 @@ static int mpc8544_load_device_tree(CPUPPCState *env,
tb_freq = kvmppc_get_tbfreq();
/* indicate KVM hypercall interface */
+ qemu_devtree_add_subnode(fdt, "/hypervisor");
qemu_devtree_setprop_string(fdt, "/hypervisor", "compatible",
"linux,kvm");
kvmppc_get_hypercall(env, hypercall, sizeof(hypercall));
diff --git a/pc-bios/mpc8544ds.dtb b/pc-bios/mpc8544ds.dtb
index a85b93c1e6e66c318c3f0c1910abae78f4b78f5e..8194aa2e6f292fb34023feb596aa19448b8af0d0 100644
GIT binary patch
delta 35
rcmZqS|G+13f%o5A1_t&51_lNT1_ri}i2~w`G8;A2*)}J$DKY{8vYZHv
delta 47
zcmeys*TOGwf%o5A1_t&P1_lNT1_ri_i2~w`1{*ch*|-@qDhpDJ$})@di#EHlX)yu-
DKg10i
diff --git a/pc-bios/mpc8544ds.dts b/pc-bios/mpc8544ds.dts
index 1fcb865..2ca7c54 100644
--- a/pc-bios/mpc8544ds.dts
+++ b/pc-bios/mpc8544ds.dts
@@ -103,7 +103,4 @@
chosen {
linux,stdout-path = "/soc8544@e0000000/serial@4500";
};
-
- hypervisor {
- };
};
--
1.6.0.2
^ permalink raw reply related [flat|nested] 89+ messages in thread
* [Qemu-devel] [PATCH 43/72] PPC: e500: dt: create / node dynamically
2012-06-23 23:06 [Qemu-devel] [PULL 00/72] ppc patch queue 2012-06-24 Alexander Graf
` (41 preceding siblings ...)
2012-06-23 23:07 ` [Qemu-devel] [PATCH 42/72] PPC: e500: dt: create /hypervisor " Alexander Graf
@ 2012-06-23 23:07 ` Alexander Graf
2012-06-23 23:07 ` [Qemu-devel] [PATCH 44/72] PPC: e500: dt: create /chosen " Alexander Graf
` (29 subsequent siblings)
72 siblings, 0 replies; 89+ messages in thread
From: Alexander Graf @ 2012-06-23 23:07 UTC (permalink / raw)
To: qemu-devel qemu-devel; +Cc: Blue Swirl, qemu-ppc Mailing List, Aurelien Jarno
Signed-off-by: Alexander Graf <agraf@suse.de>
---
hw/ppce500_mpc8544ds.c | 8 ++++++++
pc-bios/mpc8544ds.dtb | Bin 1904 -> 1810 bytes
pc-bios/mpc8544ds.dts | 5 -----
3 files changed, 8 insertions(+), 5 deletions(-)
diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c
index 54e7ec7..28c7c8c 100644
--- a/hw/ppce500_mpc8544ds.c
+++ b/hw/ppce500_mpc8544ds.c
@@ -76,6 +76,8 @@ static int mpc8544_load_device_tree(CPUPPCState *env,
uint32_t clock_freq = 400000000;
uint32_t tb_freq = 400000000;
int i;
+ char compatible[] = "MPC8544DS\0MPC85xxDS";
+ char model[] = "MPC8544DS";
filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE);
if (!filename) {
@@ -88,6 +90,12 @@ static int mpc8544_load_device_tree(CPUPPCState *env,
}
/* Manipulate device tree in memory. */
+ qemu_devtree_setprop_string(fdt, "/", "model", model);
+ qemu_devtree_setprop(fdt, "/", "compatible", compatible,
+ sizeof(compatible));
+ qemu_devtree_setprop_cell(fdt, "/", "#address-cells", 1);
+ qemu_devtree_setprop_cell(fdt, "/", "#size-cells", 1);
+
qemu_devtree_add_subnode(fdt, "/memory");
qemu_devtree_setprop_string(fdt, "/memory", "device_type", "memory");
qemu_devtree_setprop(fdt, "/memory", "reg", mem_reg_property,
diff --git a/pc-bios/mpc8544ds.dtb b/pc-bios/mpc8544ds.dtb
index 8194aa2e6f292fb34023feb596aa19448b8af0d0..25d92f681dec184530af63e2d2cea61cb4cccd04 100644
GIT binary patch
literal 1810
zcmb7EyKdA#6rCkONyI||2}FgEk^-Svaira7i!HW+bSd}&;&>;!qn)*l$3_V>REUy}
ze?a^K5)yPYv~)`kJs<>}GvjgWMJaNn>$&fHJacD0U-|Q0h?VO?h`taPe`CE1z6M?g
zgE}{1|LEk_w^M1INUO+5Lv;y!o5Hq9<9@H(9m>$rwvoAt^sw6tLk672uAUvc+l;-6
zob~N2R<>pzWo;R80ZV7GopV_{%aCs{226a^Hy88}`7l}kC9DIZW|@}3VQGKM+AqVt
z$DlbsZg*I36}&&kr!x8;53PyV+JEl-2bG`t3OICe*6QmH60@`0>)Ai`wtXS)Bgk&Q
zuQjz<4nOfc1K$I4Z+y%P$V_tkRbi@j*vA}HG1SkA=|PoR_d7SHOvS@4rv;Tj#6Wrt
z_V{>?B(J}P?Elf8gFRiIu#4f$4B|<iZKat^0(7u0o4*DzY@6%4@8E0B%ZEz0dpFkU
zVWfkyP+ApA8aLy%Fmdtj433Q6nq~G11mm)BQ{*r?oJ8h^h&iNBVAi)i{vY!i+W}%o
z%;OX`dW8Y<ypOvOHgv{*5#k5^o_NNrGY5YY;w6@v`2Y31Ech%&_?e5CR$gVZC$Z=w
zCSMopE2uSjdzIhv`F>S?%jf%5F)iOhzj_b-U0^QHgZJeYm^HlZ7i7|3Fl`}tj{&6j
z6;r+gCU{R@z2J<@C64LR&*2-aUgzvG!t0xmeSgMt*6AbLnVE~{5ZA$OM&e0oWJ1-(
z;N9&kpZ%8B?=E|g*W7y(3b*bE%t|OWqR}Xq#ssm{+K3IKp2|ud$tNn7kBXB_ia4ER
zQK1gC6nT`4@%ra-Ebv?gN4b1l$|OD!tPrSVB#%X`(|Fo&sics3US_x$wHRbkE|a2R
zh|{FVQ>|q#HcrDFFs+jEcq^Mk$p{#D-6oL<a#O^4qrxo8f>~syZIi`mVGCEr6r;2(
I0HBzNe~HoS>i_@%
literal 1904
zcmb7FyKWOf6de=fknm8DC@2t$lm;QM;z)Lsg2EP$E)o(c=+I_&Vy`mZ-R!K9Lq$3Y
z3VwhepyUgXsOaDeFdsle1r2b{JT|+IQshd<bKm#Q%-!+V>wkX=v78Gbc7$l}VZ8_3
z1l9mh>kjn58EQGr64q7nyH6kP^n1NW&#Zy^TR{6%Z@AgadeD9uU@hkI^172-p-Mt6
zHAG{(i?y?<vxr3ovTJEm%OVNYpx5tq>3QngJKuM^?t23<4>t2CF*$dT)}#@au(TG-
zSyR>PdA<9+3=z)|%2$E5PA0jM!T!{2%jmB`zYB;tf9$E#{|c}-$B$F`oX?Gly)}34
z?FY_Ic^Md5Kcn?|+o|5#?)S}3y$*N(7*6I|eXb)DW&3A8C%}DxXXAa|f@hFDFV~Yh
zVeiA9{2gDgrzbA7s(0a@@+2DcI4#HoVo#*^fbWm@Nb>SW@P3cx9?Yb2TCERfrX7uo
zyp!cJ4N$?DO#BMiVN+e@{S2Ew2WI=?WOH^SmF<Trn3jo3%0y~A<M6OG*<<@atIi}h
zpFl90mUfD)-S)}O>=1D;q;CN8n;K`wyy~q!H=M#+t!{ugs4CxKO{VX6A%4^DiFeHU
zbKsW{Z?IIv{a5p{U^6|!&RF;~;+)Rh#G;L7>GNWJ2eBfrckvCIujk?$Heb*AG;9m?
zs&nz*0%Lg}C%|ohIh>B|82X1_>bk%#9Y~)X$gcyHH~1fbA**C8`#4(qGx&hj%bZ<$
zczGSXuTOu@5p9H-nYnlkb`7vI5{)x0Q;Nn1?`~`L{I|4vcUgm2nPjn4BFZLtSSI^Q
zij6Ri3#oMwNu{*d(8(+5c>6YWg<ZD<=Bg`V`7(**i}E;^q6pIw{sRg*5_mL&gF+rn
zWf~m|<_eNDmNOBlEIO>2lC+dXG0pLLRBVukg-pwuBFfUT$dr<W*f@2wEvh7)&N}%x
pOk?!Vk8T|5pwMMh)G|!MJeY*~u&FYAnzn^aqsus(mS~_Hi~kmQ^d$fQ
diff --git a/pc-bios/mpc8544ds.dts b/pc-bios/mpc8544ds.dts
index 2ca7c54..1eac8ef 100644
--- a/pc-bios/mpc8544ds.dts
+++ b/pc-bios/mpc8544ds.dts
@@ -11,11 +11,6 @@
/dts-v1/;
/ {
- model = "MPC8544DS";
- compatible = "MPC8544DS", "MPC85xxDS";
- #address-cells = <1>;
- #size-cells = <1>;
-
aliases {
serial0 = &serial0;
serial1 = &serial1;
--
1.6.0.2
^ permalink raw reply related [flat|nested] 89+ messages in thread
* [Qemu-devel] [PATCH 44/72] PPC: e500: dt: create /chosen node dynamically
2012-06-23 23:06 [Qemu-devel] [PULL 00/72] ppc patch queue 2012-06-24 Alexander Graf
` (42 preceding siblings ...)
2012-06-23 23:07 ` [Qemu-devel] [PATCH 43/72] PPC: e500: dt: create / " Alexander Graf
@ 2012-06-23 23:07 ` Alexander Graf
2012-06-23 23:07 ` [Qemu-devel] [PATCH 45/72] PPC: e500: dt: create /soc8544 " Alexander Graf
` (28 subsequent siblings)
72 siblings, 0 replies; 89+ messages in thread
From: Alexander Graf @ 2012-06-23 23:07 UTC (permalink / raw)
To: qemu-devel qemu-devel; +Cc: Blue Swirl, qemu-ppc Mailing List, Aurelien Jarno
Signed-off-by: Alexander Graf <agraf@suse.de>
---
hw/ppce500_mpc8544ds.c | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c
index 28c7c8c..a078e24 100644
--- a/hw/ppce500_mpc8544ds.c
+++ b/hw/ppce500_mpc8544ds.c
@@ -101,6 +101,7 @@ static int mpc8544_load_device_tree(CPUPPCState *env,
qemu_devtree_setprop(fdt, "/memory", "reg", mem_reg_property,
sizeof(mem_reg_property));
+ qemu_devtree_add_subnode(fdt, "/chosen");
if (initrd_size) {
ret = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-start",
initrd_base);
--
1.6.0.2
^ permalink raw reply related [flat|nested] 89+ messages in thread
* [Qemu-devel] [PATCH 45/72] PPC: e500: dt: create /soc8544 node dynamically
2012-06-23 23:06 [Qemu-devel] [PULL 00/72] ppc patch queue 2012-06-24 Alexander Graf
` (43 preceding siblings ...)
2012-06-23 23:07 ` [Qemu-devel] [PATCH 44/72] PPC: e500: dt: create /chosen " Alexander Graf
@ 2012-06-23 23:07 ` Alexander Graf
2012-06-23 23:07 ` [Qemu-devel] [PATCH 46/72] PPC: e500: dt: create serial nodes dynamically Alexander Graf
` (27 subsequent siblings)
72 siblings, 0 replies; 89+ messages in thread
From: Alexander Graf @ 2012-06-23 23:07 UTC (permalink / raw)
To: qemu-devel qemu-devel; +Cc: Blue Swirl, qemu-ppc Mailing List, Aurelien Jarno
Signed-off-by: Alexander Graf <agraf@suse.de>
---
hw/ppce500_mpc8544ds.c | 17 +++++++++++++++++
pc-bios/mpc8544ds.dts | 9 ---------
2 files changed, 17 insertions(+), 9 deletions(-)
diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c
index a078e24..c7c16c1 100644
--- a/hw/ppce500_mpc8544ds.c
+++ b/hw/ppce500_mpc8544ds.c
@@ -43,6 +43,8 @@
#define RAM_SIZES_ALIGN (64UL << 20)
#define MPC8544_CCSRBAR_BASE 0xE0000000
+#define MPC8544_CCSRBAR_REGSIZE 0x00001000
+#define MPC8544_CCSRBAR_SIZE 0x00100000
#define MPC8544_MPIC_REGS_BASE (MPC8544_CCSRBAR_BASE + 0x40000)
#define MPC8544_SERIAL0_REGS_BASE (MPC8544_CCSRBAR_BASE + 0x4500)
#define MPC8544_SERIAL1_REGS_BASE (MPC8544_CCSRBAR_BASE + 0x4600)
@@ -78,6 +80,7 @@ static int mpc8544_load_device_tree(CPUPPCState *env,
int i;
char compatible[] = "MPC8544DS\0MPC85xxDS";
char model[] = "MPC8544DS";
+ char soc[128];
filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE);
if (!filename) {
@@ -179,6 +182,20 @@ static int mpc8544_load_device_tree(CPUPPCState *env,
}
}
+ /* XXX These should go into their respective devices' code */
+ snprintf(soc, sizeof(soc), "/soc8544@%x", MPC8544_CCSRBAR_BASE);
+ qemu_devtree_add_subnode(fdt, soc);
+ qemu_devtree_setprop_string(fdt, soc, "device_type", "soc");
+ qemu_devtree_setprop_string(fdt, soc, "compatible", "simple-bus");
+ qemu_devtree_setprop_cell(fdt, soc, "#address-cells", 1);
+ qemu_devtree_setprop_cell(fdt, soc, "#size-cells", 1);
+ qemu_devtree_setprop_cells(fdt, soc, "ranges", 0x0, MPC8544_CCSRBAR_BASE,
+ MPC8544_CCSRBAR_SIZE);
+ qemu_devtree_setprop_cells(fdt, soc, "reg", MPC8544_CCSRBAR_BASE,
+ MPC8544_CCSRBAR_REGSIZE);
+ /* XXX should contain a reasonable value */
+ qemu_devtree_setprop_cell(fdt, soc, "bus-frequency", 0);
+
ret = rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr);
if (ret < 0) {
goto out;
diff --git a/pc-bios/mpc8544ds.dts b/pc-bios/mpc8544ds.dts
index 1eac8ef..01b53ba 100644
--- a/pc-bios/mpc8544ds.dts
+++ b/pc-bios/mpc8544ds.dts
@@ -18,15 +18,6 @@
};
soc8544@e0000000 {
- #address-cells = <1>;
- #size-cells = <1>;
- device_type = "soc";
- compatible = "simple-bus";
-
- ranges = <0x0 0xe0000000 0x100000>;
- reg = <0xe0000000 0x1000>; // CCSRBAR 1M
- bus-frequency = <0>; // Filled out by uboot.
-
serial0: serial@4500 {
cell-index = <0>;
device_type = "serial";
--
1.6.0.2
^ permalink raw reply related [flat|nested] 89+ messages in thread
* [Qemu-devel] [PATCH 46/72] PPC: e500: dt: create serial nodes dynamically
2012-06-23 23:06 [Qemu-devel] [PULL 00/72] ppc patch queue 2012-06-24 Alexander Graf
` (44 preceding siblings ...)
2012-06-23 23:07 ` [Qemu-devel] [PATCH 45/72] PPC: e500: dt: create /soc8544 " Alexander Graf
@ 2012-06-23 23:07 ` Alexander Graf
2012-06-23 23:07 ` [Qemu-devel] [PATCH 47/72] PPC: e500: dt: create mpic node dynamically Alexander Graf
` (26 subsequent siblings)
72 siblings, 0 replies; 89+ messages in thread
From: Alexander Graf @ 2012-06-23 23:07 UTC (permalink / raw)
To: qemu-devel qemu-devel; +Cc: Blue Swirl, qemu-ppc Mailing List, Aurelien Jarno
Signed-off-by: Alexander Graf <agraf@suse.de>
---
hw/ppce500_mpc8544ds.c | 35 +++++++++++++++++++++++++++++++++++
pc-bios/mpc8544ds.dts | 26 --------------------------
2 files changed, 35 insertions(+), 26 deletions(-)
diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c
index c7c16c1..c68e994 100644
--- a/hw/ppce500_mpc8544ds.c
+++ b/hw/ppce500_mpc8544ds.c
@@ -81,6 +81,8 @@ static int mpc8544_load_device_tree(CPUPPCState *env,
char compatible[] = "MPC8544DS\0MPC85xxDS";
char model[] = "MPC8544DS";
char soc[128];
+ char ser0[128];
+ char ser1[128];
filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE);
if (!filename) {
@@ -182,6 +184,7 @@ static int mpc8544_load_device_tree(CPUPPCState *env,
}
}
+ qemu_devtree_add_subnode(fdt, "/aliases");
/* XXX These should go into their respective devices' code */
snprintf(soc, sizeof(soc), "/soc8544@%x", MPC8544_CCSRBAR_BASE);
qemu_devtree_add_subnode(fdt, soc);
@@ -196,6 +199,38 @@ static int mpc8544_load_device_tree(CPUPPCState *env,
/* XXX should contain a reasonable value */
qemu_devtree_setprop_cell(fdt, soc, "bus-frequency", 0);
+ /*
+ * We have to generate ser1 first, because Linux takes the first
+ * device it finds in the dt as serial output device. And we generate
+ * devices in reverse order to the dt.
+ */
+ snprintf(ser1, sizeof(ser1), "%s/serial@%x", soc,
+ MPC8544_SERIAL1_REGS_BASE - MPC8544_CCSRBAR_BASE);
+ qemu_devtree_add_subnode(fdt, ser1);
+ qemu_devtree_setprop_string(fdt, ser1, "device_type", "serial");
+ qemu_devtree_setprop_string(fdt, ser1, "compatible", "ns16550");
+ qemu_devtree_setprop_cells(fdt, ser1, "reg", MPC8544_SERIAL1_REGS_BASE -
+ MPC8544_CCSRBAR_BASE, 0x100);
+ qemu_devtree_setprop_cell(fdt, ser1, "cell-index", 1);
+ qemu_devtree_setprop_cell(fdt, ser1, "clock-frequency", 0);
+ qemu_devtree_setprop_cells(fdt, ser1, "interrupts", 42, 2);
+ qemu_devtree_setprop_phandle(fdt, ser1, "interrupt-parent", mpic);
+ qemu_devtree_setprop_string(fdt, "/aliases", "serial1", ser1);
+
+ snprintf(ser0, sizeof(ser0), "%s/serial@%x", soc,
+ MPC8544_SERIAL0_REGS_BASE - MPC8544_CCSRBAR_BASE);
+ qemu_devtree_add_subnode(fdt, ser0);
+ qemu_devtree_setprop_string(fdt, ser0, "device_type", "serial");
+ qemu_devtree_setprop_string(fdt, ser0, "compatible", "ns16550");
+ qemu_devtree_setprop_cells(fdt, ser0, "reg", MPC8544_SERIAL0_REGS_BASE -
+ MPC8544_CCSRBAR_BASE, 0x100);
+ qemu_devtree_setprop_cell(fdt, ser0, "cell-index", 0);
+ qemu_devtree_setprop_cell(fdt, ser0, "clock-frequency", 0);
+ qemu_devtree_setprop_cells(fdt, ser0, "interrupts", 42, 2);
+ qemu_devtree_setprop_phandle(fdt, ser0, "interrupt-parent", mpic);
+ qemu_devtree_setprop_string(fdt, "/aliases", "serial0", ser0);
+ qemu_devtree_setprop_string(fdt, "/chosen", "linux,stdout-path", ser0);
+
ret = rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr);
if (ret < 0) {
goto out;
diff --git a/pc-bios/mpc8544ds.dts b/pc-bios/mpc8544ds.dts
index 01b53ba..e536ab1 100644
--- a/pc-bios/mpc8544ds.dts
+++ b/pc-bios/mpc8544ds.dts
@@ -12,32 +12,10 @@
/dts-v1/;
/ {
aliases {
- serial0 = &serial0;
- serial1 = &serial1;
pci0 = &pci0;
};
soc8544@e0000000 {
- serial0: serial@4500 {
- cell-index = <0>;
- device_type = "serial";
- compatible = "ns16550";
- reg = <0x4500 0x100>;
- clock-frequency = <0>;
- interrupts = <42 2>;
- interrupt-parent = <&mpic>;
- };
-
- serial1: serial@4600 {
- cell-index = <1>;
- device_type = "serial";
- compatible = "ns16550";
- reg = <0x4600 0x100>;
- clock-frequency = <0>;
- interrupts = <42 2>;
- interrupt-parent = <&mpic>;
- };
-
mpic: pic@40000 {
interrupt-controller;
#address-cells = <0>;
@@ -85,8 +63,4 @@
#address-cells = <3>;
reg = <0xe0008000 0x1000>;
};
-
- chosen {
- linux,stdout-path = "/soc8544@e0000000/serial@4500";
- };
};
--
1.6.0.2
^ permalink raw reply related [flat|nested] 89+ messages in thread
* [Qemu-devel] [PATCH 47/72] PPC: e500: dt: create mpic node dynamically
2012-06-23 23:06 [Qemu-devel] [PULL 00/72] ppc patch queue 2012-06-24 Alexander Graf
` (45 preceding siblings ...)
2012-06-23 23:07 ` [Qemu-devel] [PATCH 46/72] PPC: e500: dt: create serial nodes dynamically Alexander Graf
@ 2012-06-23 23:07 ` Alexander Graf
2012-06-23 23:07 ` [Qemu-devel] [PATCH 48/72] PPC: e500: dt: create global-utils " Alexander Graf
` (25 subsequent siblings)
72 siblings, 0 replies; 89+ messages in thread
From: Alexander Graf @ 2012-06-23 23:07 UTC (permalink / raw)
To: qemu-devel qemu-devel; +Cc: Blue Swirl, qemu-ppc Mailing List, Aurelien Jarno
Signed-off-by: Alexander Graf <agraf@suse.de>
---
hw/ppce500_mpc8544ds.c | 16 ++++++++++++++++
1 files changed, 16 insertions(+), 0 deletions(-)
diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c
index c68e994..5c2b6ab 100644
--- a/hw/ppce500_mpc8544ds.c
+++ b/hw/ppce500_mpc8544ds.c
@@ -83,6 +83,8 @@ static int mpc8544_load_device_tree(CPUPPCState *env,
char soc[128];
char ser0[128];
char ser1[128];
+ char mpic[128];
+ uint32_t mpic_ph;
filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE);
if (!filename) {
@@ -199,6 +201,20 @@ static int mpc8544_load_device_tree(CPUPPCState *env,
/* XXX should contain a reasonable value */
qemu_devtree_setprop_cell(fdt, soc, "bus-frequency", 0);
+ snprintf(mpic, sizeof(mpic), "%s/pic@%x", soc,
+ MPC8544_MPIC_REGS_BASE - MPC8544_CCSRBAR_BASE);
+ qemu_devtree_add_subnode(fdt, mpic);
+ qemu_devtree_setprop_string(fdt, mpic, "device_type", "open-pic");
+ qemu_devtree_setprop_string(fdt, mpic, "compatible", "chrp,open-pic");
+ qemu_devtree_setprop_cells(fdt, mpic, "reg", MPC8544_MPIC_REGS_BASE -
+ MPC8544_CCSRBAR_BASE, 0x40000);
+ qemu_devtree_setprop_cell(fdt, mpic, "#address-cells", 0);
+ qemu_devtree_setprop_cell(fdt, mpic, "#interrupt-cells", 2);
+ mpic_ph = qemu_devtree_alloc_phandle(fdt);
+ qemu_devtree_setprop_cell(fdt, mpic, "phandle", mpic_ph);
+ qemu_devtree_setprop_cell(fdt, mpic, "linux,phandle", mpic_ph);
+ qemu_devtree_setprop(fdt, mpic, "interrupt-controller", NULL, 0);
+
/*
* We have to generate ser1 first, because Linux takes the first
* device it finds in the dt as serial output device. And we generate
--
1.6.0.2
^ permalink raw reply related [flat|nested] 89+ messages in thread
* [Qemu-devel] [PATCH 48/72] PPC: e500: dt: create global-utils node dynamically
2012-06-23 23:06 [Qemu-devel] [PULL 00/72] ppc patch queue 2012-06-24 Alexander Graf
` (46 preceding siblings ...)
2012-06-23 23:07 ` [Qemu-devel] [PATCH 47/72] PPC: e500: dt: create mpic node dynamically Alexander Graf
@ 2012-06-23 23:07 ` Alexander Graf
2012-06-23 23:07 ` [Qemu-devel] [PATCH 49/72] PPC: e500: dt: create pci " Alexander Graf
` (24 subsequent siblings)
72 siblings, 0 replies; 89+ messages in thread
From: Alexander Graf @ 2012-06-23 23:07 UTC (permalink / raw)
To: qemu-devel qemu-devel; +Cc: Blue Swirl, qemu-ppc Mailing List, Aurelien Jarno
Signed-off-by: Alexander Graf <agraf@suse.de>
---
hw/ppce500_mpc8544ds.c | 9 +++++++++
pc-bios/mpc8544ds.dts | 6 ------
2 files changed, 9 insertions(+), 6 deletions(-)
diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c
index 5c2b6ab..03938b2 100644
--- a/hw/ppce500_mpc8544ds.c
+++ b/hw/ppce500_mpc8544ds.c
@@ -85,6 +85,7 @@ static int mpc8544_load_device_tree(CPUPPCState *env,
char ser1[128];
char mpic[128];
uint32_t mpic_ph;
+ char gutil[128];
filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE);
if (!filename) {
@@ -247,6 +248,14 @@ static int mpc8544_load_device_tree(CPUPPCState *env,
qemu_devtree_setprop_string(fdt, "/aliases", "serial0", ser0);
qemu_devtree_setprop_string(fdt, "/chosen", "linux,stdout-path", ser0);
+ snprintf(gutil, sizeof(gutil), "%s/global-utilities@%x", soc,
+ MPC8544_UTIL_BASE - MPC8544_CCSRBAR_BASE);
+ qemu_devtree_add_subnode(fdt, gutil);
+ qemu_devtree_setprop_string(fdt, gutil, "compatible", "fsl,mpc8544-guts");
+ qemu_devtree_setprop_cells(fdt, gutil, "reg", MPC8544_UTIL_BASE -
+ MPC8544_CCSRBAR_BASE, 0x1000);
+ qemu_devtree_setprop(fdt, gutil, "fsl,has-rstcr", NULL, 0);
+
ret = rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr);
if (ret < 0) {
goto out;
diff --git a/pc-bios/mpc8544ds.dts b/pc-bios/mpc8544ds.dts
index e536ab1..4c7bd75 100644
--- a/pc-bios/mpc8544ds.dts
+++ b/pc-bios/mpc8544ds.dts
@@ -24,12 +24,6 @@
compatible = "chrp,open-pic";
device_type = "open-pic";
};
-
- global-utilities@e0000 { //global utilities block
- compatible = "fsl,mpc8544-guts";
- reg = <0xe0000 0x1000>;
- fsl,has-rstcr;
- };
};
pci0: pci@e0008000 {
--
1.6.0.2
^ permalink raw reply related [flat|nested] 89+ messages in thread
* [Qemu-devel] [PATCH 49/72] PPC: e500: dt: create pci node dynamically
2012-06-23 23:06 [Qemu-devel] [PULL 00/72] ppc patch queue 2012-06-24 Alexander Graf
` (47 preceding siblings ...)
2012-06-23 23:07 ` [Qemu-devel] [PATCH 48/72] PPC: e500: dt: create global-utils " Alexander Graf
@ 2012-06-23 23:07 ` Alexander Graf
2012-06-23 23:07 ` [Qemu-devel] [PATCH 50/72] PPC: e500: dt: start with empty device tree Alexander Graf
` (23 subsequent siblings)
72 siblings, 0 replies; 89+ messages in thread
From: Alexander Graf @ 2012-06-23 23:07 UTC (permalink / raw)
To: qemu-devel qemu-devel; +Cc: Blue Swirl, qemu-ppc Mailing List, Aurelien Jarno
Signed-off-by: Alexander Graf <agraf@suse.de>
---
hw/ppce500_mpc8544ds.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++
pc-bios/mpc8544ds.dtb | Bin 1810 -> 72 bytes
pc-bios/mpc8544ds.dts | 46 --------------------------------------------
3 files changed, 50 insertions(+), 46 deletions(-)
diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c
index 03938b2..15df515 100644
--- a/hw/ppce500_mpc8544ds.c
+++ b/hw/ppce500_mpc8544ds.c
@@ -62,6 +62,27 @@ struct boot_info
uint32_t entry;
};
+static void pci_map_create(void *fdt, uint32_t *pci_map, uint32_t mpic)
+{
+ int i;
+ const uint32_t tmp[] = {
+ /* IDSEL 0x11 J17 Slot 1 */
+ 0x8800, 0x0, 0x0, 0x1, mpic, 0x2, 0x1,
+ 0x8800, 0x0, 0x0, 0x2, mpic, 0x3, 0x1,
+ 0x8800, 0x0, 0x0, 0x3, mpic, 0x4, 0x1,
+ 0x8800, 0x0, 0x0, 0x4, mpic, 0x1, 0x1,
+
+ /* IDSEL 0x12 J16 Slot 2 */
+ 0x9000, 0x0, 0x0, 0x1, mpic, 0x3, 0x1,
+ 0x9000, 0x0, 0x0, 0x2, mpic, 0x4, 0x1,
+ 0x9000, 0x0, 0x0, 0x3, mpic, 0x2, 0x1,
+ 0x9000, 0x0, 0x0, 0x4, mpic, 0x1, 0x1,
+ };
+ for (i = 0; i < (7 * 8); i++) {
+ pci_map[i] = cpu_to_be32(tmp[i]);
+ }
+}
+
static int mpc8544_load_device_tree(CPUPPCState *env,
target_phys_addr_t addr,
uint32_t ramsize,
@@ -86,6 +107,11 @@ static int mpc8544_load_device_tree(CPUPPCState *env,
char mpic[128];
uint32_t mpic_ph;
char gutil[128];
+ char pci[128];
+ uint32_t pci_map[7 * 8];
+ uint32_t pci_ranges[12] = { 0x2000000, 0x0, 0xc0000000, 0xc0000000, 0x0,
+ 0x20000000, 0x1000000, 0x0, 0x0, 0xe1000000,
+ 0x0, 0x10000 };
filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE);
if (!filename) {
@@ -256,6 +282,30 @@ static int mpc8544_load_device_tree(CPUPPCState *env,
MPC8544_CCSRBAR_BASE, 0x1000);
qemu_devtree_setprop(fdt, gutil, "fsl,has-rstcr", NULL, 0);
+ snprintf(pci, sizeof(pci), "/pci@%x", MPC8544_PCI_REGS_BASE);
+ qemu_devtree_add_subnode(fdt, pci);
+ qemu_devtree_setprop_cell(fdt, pci, "cell-index", 0);
+ qemu_devtree_setprop_string(fdt, pci, "compatible", "fsl,mpc8540-pci");
+ qemu_devtree_setprop_string(fdt, pci, "device_type", "pci");
+ qemu_devtree_setprop_cells(fdt, pci, "interrupt-map-mask", 0xf800, 0x0,
+ 0x0, 0x7);
+ pci_map_create(fdt, pci_map, qemu_devtree_get_phandle(fdt, mpic));
+ qemu_devtree_setprop(fdt, pci, "interrupt-map", pci_map, sizeof(pci_map));
+ qemu_devtree_setprop_phandle(fdt, pci, "interrupt-parent", mpic);
+ qemu_devtree_setprop_cells(fdt, pci, "interrupts", 24, 2);
+ qemu_devtree_setprop_cells(fdt, pci, "bus-range", 0, 255);
+ for (i = 0; i < 12; i++) {
+ pci_ranges[i] = cpu_to_be32(pci_ranges[i]);
+ }
+ qemu_devtree_setprop(fdt, pci, "ranges", pci_ranges, sizeof(pci_ranges));
+ qemu_devtree_setprop_cells(fdt, pci, "reg", MPC8544_PCI_REGS_BASE,
+ 0x1000);
+ qemu_devtree_setprop_cell(fdt, pci, "clock-frequency", 66666666);
+ qemu_devtree_setprop_cell(fdt, pci, "#interrupt-cells", 1);
+ qemu_devtree_setprop_cell(fdt, pci, "#size-cells", 2);
+ qemu_devtree_setprop_cell(fdt, pci, "#address-cells", 3);
+ qemu_devtree_setprop_string(fdt, "/aliases", "pci0", pci);
+
ret = rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr);
if (ret < 0) {
goto out;
diff --git a/pc-bios/mpc8544ds.dtb b/pc-bios/mpc8544ds.dtb
index 25d92f681dec184530af63e2d2cea61cb4cccd04..90ef5c00243b04f4aa3f812b89d5b37c63be09f2 100644
GIT binary patch
literal 72
mcmcb>`|m9S1A_+;TR>?IAT0>Q0zeD{$ZVJxBb31eq&Wct_yhI;
literal 1810
zcmb7EyKdA#6rCkONyI||2}FgEk^-Svaira7i!HW+bSd}&;&>;!qn)*l$3_V>REUy}
ze?a^K5)yPYv~)`kJs<>}GvjgWMJaNn>$&fHJacD0U-|Q0h?VO?h`taPe`CE1z6M?g
zgE}{1|LEk_w^M1INUO+5Lv;y!o5Hq9<9@H(9m>$rwvoAt^sw6tLk672uAUvc+l;-6
zob~N2R<>pzWo;R80ZV7GopV_{%aCs{226a^Hy88}`7l}kC9DIZW|@}3VQGKM+AqVt
z$DlbsZg*I36}&&kr!x8;53PyV+JEl-2bG`t3OICe*6QmH60@`0>)Ai`wtXS)Bgk&Q
zuQjz<4nOfc1K$I4Z+y%P$V_tkRbi@j*vA}HG1SkA=|PoR_d7SHOvS@4rv;Tj#6Wrt
z_V{>?B(J}P?Elf8gFRiIu#4f$4B|<iZKat^0(7u0o4*DzY@6%4@8E0B%ZEz0dpFkU
zVWfkyP+ApA8aLy%Fmdtj433Q6nq~G11mm)BQ{*r?oJ8h^h&iNBVAi)i{vY!i+W}%o
z%;OX`dW8Y<ypOvOHgv{*5#k5^o_NNrGY5YY;w6@v`2Y31Ech%&_?e5CR$gVZC$Z=w
zCSMopE2uSjdzIhv`F>S?%jf%5F)iOhzj_b-U0^QHgZJeYm^HlZ7i7|3Fl`}tj{&6j
z6;r+gCU{R@z2J<@C64LR&*2-aUgzvG!t0xmeSgMt*6AbLnVE~{5ZA$OM&e0oWJ1-(
z;N9&kpZ%8B?=E|g*W7y(3b*bE%t|OWqR}Xq#ssm{+K3IKp2|ud$tNn7kBXB_ia4ER
zQK1gC6nT`4@%ra-Ebv?gN4b1l$|OD!tPrSVB#%X`(|Fo&sics3US_x$wHRbkE|a2R
zh|{FVQ>|q#HcrDFFs+jEcq^Mk$p{#D-6oL<a#O^4qrxo8f>~syZIi`mVGCEr6r;2(
I0HBzNe~HoS>i_@%
diff --git a/pc-bios/mpc8544ds.dts b/pc-bios/mpc8544ds.dts
index 4c7bd75..16aba2b 100644
--- a/pc-bios/mpc8544ds.dts
+++ b/pc-bios/mpc8544ds.dts
@@ -11,50 +11,4 @@
/dts-v1/;
/ {
- aliases {
- pci0 = &pci0;
- };
-
- soc8544@e0000000 {
- mpic: pic@40000 {
- interrupt-controller;
- #address-cells = <0>;
- #interrupt-cells = <2>;
- reg = <0x40000 0x40000>;
- compatible = "chrp,open-pic";
- device_type = "open-pic";
- };
- };
-
- pci0: pci@e0008000 {
- cell-index = <0>;
- compatible = "fsl,mpc8540-pci";
- device_type = "pci";
- interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
- interrupt-map = <
-
- /* IDSEL 0x11 J17 Slot 1 */
- 0x8800 0x0 0x0 0x1 &mpic 0x2 0x1
- 0x8800 0x0 0x0 0x2 &mpic 0x3 0x1
- 0x8800 0x0 0x0 0x3 &mpic 0x4 0x1
- 0x8800 0x0 0x0 0x4 &mpic 0x1 0x1
-
- /* IDSEL 0x12 J16 Slot 2 */
-
- 0x9000 0x0 0x0 0x1 &mpic 0x3 0x1
- 0x9000 0x0 0x0 0x2 &mpic 0x4 0x1
- 0x9000 0x0 0x0 0x3 &mpic 0x2 0x1
- 0x9000 0x0 0x0 0x4 &mpic 0x1 0x1>;
-
- interrupt-parent = <&mpic>;
- interrupts = <24 2>;
- bus-range = <0 255>;
- ranges = <0x2000000 0x0 0xc0000000 0xc0000000 0x0 0x20000000
- 0x1000000 0x0 0x0 0xe1000000 0x0 0x10000>;
- clock-frequency = <66666666>;
- #interrupt-cells = <1>;
- #size-cells = <2>;
- #address-cells = <3>;
- reg = <0xe0008000 0x1000>;
- };
};
--
1.6.0.2
^ permalink raw reply related [flat|nested] 89+ messages in thread
* [Qemu-devel] [PATCH 50/72] PPC: e500: dt: start with empty device tree
2012-06-23 23:06 [Qemu-devel] [PULL 00/72] ppc patch queue 2012-06-24 Alexander Graf
` (48 preceding siblings ...)
2012-06-23 23:07 ` [Qemu-devel] [PATCH 49/72] PPC: e500: dt: create pci " Alexander Graf
@ 2012-06-23 23:07 ` Alexander Graf
2012-06-23 23:07 ` [Qemu-devel] [PATCH 51/72] dt: Add -machine dumpdtb option to dump the current dtb Alexander Graf
` (22 subsequent siblings)
72 siblings, 0 replies; 89+ messages in thread
From: Alexander Graf @ 2012-06-23 23:07 UTC (permalink / raw)
To: qemu-devel qemu-devel; +Cc: Blue Swirl, qemu-ppc Mailing List, Aurelien Jarno
Now that all of the device tree bits are generated during runtime, we
can get rid of the device tree blob and instead start from scratch with
an empty device tree.
Signed-off-by: Alexander Graf <agraf@suse.de>
---
Makefile | 1 -
hw/ppce500_mpc8544ds.c | 8 +-------
pc-bios/mpc8544ds.dtb | Bin 72 -> 0 bytes
pc-bios/mpc8544ds.dts | 14 --------------
4 files changed, 1 insertions(+), 22 deletions(-)
delete mode 100644 pc-bios/mpc8544ds.dtb
delete mode 100644 pc-bios/mpc8544ds.dts
diff --git a/Makefile b/Makefile
index a7281b0..827e1ad 100644
--- a/Makefile
+++ b/Makefile
@@ -260,7 +260,6 @@ pxe-e1000.rom pxe-eepro100.rom pxe-ne2k_pci.rom \
pxe-pcnet.rom pxe-rtl8139.rom pxe-virtio.rom \
qemu-icon.bmp \
bamboo.dtb petalogix-s3adsp1800.dtb petalogix-ml605.dtb \
-mpc8544ds.dtb \
multiboot.bin linuxboot.bin kvmvapic.bin \
s390-zipl.rom \
spapr-rtas.bin slof.bin \
diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c
index 15df515..880ed55 100644
--- a/hw/ppce500_mpc8544ds.c
+++ b/hw/ppce500_mpc8544ds.c
@@ -92,7 +92,6 @@ static int mpc8544_load_device_tree(CPUPPCState *env,
{
int ret = -1;
uint32_t mem_reg_property[] = {0, cpu_to_be32(ramsize)};
- char *filename;
int fdt_size;
void *fdt;
uint8_t hypercall[16];
@@ -113,12 +112,7 @@ static int mpc8544_load_device_tree(CPUPPCState *env,
0x20000000, 0x1000000, 0x0, 0x0, 0xe1000000,
0x0, 0x10000 };
- filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE);
- if (!filename) {
- goto out;
- }
- fdt = load_device_tree(filename, &fdt_size);
- g_free(filename);
+ fdt = create_device_tree(&fdt_size);
if (fdt == NULL) {
goto out;
}
diff --git a/pc-bios/mpc8544ds.dtb b/pc-bios/mpc8544ds.dtb
deleted file mode 100644
index 90ef5c00243b04f4aa3f812b89d5b37c63be09f2..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 72
mcmcb>`|m9S1A_+;TR>?IAT0>Q0zeD{$ZVJxBb31eq&Wct_yhI;
diff --git a/pc-bios/mpc8544ds.dts b/pc-bios/mpc8544ds.dts
deleted file mode 100644
index 16aba2b..0000000
--- a/pc-bios/mpc8544ds.dts
+++ /dev/null
@@ -1,14 +0,0 @@
-/*
- * MPC8544 DS Device Tree Source
- *
- * Copyright 2007, 2008 Freescale Semiconductor Inc.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- */
-
-/dts-v1/;
-/ {
-};
--
1.6.0.2
^ permalink raw reply related [flat|nested] 89+ messages in thread
* [Qemu-devel] [PATCH 51/72] dt: Add -machine dumpdtb option to dump the current dtb
2012-06-23 23:06 [Qemu-devel] [PULL 00/72] ppc patch queue 2012-06-24 Alexander Graf
` (49 preceding siblings ...)
2012-06-23 23:07 ` [Qemu-devel] [PATCH 50/72] PPC: e500: dt: start with empty device tree Alexander Graf
@ 2012-06-23 23:07 ` Alexander Graf
2012-06-23 23:07 ` [Qemu-devel] [PATCH 52/72] PPC: e500: dt: use 64bit cell helper Alexander Graf
` (21 subsequent siblings)
72 siblings, 0 replies; 89+ messages in thread
From: Alexander Graf @ 2012-06-23 23:07 UTC (permalink / raw)
To: qemu-devel qemu-devel; +Cc: Blue Swirl, qemu-ppc Mailing List, Aurelien Jarno
Now that we are dynamically creating the dtb, it's really useful to
be able to dump the created blob for debugging.
This patch implements a -machine dumpdtb=<file> option for e500 that
dumps the dtb exactly in the form the guest would get it to disk. It
can then be analyzed by dtc to get information about the guest
configuration.
Signed-off-by: Alexander Graf <agraf@suse.de>
---
hw/ppce500_mpc8544ds.c | 18 ++++++++++++++++++
qemu-config.c | 4 ++++
2 files changed, 22 insertions(+), 0 deletions(-)
diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c
index 880ed55..7c6edc2 100644
--- a/hw/ppce500_mpc8544ds.c
+++ b/hw/ppce500_mpc8544ds.c
@@ -111,6 +111,8 @@ static int mpc8544_load_device_tree(CPUPPCState *env,
uint32_t pci_ranges[12] = { 0x2000000, 0x0, 0xc0000000, 0xc0000000, 0x0,
0x20000000, 0x1000000, 0x0, 0x0, 0xe1000000,
0x0, 0x10000 };
+ QemuOpts *machine_opts;
+ const char *dumpdtb = NULL;
fdt = create_device_tree(&fdt_size);
if (fdt == NULL) {
@@ -300,6 +302,22 @@ static int mpc8544_load_device_tree(CPUPPCState *env,
qemu_devtree_setprop_cell(fdt, pci, "#address-cells", 3);
qemu_devtree_setprop_string(fdt, "/aliases", "pci0", pci);
+ machine_opts = qemu_opts_find(qemu_find_opts("machine"), 0);
+ if (machine_opts) {
+ dumpdtb = qemu_opt_get(machine_opts, "dumpdtb");
+ }
+ if (dumpdtb) {
+ /* Dump the dtb to a file and quit */
+ FILE *f = fopen(dumpdtb, "wb");
+ size_t len;
+ len = fwrite(fdt, fdt_size, 1, f);
+ fclose(f);
+ if (len != fdt_size) {
+ exit(1);
+ }
+ exit(0);
+ }
+
ret = rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr);
if (ret < 0) {
goto out;
diff --git a/qemu-config.c b/qemu-config.c
index bb3bff4..5bbebaf 100644
--- a/qemu-config.c
+++ b/qemu-config.c
@@ -583,6 +583,10 @@ static QemuOptsList qemu_machine_opts = {
.name = "dtb",
.type = QEMU_OPT_STRING,
.help = "Linux kernel device tree file",
+ }, {
+ .name = "dumpdtb",
+ .type = QEMU_OPT_STRING,
+ .help = "Dump current dtb to a file and quit",
},
{ /* End of list */ }
},
--
1.6.0.2
^ permalink raw reply related [flat|nested] 89+ messages in thread
* [Qemu-devel] [PATCH 52/72] PPC: e500: dt: use 64bit cell helper
2012-06-23 23:06 [Qemu-devel] [PULL 00/72] ppc patch queue 2012-06-24 Alexander Graf
` (50 preceding siblings ...)
2012-06-23 23:07 ` [Qemu-devel] [PATCH 51/72] dt: Add -machine dumpdtb option to dump the current dtb Alexander Graf
@ 2012-06-23 23:07 ` Alexander Graf
2012-06-23 23:07 ` [Qemu-devel] [PATCH 53/72] PPC: e500: dt: use target_phys_addr_t for ramsize Alexander Graf
` (20 subsequent siblings)
72 siblings, 0 replies; 89+ messages in thread
From: Alexander Graf @ 2012-06-23 23:07 UTC (permalink / raw)
To: qemu-devel qemu-devel; +Cc: Blue Swirl, qemu-ppc Mailing List, Aurelien Jarno
We have a nice 64bit helper to ease the device tree generation and
make the code more readable when creating 64bit 2-cell parameters.
Use it when generating the device tree.
Signed-off-by: Alexander Graf <agraf@suse.de>
---
hw/ppce500_mpc8544ds.c | 6 +++---
1 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c
index 7c6edc2..5fa2089 100644
--- a/hw/ppce500_mpc8544ds.c
+++ b/hw/ppce500_mpc8544ds.c
@@ -174,7 +174,7 @@ static int mpc8544_load_device_tree(CPUPPCState *env,
the first node as boot node and be happy */
for (i = smp_cpus - 1; i >= 0; i--) {
char cpu_name[128];
- uint64_t cpu_release_addr = cpu_to_be64(MPC8544_SPIN_BASE + (i * 0x20));
+ uint64_t cpu_release_addr = MPC8544_SPIN_BASE + (i * 0x20);
for (env = first_cpu; env != NULL; env = env->next_cpu) {
if (env->cpu_index == i) {
@@ -202,8 +202,8 @@ static int mpc8544_load_device_tree(CPUPPCState *env,
if (env->cpu_index) {
qemu_devtree_setprop_string(fdt, cpu_name, "status", "disabled");
qemu_devtree_setprop_string(fdt, cpu_name, "enable-method", "spin-table");
- qemu_devtree_setprop(fdt, cpu_name, "cpu-release-addr",
- &cpu_release_addr, sizeof(cpu_release_addr));
+ qemu_devtree_setprop_u64(fdt, cpu_name, "cpu-release-addr",
+ cpu_release_addr);
} else {
qemu_devtree_setprop_string(fdt, cpu_name, "status", "okay");
}
--
1.6.0.2
^ permalink raw reply related [flat|nested] 89+ messages in thread
* [Qemu-devel] [PATCH 53/72] PPC: e500: dt: use target_phys_addr_t for ramsize
2012-06-23 23:06 [Qemu-devel] [PULL 00/72] ppc patch queue 2012-06-24 Alexander Graf
` (51 preceding siblings ...)
2012-06-23 23:07 ` [Qemu-devel] [PATCH 52/72] PPC: e500: dt: use 64bit cell helper Alexander Graf
@ 2012-06-23 23:07 ` Alexander Graf
2012-06-23 23:07 ` [Qemu-devel] [PATCH 54/72] PPC: e500: enable manual loading of dtb blob Alexander Graf
` (19 subsequent siblings)
72 siblings, 0 replies; 89+ messages in thread
From: Alexander Graf @ 2012-06-23 23:07 UTC (permalink / raw)
To: qemu-devel qemu-devel; +Cc: Blue Swirl, qemu-ppc Mailing List, Aurelien Jarno
We're passing the ram size as uint32_t, capping it to 32 bits atm.
Change to target_phys_addr_t (uint64_t) to make sure we have all
the bits.
Signed-off-by: Alexander Graf <agraf@suse.de>
---
hw/ppce500_mpc8544ds.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c
index 5fa2089..f8a3d9a 100644
--- a/hw/ppce500_mpc8544ds.c
+++ b/hw/ppce500_mpc8544ds.c
@@ -85,7 +85,7 @@ static void pci_map_create(void *fdt, uint32_t *pci_map, uint32_t mpic)
static int mpc8544_load_device_tree(CPUPPCState *env,
target_phys_addr_t addr,
- uint32_t ramsize,
+ target_phys_addr_t ramsize,
target_phys_addr_t initrd_base,
target_phys_addr_t initrd_size,
const char *kernel_cmdline)
--
1.6.0.2
^ permalink raw reply related [flat|nested] 89+ messages in thread
* [Qemu-devel] [PATCH 54/72] PPC: e500: enable manual loading of dtb blob
2012-06-23 23:06 [Qemu-devel] [PULL 00/72] ppc patch queue 2012-06-24 Alexander Graf
` (52 preceding siblings ...)
2012-06-23 23:07 ` [Qemu-devel] [PATCH 53/72] PPC: e500: dt: use target_phys_addr_t for ramsize Alexander Graf
@ 2012-06-23 23:07 ` Alexander Graf
2012-06-23 23:07 ` [Qemu-devel] [PATCH 55/72] Revert "dt: temporarily disable subtree creation failure check" Alexander Graf
` (18 subsequent siblings)
72 siblings, 0 replies; 89+ messages in thread
From: Alexander Graf @ 2012-06-23 23:07 UTC (permalink / raw)
To: qemu-devel qemu-devel; +Cc: Blue Swirl, qemu-ppc Mailing List, Aurelien Jarno
We want to be able to override the automatically created device tree
by using the -dtb option. Implement this for the mpc8544ds machine.
Signed-off-by: Alexander Graf <agraf@suse.de>
---
hw/ppce500_mpc8544ds.c | 26 ++++++++++++++++++++++----
1 files changed, 22 insertions(+), 4 deletions(-)
diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c
index f8a3d9a..fa10df2 100644
--- a/hw/ppce500_mpc8544ds.c
+++ b/hw/ppce500_mpc8544ds.c
@@ -113,6 +113,27 @@ static int mpc8544_load_device_tree(CPUPPCState *env,
0x0, 0x10000 };
QemuOpts *machine_opts;
const char *dumpdtb = NULL;
+ const char *dtb_file = NULL;
+
+ machine_opts = qemu_opts_find(qemu_find_opts("machine"), 0);
+ if (machine_opts) {
+ dumpdtb = qemu_opt_get(machine_opts, "dumpdtb");
+ dtb_file = qemu_opt_get(machine_opts, "dtb");
+ }
+
+ if (dtb_file) {
+ char *filename;
+ filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, dtb_file);
+ if (!filename) {
+ goto out;
+ }
+
+ fdt = load_device_tree(filename, &fdt_size);
+ if (!fdt) {
+ goto out;
+ }
+ goto done;
+ }
fdt = create_device_tree(&fdt_size);
if (fdt == NULL) {
@@ -302,10 +323,7 @@ static int mpc8544_load_device_tree(CPUPPCState *env,
qemu_devtree_setprop_cell(fdt, pci, "#address-cells", 3);
qemu_devtree_setprop_string(fdt, "/aliases", "pci0", pci);
- machine_opts = qemu_opts_find(qemu_find_opts("machine"), 0);
- if (machine_opts) {
- dumpdtb = qemu_opt_get(machine_opts, "dumpdtb");
- }
+done:
if (dumpdtb) {
/* Dump the dtb to a file and quit */
FILE *f = fopen(dumpdtb, "wb");
--
1.6.0.2
^ permalink raw reply related [flat|nested] 89+ messages in thread
* [Qemu-devel] [PATCH 55/72] Revert "dt: temporarily disable subtree creation failure check"
2012-06-23 23:06 [Qemu-devel] [PULL 00/72] ppc patch queue 2012-06-24 Alexander Graf
` (53 preceding siblings ...)
2012-06-23 23:07 ` [Qemu-devel] [PATCH 54/72] PPC: e500: enable manual loading of dtb blob Alexander Graf
@ 2012-06-23 23:07 ` Alexander Graf
2012-06-23 23:07 ` [Qemu-devel] [PATCH 56/72] PPC: e500: Use new MPIC dt format Alexander Graf
` (17 subsequent siblings)
72 siblings, 0 replies; 89+ messages in thread
From: Alexander Graf @ 2012-06-23 23:07 UTC (permalink / raw)
To: qemu-devel qemu-devel; +Cc: Blue Swirl, qemu-ppc Mailing List, Aurelien Jarno
This reverts commit "dt: temporarily disable subtree creation
failure check" which was meant as a temporary solution to keep
external and dynamic device tree construction intact.
Now that we switched to fully dynamic dt construction, it's no
longer necessary.
Signed-off-by: Alexander Graf <agraf@suse.de>
---
device_tree.c | 2 --
1 files changed, 0 insertions(+), 2 deletions(-)
diff --git a/device_tree.c b/device_tree.c
index c8d68c2..cc83f0f 100644
--- a/device_tree.c
+++ b/device_tree.c
@@ -239,13 +239,11 @@ int qemu_devtree_add_subnode(void *fdt, const char *name)
}
retval = fdt_add_subnode(fdt, parent, basename);
-#if 0
if (retval < 0) {
fprintf(stderr, "FDT: Failed to create subnode %s: %s\n", name,
fdt_strerror(retval));
exit(1);
}
-#endif
g_free(dupname);
return retval;
--
1.6.0.2
^ permalink raw reply related [flat|nested] 89+ messages in thread
* [Qemu-devel] [PATCH 56/72] PPC: e500: Use new MPIC dt format
2012-06-23 23:06 [Qemu-devel] [PULL 00/72] ppc patch queue 2012-06-24 Alexander Graf
` (54 preceding siblings ...)
2012-06-23 23:07 ` [Qemu-devel] [PATCH 55/72] Revert "dt: temporarily disable subtree creation failure check" Alexander Graf
@ 2012-06-23 23:07 ` Alexander Graf
2012-08-08 21:16 ` [Qemu-devel] [Qemu-ppc] " Alexander Graf
2012-08-08 22:40 ` [Qemu-devel] " Peter Maydell
2012-06-23 23:07 ` [Qemu-devel] [PATCH 57/72] PPC: e500: Use new SOC " Alexander Graf
` (16 subsequent siblings)
72 siblings, 2 replies; 89+ messages in thread
From: Alexander Graf @ 2012-06-23 23:07 UTC (permalink / raw)
To: qemu-devel qemu-devel; +Cc: Blue Swirl, qemu-ppc Mailing List, Aurelien Jarno
Due to popular demand, we're updating the way we generate the MPIC
node and interrupt lines based on what the current state of art is.
Requested-by: Scott Wood <scottwood@freescale.com>
Signed-off-by: Alexander Graf <agraf@suse.de>
---
hw/ppce500_mpc8544ds.c | 33 ++++++++++++++++++---------------
1 files changed, 18 insertions(+), 15 deletions(-)
diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c
index fa10df2..e3e0659 100644
--- a/hw/ppce500_mpc8544ds.c
+++ b/hw/ppce500_mpc8544ds.c
@@ -67,18 +67,18 @@ static void pci_map_create(void *fdt, uint32_t *pci_map, uint32_t mpic)
int i;
const uint32_t tmp[] = {
/* IDSEL 0x11 J17 Slot 1 */
- 0x8800, 0x0, 0x0, 0x1, mpic, 0x2, 0x1,
- 0x8800, 0x0, 0x0, 0x2, mpic, 0x3, 0x1,
- 0x8800, 0x0, 0x0, 0x3, mpic, 0x4, 0x1,
- 0x8800, 0x0, 0x0, 0x4, mpic, 0x1, 0x1,
+ 0x8800, 0x0, 0x0, 0x1, mpic, 0x2, 0x1, 0x0, 0x0,
+ 0x8800, 0x0, 0x0, 0x2, mpic, 0x3, 0x1, 0x0, 0x0,
+ 0x8800, 0x0, 0x0, 0x3, mpic, 0x4, 0x1, 0x0, 0x0,
+ 0x8800, 0x0, 0x0, 0x4, mpic, 0x1, 0x1, 0x0, 0x0,
/* IDSEL 0x12 J16 Slot 2 */
- 0x9000, 0x0, 0x0, 0x1, mpic, 0x3, 0x1,
- 0x9000, 0x0, 0x0, 0x2, mpic, 0x4, 0x1,
- 0x9000, 0x0, 0x0, 0x3, mpic, 0x2, 0x1,
- 0x9000, 0x0, 0x0, 0x4, mpic, 0x1, 0x1,
+ 0x9000, 0x0, 0x0, 0x1, mpic, 0x3, 0x1, 0x0, 0x0,
+ 0x9000, 0x0, 0x0, 0x2, mpic, 0x4, 0x1, 0x0, 0x0,
+ 0x9000, 0x0, 0x0, 0x3, mpic, 0x2, 0x1, 0x0, 0x0,
+ 0x9000, 0x0, 0x0, 0x4, mpic, 0x1, 0x1, 0x0, 0x0,
};
- for (i = 0; i < (7 * 8); i++) {
+ for (i = 0; i < ARRAY_SIZE(tmp); i++) {
pci_map[i] = cpu_to_be32(tmp[i]);
}
}
@@ -107,7 +107,7 @@ static int mpc8544_load_device_tree(CPUPPCState *env,
uint32_t mpic_ph;
char gutil[128];
char pci[128];
- uint32_t pci_map[7 * 8];
+ uint32_t pci_map[9 * 8];
uint32_t pci_ranges[12] = { 0x2000000, 0x0, 0xc0000000, 0xc0000000, 0x0,
0x20000000, 0x1000000, 0x0, 0x0, 0xe1000000,
0x0, 0x10000 };
@@ -249,15 +249,18 @@ static int mpc8544_load_device_tree(CPUPPCState *env,
MPC8544_MPIC_REGS_BASE - MPC8544_CCSRBAR_BASE);
qemu_devtree_add_subnode(fdt, mpic);
qemu_devtree_setprop_string(fdt, mpic, "device_type", "open-pic");
- qemu_devtree_setprop_string(fdt, mpic, "compatible", "chrp,open-pic");
+ qemu_devtree_setprop_string(fdt, mpic, "compatible", "fsl,mpic");
qemu_devtree_setprop_cells(fdt, mpic, "reg", MPC8544_MPIC_REGS_BASE -
MPC8544_CCSRBAR_BASE, 0x40000);
qemu_devtree_setprop_cell(fdt, mpic, "#address-cells", 0);
- qemu_devtree_setprop_cell(fdt, mpic, "#interrupt-cells", 2);
+ qemu_devtree_setprop_cell(fdt, mpic, "#interrupt-cells", 4);
mpic_ph = qemu_devtree_alloc_phandle(fdt);
qemu_devtree_setprop_cell(fdt, mpic, "phandle", mpic_ph);
qemu_devtree_setprop_cell(fdt, mpic, "linux,phandle", mpic_ph);
qemu_devtree_setprop(fdt, mpic, "interrupt-controller", NULL, 0);
+ qemu_devtree_setprop(fdt, mpic, "big-endian", NULL, 0);
+ qemu_devtree_setprop(fdt, mpic, "single-cpu-affinity", NULL, 0);
+ qemu_devtree_setprop_cell(fdt, mpic, "last-interrupt-source", 255);
/*
* We have to generate ser1 first, because Linux takes the first
@@ -273,7 +276,7 @@ static int mpc8544_load_device_tree(CPUPPCState *env,
MPC8544_CCSRBAR_BASE, 0x100);
qemu_devtree_setprop_cell(fdt, ser1, "cell-index", 1);
qemu_devtree_setprop_cell(fdt, ser1, "clock-frequency", 0);
- qemu_devtree_setprop_cells(fdt, ser1, "interrupts", 42, 2);
+ qemu_devtree_setprop_cells(fdt, ser1, "interrupts", 42, 2, 0, 0);
qemu_devtree_setprop_phandle(fdt, ser1, "interrupt-parent", mpic);
qemu_devtree_setprop_string(fdt, "/aliases", "serial1", ser1);
@@ -286,7 +289,7 @@ static int mpc8544_load_device_tree(CPUPPCState *env,
MPC8544_CCSRBAR_BASE, 0x100);
qemu_devtree_setprop_cell(fdt, ser0, "cell-index", 0);
qemu_devtree_setprop_cell(fdt, ser0, "clock-frequency", 0);
- qemu_devtree_setprop_cells(fdt, ser0, "interrupts", 42, 2);
+ qemu_devtree_setprop_cells(fdt, ser0, "interrupts", 42, 2, 0, 0);
qemu_devtree_setprop_phandle(fdt, ser0, "interrupt-parent", mpic);
qemu_devtree_setprop_string(fdt, "/aliases", "serial0", ser0);
qemu_devtree_setprop_string(fdt, "/chosen", "linux,stdout-path", ser0);
@@ -309,7 +312,7 @@ static int mpc8544_load_device_tree(CPUPPCState *env,
pci_map_create(fdt, pci_map, qemu_devtree_get_phandle(fdt, mpic));
qemu_devtree_setprop(fdt, pci, "interrupt-map", pci_map, sizeof(pci_map));
qemu_devtree_setprop_phandle(fdt, pci, "interrupt-parent", mpic);
- qemu_devtree_setprop_cells(fdt, pci, "interrupts", 24, 2);
+ qemu_devtree_setprop_cells(fdt, pci, "interrupts", 24, 2, 0, 0);
qemu_devtree_setprop_cells(fdt, pci, "bus-range", 0, 255);
for (i = 0; i < 12; i++) {
pci_ranges[i] = cpu_to_be32(pci_ranges[i]);
--
1.6.0.2
^ permalink raw reply related [flat|nested] 89+ messages in thread
* [Qemu-devel] [PATCH 57/72] PPC: e500: Use new SOC dt format
2012-06-23 23:06 [Qemu-devel] [PULL 00/72] ppc patch queue 2012-06-24 Alexander Graf
` (55 preceding siblings ...)
2012-06-23 23:07 ` [Qemu-devel] [PATCH 56/72] PPC: e500: Use new MPIC dt format Alexander Graf
@ 2012-06-23 23:07 ` Alexander Graf
2012-06-23 23:07 ` [Qemu-devel] [PATCH 58/72] PPC: e500: Define addresses as always 64bit Alexander Graf
` (15 subsequent siblings)
72 siblings, 0 replies; 89+ messages in thread
From: Alexander Graf @ 2012-06-23 23:07 UTC (permalink / raw)
To: qemu-devel qemu-devel; +Cc: Blue Swirl, qemu-ppc Mailing List, Aurelien Jarno
Due to popular demand, let's clean up the soc node a bit and use
more recent dt notions.
Requested-by: Scott Wood <scottwood@freescale.com>
Signed-off-by: Alexander Graf <agraf@suse.de>
---
hw/ppce500_mpc8544ds.c | 9 ++++-----
1 files changed, 4 insertions(+), 5 deletions(-)
diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c
index e3e0659..7dc3a07 100644
--- a/hw/ppce500_mpc8544ds.c
+++ b/hw/ppce500_mpc8544ds.c
@@ -43,7 +43,6 @@
#define RAM_SIZES_ALIGN (64UL << 20)
#define MPC8544_CCSRBAR_BASE 0xE0000000
-#define MPC8544_CCSRBAR_REGSIZE 0x00001000
#define MPC8544_CCSRBAR_SIZE 0x00100000
#define MPC8544_MPIC_REGS_BASE (MPC8544_CCSRBAR_BASE + 0x40000)
#define MPC8544_SERIAL0_REGS_BASE (MPC8544_CCSRBAR_BASE + 0x4500)
@@ -99,6 +98,7 @@ static int mpc8544_load_device_tree(CPUPPCState *env,
uint32_t tb_freq = 400000000;
int i;
char compatible[] = "MPC8544DS\0MPC85xxDS";
+ char compatible_sb[] = "fsl,mpc8544-immr\0simple-bus";
char model[] = "MPC8544DS";
char soc[128];
char ser0[128];
@@ -232,16 +232,15 @@ static int mpc8544_load_device_tree(CPUPPCState *env,
qemu_devtree_add_subnode(fdt, "/aliases");
/* XXX These should go into their respective devices' code */
- snprintf(soc, sizeof(soc), "/soc8544@%x", MPC8544_CCSRBAR_BASE);
+ snprintf(soc, sizeof(soc), "/soc@%x", MPC8544_CCSRBAR_BASE);
qemu_devtree_add_subnode(fdt, soc);
qemu_devtree_setprop_string(fdt, soc, "device_type", "soc");
- qemu_devtree_setprop_string(fdt, soc, "compatible", "simple-bus");
+ qemu_devtree_setprop(fdt, soc, "compatible", compatible_sb,
+ sizeof(compatible_sb));
qemu_devtree_setprop_cell(fdt, soc, "#address-cells", 1);
qemu_devtree_setprop_cell(fdt, soc, "#size-cells", 1);
qemu_devtree_setprop_cells(fdt, soc, "ranges", 0x0, MPC8544_CCSRBAR_BASE,
MPC8544_CCSRBAR_SIZE);
- qemu_devtree_setprop_cells(fdt, soc, "reg", MPC8544_CCSRBAR_BASE,
- MPC8544_CCSRBAR_REGSIZE);
/* XXX should contain a reasonable value */
qemu_devtree_setprop_cell(fdt, soc, "bus-frequency", 0);
--
1.6.0.2
^ permalink raw reply related [flat|nested] 89+ messages in thread
* [Qemu-devel] [PATCH 58/72] PPC: e500: Define addresses as always 64bit
2012-06-23 23:06 [Qemu-devel] [PULL 00/72] ppc patch queue 2012-06-24 Alexander Graf
` (56 preceding siblings ...)
2012-06-23 23:07 ` [Qemu-devel] [PATCH 57/72] PPC: e500: Use new SOC " Alexander Graf
@ 2012-06-23 23:07 ` Alexander Graf
2012-06-23 23:07 ` [Qemu-devel] [PATCH 59/72] PPC: e500: Extend address/size of / to 64bit Alexander Graf
` (14 subsequent siblings)
72 siblings, 0 replies; 89+ messages in thread
From: Alexander Graf @ 2012-06-23 23:07 UTC (permalink / raw)
To: qemu-devel qemu-devel; +Cc: Blue Swirl, qemu-ppc Mailing List, Aurelien Jarno
Every time we use an address constant, it needs to potentially fit into
a 64bit physical address space. So let's define things accordingly.
Signed-off-by: Alexander Graf <agraf@suse.de>
---
hw/ppce500_mpc8544ds.c | 34 +++++++++++++++++-----------------
1 files changed, 17 insertions(+), 17 deletions(-)
diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c
index 7dc3a07..c6a09bb 100644
--- a/hw/ppce500_mpc8544ds.c
+++ b/hw/ppce500_mpc8544ds.c
@@ -42,17 +42,17 @@
#define RAM_SIZES_ALIGN (64UL << 20)
-#define MPC8544_CCSRBAR_BASE 0xE0000000
-#define MPC8544_CCSRBAR_SIZE 0x00100000
-#define MPC8544_MPIC_REGS_BASE (MPC8544_CCSRBAR_BASE + 0x40000)
-#define MPC8544_SERIAL0_REGS_BASE (MPC8544_CCSRBAR_BASE + 0x4500)
-#define MPC8544_SERIAL1_REGS_BASE (MPC8544_CCSRBAR_BASE + 0x4600)
-#define MPC8544_PCI_REGS_BASE (MPC8544_CCSRBAR_BASE + 0x8000)
-#define MPC8544_PCI_REGS_SIZE 0x1000
-#define MPC8544_PCI_IO 0xE1000000
-#define MPC8544_PCI_IOLEN 0x10000
-#define MPC8544_UTIL_BASE (MPC8544_CCSRBAR_BASE + 0xe0000)
-#define MPC8544_SPIN_BASE 0xEF000000
+#define MPC8544_CCSRBAR_BASE 0xE0000000ULL
+#define MPC8544_CCSRBAR_SIZE 0x00100000ULL
+#define MPC8544_MPIC_REGS_BASE (MPC8544_CCSRBAR_BASE + 0x40000ULL)
+#define MPC8544_SERIAL0_REGS_BASE (MPC8544_CCSRBAR_BASE + 0x4500ULL)
+#define MPC8544_SERIAL1_REGS_BASE (MPC8544_CCSRBAR_BASE + 0x4600ULL)
+#define MPC8544_PCI_REGS_BASE (MPC8544_CCSRBAR_BASE + 0x8000ULL)
+#define MPC8544_PCI_REGS_SIZE 0x1000ULL
+#define MPC8544_PCI_IO 0xE1000000ULL
+#define MPC8544_PCI_IOLEN 0x10000ULL
+#define MPC8544_UTIL_BASE (MPC8544_CCSRBAR_BASE + 0xe0000ULL)
+#define MPC8544_SPIN_BASE 0xEF000000ULL
struct boot_info
{
@@ -232,7 +232,7 @@ static int mpc8544_load_device_tree(CPUPPCState *env,
qemu_devtree_add_subnode(fdt, "/aliases");
/* XXX These should go into their respective devices' code */
- snprintf(soc, sizeof(soc), "/soc@%x", MPC8544_CCSRBAR_BASE);
+ snprintf(soc, sizeof(soc), "/soc@%llx", MPC8544_CCSRBAR_BASE);
qemu_devtree_add_subnode(fdt, soc);
qemu_devtree_setprop_string(fdt, soc, "device_type", "soc");
qemu_devtree_setprop(fdt, soc, "compatible", compatible_sb,
@@ -244,7 +244,7 @@ static int mpc8544_load_device_tree(CPUPPCState *env,
/* XXX should contain a reasonable value */
qemu_devtree_setprop_cell(fdt, soc, "bus-frequency", 0);
- snprintf(mpic, sizeof(mpic), "%s/pic@%x", soc,
+ snprintf(mpic, sizeof(mpic), "%s/pic@%llx", soc,
MPC8544_MPIC_REGS_BASE - MPC8544_CCSRBAR_BASE);
qemu_devtree_add_subnode(fdt, mpic);
qemu_devtree_setprop_string(fdt, mpic, "device_type", "open-pic");
@@ -266,7 +266,7 @@ static int mpc8544_load_device_tree(CPUPPCState *env,
* device it finds in the dt as serial output device. And we generate
* devices in reverse order to the dt.
*/
- snprintf(ser1, sizeof(ser1), "%s/serial@%x", soc,
+ snprintf(ser1, sizeof(ser1), "%s/serial@%llx", soc,
MPC8544_SERIAL1_REGS_BASE - MPC8544_CCSRBAR_BASE);
qemu_devtree_add_subnode(fdt, ser1);
qemu_devtree_setprop_string(fdt, ser1, "device_type", "serial");
@@ -279,7 +279,7 @@ static int mpc8544_load_device_tree(CPUPPCState *env,
qemu_devtree_setprop_phandle(fdt, ser1, "interrupt-parent", mpic);
qemu_devtree_setprop_string(fdt, "/aliases", "serial1", ser1);
- snprintf(ser0, sizeof(ser0), "%s/serial@%x", soc,
+ snprintf(ser0, sizeof(ser0), "%s/serial@%llx", soc,
MPC8544_SERIAL0_REGS_BASE - MPC8544_CCSRBAR_BASE);
qemu_devtree_add_subnode(fdt, ser0);
qemu_devtree_setprop_string(fdt, ser0, "device_type", "serial");
@@ -293,7 +293,7 @@ static int mpc8544_load_device_tree(CPUPPCState *env,
qemu_devtree_setprop_string(fdt, "/aliases", "serial0", ser0);
qemu_devtree_setprop_string(fdt, "/chosen", "linux,stdout-path", ser0);
- snprintf(gutil, sizeof(gutil), "%s/global-utilities@%x", soc,
+ snprintf(gutil, sizeof(gutil), "%s/global-utilities@%llx", soc,
MPC8544_UTIL_BASE - MPC8544_CCSRBAR_BASE);
qemu_devtree_add_subnode(fdt, gutil);
qemu_devtree_setprop_string(fdt, gutil, "compatible", "fsl,mpc8544-guts");
@@ -301,7 +301,7 @@ static int mpc8544_load_device_tree(CPUPPCState *env,
MPC8544_CCSRBAR_BASE, 0x1000);
qemu_devtree_setprop(fdt, gutil, "fsl,has-rstcr", NULL, 0);
- snprintf(pci, sizeof(pci), "/pci@%x", MPC8544_PCI_REGS_BASE);
+ snprintf(pci, sizeof(pci), "/pci@%llx", MPC8544_PCI_REGS_BASE);
qemu_devtree_add_subnode(fdt, pci);
qemu_devtree_setprop_cell(fdt, pci, "cell-index", 0);
qemu_devtree_setprop_string(fdt, pci, "compatible", "fsl,mpc8540-pci");
--
1.6.0.2
^ permalink raw reply related [flat|nested] 89+ messages in thread
* [Qemu-devel] [PATCH 59/72] PPC: e500: Extend address/size of / to 64bit
2012-06-23 23:06 [Qemu-devel] [PULL 00/72] ppc patch queue 2012-06-24 Alexander Graf
` (57 preceding siblings ...)
2012-06-23 23:07 ` [Qemu-devel] [PATCH 58/72] PPC: e500: Define addresses as always 64bit Alexander Graf
@ 2012-06-23 23:07 ` Alexander Graf
2012-06-23 23:07 ` [Qemu-devel] [PATCH 60/72] dt: Add global option to set phandle start offset Alexander Graf
` (13 subsequent siblings)
72 siblings, 0 replies; 89+ messages in thread
From: Alexander Graf @ 2012-06-23 23:07 UTC (permalink / raw)
To: qemu-devel qemu-devel; +Cc: Blue Swirl, qemu-ppc Mailing List, Aurelien Jarno
We want to be able to support >= 4GB of RAM. To do so, we need to be able
to tell the guest OS how much RAM it has.
However, that information today is capped to 32bit. So let's extend the
offset and size fields to 64bit, so we can fit in big addresses and even
one day - if we wish to do so - map devices above 32bit.
Signed-off-by: Alexander Graf <agraf@suse.de>
---
hw/ppce500_mpc8544ds.c | 28 ++++++++++++++++++----------
1 files changed, 18 insertions(+), 10 deletions(-)
diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c
index c6a09bb..bf48bc7 100644
--- a/hw/ppce500_mpc8544ds.c
+++ b/hw/ppce500_mpc8544ds.c
@@ -90,7 +90,7 @@ static int mpc8544_load_device_tree(CPUPPCState *env,
const char *kernel_cmdline)
{
int ret = -1;
- uint32_t mem_reg_property[] = {0, cpu_to_be32(ramsize)};
+ uint64_t mem_reg_property[] = { 0, cpu_to_be64(ramsize) };
int fdt_size;
void *fdt;
uint8_t hypercall[16];
@@ -108,9 +108,16 @@ static int mpc8544_load_device_tree(CPUPPCState *env,
char gutil[128];
char pci[128];
uint32_t pci_map[9 * 8];
- uint32_t pci_ranges[12] = { 0x2000000, 0x0, 0xc0000000, 0xc0000000, 0x0,
- 0x20000000, 0x1000000, 0x0, 0x0, 0xe1000000,
- 0x0, 0x10000 };
+ uint32_t pci_ranges[14] =
+ {
+ 0x2000000, 0x0, 0xc0000000,
+ 0x0, 0xc0000000,
+ 0x0, 0x20000000,
+
+ 0x1000000, 0x0, 0x0,
+ 0x0, 0xe1000000,
+ 0x0, 0x10000,
+ };
QemuOpts *machine_opts;
const char *dumpdtb = NULL;
const char *dtb_file = NULL;
@@ -144,8 +151,8 @@ static int mpc8544_load_device_tree(CPUPPCState *env,
qemu_devtree_setprop_string(fdt, "/", "model", model);
qemu_devtree_setprop(fdt, "/", "compatible", compatible,
sizeof(compatible));
- qemu_devtree_setprop_cell(fdt, "/", "#address-cells", 1);
- qemu_devtree_setprop_cell(fdt, "/", "#size-cells", 1);
+ qemu_devtree_setprop_cell(fdt, "/", "#address-cells", 2);
+ qemu_devtree_setprop_cell(fdt, "/", "#size-cells", 2);
qemu_devtree_add_subnode(fdt, "/memory");
qemu_devtree_setprop_string(fdt, "/memory", "device_type", "memory");
@@ -239,7 +246,8 @@ static int mpc8544_load_device_tree(CPUPPCState *env,
sizeof(compatible_sb));
qemu_devtree_setprop_cell(fdt, soc, "#address-cells", 1);
qemu_devtree_setprop_cell(fdt, soc, "#size-cells", 1);
- qemu_devtree_setprop_cells(fdt, soc, "ranges", 0x0, MPC8544_CCSRBAR_BASE,
+ qemu_devtree_setprop_cells(fdt, soc, "ranges", 0x0,
+ MPC8544_CCSRBAR_BASE >> 32, MPC8544_CCSRBAR_BASE,
MPC8544_CCSRBAR_SIZE);
/* XXX should contain a reasonable value */
qemu_devtree_setprop_cell(fdt, soc, "bus-frequency", 0);
@@ -313,12 +321,12 @@ static int mpc8544_load_device_tree(CPUPPCState *env,
qemu_devtree_setprop_phandle(fdt, pci, "interrupt-parent", mpic);
qemu_devtree_setprop_cells(fdt, pci, "interrupts", 24, 2, 0, 0);
qemu_devtree_setprop_cells(fdt, pci, "bus-range", 0, 255);
- for (i = 0; i < 12; i++) {
+ for (i = 0; i < 14; i++) {
pci_ranges[i] = cpu_to_be32(pci_ranges[i]);
}
qemu_devtree_setprop(fdt, pci, "ranges", pci_ranges, sizeof(pci_ranges));
- qemu_devtree_setprop_cells(fdt, pci, "reg", MPC8544_PCI_REGS_BASE,
- 0x1000);
+ qemu_devtree_setprop_cells(fdt, pci, "reg", MPC8544_PCI_REGS_BASE >> 32,
+ MPC8544_PCI_REGS_BASE, 0, 0x1000);
qemu_devtree_setprop_cell(fdt, pci, "clock-frequency", 66666666);
qemu_devtree_setprop_cell(fdt, pci, "#interrupt-cells", 1);
qemu_devtree_setprop_cell(fdt, pci, "#size-cells", 2);
--
1.6.0.2
^ permalink raw reply related [flat|nested] 89+ messages in thread
* [Qemu-devel] [PATCH 60/72] dt: Add global option to set phandle start offset
2012-06-23 23:06 [Qemu-devel] [PULL 00/72] ppc patch queue 2012-06-24 Alexander Graf
` (58 preceding siblings ...)
2012-06-23 23:07 ` [Qemu-devel] [PATCH 59/72] PPC: e500: Extend address/size of / to 64bit Alexander Graf
@ 2012-06-23 23:07 ` Alexander Graf
2012-06-23 23:07 ` [Qemu-devel] [PATCH 61/72] PPC: e500: Refactor serial dt generation Alexander Graf
` (12 subsequent siblings)
72 siblings, 0 replies; 89+ messages in thread
From: Alexander Graf @ 2012-06-23 23:07 UTC (permalink / raw)
To: qemu-devel qemu-devel; +Cc: Blue Swirl, qemu-ppc Mailing List, Aurelien Jarno
If anyone outside of QEMU wants to mess with a QEMU generated device tree,
he needs to know which range phandles are valid in. So let's expose a
machine option that an external program can use to set the start allocate
id for phandles in QEMU.
Signed-off-by: Alexander Graf <agraf@suse.de>
---
device_tree.c | 28 +++++++++++++++++++++++++++-
qemu-config.c | 4 ++++
2 files changed, 31 insertions(+), 1 deletions(-)
diff --git a/device_tree.c b/device_tree.c
index cc83f0f..acae53e 100644
--- a/device_tree.c
+++ b/device_tree.c
@@ -22,6 +22,8 @@
#include "qemu-common.h"
#include "device_tree.h"
#include "hw/loader.h"
+#include "qemu-option.h"
+#include "qemu-config.h"
#include <libfdt.h>
@@ -200,7 +202,31 @@ int qemu_devtree_setprop_phandle(void *fdt, const char *node_path,
uint32_t qemu_devtree_alloc_phandle(void *fdt)
{
- static int phandle = 0x8000;
+ static int phandle = 0x0;
+
+ /*
+ * We need to find out if the user gave us special instruction at
+ * which phandle id to start allocting phandles.
+ */
+ if (!phandle) {
+ QemuOpts *machine_opts;
+ machine_opts = qemu_opts_find(qemu_find_opts("machine"), 0);
+ if (machine_opts) {
+ const char *phandle_start;
+ phandle_start = qemu_opt_get(machine_opts, "phandle_start");
+ if (phandle_start) {
+ phandle = strtoul(phandle_start, NULL, 0);
+ }
+ }
+ }
+
+ if (!phandle) {
+ /*
+ * None or invalid phandle given on the command line, so fall back to
+ * default starting point.
+ */
+ phandle = 0x8000;
+ }
return phandle++;
}
diff --git a/qemu-config.c b/qemu-config.c
index 5bbebaf..2cd2726 100644
--- a/qemu-config.c
+++ b/qemu-config.c
@@ -587,6 +587,10 @@ static QemuOptsList qemu_machine_opts = {
.name = "dumpdtb",
.type = QEMU_OPT_STRING,
.help = "Dump current dtb to a file and quit",
+ }, {
+ .name = "phandle_start",
+ .type = QEMU_OPT_STRING,
+ .help = "The first phandle ID we may generate dynamically",
},
{ /* End of list */ }
},
--
1.6.0.2
^ permalink raw reply related [flat|nested] 89+ messages in thread
* [Qemu-devel] [PATCH 61/72] PPC: e500: Refactor serial dt generation
2012-06-23 23:06 [Qemu-devel] [PULL 00/72] ppc patch queue 2012-06-24 Alexander Graf
` (59 preceding siblings ...)
2012-06-23 23:07 ` [Qemu-devel] [PATCH 60/72] dt: Add global option to set phandle start offset Alexander Graf
@ 2012-06-23 23:07 ` Alexander Graf
2012-06-23 23:07 ` [Qemu-devel] [PATCH 62/72] dt: make setprop argument static Alexander Graf
` (11 subsequent siblings)
72 siblings, 0 replies; 89+ messages in thread
From: Alexander Graf @ 2012-06-23 23:07 UTC (permalink / raw)
To: qemu-devel qemu-devel; +Cc: Blue Swirl, qemu-ppc Mailing List, Aurelien Jarno
When generating serial port device tree nodes, we duplicate quite a bit
of code, because there are 2 of them in the mpc8544ds board we emulate.
Shove the generating code into a function, so we duplicate less code.
Signed-off-by: Alexander Graf <agraf@suse.de>
---
hw/ppce500_mpc8544ds.c | 54 +++++++++++++++++++++++------------------------
1 files changed, 26 insertions(+), 28 deletions(-)
diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c
index bf48bc7..f6da25b 100644
--- a/hw/ppce500_mpc8544ds.c
+++ b/hw/ppce500_mpc8544ds.c
@@ -82,6 +82,28 @@ static void pci_map_create(void *fdt, uint32_t *pci_map, uint32_t mpic)
}
}
+static void dt_serial_create(void *fdt, unsigned long long offset,
+ const char *soc, const char *mpic,
+ const char *alias, int idx, bool defcon)
+{
+ char ser[128];
+
+ snprintf(ser, sizeof(ser), "%s/serial@%llx", soc, offset);
+ qemu_devtree_add_subnode(fdt, ser);
+ qemu_devtree_setprop_string(fdt, ser, "device_type", "serial");
+ qemu_devtree_setprop_string(fdt, ser, "compatible", "ns16550");
+ qemu_devtree_setprop_cells(fdt, ser, "reg", offset, 0x100);
+ qemu_devtree_setprop_cell(fdt, ser, "cell-index", idx);
+ qemu_devtree_setprop_cell(fdt, ser, "clock-frequency", 0);
+ qemu_devtree_setprop_cells(fdt, ser, "interrupts", 42, 2, 0, 0);
+ qemu_devtree_setprop_phandle(fdt, ser, "interrupt-parent", mpic);
+ qemu_devtree_setprop_string(fdt, "/aliases", alias, ser);
+
+ if (defcon) {
+ qemu_devtree_setprop_string(fdt, "/chosen", "linux,stdout-path", ser);
+ }
+}
+
static int mpc8544_load_device_tree(CPUPPCState *env,
target_phys_addr_t addr,
target_phys_addr_t ramsize,
@@ -101,8 +123,6 @@ static int mpc8544_load_device_tree(CPUPPCState *env,
char compatible_sb[] = "fsl,mpc8544-immr\0simple-bus";
char model[] = "MPC8544DS";
char soc[128];
- char ser0[128];
- char ser1[128];
char mpic[128];
uint32_t mpic_ph;
char gutil[128];
@@ -274,32 +294,10 @@ static int mpc8544_load_device_tree(CPUPPCState *env,
* device it finds in the dt as serial output device. And we generate
* devices in reverse order to the dt.
*/
- snprintf(ser1, sizeof(ser1), "%s/serial@%llx", soc,
- MPC8544_SERIAL1_REGS_BASE - MPC8544_CCSRBAR_BASE);
- qemu_devtree_add_subnode(fdt, ser1);
- qemu_devtree_setprop_string(fdt, ser1, "device_type", "serial");
- qemu_devtree_setprop_string(fdt, ser1, "compatible", "ns16550");
- qemu_devtree_setprop_cells(fdt, ser1, "reg", MPC8544_SERIAL1_REGS_BASE -
- MPC8544_CCSRBAR_BASE, 0x100);
- qemu_devtree_setprop_cell(fdt, ser1, "cell-index", 1);
- qemu_devtree_setprop_cell(fdt, ser1, "clock-frequency", 0);
- qemu_devtree_setprop_cells(fdt, ser1, "interrupts", 42, 2, 0, 0);
- qemu_devtree_setprop_phandle(fdt, ser1, "interrupt-parent", mpic);
- qemu_devtree_setprop_string(fdt, "/aliases", "serial1", ser1);
-
- snprintf(ser0, sizeof(ser0), "%s/serial@%llx", soc,
- MPC8544_SERIAL0_REGS_BASE - MPC8544_CCSRBAR_BASE);
- qemu_devtree_add_subnode(fdt, ser0);
- qemu_devtree_setprop_string(fdt, ser0, "device_type", "serial");
- qemu_devtree_setprop_string(fdt, ser0, "compatible", "ns16550");
- qemu_devtree_setprop_cells(fdt, ser0, "reg", MPC8544_SERIAL0_REGS_BASE -
- MPC8544_CCSRBAR_BASE, 0x100);
- qemu_devtree_setprop_cell(fdt, ser0, "cell-index", 0);
- qemu_devtree_setprop_cell(fdt, ser0, "clock-frequency", 0);
- qemu_devtree_setprop_cells(fdt, ser0, "interrupts", 42, 2, 0, 0);
- qemu_devtree_setprop_phandle(fdt, ser0, "interrupt-parent", mpic);
- qemu_devtree_setprop_string(fdt, "/aliases", "serial0", ser0);
- qemu_devtree_setprop_string(fdt, "/chosen", "linux,stdout-path", ser0);
+ dt_serial_create(fdt, MPC8544_SERIAL1_REGS_BASE - MPC8544_CCSRBAR_BASE,
+ soc, mpic, "serial1", 1, false);
+ dt_serial_create(fdt, MPC8544_SERIAL0_REGS_BASE - MPC8544_CCSRBAR_BASE,
+ soc, mpic, "serial0", 0, true);
snprintf(gutil, sizeof(gutil), "%s/global-utilities@%llx", soc,
MPC8544_UTIL_BASE - MPC8544_CCSRBAR_BASE);
--
1.6.0.2
^ permalink raw reply related [flat|nested] 89+ messages in thread
* [Qemu-devel] [PATCH 62/72] dt: make setprop argument static
2012-06-23 23:06 [Qemu-devel] [PULL 00/72] ppc patch queue 2012-06-24 Alexander Graf
` (60 preceding siblings ...)
2012-06-23 23:07 ` [Qemu-devel] [PATCH 61/72] PPC: e500: Refactor serial dt generation Alexander Graf
@ 2012-06-23 23:07 ` Alexander Graf
2012-06-23 23:07 ` [Qemu-devel] [PATCH 63/72] PPC: e500: allow users to set the /compatible property via -machine Alexander Graf
` (10 subsequent siblings)
72 siblings, 0 replies; 89+ messages in thread
From: Alexander Graf @ 2012-06-23 23:07 UTC (permalink / raw)
To: qemu-devel qemu-devel; +Cc: Blue Swirl, qemu-ppc Mailing List, Aurelien Jarno
Whatever we pass in to qemu_devtree_setprop to put into the device tree
will not get modified by that function, so it can easily be declared const.
Signed-off-by: Alexander Graf <agraf@suse.de>
Reviewed-by: Peter Crosthwaite <peter.crosthwaite@petalogix.com>
---
device_tree.c | 2 +-
device_tree.h | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/device_tree.c b/device_tree.c
index acae53e..b366fdd 100644
--- a/device_tree.c
+++ b/device_tree.c
@@ -127,7 +127,7 @@ static int findnode_nofail(void *fdt, const char *node_path)
}
int qemu_devtree_setprop(void *fdt, const char *node_path,
- const char *property, void *val_array, int size)
+ const char *property, const void *val_array, int size)
{
int r;
diff --git a/device_tree.h b/device_tree.h
index 4898d95..2244270 100644
--- a/device_tree.h
+++ b/device_tree.h
@@ -18,7 +18,7 @@ void *create_device_tree(int *sizep);
void *load_device_tree(const char *filename_path, int *sizep);
int qemu_devtree_setprop(void *fdt, const char *node_path,
- const char *property, void *val_array, int size);
+ const char *property, const void *val_array, int size);
int qemu_devtree_setprop_cell(void *fdt, const char *node_path,
const char *property, uint32_t val);
int qemu_devtree_setprop_u64(void *fdt, const char *node_path,
--
1.6.0.2
^ permalink raw reply related [flat|nested] 89+ messages in thread
* [Qemu-devel] [PATCH 63/72] PPC: e500: allow users to set the /compatible property via -machine
2012-06-23 23:06 [Qemu-devel] [PULL 00/72] ppc patch queue 2012-06-24 Alexander Graf
` (61 preceding siblings ...)
2012-06-23 23:07 ` [Qemu-devel] [PATCH 62/72] dt: make setprop argument static Alexander Graf
@ 2012-06-23 23:07 ` Alexander Graf
2012-06-23 23:07 ` [Qemu-devel] [PATCH 64/72] uImage: increase the gzip load size Alexander Graf
` (9 subsequent siblings)
72 siblings, 0 replies; 89+ messages in thread
From: Alexander Graf @ 2012-06-23 23:07 UTC (permalink / raw)
To: qemu-devel qemu-devel; +Cc: Blue Swirl, qemu-ppc Mailing List, Aurelien Jarno
Device trees usually have a node /compatible, which indicate which machine
type we're looking at. For quick prototyping, it can be very useful to change
the contents of that node via the command line.
Thus, introduce a new option to -machine called dt_compatible, which when
set changes the /compatible contents to its value.
Signed-off-by: Alexander Graf <agraf@suse.de>
---
hw/ppce500_mpc8544ds.c | 12 +++++++++---
qemu-config.c | 4 ++++
2 files changed, 13 insertions(+), 3 deletions(-)
diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c
index f6da25b..d38ad99 100644
--- a/hw/ppce500_mpc8544ds.c
+++ b/hw/ppce500_mpc8544ds.c
@@ -119,7 +119,8 @@ static int mpc8544_load_device_tree(CPUPPCState *env,
uint32_t clock_freq = 400000000;
uint32_t tb_freq = 400000000;
int i;
- char compatible[] = "MPC8544DS\0MPC85xxDS";
+ const char *compatible = "MPC8544DS\0MPC85xxDS";
+ int compatible_len = sizeof("MPC8544DS\0MPC85xxDS");
char compatible_sb[] = "fsl,mpc8544-immr\0simple-bus";
char model[] = "MPC8544DS";
char soc[128];
@@ -144,8 +145,14 @@ static int mpc8544_load_device_tree(CPUPPCState *env,
machine_opts = qemu_opts_find(qemu_find_opts("machine"), 0);
if (machine_opts) {
+ const char *tmp;
dumpdtb = qemu_opt_get(machine_opts, "dumpdtb");
dtb_file = qemu_opt_get(machine_opts, "dtb");
+ tmp = qemu_opt_get(machine_opts, "dt_compatible");
+ if (tmp) {
+ compatible = tmp;
+ compatible_len = strlen(compatible) + 1;
+ }
}
if (dtb_file) {
@@ -169,8 +176,7 @@ static int mpc8544_load_device_tree(CPUPPCState *env,
/* Manipulate device tree in memory. */
qemu_devtree_setprop_string(fdt, "/", "model", model);
- qemu_devtree_setprop(fdt, "/", "compatible", compatible,
- sizeof(compatible));
+ qemu_devtree_setprop(fdt, "/", "compatible", compatible, compatible_len);
qemu_devtree_setprop_cell(fdt, "/", "#address-cells", 2);
qemu_devtree_setprop_cell(fdt, "/", "#size-cells", 2);
diff --git a/qemu-config.c b/qemu-config.c
index 2cd2726..5c3296b 100644
--- a/qemu-config.c
+++ b/qemu-config.c
@@ -591,6 +591,10 @@ static QemuOptsList qemu_machine_opts = {
.name = "phandle_start",
.type = QEMU_OPT_STRING,
.help = "The first phandle ID we may generate dynamically",
+ }, {
+ .name = "dt_compatible",
+ .type = QEMU_OPT_STRING,
+ .help = "Overrides the \"compatible\" property of the dt root node",
},
{ /* End of list */ }
},
--
1.6.0.2
^ permalink raw reply related [flat|nested] 89+ messages in thread
* [Qemu-devel] [PATCH 64/72] uImage: increase the gzip load size
2012-06-23 23:06 [Qemu-devel] [PULL 00/72] ppc patch queue 2012-06-24 Alexander Graf
` (62 preceding siblings ...)
2012-06-23 23:07 ` [Qemu-devel] [PATCH 63/72] PPC: e500: allow users to set the /compatible property via -machine Alexander Graf
@ 2012-06-23 23:07 ` Alexander Graf
2012-06-23 23:07 ` [Qemu-devel] [PATCH 65/72] PPC: Add some booke SPR defines Alexander Graf
` (8 subsequent siblings)
72 siblings, 0 replies; 89+ messages in thread
From: Alexander Graf @ 2012-06-23 23:07 UTC (permalink / raw)
To: qemu-devel qemu-devel; +Cc: Blue Swirl, qemu-ppc Mailing List, Aurelien Jarno
Recent u-boot has different defines for its gzip extract buffer, but the
common ground seems to be 64MB. So let's bump it up to that, enabling me
to load my test image again ;).
Signed-off-by: Alexander Graf <agraf@suse.de>
---
hw/loader.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/hw/loader.c b/hw/loader.c
index 7d64113..33acc2f 100644
--- a/hw/loader.c
+++ b/hw/loader.c
@@ -377,9 +377,9 @@ static void zfree(void *x, void *addr)
#define DEFLATED 8
-/* This is the maximum in uboot, so if a uImage overflows this, it would
+/* This is the usual maximum in uboot, so if a uImage overflows this, it would
* overflow on real hardware too. */
-#define UBOOT_MAX_GUNZIP_BYTES 0x800000
+#define UBOOT_MAX_GUNZIP_BYTES (64 << 20)
static ssize_t gunzip(void *dst, size_t dstlen, uint8_t *src,
size_t srclen)
--
1.6.0.2
^ permalink raw reply related [flat|nested] 89+ messages in thread
* [Qemu-devel] [PATCH 65/72] PPC: Add some booke SPR defines
2012-06-23 23:06 [Qemu-devel] [PULL 00/72] ppc patch queue 2012-06-24 Alexander Graf
` (63 preceding siblings ...)
2012-06-23 23:07 ` [Qemu-devel] [PATCH 64/72] uImage: increase the gzip load size Alexander Graf
@ 2012-06-23 23:07 ` Alexander Graf
2012-06-23 23:07 ` [Qemu-devel] [PATCH 66/72] PPC: Add support for MSR_CM Alexander Graf
` (7 subsequent siblings)
72 siblings, 0 replies; 89+ messages in thread
From: Alexander Graf @ 2012-06-23 23:07 UTC (permalink / raw)
To: qemu-devel qemu-devel; +Cc: Blue Swirl, qemu-ppc Mailing List, Aurelien Jarno
The number of SPRs avaiable in different PowerPC chip is still increasing. Add
definitions for the MAS7_MAS3 SPR and all currently known bits in EPCR.
Signed-off-by: Alexander Graf <agraf@suse.de>
---
target-ppc/cpu.h | 22 ++++++++++++++++++++++
1 files changed, 22 insertions(+), 0 deletions(-)
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index 67e699c..12200ab 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -1395,6 +1395,7 @@ static inline void cpu_clone_regs(CPUPPCState *env, target_ulong newsp)
#define SPR_BOOKE_TLB1PS (0x159)
#define SPR_BOOKE_TLB2PS (0x15A)
#define SPR_BOOKE_TLB3PS (0x15B)
+#define SPR_BOOKE_MAS7_MAS3 (0x174)
#define SPR_BOOKE_IVOR0 (0x190)
#define SPR_BOOKE_IVOR1 (0x191)
#define SPR_BOOKE_IVOR2 (0x192)
@@ -1762,6 +1763,27 @@ static inline void cpu_clone_regs(CPUPPCState *env, target_ulong newsp)
#define SPR_604_HID15 (0x3FF)
#define SPR_E500_SVR (0x3FF)
+/* Disable MAS Interrupt Updates for Hypervisor */
+#define EPCR_DMIUH (1 << 22)
+/* Disable Guest TLB Management Instructions */
+#define EPCR_DGTMI (1 << 23)
+/* Guest Interrupt Computation Mode */
+#define EPCR_GICM (1 << 24)
+/* Interrupt Computation Mode */
+#define EPCR_ICM (1 << 25)
+/* Disable Embedded Hypervisor Debug */
+#define EPCR_DUVD (1 << 26)
+/* Instruction Storage Interrupt Directed to Guest State */
+#define EPCR_ISIGS (1 << 27)
+/* Data Storage Interrupt Directed to Guest State */
+#define EPCR_DSIGS (1 << 28)
+/* Instruction TLB Error Interrupt Directed to Guest State */
+#define EPCR_ITLBGS (1 << 29)
+/* Data TLB Error Interrupt Directed to Guest State */
+#define EPCR_DTLBGS (1 << 30)
+/* External Input Interrupt Directed to Guest State */
+#define EPCR_EXTGS (1 << 31)
+
/*****************************************************************************/
/* PowerPC Instructions types definitions */
enum {
--
1.6.0.2
^ permalink raw reply related [flat|nested] 89+ messages in thread
* [Qemu-devel] [PATCH 66/72] PPC: Add support for MSR_CM
2012-06-23 23:06 [Qemu-devel] [PULL 00/72] ppc patch queue 2012-06-24 Alexander Graf
` (64 preceding siblings ...)
2012-06-23 23:07 ` [Qemu-devel] [PATCH 65/72] PPC: Add some booke SPR defines Alexander Graf
@ 2012-06-23 23:07 ` Alexander Graf
2012-06-23 23:07 ` [Qemu-devel] [PATCH 67/72] PPC: BookE: Implement EPR SPR Alexander Graf
` (6 subsequent siblings)
72 siblings, 0 replies; 89+ messages in thread
From: Alexander Graf @ 2012-06-23 23:07 UTC (permalink / raw)
To: qemu-devel qemu-devel; +Cc: Blue Swirl, qemu-ppc Mailing List, Aurelien Jarno
The BookE variant of MSR_SF is MSR_CM. Implement everything it takes in TCG to
support running 64bit code with MSR_CM set.
Signed-off-by: Alexander Graf <agraf@suse.de>
---
target-ppc/cpu.h | 9 +++++++++
target-ppc/excp_helper.c | 9 +++++----
target-ppc/mem_helper.c | 2 +-
target-ppc/translate.c | 2 +-
4 files changed, 16 insertions(+), 6 deletions(-)
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index 12200ab..7a77fff 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -2212,6 +2212,15 @@ static inline uint32_t booke206_tlbnps(CPUPPCState *env, const int tlbn)
#endif
+static inline bool msr_is_64bit(CPUPPCState *env, target_ulong msr)
+{
+ if (env->mmu_model == POWERPC_MMU_BOOKE206) {
+ return msr & (1ULL << MSR_CM);
+ }
+
+ return msr & (1ULL << MSR_SF);
+}
+
extern void (*cpu_ppc_hypercall)(CPUPPCState *);
static inline bool cpu_has_work(CPUPPCState *env)
diff --git a/target-ppc/excp_helper.c b/target-ppc/excp_helper.c
index c7762b9..1a593f6 100644
--- a/target-ppc/excp_helper.c
+++ b/target-ppc/excp_helper.c
@@ -608,10 +608,11 @@ static inline void powerpc_excp(CPUPPCState *env, int excp_model, int excp)
vector |= env->excp_prefix;
#if defined(TARGET_PPC64)
if (excp_model == POWERPC_EXCP_BOOKE) {
- if (!msr_icm) {
- vector = (uint32_t)vector;
- } else {
+ if (env->spr[SPR_BOOKE_EPCR] & EPCR_ICM) {
+ /* Cat.64-bit: EPCR.ICM is copied to MSR.CM */
new_msr |= (target_ulong)1 << MSR_CM;
+ } else {
+ vector = (uint32_t)vector;
}
} else {
if (!msr_isf && !(env->mmu_model & POWERPC_MMU_64)) {
@@ -803,7 +804,7 @@ static inline void do_rfi(CPUPPCState *env, target_ulong nip, target_ulong msr,
target_ulong msrm, int keep_msrh)
{
#if defined(TARGET_PPC64)
- if (msr & (1ULL << MSR_SF)) {
+ if (msr_is_64bit(env, msr)) {
nip = (uint64_t)nip;
msr &= (uint64_t)msrm;
} else {
diff --git a/target-ppc/mem_helper.c b/target-ppc/mem_helper.c
index ebcd7b2..5b5f1bd 100644
--- a/target-ppc/mem_helper.c
+++ b/target-ppc/mem_helper.c
@@ -35,7 +35,7 @@ static inline target_ulong addr_add(CPUPPCState *env, target_ulong addr,
target_long arg)
{
#if defined(TARGET_PPC64)
- if (!msr_sf) {
+ if (!msr_is_64bit(env, env->msr)) {
return (uint32_t)(addr + arg);
} else
#endif
diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index 9103fd5..73ee74b 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -9626,7 +9626,7 @@ static inline void gen_intermediate_code_internal(CPUPPCState *env,
ctx.access_type = -1;
ctx.le_mode = env->hflags & (1 << MSR_LE) ? 1 : 0;
#if defined(TARGET_PPC64)
- ctx.sf_mode = msr_sf;
+ ctx.sf_mode = msr_is_64bit(env, env->msr);
ctx.has_cfar = !!(env->flags & POWERPC_FLAG_CFAR);
#endif
ctx.fpu_enabled = msr_fp;
--
1.6.0.2
^ permalink raw reply related [flat|nested] 89+ messages in thread
* [Qemu-devel] [PATCH 67/72] PPC: BookE: Implement EPR SPR
2012-06-23 23:06 [Qemu-devel] [PULL 00/72] ppc patch queue 2012-06-24 Alexander Graf
` (65 preceding siblings ...)
2012-06-23 23:07 ` [Qemu-devel] [PATCH 66/72] PPC: Add support for MSR_CM Alexander Graf
@ 2012-06-23 23:07 ` Alexander Graf
2012-06-23 23:07 ` [Qemu-devel] [PATCH 68/72] PPC: BookE: Make ivpr selectable by CPU type Alexander Graf
` (5 subsequent siblings)
72 siblings, 0 replies; 89+ messages in thread
From: Alexander Graf @ 2012-06-23 23:07 UTC (permalink / raw)
To: qemu-devel qemu-devel; +Cc: Blue Swirl, qemu-ppc Mailing List, Aurelien Jarno
On the e500 series, accessing SPR_EPR magically turns into an access at
that CPU's IACK register on the MPIC. Implement that logic to get kernels
that make use of that feature work.
Signed-off-by: Alexander Graf <agraf@suse.de>
---
hw/ppce500_mpc8544ds.c | 1 +
target-ppc/Makefile.objs | 1 +
target-ppc/cpu.h | 1 +
target-ppc/helper.h | 1 +
target-ppc/mpic_helper.c | 35 +++++++++++++++++++++++++++++++++++
5 files changed, 39 insertions(+), 0 deletions(-)
create mode 100644 target-ppc/mpic_helper.c
diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c
index d38ad99..8b9fd83 100644
--- a/hw/ppce500_mpc8544ds.c
+++ b/hw/ppce500_mpc8544ds.c
@@ -469,6 +469,7 @@ static void mpc8544ds_init(ram_addr_t ram_size,
irqs[i][OPENPIC_OUTPUT_INT] = input[PPCE500_INPUT_INT];
irqs[i][OPENPIC_OUTPUT_CINT] = input[PPCE500_INPUT_CINT];
env->spr[SPR_BOOKE_PIR] = env->cpu_index = i;
+ env->mpic_cpu_base = MPC8544_MPIC_REGS_BASE + 0x20000;
ppc_booke_timers_init(env, 400000000, PPC_TIMER_E500);
diff --git a/target-ppc/Makefile.objs b/target-ppc/Makefile.objs
index 6c11ef8..237a0ed 100644
--- a/target-ppc/Makefile.objs
+++ b/target-ppc/Makefile.objs
@@ -9,3 +9,4 @@ obj-y += mmu_helper.o
obj-y += timebase_helper.o
obj-y += misc_helper.o
obj-y += mem_helper.o
+obj-y += mpic_helper.o
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index 7a77fff..652a35a 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -1066,6 +1066,7 @@ struct CPUPPCState {
target_ulong ivor_mask;
target_ulong ivpr_mask;
target_ulong hreset_vector;
+ target_phys_addr_t mpic_cpu_base;
#endif
/* Those resources are used only during code translation */
diff --git a/target-ppc/helper.h b/target-ppc/helper.h
index ddab97b..fd04c06 100644
--- a/target-ppc/helper.h
+++ b/target-ppc/helper.h
@@ -405,6 +405,7 @@ DEF_HELPER_2(store_40x_dbcr0, void, env, tl)
DEF_HELPER_2(store_40x_sler, void, env, tl)
DEF_HELPER_2(store_booke_tcr, void, env, tl)
DEF_HELPER_2(store_booke_tsr, void, env, tl)
+DEF_HELPER_1(load_epr, tl, env)
DEF_HELPER_3(store_ibatl, void, env, i32, tl)
DEF_HELPER_3(store_ibatu, void, env, i32, tl)
DEF_HELPER_3(store_dbatl, void, env, i32, tl)
diff --git a/target-ppc/mpic_helper.c b/target-ppc/mpic_helper.c
new file mode 100644
index 0000000..2c6a4d3
--- /dev/null
+++ b/target-ppc/mpic_helper.c
@@ -0,0 +1,35 @@
+/*
+ * PowerPC emulation helpers for QEMU.
+ *
+ * Copyright (c) 2003-2007 Jocelyn Mayer
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "cpu.h"
+#include "helper.h"
+
+/*****************************************************************************/
+/* SPR accesses */
+
+#if !defined(CONFIG_USER_ONLY)
+/*
+ * This is an ugly helper for EPR, which is basically the same as accessing
+ * the IACK (PIAC) register on the MPIC. Because we model the MPIC as a device
+ * that can only talk to the CPU through MMIO, let's access it that way!
+ */
+target_ulong helper_load_epr(CPUPPCState *env)
+{
+ return ldl_phys(env->mpic_cpu_base + 0xA0);
+}
+#endif
--
1.6.0.2
^ permalink raw reply related [flat|nested] 89+ messages in thread
* [Qemu-devel] [PATCH 68/72] PPC: BookE: Make ivpr selectable by CPU type
2012-06-23 23:06 [Qemu-devel] [PULL 00/72] ppc patch queue 2012-06-24 Alexander Graf
` (66 preceding siblings ...)
2012-06-23 23:07 ` [Qemu-devel] [PATCH 67/72] PPC: BookE: Implement EPR SPR Alexander Graf
@ 2012-06-23 23:07 ` Alexander Graf
2012-06-23 23:07 ` [Qemu-devel] [PATCH 69/72] PPC: Add e5500 CPU target Alexander Graf
` (4 subsequent siblings)
72 siblings, 0 replies; 89+ messages in thread
From: Alexander Graf @ 2012-06-23 23:07 UTC (permalink / raw)
To: qemu-devel qemu-devel; +Cc: Blue Swirl, qemu-ppc Mailing List, Aurelien Jarno
IVPR can either hold 32 or 64 bit addresses, depending on the CPU type. Let
the CPU initialization function pass in its mask itself, so we can easily
extend it.
Signed-off-by: Alexander Graf <agraf@suse.de>
---
target-ppc/translate_init.c | 9 +++++----
1 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index 57027a2..98695ab 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -2804,7 +2804,7 @@ static void init_excp_G2 (CPUPPCState *env)
#endif
}
-static void init_excp_e200 (CPUPPCState *env)
+static void init_excp_e200(CPUPPCState *env, target_ulong ivpr_mask)
{
#if !defined(CONFIG_USER_ONLY)
env->excp_vectors[POWERPC_EXCP_RESET] = 0x00000FFC;
@@ -2829,7 +2829,7 @@ static void init_excp_e200 (CPUPPCState *env)
env->excp_vectors[POWERPC_EXCP_EFPRI] = 0x00000000;
env->hreset_excp_prefix = 0x00000000UL;
env->ivor_mask = 0x0000FFF7UL;
- env->ivpr_mask = 0xFFFF0000UL;
+ env->ivpr_mask = ivpr_mask;
/* Hardware reset vector */
env->hreset_vector = 0xFFFFFFFCUL;
#endif
@@ -4307,7 +4307,7 @@ static void init_proc_e200 (CPUPPCState *env)
env->id_tlbs = 0;
env->tlb_type = TLB_EMB;
#endif
- init_excp_e200(env);
+ init_excp_e200(env, 0xFFFF0000UL);
env->dcache_line_size = 32;
env->icache_line_size = 32;
/* XXX: TODO: allocate internal IRQ controller */
@@ -4434,6 +4434,7 @@ static void init_proc_e500 (CPUPPCState *env, int version)
{
uint32_t tlbncfg[2];
uint64_t ivor_mask = 0x0000000F0000FFFFULL;
+ uint64_t ivpr_mask = 0xFFFF0000ULL;
uint32_t l1cfg0 = 0x3800 /* 8 ways */
| 0x0020; /* 32 kb */
#if !defined(CONFIG_USER_ONLY)
@@ -4575,7 +4576,7 @@ static void init_proc_e500 (CPUPPCState *env, int version)
}
#endif
- init_excp_e200(env);
+ init_excp_e200(env, ivpr_mask);
/* Allocate hardware IRQ controller */
ppce500_irq_init(env);
}
--
1.6.0.2
^ permalink raw reply related [flat|nested] 89+ messages in thread
* [Qemu-devel] [PATCH 69/72] PPC: Add e5500 CPU target
2012-06-23 23:06 [Qemu-devel] [PULL 00/72] ppc patch queue 2012-06-24 Alexander Graf
` (67 preceding siblings ...)
2012-06-23 23:07 ` [Qemu-devel] [PATCH 68/72] PPC: BookE: Make ivpr selectable by CPU type Alexander Graf
@ 2012-06-23 23:07 ` Alexander Graf
2012-06-23 23:07 ` [Qemu-devel] [PATCH 70/72] PPC: Extract SPR dump generation into its own function Alexander Graf
` (3 subsequent siblings)
72 siblings, 0 replies; 89+ messages in thread
From: Alexander Graf @ 2012-06-23 23:07 UTC (permalink / raw)
To: qemu-devel qemu-devel; +Cc: Blue Swirl, qemu-ppc Mailing List, Aurelien Jarno
This patch adds e5500's CPU initialization to the TCG CPU initialization
code.
Signed-off-by: Alexander Graf <agraf@suse.de>
---
target-ppc/translate_init.c | 96 +++++++++++++++++++++++++++++++++++++++++-
1 files changed, 93 insertions(+), 3 deletions(-)
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index 98695ab..d185aaa 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -4424,16 +4424,69 @@ static void init_proc_e300 (CPUPPCState *env)
#define check_pow_e500mc check_pow_none
#define init_proc_e500mc init_proc_e500mc
+/* e5500 core */
+#define POWERPC_INSNS_e5500 (PPC_INSNS_BASE | PPC_ISEL | \
+ PPC_WRTEE | PPC_RFDI | PPC_RFMCI | \
+ PPC_CACHE | PPC_CACHE_LOCK | PPC_CACHE_ICBI | \
+ PPC_CACHE_DCBZ | PPC_CACHE_DCBA | \
+ PPC_FLOAT | PPC_FLOAT_FRES | \
+ PPC_FLOAT_FRSQRTE | PPC_FLOAT_FSEL | \
+ PPC_FLOAT_STFIWX | PPC_WAIT | \
+ PPC_MEM_TLBSYNC | PPC_TLBIVAX | PPC_MEM_SYNC | \
+ PPC_64B | PPC_POPCNTB | PPC_POPCNTWD)
+#define POWERPC_INSNS2_e5500 (PPC2_BOOKE206 | PPC2_PRCNTL)
+#define POWERPC_MSRM_e5500 (0x000000009402FB36ULL)
+#define POWERPC_MMU_e5500 (POWERPC_MMU_BOOKE206)
+#define POWERPC_EXCP_e5500 (POWERPC_EXCP_BOOKE)
+#define POWERPC_INPUT_e5500 (PPC_FLAGS_INPUT_BookE)
+/* Fixme: figure out the correct flag for e5500 */
+#define POWERPC_BFDM_e5500 (bfd_mach_ppc_e500)
+#define POWERPC_FLAG_e5500 (POWERPC_FLAG_CE | POWERPC_FLAG_DE | \
+ POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK)
+#define check_pow_e5500 check_pow_none
+#define init_proc_e5500 init_proc_e5500
+
+#if !defined(CONFIG_USER_ONLY)
+static void spr_write_mas73(void *opaque, int sprn, int gprn)
+{
+ TCGv val = tcg_temp_new();
+ tcg_gen_ext32u_tl(val, cpu_gpr[gprn]);
+ gen_store_spr(SPR_BOOKE_MAS3, val);
+ tcg_gen_shri_tl(val, gprn, 32);
+ gen_store_spr(SPR_BOOKE_MAS7, val);
+ tcg_temp_free(val);
+}
+
+static void spr_read_mas73(void *opaque, int gprn, int sprn)
+{
+ TCGv mas7 = tcg_temp_new();
+ TCGv mas3 = tcg_temp_new();
+ gen_load_spr(mas7, SPR_BOOKE_MAS7);
+ tcg_gen_shli_tl(mas7, mas7, 32);
+ gen_load_spr(mas3, SPR_BOOKE_MAS3);
+ tcg_gen_or_tl(cpu_gpr[gprn], mas3, mas7);
+ tcg_temp_free(mas3);
+ tcg_temp_free(mas7);
+}
+
+static void spr_load_epr(void *opaque, int gprn, int sprn)
+{
+ gen_helper_load_epr(cpu_gpr[gprn], cpu_env);
+}
+
+#endif
+
enum fsl_e500_version {
fsl_e500v1,
fsl_e500v2,
fsl_e500mc,
+ fsl_e5500,
};
static void init_proc_e500 (CPUPPCState *env, int version)
{
uint32_t tlbncfg[2];
- uint64_t ivor_mask = 0x0000000F0000FFFFULL;
+ uint64_t ivor_mask;
uint64_t ivpr_mask = 0xFFFF0000ULL;
uint32_t l1cfg0 = 0x3800 /* 8 ways */
| 0x0020; /* 32 kb */
@@ -4448,8 +4501,16 @@ static void init_proc_e500 (CPUPPCState *env, int version)
* complain when accessing them.
* gen_spr_BookE(env, 0x0000000F0000FD7FULL);
*/
- if (version == fsl_e500mc) {
- ivor_mask = 0x000003FE0000FFFFULL;
+ switch (version) {
+ case fsl_e500v1:
+ case fsl_e500v2:
+ default:
+ ivor_mask = 0x0000000F0000FFFFULL;
+ break;
+ case fsl_e500mc:
+ case fsl_e5500:
+ ivor_mask = 0x000003FE0000FFFFULL;
+ break;
}
gen_spr_BookE(env, ivor_mask);
/* Processor identification */
@@ -4477,6 +4538,7 @@ static void init_proc_e500 (CPUPPCState *env, int version)
tlbncfg[1] = gen_tlbncfg(16, 1, 12, TLBnCFG_AVAIL | TLBnCFG_IPROT, 16);
break;
case fsl_e500mc:
+ case fsl_e5500:
tlbncfg[0] = gen_tlbncfg(4, 1, 1, 0, 512);
tlbncfg[1] = gen_tlbncfg(64, 1, 12, TLBnCFG_AVAIL | TLBnCFG_IPROT, 64);
break;
@@ -4492,6 +4554,7 @@ static void init_proc_e500 (CPUPPCState *env, int version)
env->icache_line_size = 32;
break;
case fsl_e500mc:
+ case fsl_e5500:
env->dcache_line_size = 64;
env->icache_line_size = 64;
l1cfg0 |= 0x1000000; /* 64 byte cache block size */
@@ -4567,6 +4630,22 @@ static void init_proc_e500 (CPUPPCState *env, int version)
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_booke206_mmucsr0,
0x00000000);
+ spr_register(env, SPR_BOOKE_EPR, "EPR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_load_epr, SPR_NOACCESS,
+ 0x00000000);
+ /* XXX better abstract into Emb.xxx features */
+ if (version == fsl_e5500) {
+ spr_register(env, SPR_BOOKE_EPCR, "EPCR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_BOOKE_MAS7_MAS3, "MAS7_MAS3",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_mas73, &spr_write_mas73,
+ 0x00000000);
+ ivpr_mask = (target_ulong)~0xFFFFULL;
+ }
#if !defined(CONFIG_USER_ONLY)
env->nb_tlb = 0;
@@ -4596,6 +4675,13 @@ static void init_proc_e500mc(CPUPPCState *env)
init_proc_e500(env, fsl_e500mc);
}
+#ifdef TARGET_PPC64
+static void init_proc_e5500(CPUPPCState *env)
+{
+ init_proc_e500(env, fsl_e5500);
+}
+#endif
+
/* Non-embedded PowerPC */
/* POWER : same as 601, without mfmsr, mfsr */
@@ -7134,6 +7220,7 @@ enum {
CPU_POWERPC_e500v2_v22 = 0x80210022,
CPU_POWERPC_e500v2_v30 = 0x80210030,
CPU_POWERPC_e500mc = 0x80230020,
+ CPU_POWERPC_e5500 = 0x80240020,
/* MPC85xx microcontrollers */
#define CPU_POWERPC_MPC8533 CPU_POWERPC_MPC8533_v11
#define CPU_POWERPC_MPC8533_v10 CPU_POWERPC_e500v2_v21
@@ -8528,6 +8615,9 @@ static const ppc_def_t ppc_defs[] = {
/* PowerPC e500v2 v3.0 core */
POWERPC_DEF("e500v2_v30", CPU_POWERPC_e500v2_v30, e500v2),
POWERPC_DEF("e500mc", CPU_POWERPC_e500mc, e500mc),
+#ifdef TARGET_PPC64
+ POWERPC_DEF("e5500", CPU_POWERPC_e5500, e5500),
+#endif
/* PowerPC e500 microcontrollers */
/* MPC8533 */
POWERPC_DEF_SVR("MPC8533",
--
1.6.0.2
^ permalink raw reply related [flat|nested] 89+ messages in thread
* [Qemu-devel] [PATCH 70/72] PPC: Extract SPR dump generation into its own function
2012-06-23 23:06 [Qemu-devel] [PULL 00/72] ppc patch queue 2012-06-24 Alexander Graf
` (68 preceding siblings ...)
2012-06-23 23:07 ` [Qemu-devel] [PATCH 69/72] PPC: Add e5500 CPU target Alexander Graf
@ 2012-06-23 23:07 ` Alexander Graf
2012-06-23 23:07 ` [Qemu-devel] [PATCH 71/72] PPC: BookE: Support 32 and 64 bit wide MAS2 Alexander Graf
` (2 subsequent siblings)
72 siblings, 0 replies; 89+ messages in thread
From: Alexander Graf @ 2012-06-23 23:07 UTC (permalink / raw)
To: qemu-devel qemu-devel; +Cc: Blue Swirl, qemu-ppc Mailing List, Aurelien Jarno
This patch moves the debug #ifdef'ed SPR trace generation into its
own function, so we can call it from multiple places.
Signed-off-by: Alexander Graf <agraf@suse.de>
---
target-ppc/translate_init.c | 30 ++++++++++++++++++------------
1 files changed, 18 insertions(+), 12 deletions(-)
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index d185aaa..8ff47ae 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -55,28 +55,34 @@ PPC_IRQ_INIT_FN(e500);
/* Generic callbacks:
* do nothing but store/retrieve spr value
*/
+static void spr_load_dump_spr(int sprn)
+{
+#ifdef PPC_DUMP_SPR_ACCESSES
+ TCGv_i32 t0 = tcg_const_i32(sprn);
+ gen_helper_load_dump_spr(t0);
+ tcg_temp_free_i32(t0);
+#endif
+}
+
static void spr_read_generic (void *opaque, int gprn, int sprn)
{
gen_load_spr(cpu_gpr[gprn], sprn);
+ spr_load_dump_spr(sprn);
+}
+
+static void spr_store_dump_spr(int sprn)
+{
#ifdef PPC_DUMP_SPR_ACCESSES
- {
- TCGv_i32 t0 = tcg_const_i32(sprn);
- gen_helper_load_dump_spr(t0);
- tcg_temp_free_i32(t0);
- }
+ TCGv_i32 t0 = tcg_const_i32(sprn);
+ gen_helper_store_dump_spr(t0);
+ tcg_temp_free_i32(t0);
#endif
}
static void spr_write_generic (void *opaque, int sprn, int gprn)
{
gen_store_spr(sprn, cpu_gpr[gprn]);
-#ifdef PPC_DUMP_SPR_ACCESSES
- {
- TCGv_i32 t0 = tcg_const_i32(sprn);
- gen_helper_store_dump_spr(t0);
- tcg_temp_free_i32(t0);
- }
-#endif
+ spr_store_dump_spr(sprn);
}
#if !defined(CONFIG_USER_ONLY)
--
1.6.0.2
^ permalink raw reply related [flat|nested] 89+ messages in thread
* [Qemu-devel] [PATCH 71/72] PPC: BookE: Support 32 and 64 bit wide MAS2
2012-06-23 23:06 [Qemu-devel] [PULL 00/72] ppc patch queue 2012-06-24 Alexander Graf
` (69 preceding siblings ...)
2012-06-23 23:07 ` [Qemu-devel] [PATCH 70/72] PPC: Extract SPR dump generation into its own function Alexander Graf
@ 2012-06-23 23:07 ` Alexander Graf
2012-06-23 23:07 ` [Qemu-devel] [PATCH 72/72] PPC: BookE206: Bump MAS2 to 64bit Alexander Graf
2012-06-24 12:27 ` [Qemu-devel] [PULL 00/72] ppc patch queue 2012-06-24 Blue Swirl
72 siblings, 0 replies; 89+ messages in thread
From: Alexander Graf @ 2012-06-23 23:07 UTC (permalink / raw)
To: qemu-devel qemu-devel; +Cc: Blue Swirl, qemu-ppc Mailing List, Aurelien Jarno
The MAS registers on BookE are all 32 bit wide, except for MAS2, which
can hold up to 64 bit on 64 bit capable CPUs. Reflect this in the SPR
setting code, so that the guest can never write invalid values in them.
Signed-off-by: Alexander Graf <agraf@suse.de>
---
target-ppc/translate_init.c | 19 ++++++++++++++++++-
1 files changed, 18 insertions(+), 1 deletions(-)
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index 8ff47ae..e6580ff 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -86,6 +86,19 @@ static void spr_write_generic (void *opaque, int sprn, int gprn)
}
#if !defined(CONFIG_USER_ONLY)
+static void spr_write_generic32(void *opaque, int sprn, int gprn)
+{
+#ifdef TARGET_PPC64
+ TCGv t0 = tcg_temp_new();
+ tcg_gen_ext32u_tl(t0, cpu_gpr[gprn]);
+ gen_store_spr(sprn, t0);
+ tcg_temp_free(t0);
+ spr_store_dump_spr(sprn);
+#else
+ spr_write_generic(opaque, sprn, gprn);
+#endif
+}
+
static void spr_write_clear (void *opaque, int sprn, int gprn)
{
TCGv t0 = tcg_temp_new();
@@ -1597,10 +1610,14 @@ static void gen_spr_BookE206(CPUPPCState *env, uint32_t mas_mask,
/* TLB assist registers */
/* XXX : not implemented */
for (i = 0; i < 8; i++) {
+ void (*uea_write)(void *o, int sprn, int gprn) = &spr_write_generic32;
+ if (i == 2 && (mas_mask & (1 << i)) && (env->insns_flags & PPC_64B)) {
+ uea_write = &spr_write_generic;
+ }
if (mas_mask & (1 << i)) {
spr_register(env, mas_sprn[i], mas_names[i],
SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
+ &spr_read_generic, uea_write,
0x00000000);
}
}
--
1.6.0.2
^ permalink raw reply related [flat|nested] 89+ messages in thread
* [Qemu-devel] [PATCH 72/72] PPC: BookE206: Bump MAS2 to 64bit
2012-06-23 23:06 [Qemu-devel] [PULL 00/72] ppc patch queue 2012-06-24 Alexander Graf
` (70 preceding siblings ...)
2012-06-23 23:07 ` [Qemu-devel] [PATCH 71/72] PPC: BookE: Support 32 and 64 bit wide MAS2 Alexander Graf
@ 2012-06-23 23:07 ` Alexander Graf
2012-06-24 12:27 ` [Qemu-devel] [PULL 00/72] ppc patch queue 2012-06-24 Blue Swirl
72 siblings, 0 replies; 89+ messages in thread
From: Alexander Graf @ 2012-06-23 23:07 UTC (permalink / raw)
To: qemu-devel qemu-devel; +Cc: Blue Swirl, qemu-ppc Mailing List, Aurelien Jarno
On 64bit capable systems, MAS2 can actually hold a 64bit virtual page
address. So increase the mask for its EPN.
Signed-off-by: Alexander Graf <agraf@suse.de>
---
target-ppc/cpu.h | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index 652a35a..ca2fc21 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -693,7 +693,7 @@ enum {
#define MAS1_VALID 0x80000000
#define MAS2_EPN_SHIFT 12
-#define MAS2_EPN_MASK (0xfffff << MAS2_EPN_SHIFT)
+#define MAS2_EPN_MASK (~0ULL << MAS2_EPN_SHIFT)
#define MAS2_ACM_SHIFT 6
#define MAS2_ACM (1 << MAS2_ACM_SHIFT)
--
1.6.0.2
^ permalink raw reply related [flat|nested] 89+ messages in thread
* Re: [Qemu-devel] [PULL 00/72] ppc patch queue 2012-06-24
2012-06-23 23:06 [Qemu-devel] [PULL 00/72] ppc patch queue 2012-06-24 Alexander Graf
` (71 preceding siblings ...)
2012-06-23 23:07 ` [Qemu-devel] [PATCH 72/72] PPC: BookE206: Bump MAS2 to 64bit Alexander Graf
@ 2012-06-24 12:27 ` Blue Swirl
72 siblings, 0 replies; 89+ messages in thread
From: Blue Swirl @ 2012-06-24 12:27 UTC (permalink / raw)
To: Alexander Graf
Cc: qemu-ppc Mailing List, qemu-devel qemu-devel, Aurelien Jarno
On Sat, Jun 23, 2012 at 11:06 PM, Alexander Graf <agraf@suse.de> wrote:
> Hi Blue / Aurelien,
>
> This is my current patch queue for ppc. Please pull.
Thanks, pulled.
>
> Alex
>
>
> The following changes since commit affe5189907f397514cdd4ee7446595c1246a0e9:
> Alexander Graf (1):
> TCG: Fix compile breakage in tcg_dump_ops
>
> are available in the git repository at:
>
> git://repo.or.cz/qemu/agraf.git ppc-for-upstream
>
> Alexander Graf (43):
> PPC: mpc8544ds: Span initial TLB entry over as much RAM as we need
> dt: allow add_subnode to create root subnodes
> dt: add helpers for multi-cell adds
> dt: add helper for phandle references
> dt: temporarily disable subtree creation failure check
> dt: add helper for phandle enumeration
> dt: add helper for empty dt creation
> dt: add helper for phandle allocation
> dt: add helper for 64bit cell adds
> PPC: e500: require libfdt
> PPC: e500: dt: create memory node dynamically
> PPC: e500: dt: create /cpus node dynamically
> PPC: e500: dt: create /hypervisor node dynamically
> PPC: e500: dt: create / node dynamically
> PPC: e500: dt: create /chosen node dynamically
> PPC: e500: dt: create /soc8544 node dynamically
> PPC: e500: dt: create serial nodes dynamically
> PPC: e500: dt: create mpic node dynamically
> PPC: e500: dt: create global-utils node dynamically
> PPC: e500: dt: create pci node dynamically
> PPC: e500: dt: start with empty device tree
> dt: Add -machine dumpdtb option to dump the current dtb
> PPC: e500: dt: use 64bit cell helper
> PPC: e500: dt: use target_phys_addr_t for ramsize
> PPC: e500: enable manual loading of dtb blob
> Revert "dt: temporarily disable subtree creation failure check"
> PPC: e500: Use new MPIC dt format
> PPC: e500: Use new SOC dt format
> PPC: e500: Define addresses as always 64bit
> PPC: e500: Extend address/size of / to 64bit
> dt: Add global option to set phandle start offset
> PPC: e500: Refactor serial dt generation
> dt: make setprop argument static
> PPC: e500: allow users to set the /compatible property via -machine
> uImage: increase the gzip load size
> PPC: Add some booke SPR defines
> PPC: Add support for MSR_CM
> PPC: BookE: Implement EPR SPR
> PPC: BookE: Make ivpr selectable by CPU type
> PPC: Add e5500 CPU target
> PPC: Extract SPR dump generation into its own function
> PPC: BookE: Support 32 and 64 bit wide MAS2
> PPC: BookE206: Bump MAS2 to 64bit
>
> Benjamin Herrenschmidt (4):
> ppc64: Rudimentary Support for extra page sizes on server CPUs
> pseries: Correctly create ibm,segment-page-sizes property
> spapr_vscsi: Error handling fixes
> spapr: Add "memop" hypercall
>
> Blue Swirl (22):
> ppc: Fix coding style in op_helper.c
> ppc: Split exception helpers
> ppc: Avoid AREG0 for exception helpers
> ppc: Fix coding style in helper.c
> ppc: Move exception helpers from helper.c to excp_helper.c
> ppc: Split FPU and SPE ops
> ppc: Avoid AREG0 for FPU and SPE helpers
> ppc: Split integer and vector ops
> ppc: Avoid AREG0 for integer and vector helpers
> ppc: Split MMU etc. helpers from op_helper.c
> ppc: Avoid AREG0 for MMU etc. helpers
> ppc: Avoid a warning with the next patch
> ppc: Move MMU helpers from helper.c to mmu_helper.c
> ppc: Cleanup MMU merge
> ppc: Split off timebase helpers
> ppc: Avoid AREG0 for timebase helpers
> ppc: Split off misc helpers
> ppc: Avoid AREG0 for misc helpers
> ppc: Move misc helpers from helper.c to misc_helper.c
> ppc: Move load and store helpers, switch to AREG0 free mode
> ppc: Add missing break
> ppc: Make hbrev table const
>
> Fabien Chouteau (2):
> Avoid segfault in cpu_dump_state
> booke_206_tlbwe: Discard invalid bits in MAS2
>
> Kevin Wolf (1):
> raw-posix: Fix build without is_allocated support
>
> Makefile | 1 -
> block/raw-posix.c | 9 +-
> configure | 2 +-
> cpu-all.h | 9 +
> device_tree.c | 108 +-
> device_tree.h | 22 +-
> docs/specs/ppc-spapr-hcalls.txt | 78 +
> hw/loader.c | 4 +-
> hw/ppc/Makefile.objs | 2 +-
> hw/ppce500_mpc8544ds.c | 283 ++-
> hw/spapr.c | 46 +
> hw/spapr.h | 3 +-
> hw/spapr_hcall.c | 68 +
> hw/spapr_vscsi.c | 4 +-
> pc-bios/mpc8544ds.dtb | Bin 2028 -> 0 bytes
> pc-bios/mpc8544ds.dts | 119 -
> qemu-config.c | 12 +
> qemu-log.h | 4 +-
> target-ppc/Makefile.objs | 14 +-
> target-ppc/cpu.h | 88 +-
> target-ppc/excp_helper.c | 969 +++++++++
> target-ppc/fpu_helper.c | 1740 +++++++++++++++
> target-ppc/helper.c | 3168 +---------------------------
> target-ppc/helper.h | 573 +++---
> target-ppc/int_helper.c | 1564 ++++++++++++++
> target-ppc/kvm.c | 208 ++
> target-ppc/kvm_ppc.h | 5 +
> target-ppc/mem_helper.c | 295 +++
> target-ppc/misc_helper.c | 124 ++
> target-ppc/mmu_helper.c | 3326 ++++++++++++++++++++++++++++
> target-ppc/mpic_helper.c | 35 +
> target-ppc/op_helper.c | 4568 ---------------------------------------
> target-ppc/timebase_helper.c | 159 ++
> target-ppc/translate.c | 462 +++--
> target-ppc/translate_init.c | 249 ++-
> 35 files changed, 9858 insertions(+), 8463 deletions(-)
> create mode 100644 docs/specs/ppc-spapr-hcalls.txt
> delete mode 100644 pc-bios/mpc8544ds.dtb
> delete mode 100644 pc-bios/mpc8544ds.dts
> create mode 100644 target-ppc/excp_helper.c
> create mode 100644 target-ppc/fpu_helper.c
> create mode 100644 target-ppc/int_helper.c
> create mode 100644 target-ppc/mem_helper.c
> create mode 100644 target-ppc/misc_helper.c
> create mode 100644 target-ppc/mmu_helper.c
> create mode 100644 target-ppc/mpic_helper.c
> delete mode 100644 target-ppc/op_helper.c
> create mode 100644 target-ppc/timebase_helper.c
^ permalink raw reply [flat|nested] 89+ messages in thread
* Re: [Qemu-devel] [Qemu-ppc] [PATCH 56/72] PPC: e500: Use new MPIC dt format
2012-06-23 23:07 ` [Qemu-devel] [PATCH 56/72] PPC: e500: Use new MPIC dt format Alexander Graf
@ 2012-08-08 21:16 ` Alexander Graf
2012-08-08 22:40 ` Scott Wood
2012-08-08 22:40 ` [Qemu-devel] " Peter Maydell
1 sibling, 1 reply; 89+ messages in thread
From: Alexander Graf @ 2012-08-08 21:16 UTC (permalink / raw)
To: qemu-devel qemu-devel; +Cc: Scott Wood, qemu-ppc Mailing List
On 24.06.2012, at 01:07, Alexander Graf wrote:
> Due to popular demand, we're updating the way we generate the MPIC
> node and interrupt lines based on what the current state of art is.
>
> Requested-by: Scott Wood <scottwood@freescale.com>
> Signed-off-by: Alexander Graf <agraf@suse.de>
Hey Scott,
This patch breaks SMP for me. The reason for the breakage is that Linux does some things differently when it finds an fsl,mpic instead of a generic openpic. I have assembled logs between a working version (compatible openpic) and a broken version (compatible fsl,mpic) with guest and host debug turned on.
Maybe you have an idea what's going wrong.
Alex
--- log.fails 2012-08-08 23:06:59.000000000 +0200
+++ log.works 2012-08-08 23:07:13.000000000 +0200
@@ -51,34 +51,34 @@
mpic: Initializing for 256 sources
openpic_cpu_write_internal: cpu 0 addr 0000000000000080 <= 0000000f
mpic_timer_write: addr 0000000000000040 <= 00000001
-mpic_timer_write: addr 0000000000000030 <= 800907f3
-Set IDE 76 to 0x800007f3
+mpic_timer_write: addr 0000000000000030 <= 800900f3
+Set IDE 76 to 0x800000f3
mpic_timer_write: addr 0000000000000080 <= 00000001
-mpic_timer_write: addr 0000000000000070 <= 800907f4
-Set IDE 77 to 0x800007f4
+mpic_timer_write: addr 0000000000000070 <= 800900f4
+Set IDE 77 to 0x800000f4
mpic_timer_write: addr 00000000000000c0 <= 00000001
-mpic_timer_write: addr 00000000000000b0 <= 800907f5
-Set IDE 78 to 0x800007f5
+mpic_timer_write: addr 00000000000000b0 <= 800900f5
+Set IDE 78 to 0x800000f5
mpic_timer_write: addr 0000000000000100 <= 00000001
-mpic_timer_write: addr 00000000000000f0 <= 800907f6
+mpic_timer_write: addr 00000000000000f0 <= 800900f6
openpic_gbl_write: addr 00000000000010a0 <= 80000000
openpic_update_irq: IRQ 92 is not pending
Set IPVP 92 to 0x80000000 -> 0x80000000
openpic_gbl_read: addr 00000000000010a0
openpic_gbl_read: => 80000000
-openpic_gbl_write: addr 00000000000010a0 <= 800a07fb
+openpic_gbl_write: addr 00000000000010a0 <= 800a00fb
openpic_update_irq: IRQ 92 is not pending
-Set IPVP 92 to 0x800a07fb -> 0x800a00fb
-openpic_gbl_write: addr 00000000000010b0 <= 800a07fc
+Set IPVP 92 to 0x800a00fb -> 0x800a00fb
+openpic_gbl_write: addr 00000000000010b0 <= 800a00fc
openpic_update_irq: IRQ 93 is not pending
-Set IPVP 93 to 0x800a07fc -> 0x800a00fc
-openpic_gbl_write: addr 00000000000010c0 <= 800a07fd
+Set IPVP 93 to 0x800a00fc -> 0x800a00fc
+openpic_gbl_write: addr 00000000000010c0 <= 800a00fd
openpic_update_irq: IRQ 94 is not pending
-Set IPVP 94 to 0x800a07fd -> 0x800a00fd
-openpic_gbl_write: addr 00000000000010d0 <= 800a07fe
+Set IPVP 94 to 0x800a00fd -> 0x800a00fd
+openpic_gbl_write: addr 00000000000010d0 <= 800a00fe
openpic_update_irq: IRQ 95 is not pending
-Set IPVP 95 to 0x800a07fe -> 0x800a00fe
-MPIC flags: 9102
+Set IPVP 95 to 0x800a00fe -> 0x800a00fe
+MPIC flags: 1002
mpic_src_ext_write: addr 0000000000000000 <= 80080000
openpic_update_irq: IRQ 0 is not pending
Set IPVP 0 to 0x80080000 -> 0x80080000
@@ -542,7 +542,7 @@
mpic_src_msi_write: addr 00000000000000f0 <= 00000001
Set IDE 91 to 0x00000001
mpic_src_msi_write: addr 0000000000000100 <= 800800e8
-openpic_gbl_write: addr 00000000000010e0 <= 000007ff
+openpic_gbl_write: addr 00000000000010e0 <= 000000ff
openpic_gbl_read: addr 0000000000001020
openpic_gbl_read: => 00000000
openpic_gbl_write: addr 0000000000001020 <= 20000000
@@ -554,31 +554,31 @@
smp_mpic_probe()...
nr_cpus: 2
mpic: requesting IPIs...
-mpic: map virq 507, hwirq 0x7fb
+mpic: map virq 251, hwirq 0xfb
mpic: mapping as IPI
- OpenPIC : enable_ipi: 507 (ipi 0)
+ OpenPIC : enable_ipi: 251 (ipi 0)
openpic_gbl_read: addr 00000000000010a0
openpic_gbl_read: => 800a00fb
openpic_gbl_write: addr 00000000000010a0 <= 000a00fb
openpic_update_irq: IRQ 92 is not pending
Set IPVP 92 to 0x000a00fb -> 0x000a00fb
-mpic: map virq 508, hwirq 0x7fc
+mpic: map virq 252, hwirq 0xfc
mpic: mapping as IPI
- OpenPIC : enable_ipi: 508 (ipi 1)
+ OpenPIC : enable_ipi: 252 (ipi 1)
openpic_gbl_read: addr 00000000000010b0
openpic_gbl_read: => 800a00fc
openpic_gbl_write: addr 00000000000010b0 <= 000a00fc
openpic_update_irq: IRQ 93 is not pending
Set IPVP 93 to 0x000a00fc -> 0x000a00fc
-mpic: map virq 509, hwirq 0x7fd
+mpic: map virq 253, hwirq 0xfd
mpic: mapping as IPI
- OpenPIC : enable_ipi: 509 (ipi 2)
+ OpenPIC : enable_ipi: 253 (ipi 2)
openpic_gbl_read: addr 00000000000010c0
openpic_gbl_read: => 800a00fd
openpic_gbl_write: addr 00000000000010c0 <= 000a00fd
openpic_update_irq: IRQ 94 is not pending
Set IPVP 94 to 0x000a00fd -> 0x000a00fd
-mpic: map virq 510, hwirq 0x7fe
+mpic: map virq 254, hwirq 0xfe
mpic: mapping as IPI
OpenPIC : setup_this_cpu(1)
openpic_cpu_write_internal: cpu 1 addr 0000000000001080 <= 00000000
@@ -595,6 +595,11 @@
PIAC: irq=93
openpic_cpu_read_internal: => 000000fc
OpenPIC : get_one_irq(reg 0xa0): 252
+openpic_cpu_write_internal: cpu 1 addr 00000000000010b0 <= 00000000
+PEOI
+IRQ_check: irq 93 set ipvp_pr=10 pr=-1
+openpic_cpu_read_internal: cpu 1 addr 0000000000001090
+openpic_cpu_read_internal: => 00000001
OpenPIC : send_ipi(ipi_no: 1)
openpic_cpu_write_internal: cpu 1 addr 0000000000001050 <= 00000001
Set IDE 93 to 0x00000001
^ permalink raw reply [flat|nested] 89+ messages in thread
* Re: [Qemu-devel] [Qemu-ppc] [PATCH 56/72] PPC: e500: Use new MPIC dt format
2012-08-08 21:16 ` [Qemu-devel] [Qemu-ppc] " Alexander Graf
@ 2012-08-08 22:40 ` Scott Wood
2012-08-09 20:48 ` Alexander Graf
0 siblings, 1 reply; 89+ messages in thread
From: Scott Wood @ 2012-08-08 22:40 UTC (permalink / raw)
To: Alexander Graf; +Cc: qemu-ppc Mailing List, qemu-devel qemu-devel
On 08/08/2012 04:16 PM, Alexander Graf wrote:
>
> On 24.06.2012, at 01:07, Alexander Graf wrote:
>
>> Due to popular demand, we're updating the way we generate the MPIC
>> node and interrupt lines based on what the current state of art is.
>>
>> Requested-by: Scott Wood <scottwood@freescale.com>
>> Signed-off-by: Alexander Graf <agraf@suse.de>
>
> Hey Scott,
>
> This patch breaks SMP for me. The reason for the breakage is that
> Linux does some things differently when it finds an fsl,mpic instead
> of a generic openpic. I have assembled logs between a working version
> (compatible openpic) and a broken version (compatible fsl,mpic) with
> guest and host debug turned on.
>
> Maybe you have an idea what's going wrong.
IIRC QEMU is missing support for large vectors, which is probably
breaking IPIs. A recent change to Linux has it assuming it can use
large vectors when it sees fsl,mpic, as we're running out of vectors (on
p4080 MSIs collided with the arbitrarily chosen timer vector, and on
t4240 the normal internal interrupts alone go beyond 256).
We need to get the enhancements from our internal KVM MPIC back into QEMU.
-Scott
^ permalink raw reply [flat|nested] 89+ messages in thread
* Re: [Qemu-devel] [PATCH 56/72] PPC: e500: Use new MPIC dt format
2012-06-23 23:07 ` [Qemu-devel] [PATCH 56/72] PPC: e500: Use new MPIC dt format Alexander Graf
2012-08-08 21:16 ` [Qemu-devel] [Qemu-ppc] " Alexander Graf
@ 2012-08-08 22:40 ` Peter Maydell
2012-08-08 22:43 ` Peter Maydell
1 sibling, 1 reply; 89+ messages in thread
From: Peter Maydell @ 2012-08-08 22:40 UTC (permalink / raw)
To: Alexander Graf
Cc: Blue Swirl, qemu-ppc Mailing List, qemu-devel qemu-devel,
Aurelien Jarno
On 24 June 2012 00:07, Alexander Graf <agraf@suse.de> wrote:
> Due to popular demand, we're updating the way we generate the MPIC
> node and interrupt lines based on what the current state of art is.
Any chance of a slightly more detailed commit message?
thanks
-- PMM
^ permalink raw reply [flat|nested] 89+ messages in thread
* Re: [Qemu-devel] [PATCH 56/72] PPC: e500: Use new MPIC dt format
2012-08-08 22:40 ` [Qemu-devel] " Peter Maydell
@ 2012-08-08 22:43 ` Peter Maydell
0 siblings, 0 replies; 89+ messages in thread
From: Peter Maydell @ 2012-08-08 22:43 UTC (permalink / raw)
To: Alexander Graf
Cc: Blue Swirl, qemu-ppc Mailing List, qemu-devel qemu-devel,
Aurelien Jarno
On 8 August 2012 23:40, Peter Maydell <peter.maydell@linaro.org> wrote:
> On 24 June 2012 00:07, Alexander Graf <agraf@suse.de> wrote:
>> Due to popular demand, we're updating the way we generate the MPIC
>> node and interrupt lines based on what the current state of art is.
>
> Any chance of a slightly more detailed commit message?
Whoops, didn't realise this was an old already-committed patch. Never mind...
-- PMM
^ permalink raw reply [flat|nested] 89+ messages in thread
* Re: [Qemu-devel] [Qemu-ppc] [PATCH 56/72] PPC: e500: Use new MPIC dt format
2012-08-08 22:40 ` Scott Wood
@ 2012-08-09 20:48 ` Alexander Graf
2012-08-09 20:50 ` Scott Wood
0 siblings, 1 reply; 89+ messages in thread
From: Alexander Graf @ 2012-08-09 20:48 UTC (permalink / raw)
To: Scott Wood; +Cc: qemu-ppc Mailing List, qemu-devel qemu-devel
On 09.08.2012, at 00:40, Scott Wood wrote:
> On 08/08/2012 04:16 PM, Alexander Graf wrote:
>>
>> On 24.06.2012, at 01:07, Alexander Graf wrote:
>>
>>> Due to popular demand, we're updating the way we generate the MPIC
>>> node and interrupt lines based on what the current state of art is.
>>>
>>> Requested-by: Scott Wood <scottwood@freescale.com>
>>> Signed-off-by: Alexander Graf <agraf@suse.de>
>>
>> Hey Scott,
>>
>> This patch breaks SMP for me. The reason for the breakage is that
>> Linux does some things differently when it finds an fsl,mpic instead
>> of a generic openpic. I have assembled logs between a working version
>> (compatible openpic) and a broken version (compatible fsl,mpic) with
>> guest and host debug turned on.
>>
>> Maybe you have an idea what's going wrong.
>
> IIRC QEMU is missing support for large vectors, which is probably
> breaking IPIs. A recent change to Linux has it assuming it can use
> large vectors when it sees fsl,mpic, as we're running out of vectors (on
> p4080 MSIs collided with the arbitrarily chosen timer vector, and on
> t4240 the normal internal interrupts alone go beyond 256).
>
> We need to get the enhancements from our internal KVM MPIC back into QEMU.
Ok, so the quick fix for 1.2 would be to revert to the old compatible name. Can we leave the 4-field interrupt numbers or do we need to revert the whole patch?
Alex
^ permalink raw reply [flat|nested] 89+ messages in thread
* Re: [Qemu-devel] [Qemu-ppc] [PATCH 56/72] PPC: e500: Use new MPIC dt format
2012-08-09 20:48 ` Alexander Graf
@ 2012-08-09 20:50 ` Scott Wood
2012-08-09 20:52 ` Alexander Graf
0 siblings, 1 reply; 89+ messages in thread
From: Scott Wood @ 2012-08-09 20:50 UTC (permalink / raw)
To: Alexander Graf; +Cc: qemu-ppc Mailing List, qemu-devel qemu-devel
On 08/09/2012 03:48 PM, Alexander Graf wrote:
>
> On 09.08.2012, at 00:40, Scott Wood wrote:
>
>> On 08/08/2012 04:16 PM, Alexander Graf wrote:
>>>
>>> On 24.06.2012, at 01:07, Alexander Graf wrote:
>>>
>>>> Due to popular demand, we're updating the way we generate the MPIC
>>>> node and interrupt lines based on what the current state of art is.
>>>>
>>>> Requested-by: Scott Wood <scottwood@freescale.com>
>>>> Signed-off-by: Alexander Graf <agraf@suse.de>
>>>
>>> Hey Scott,
>>>
>>> This patch breaks SMP for me. The reason for the breakage is that
>>> Linux does some things differently when it finds an fsl,mpic instead
>>> of a generic openpic. I have assembled logs between a working version
>>> (compatible openpic) and a broken version (compatible fsl,mpic) with
>>> guest and host debug turned on.
>>>
>>> Maybe you have an idea what's going wrong.
>>
>> IIRC QEMU is missing support for large vectors, which is probably
>> breaking IPIs. A recent change to Linux has it assuming it can use
>> large vectors when it sees fsl,mpic, as we're running out of vectors (on
>> p4080 MSIs collided with the arbitrarily chosen timer vector, and on
>> t4240 the normal internal interrupts alone go beyond 256).
>>
>> We need to get the enhancements from our internal KVM MPIC back into QEMU.
>
> Ok, so the quick fix for 1.2 would be to revert to the old compatible
> name. Can we leave the 4-field interrupt numbers or do we need to
> revert the whole patch?
In theory you shouldn't have 4-cell interrupt numbers without fsl,mpic,
but I don't think it will actually break in Linux -- the extra cells
should just be ignored.
-Scott
^ permalink raw reply [flat|nested] 89+ messages in thread
* Re: [Qemu-devel] [Qemu-ppc] [PATCH 56/72] PPC: e500: Use new MPIC dt format
2012-08-09 20:50 ` Scott Wood
@ 2012-08-09 20:52 ` Alexander Graf
2012-08-09 20:58 ` Scott Wood
0 siblings, 1 reply; 89+ messages in thread
From: Alexander Graf @ 2012-08-09 20:52 UTC (permalink / raw)
To: Scott Wood; +Cc: qemu-ppc Mailing List, qemu-devel qemu-devel
On 09.08.2012, at 22:50, Scott Wood wrote:
> On 08/09/2012 03:48 PM, Alexander Graf wrote:
>>
>> On 09.08.2012, at 00:40, Scott Wood wrote:
>>
>>> On 08/08/2012 04:16 PM, Alexander Graf wrote:
>>>>
>>>> On 24.06.2012, at 01:07, Alexander Graf wrote:
>>>>
>>>>> Due to popular demand, we're updating the way we generate the MPIC
>>>>> node and interrupt lines based on what the current state of art is.
>>>>>
>>>>> Requested-by: Scott Wood <scottwood@freescale.com>
>>>>> Signed-off-by: Alexander Graf <agraf@suse.de>
>>>>
>>>> Hey Scott,
>>>>
>>>> This patch breaks SMP for me. The reason for the breakage is that
>>>> Linux does some things differently when it finds an fsl,mpic instead
>>>> of a generic openpic. I have assembled logs between a working version
>>>> (compatible openpic) and a broken version (compatible fsl,mpic) with
>>>> guest and host debug turned on.
>>>>
>>>> Maybe you have an idea what's going wrong.
>>>
>>> IIRC QEMU is missing support for large vectors, which is probably
>>> breaking IPIs. A recent change to Linux has it assuming it can use
>>> large vectors when it sees fsl,mpic, as we're running out of vectors (on
>>> p4080 MSIs collided with the arbitrarily chosen timer vector, and on
>>> t4240 the normal internal interrupts alone go beyond 256).
>>>
>>> We need to get the enhancements from our internal KVM MPIC back into QEMU.
>>
>> Ok, so the quick fix for 1.2 would be to revert to the old compatible
>> name. Can we leave the 4-field interrupt numbers or do we need to
>> revert the whole patch?
>
> In theory you shouldn't have 4-cell interrupt numbers without fsl,mpic,
> but I don't think it will actually break in Linux -- the extra cells
> should just be ignored.
So I suppose the best would be to revert the whole patch and simply go back to the old format then, to make sure we don't introduce more oddness for non-Linux guests (not that I'm aware we're capable of running any, especially any that would use the dtb).
Once we have working large vectors in our MPIC emulation, we can easily put the patch into place again and generate dt's that show an fsl mpic.
Alex
^ permalink raw reply [flat|nested] 89+ messages in thread
* Re: [Qemu-devel] [Qemu-ppc] [PATCH 56/72] PPC: e500: Use new MPIC dt format
2012-08-09 20:52 ` Alexander Graf
@ 2012-08-09 20:58 ` Scott Wood
2012-08-09 21:01 ` Alexander Graf
0 siblings, 1 reply; 89+ messages in thread
From: Scott Wood @ 2012-08-09 20:58 UTC (permalink / raw)
To: Alexander Graf; +Cc: qemu-ppc Mailing List, qemu-devel qemu-devel
On 08/09/2012 03:52 PM, Alexander Graf wrote:
>
> On 09.08.2012, at 22:50, Scott Wood wrote:
>
>> On 08/09/2012 03:48 PM, Alexander Graf wrote:
>>>
>>> On 09.08.2012, at 00:40, Scott Wood wrote:
>>>
>>>> On 08/08/2012 04:16 PM, Alexander Graf wrote:
>>>>>
>>>>> On 24.06.2012, at 01:07, Alexander Graf wrote:
>>>>>
>>>>>> Due to popular demand, we're updating the way we generate the MPIC
>>>>>> node and interrupt lines based on what the current state of art is.
>>>>>>
>>>>>> Requested-by: Scott Wood <scottwood@freescale.com>
>>>>>> Signed-off-by: Alexander Graf <agraf@suse.de>
>>>>>
>>>>> Hey Scott,
>>>>>
>>>>> This patch breaks SMP for me. The reason for the breakage is that
>>>>> Linux does some things differently when it finds an fsl,mpic instead
>>>>> of a generic openpic. I have assembled logs between a working version
>>>>> (compatible openpic) and a broken version (compatible fsl,mpic) with
>>>>> guest and host debug turned on.
>>>>>
>>>>> Maybe you have an idea what's going wrong.
>>>>
>>>> IIRC QEMU is missing support for large vectors, which is probably
>>>> breaking IPIs. A recent change to Linux has it assuming it can use
>>>> large vectors when it sees fsl,mpic, as we're running out of vectors (on
>>>> p4080 MSIs collided with the arbitrarily chosen timer vector, and on
>>>> t4240 the normal internal interrupts alone go beyond 256).
>>>>
>>>> We need to get the enhancements from our internal KVM MPIC back into QEMU.
>>>
>>> Ok, so the quick fix for 1.2 would be to revert to the old compatible
>>> name. Can we leave the 4-field interrupt numbers or do we need to
>>> revert the whole patch?
>>
>> In theory you shouldn't have 4-cell interrupt numbers without fsl,mpic,
>> but I don't think it will actually break in Linux -- the extra cells
>> should just be ignored.
>
> So I suppose the best would be to revert the whole patch and simply
> go back to the old format then, to make sure we don't introduce more
> oddness for non-Linux guests (not that I'm aware we're capable of
> running any, especially any that would use the dtb).
>
> Once we have working large vectors in our MPIC emulation, we can
> easily put the patch into place again and generate dt's that show an
> fsl mpic.
Additionally, we should consider adding extra compatibles with the major
QEMU version in them, so that QEMU-aware target code can work around
QEMU limitations even if it's been fixed in a more recent QEMU.
I think this is what you were getting at in the e500 platform
discussion, when you pointed at the PC versioning, but it's not about
documenting semantics so much as identifying the actual implementation.
-Scott
^ permalink raw reply [flat|nested] 89+ messages in thread
* Re: [Qemu-devel] [Qemu-ppc] [PATCH 56/72] PPC: e500: Use new MPIC dt format
2012-08-09 20:58 ` Scott Wood
@ 2012-08-09 21:01 ` Alexander Graf
2012-08-09 21:11 ` Scott Wood
0 siblings, 1 reply; 89+ messages in thread
From: Alexander Graf @ 2012-08-09 21:01 UTC (permalink / raw)
To: Scott Wood; +Cc: qemu-ppc Mailing List, qemu-devel qemu-devel
On 09.08.2012, at 22:58, Scott Wood wrote:
> On 08/09/2012 03:52 PM, Alexander Graf wrote:
>>
>> On 09.08.2012, at 22:50, Scott Wood wrote:
>>
>>> On 08/09/2012 03:48 PM, Alexander Graf wrote:
>>>>
>>>> On 09.08.2012, at 00:40, Scott Wood wrote:
>>>>
>>>>> On 08/08/2012 04:16 PM, Alexander Graf wrote:
>>>>>>
>>>>>> On 24.06.2012, at 01:07, Alexander Graf wrote:
>>>>>>
>>>>>>> Due to popular demand, we're updating the way we generate the MPIC
>>>>>>> node and interrupt lines based on what the current state of art is.
>>>>>>>
>>>>>>> Requested-by: Scott Wood <scottwood@freescale.com>
>>>>>>> Signed-off-by: Alexander Graf <agraf@suse.de>
>>>>>>
>>>>>> Hey Scott,
>>>>>>
>>>>>> This patch breaks SMP for me. The reason for the breakage is that
>>>>>> Linux does some things differently when it finds an fsl,mpic instead
>>>>>> of a generic openpic. I have assembled logs between a working version
>>>>>> (compatible openpic) and a broken version (compatible fsl,mpic) with
>>>>>> guest and host debug turned on.
>>>>>>
>>>>>> Maybe you have an idea what's going wrong.
>>>>>
>>>>> IIRC QEMU is missing support for large vectors, which is probably
>>>>> breaking IPIs. A recent change to Linux has it assuming it can use
>>>>> large vectors when it sees fsl,mpic, as we're running out of vectors (on
>>>>> p4080 MSIs collided with the arbitrarily chosen timer vector, and on
>>>>> t4240 the normal internal interrupts alone go beyond 256).
>>>>>
>>>>> We need to get the enhancements from our internal KVM MPIC back into QEMU.
>>>>
>>>> Ok, so the quick fix for 1.2 would be to revert to the old compatible
>>>> name. Can we leave the 4-field interrupt numbers or do we need to
>>>> revert the whole patch?
>>>
>>> In theory you shouldn't have 4-cell interrupt numbers without fsl,mpic,
>>> but I don't think it will actually break in Linux -- the extra cells
>>> should just be ignored.
>>
>> So I suppose the best would be to revert the whole patch and simply
>> go back to the old format then, to make sure we don't introduce more
>> oddness for non-Linux guests (not that I'm aware we're capable of
>> running any, especially any that would use the dtb).
>>
>> Once we have working large vectors in our MPIC emulation, we can
>> easily put the patch into place again and generate dt's that show an
>> fsl mpic.
>
> Additionally, we should consider adding extra compatibles with the major
> QEMU version in them, so that QEMU-aware target code can work around
> QEMU limitations even if it's been fixed in a more recent QEMU.
>
> I think this is what you were getting at in the e500 platform
> discussion, when you pointed at the PC versioning, but it's not about
> documenting semantics so much as identifying the actual implementation.
Yes, -M e500-1.2 should expose chrp,open-pic while -M e500 should expose fsl,mpic. We also need to make the MPIC code capabilities conditional here, so that large vectors are only supported when the machine requests them.
Alex
^ permalink raw reply [flat|nested] 89+ messages in thread
* Re: [Qemu-devel] [Qemu-ppc] [PATCH 56/72] PPC: e500: Use new MPIC dt format
2012-08-09 21:01 ` Alexander Graf
@ 2012-08-09 21:11 ` Scott Wood
2012-08-09 21:19 ` Alexander Graf
0 siblings, 1 reply; 89+ messages in thread
From: Scott Wood @ 2012-08-09 21:11 UTC (permalink / raw)
To: Alexander Graf; +Cc: qemu-ppc Mailing List, qemu-devel qemu-devel
On 08/09/2012 04:01 PM, Alexander Graf wrote:
>
> On 09.08.2012, at 22:58, Scott Wood wrote:
>
>> On 08/09/2012 03:52 PM, Alexander Graf wrote:
>>>
>>> On 09.08.2012, at 22:50, Scott Wood wrote:
>>>
>>>> On 08/09/2012 03:48 PM, Alexander Graf wrote:
>>>>>
>>>>> On 09.08.2012, at 00:40, Scott Wood wrote:
>>>>>
>>>>>> On 08/08/2012 04:16 PM, Alexander Graf wrote:
>>>>>>>
>>>>>>> On 24.06.2012, at 01:07, Alexander Graf wrote:
>>>>>>>
>>>>>>>> Due to popular demand, we're updating the way we generate the MPIC
>>>>>>>> node and interrupt lines based on what the current state of art is.
>>>>>>>>
>>>>>>>> Requested-by: Scott Wood <scottwood@freescale.com>
>>>>>>>> Signed-off-by: Alexander Graf <agraf@suse.de>
>>>>>>>
>>>>>>> Hey Scott,
>>>>>>>
>>>>>>> This patch breaks SMP for me. The reason for the breakage is that
>>>>>>> Linux does some things differently when it finds an fsl,mpic instead
>>>>>>> of a generic openpic. I have assembled logs between a working version
>>>>>>> (compatible openpic) and a broken version (compatible fsl,mpic) with
>>>>>>> guest and host debug turned on.
>>>>>>>
>>>>>>> Maybe you have an idea what's going wrong.
>>>>>>
>>>>>> IIRC QEMU is missing support for large vectors, which is probably
>>>>>> breaking IPIs. A recent change to Linux has it assuming it can use
>>>>>> large vectors when it sees fsl,mpic, as we're running out of vectors (on
>>>>>> p4080 MSIs collided with the arbitrarily chosen timer vector, and on
>>>>>> t4240 the normal internal interrupts alone go beyond 256).
>>>>>>
>>>>>> We need to get the enhancements from our internal KVM MPIC back into QEMU.
>>>>>
>>>>> Ok, so the quick fix for 1.2 would be to revert to the old compatible
>>>>> name. Can we leave the 4-field interrupt numbers or do we need to
>>>>> revert the whole patch?
>>>>
>>>> In theory you shouldn't have 4-cell interrupt numbers without fsl,mpic,
>>>> but I don't think it will actually break in Linux -- the extra cells
>>>> should just be ignored.
>>>
>>> So I suppose the best would be to revert the whole patch and simply
>>> go back to the old format then, to make sure we don't introduce more
>>> oddness for non-Linux guests (not that I'm aware we're capable of
>>> running any, especially any that would use the dtb).
>>>
>>> Once we have working large vectors in our MPIC emulation, we can
>>> easily put the patch into place again and generate dt's that show an
>>> fsl mpic.
>>
>> Additionally, we should consider adding extra compatibles with the major
>> QEMU version in them, so that QEMU-aware target code can work around
>> QEMU limitations even if it's been fixed in a more recent QEMU.
>>
>> I think this is what you were getting at in the e500 platform
>> discussion, when you pointed at the PC versioning, but it's not about
>> documenting semantics so much as identifying the actual implementation.
>
> Yes, -M e500-1.2 should expose chrp,open-pic while -M e500 should expose fsl,mpic.
We could do that too if the chrp,open-pic version actually makes it into
a release before we fix fsl,mpic (I don't know what the release schedule
is), but what I meant was that the device tree should have something like
compatible = "qemu,1.2-chrp-openpic", "chrp,open-pic"
or
compatible = "qemu,1.3-fsl-mpic", "fsl,mpic"
...so that we can run new kernels on old QEMUs, not just the other way
around.
> We also need to make the MPIC code capabilities conditional here, so
> that large vectors are only supported when the machine requests
> them.
Maybe, but the risk is minimal (target software would have to be setting
those bits to non-zero and expecting them to be ignored) and the
potential for making (more of) a mess of the code is high if we
conditionalize everything.
Are there any currently supported machines where real hardware doesn't
have large vectors?
-Scott
^ permalink raw reply [flat|nested] 89+ messages in thread
* Re: [Qemu-devel] [Qemu-ppc] [PATCH 56/72] PPC: e500: Use new MPIC dt format
2012-08-09 21:11 ` Scott Wood
@ 2012-08-09 21:19 ` Alexander Graf
2012-08-09 21:28 ` Scott Wood
0 siblings, 1 reply; 89+ messages in thread
From: Alexander Graf @ 2012-08-09 21:19 UTC (permalink / raw)
To: Scott Wood; +Cc: qemu-ppc Mailing List, qemu-devel qemu-devel
On 09.08.2012, at 23:11, Scott Wood wrote:
> On 08/09/2012 04:01 PM, Alexander Graf wrote:
>>
>> On 09.08.2012, at 22:58, Scott Wood wrote:
>>
>>> On 08/09/2012 03:52 PM, Alexander Graf wrote:
>>>>
>>>> On 09.08.2012, at 22:50, Scott Wood wrote:
>>>>
>>>>> On 08/09/2012 03:48 PM, Alexander Graf wrote:
>>>>>>
>>>>>> On 09.08.2012, at 00:40, Scott Wood wrote:
>>>>>>
>>>>>>> On 08/08/2012 04:16 PM, Alexander Graf wrote:
>>>>>>>>
>>>>>>>> On 24.06.2012, at 01:07, Alexander Graf wrote:
>>>>>>>>
>>>>>>>>> Due to popular demand, we're updating the way we generate the MPIC
>>>>>>>>> node and interrupt lines based on what the current state of art is.
>>>>>>>>>
>>>>>>>>> Requested-by: Scott Wood <scottwood@freescale.com>
>>>>>>>>> Signed-off-by: Alexander Graf <agraf@suse.de>
>>>>>>>>
>>>>>>>> Hey Scott,
>>>>>>>>
>>>>>>>> This patch breaks SMP for me. The reason for the breakage is that
>>>>>>>> Linux does some things differently when it finds an fsl,mpic instead
>>>>>>>> of a generic openpic. I have assembled logs between a working version
>>>>>>>> (compatible openpic) and a broken version (compatible fsl,mpic) with
>>>>>>>> guest and host debug turned on.
>>>>>>>>
>>>>>>>> Maybe you have an idea what's going wrong.
>>>>>>>
>>>>>>> IIRC QEMU is missing support for large vectors, which is probably
>>>>>>> breaking IPIs. A recent change to Linux has it assuming it can use
>>>>>>> large vectors when it sees fsl,mpic, as we're running out of vectors (on
>>>>>>> p4080 MSIs collided with the arbitrarily chosen timer vector, and on
>>>>>>> t4240 the normal internal interrupts alone go beyond 256).
>>>>>>>
>>>>>>> We need to get the enhancements from our internal KVM MPIC back into QEMU.
>>>>>>
>>>>>> Ok, so the quick fix for 1.2 would be to revert to the old compatible
>>>>>> name. Can we leave the 4-field interrupt numbers or do we need to
>>>>>> revert the whole patch?
>>>>>
>>>>> In theory you shouldn't have 4-cell interrupt numbers without fsl,mpic,
>>>>> but I don't think it will actually break in Linux -- the extra cells
>>>>> should just be ignored.
>>>>
>>>> So I suppose the best would be to revert the whole patch and simply
>>>> go back to the old format then, to make sure we don't introduce more
>>>> oddness for non-Linux guests (not that I'm aware we're capable of
>>>> running any, especially any that would use the dtb).
>>>>
>>>> Once we have working large vectors in our MPIC emulation, we can
>>>> easily put the patch into place again and generate dt's that show an
>>>> fsl mpic.
>>>
>>> Additionally, we should consider adding extra compatibles with the major
>>> QEMU version in them, so that QEMU-aware target code can work around
>>> QEMU limitations even if it's been fixed in a more recent QEMU.
>>>
>>> I think this is what you were getting at in the e500 platform
>>> discussion, when you pointed at the PC versioning, but it's not about
>>> documenting semantics so much as identifying the actual implementation.
>>
>> Yes, -M e500-1.2 should expose chrp,open-pic while -M e500 should expose fsl,mpic.
>
> We could do that too if the chrp,open-pic version actually makes it into
> a release before we fix fsl,mpic (I don't know what the release schedule
We are past soft freeze, hard feature freeze is coming up next week.
> is), but what I meant was that the device tree should have something like
> compatible = "qemu,1.2-chrp-openpic", "chrp,open-pic"
> or
> compatible = "qemu,1.3-fsl-mpic", "fsl,mpic"
>
> ...so that we can run new kernels on old QEMUs, not just the other way
> around.
Why would we bother?
>
>> We also need to make the MPIC code capabilities conditional here, so
>> that large vectors are only supported when the machine requests
>> them.
>
> Maybe, but the risk is minimal (target software would have to be setting
> those bits to non-zero and expecting them to be ignored) and the
> potential for making (more of) a mess of the code is high if we
> conditionalize everything.
>
> Are there any currently supported machines where real hardware doesn't
> have large vectors?
I'm not sure what bamboo would support in real hw. Same for the frankenstein-U3 we expose.
I agree that risk looks low for now, but let's evaluate it when I see the patch that actually changes things.
Alex
^ permalink raw reply [flat|nested] 89+ messages in thread
* Re: [Qemu-devel] [Qemu-ppc] [PATCH 56/72] PPC: e500: Use new MPIC dt format
2012-08-09 21:19 ` Alexander Graf
@ 2012-08-09 21:28 ` Scott Wood
2012-08-09 21:36 ` Alexander Graf
0 siblings, 1 reply; 89+ messages in thread
From: Scott Wood @ 2012-08-09 21:28 UTC (permalink / raw)
To: Alexander Graf; +Cc: qemu-ppc Mailing List, qemu-devel qemu-devel
On 08/09/2012 04:19 PM, Alexander Graf wrote:
>
> On 09.08.2012, at 23:11, Scott Wood wrote:
>
>> On 08/09/2012 04:01 PM, Alexander Graf wrote:
>>>
>>> On 09.08.2012, at 22:58, Scott Wood wrote:
>>>> Additionally, we should consider adding extra compatibles with the major
>>>> QEMU version in them, so that QEMU-aware target code can work around
>>>> QEMU limitations even if it's been fixed in a more recent QEMU.
>>>>
>>>> I think this is what you were getting at in the e500 platform
>>>> discussion, when you pointed at the PC versioning, but it's not about
>>>> documenting semantics so much as identifying the actual implementation.
>>>
>>> Yes, -M e500-1.2 should expose chrp,open-pic while -M e500 should expose fsl,mpic.
>>
>> We could do that too if the chrp,open-pic version actually makes it into
>> a release before we fix fsl,mpic (I don't know what the release schedule
>
> We are past soft freeze, hard feature freeze is coming up next week.
>
>> is), but what I meant was that the device tree should have something like
>> compatible = "qemu,1.2-chrp-openpic", "chrp,open-pic"
>> or
>> compatible = "qemu,1.3-fsl-mpic", "fsl,mpic"
>>
>> ...so that we can run new kernels on old QEMUs, not just the other way
>> around.
>
> Why would we bother?
Why not? It's much easier than the other way around -- it's just an
extra string in the device tree. It's up to someone who cares to put
relevant workarounds in the kernel.
Compare it to real hardware, where we expect new kernels to run on old
hardware but not the other way around, and where we expect to be able to
identify the specific hardware we're running on (there are version
registers in the MPIC for identifying real hardware version, but not
QEMU implementation version).
If we had this, we could have avoided needing to postpone fsl,mpic,
because I think the Linux patch using large vectors hasn't been released
yet, so we could have added a check for qemu,1.2-fsl-mpic and known that
it didn't include large vectors. I guess it's still not too late...
It would also be useful for overriding SVR checks in drivers (for errata
and such), which can get particularly awkward if you mix some emulated
devices with some directly assigned devices (no one SVR will be right
for all of them, even if all the emulated devices faithfully emulate one
SoC's behavior).
-Scott
^ permalink raw reply [flat|nested] 89+ messages in thread
* Re: [Qemu-devel] [Qemu-ppc] [PATCH 56/72] PPC: e500: Use new MPIC dt format
2012-08-09 21:28 ` Scott Wood
@ 2012-08-09 21:36 ` Alexander Graf
2012-08-09 21:45 ` Scott Wood
0 siblings, 1 reply; 89+ messages in thread
From: Alexander Graf @ 2012-08-09 21:36 UTC (permalink / raw)
To: Scott Wood; +Cc: qemu-ppc Mailing List, qemu-devel qemu-devel
On 09.08.2012, at 23:28, Scott Wood wrote:
> On 08/09/2012 04:19 PM, Alexander Graf wrote:
>>
>> On 09.08.2012, at 23:11, Scott Wood wrote:
>>
>>> On 08/09/2012 04:01 PM, Alexander Graf wrote:
>>>>
>>>> On 09.08.2012, at 22:58, Scott Wood wrote:
>>>>> Additionally, we should consider adding extra compatibles with the major
>>>>> QEMU version in them, so that QEMU-aware target code can work around
>>>>> QEMU limitations even if it's been fixed in a more recent QEMU.
>>>>>
>>>>> I think this is what you were getting at in the e500 platform
>>>>> discussion, when you pointed at the PC versioning, but it's not about
>>>>> documenting semantics so much as identifying the actual implementation.
>>>>
>>>> Yes, -M e500-1.2 should expose chrp,open-pic while -M e500 should expose fsl,mpic.
>>>
>>> We could do that too if the chrp,open-pic version actually makes it into
>>> a release before we fix fsl,mpic (I don't know what the release schedule
>>
>> We are past soft freeze, hard feature freeze is coming up next week.
>>
>>> is), but what I meant was that the device tree should have something like
>>> compatible = "qemu,1.2-chrp-openpic", "chrp,open-pic"
>>> or
>>> compatible = "qemu,1.3-fsl-mpic", "fsl,mpic"
>>>
>>> ...so that we can run new kernels on old QEMUs, not just the other way
>>> around.
>>
>> Why would we bother?
>
> Why not? It's much easier than the other way around -- it's just an
> extra string in the device tree. It's up to someone who cares to put
> relevant workarounds in the kernel.
>
> Compare it to real hardware, where we expect new kernels to run on old
> hardware but not the other way around, and where we expect to be able to
> identify the specific hardware we're running on (there are version
> registers in the MPIC for identifying real hardware version, but not
> QEMU implementation version).
>
> If we had this, we could have avoided needing to postpone fsl,mpic,
> because I think the Linux patch using large vectors hasn't been released
> yet, so we could have added a check for qemu,1.2-fsl-mpic and known that
> it didn't include large vectors. I guess it's still not too late...
I'm not sure I like the idea. Usually, in the real hardware world, erratas happen on the board level, right? So we could have a compatible "qemu,1.2-e500" in the board compatible. But having one for every device sounds a bit too much to me.
Also, not implementing large vectors essentially mean we don't emulate an fsl,mpic well. That's fine, let's just not tell the guest we do. I don't think we should teach Linux about broken emulation. I'd rather see the emulation fixed.
> It would also be useful for overriding SVR checks in drivers (for errata
> and such), which can get particularly awkward if you mix some emulated
> devices with some directly assigned devices (no one SVR will be right
> for all of them, even if all the emulated devices faithfully emulate one
> SoC's behavior).
Hmm. Yes. Maybe it'd be good to just never check SVR but instead always rely on dt properties?
Alex
^ permalink raw reply [flat|nested] 89+ messages in thread
* Re: [Qemu-devel] [Qemu-ppc] [PATCH 56/72] PPC: e500: Use new MPIC dt format
2012-08-09 21:36 ` Alexander Graf
@ 2012-08-09 21:45 ` Scott Wood
2012-08-09 21:48 ` Alexander Graf
0 siblings, 1 reply; 89+ messages in thread
From: Scott Wood @ 2012-08-09 21:45 UTC (permalink / raw)
To: Alexander Graf; +Cc: qemu-ppc Mailing List, qemu-devel qemu-devel
On 08/09/2012 04:36 PM, Alexander Graf wrote:
>
> On 09.08.2012, at 23:28, Scott Wood wrote:
>
>> On 08/09/2012 04:19 PM, Alexander Graf wrote:
>>>
>>> On 09.08.2012, at 23:11, Scott Wood wrote:
>>>> ...so that we can run new kernels on old QEMUs, not just the other way
>>>> around.
>>>
>>> Why would we bother?
>>
>> Why not? It's much easier than the other way around -- it's just an
>> extra string in the device tree. It's up to someone who cares to put
>> relevant workarounds in the kernel.
>>
>> Compare it to real hardware, where we expect new kernels to run on old
>> hardware but not the other way around, and where we expect to be able to
>> identify the specific hardware we're running on (there are version
>> registers in the MPIC for identifying real hardware version, but not
>> QEMU implementation version).
>>
>> If we had this, we could have avoided needing to postpone fsl,mpic,
>> because I think the Linux patch using large vectors hasn't been released
>> yet, so we could have added a check for qemu,1.2-fsl-mpic and known that
>> it didn't include large vectors. I guess it's still not too late...
>
> I'm not sure I like the idea. Usually, in the real hardware world,
> erratas happen on the board level, right?
More often on a chip revision level.
> So we could have a
> compatible "qemu,1.2-e500" in the board compatible. But having one
> for every device sounds a bit too much to me.
But not every device is necessarily emulated.
> Also, not implementing large vectors essentially mean we don't
> emulate an fsl,mpic well. That's fine, let's just not tell the guest
> we do. I don't think we should teach Linux about broken emulation.
> I'd rather see the emulation fixed.
My point is even after we add large vector support, we probably aren't
100% emulating an FSL MPIC.
>> It would also be useful for overriding SVR checks in drivers (for errata
>> and such), which can get particularly awkward if you mix some emulated
>> devices with some directly assigned devices (no one SVR will be right
>> for all of them, even if all the emulated devices faithfully emulate one
>> SoC's behavior).
>
> Hmm. Yes. Maybe it'd be good to just never check SVR but instead always rely on dt properties?
That assumes we know about the problem when the device tree is created
(we like to maintain compatibility with old trees), and that we maintain
the information accurately in all trees (which means u-boot fixups, and
compatibility is even more of an issue there, because some people don't
like upgrading u-boot in the field). The only practical way to do that
would be to put the SVR in each device tree node, which seems like
overkill. At least the QEMU compatibles only affect QEMU and target
code that specifically wants to improve its QEMU compatibility, rather
than wait for QEMU to improve.
-Scott
^ permalink raw reply [flat|nested] 89+ messages in thread
* Re: [Qemu-devel] [Qemu-ppc] [PATCH 56/72] PPC: e500: Use new MPIC dt format
2012-08-09 21:45 ` Scott Wood
@ 2012-08-09 21:48 ` Alexander Graf
0 siblings, 0 replies; 89+ messages in thread
From: Alexander Graf @ 2012-08-09 21:48 UTC (permalink / raw)
To: Scott Wood; +Cc: qemu-ppc Mailing List, qemu-devel qemu-devel
On 09.08.2012, at 23:45, Scott Wood wrote:
> On 08/09/2012 04:36 PM, Alexander Graf wrote:
>>
>> On 09.08.2012, at 23:28, Scott Wood wrote:
>>
>>> On 08/09/2012 04:19 PM, Alexander Graf wrote:
>>>>
>>>> On 09.08.2012, at 23:11, Scott Wood wrote:
>>>>> ...so that we can run new kernels on old QEMUs, not just the other way
>>>>> around.
>>>>
>>>> Why would we bother?
>>>
>>> Why not? It's much easier than the other way around -- it's just an
>>> extra string in the device tree. It's up to someone who cares to put
>>> relevant workarounds in the kernel.
>>>
>>> Compare it to real hardware, where we expect new kernels to run on old
>>> hardware but not the other way around, and where we expect to be able to
>>> identify the specific hardware we're running on (there are version
>>> registers in the MPIC for identifying real hardware version, but not
>>> QEMU implementation version).
>>>
>>> If we had this, we could have avoided needing to postpone fsl,mpic,
>>> because I think the Linux patch using large vectors hasn't been released
>>> yet, so we could have added a check for qemu,1.2-fsl-mpic and known that
>>> it didn't include large vectors. I guess it's still not too late...
>>
>> I'm not sure I like the idea. Usually, in the real hardware world,
>> erratas happen on the board level, right?
>
> More often on a chip revision level.
>
>> So we could have a
>> compatible "qemu,1.2-e500" in the board compatible. But having one
>> for every device sounds a bit too much to me.
>
> But not every device is necessarily emulated.
>
>> Also, not implementing large vectors essentially mean we don't
>> emulate an fsl,mpic well. That's fine, let's just not tell the guest
>> we do. I don't think we should teach Linux about broken emulation.
>> I'd rather see the emulation fixed.
>
> My point is even after we add large vector support, we probably aren't
> 100% emulating an FSL MPIC.
>
>>> It would also be useful for overriding SVR checks in drivers (for errata
>>> and such), which can get particularly awkward if you mix some emulated
>>> devices with some directly assigned devices (no one SVR will be right
>>> for all of them, even if all the emulated devices faithfully emulate one
>>> SoC's behavior).
>>
>> Hmm. Yes. Maybe it'd be good to just never check SVR but instead always rely on dt properties?
>
> That assumes we know about the problem when the device tree is created
> (we like to maintain compatibility with old trees), and that we maintain
> the information accurately in all trees (which means u-boot fixups, and
> compatibility is even more of an issue there, because some people don't
> like upgrading u-boot in the field). The only practical way to do that
> would be to put the SVR in each device tree node, which seems like
> overkill. At least the QEMU compatibles only affect QEMU and target
> code that specifically wants to improve its QEMU compatibility, rather
> than wait for QEMU to improve.
Ah, you mean we should indicate "This is the QEMU emulated version of device x". I think I slowly see what you're getting at. In this case, the fix really is to get QEMU work properly, but I like the idea of exposing to the guest that a device is emulated by QEMU, and emulated by version X.
Alex
^ permalink raw reply [flat|nested] 89+ messages in thread
end of thread, other threads:[~2012-08-09 21:48 UTC | newest]
Thread overview: 89+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-06-23 23:06 [Qemu-devel] [PULL 00/72] ppc patch queue 2012-06-24 Alexander Graf
2012-06-23 23:06 ` [Qemu-devel] [PATCH 01/72] ppc: Fix coding style in op_helper.c Alexander Graf
2012-06-23 23:06 ` [Qemu-devel] [PATCH 02/72] ppc: Split exception helpers Alexander Graf
2012-06-23 23:06 ` [Qemu-devel] [PATCH 03/72] ppc: Avoid AREG0 for " Alexander Graf
2012-06-23 23:06 ` [Qemu-devel] [PATCH 04/72] ppc: Fix coding style in helper.c Alexander Graf
2012-06-23 23:06 ` [Qemu-devel] [PATCH 05/72] ppc: Move exception helpers from helper.c to excp_helper.c Alexander Graf
2012-06-23 23:06 ` [Qemu-devel] [PATCH 06/72] ppc: Split FPU and SPE ops Alexander Graf
2012-06-23 23:06 ` [Qemu-devel] [PATCH 07/72] ppc: Avoid AREG0 for FPU and SPE helpers Alexander Graf
2012-06-23 23:06 ` [Qemu-devel] [PATCH 08/72] ppc: Split integer and vector ops Alexander Graf
2012-06-23 23:06 ` [Qemu-devel] [PATCH 09/72] ppc: Avoid AREG0 for integer and vector helpers Alexander Graf
2012-06-23 23:06 ` [Qemu-devel] [PATCH 10/72] ppc: Split MMU etc. helpers from op_helper.c Alexander Graf
2012-06-23 23:06 ` [Qemu-devel] [PATCH 11/72] ppc: Avoid AREG0 for MMU etc. helpers Alexander Graf
2012-06-23 23:06 ` [Qemu-devel] [PATCH 12/72] ppc: Avoid a warning with the next patch Alexander Graf
2012-06-23 23:06 ` [Qemu-devel] [PATCH 13/72] ppc: Move MMU helpers from helper.c to mmu_helper.c Alexander Graf
2012-06-23 23:06 ` [Qemu-devel] [PATCH 14/72] ppc: Cleanup MMU merge Alexander Graf
2012-06-23 23:06 ` [Qemu-devel] [PATCH 15/72] ppc: Split off timebase helpers Alexander Graf
2012-06-23 23:06 ` [Qemu-devel] [PATCH 16/72] ppc: Avoid AREG0 for " Alexander Graf
2012-06-23 23:06 ` [Qemu-devel] [PATCH 17/72] ppc: Split off misc helpers Alexander Graf
2012-06-23 23:06 ` [Qemu-devel] [PATCH 18/72] ppc: Avoid AREG0 for " Alexander Graf
2012-06-23 23:06 ` [Qemu-devel] [PATCH 19/72] ppc: Move misc helpers from helper.c to misc_helper.c Alexander Graf
2012-06-23 23:06 ` [Qemu-devel] [PATCH 20/72] ppc: Move load and store helpers, switch to AREG0 free mode Alexander Graf
2012-06-23 23:06 ` [Qemu-devel] [PATCH 21/72] ppc: Add missing break Alexander Graf
2012-06-23 23:06 ` [Qemu-devel] [PATCH 22/72] ppc: Make hbrev table const Alexander Graf
2012-06-23 23:06 ` [Qemu-devel] [PATCH 23/72] PPC: mpc8544ds: Span initial TLB entry over as much RAM as we need Alexander Graf
2012-06-23 23:06 ` [Qemu-devel] [PATCH 24/72] Avoid segfault in cpu_dump_state Alexander Graf
2012-06-23 23:06 ` [Qemu-devel] [PATCH 25/72] booke_206_tlbwe: Discard invalid bits in MAS2 Alexander Graf
2012-06-23 23:06 ` [Qemu-devel] [PATCH 26/72] ppc64: Rudimentary Support for extra page sizes on server CPUs Alexander Graf
2012-06-23 23:06 ` [Qemu-devel] [PATCH 27/72] pseries: Correctly create ibm, segment-page-sizes property Alexander Graf
2012-06-23 23:06 ` [Qemu-devel] [PATCH 28/72] spapr_vscsi: Error handling fixes Alexander Graf
2012-06-23 23:06 ` [Qemu-devel] [PATCH 29/72] spapr: Add "memop" hypercall Alexander Graf
2012-06-23 23:06 ` [Qemu-devel] [PATCH 30/72] raw-posix: Fix build without is_allocated support Alexander Graf
2012-06-23 23:06 ` [Qemu-devel] [PATCH 31/72] dt: allow add_subnode to create root subnodes Alexander Graf
2012-06-23 23:06 ` [Qemu-devel] [PATCH 32/72] dt: add helpers for multi-cell adds Alexander Graf
2012-06-23 23:06 ` [Qemu-devel] [PATCH 33/72] dt: add helper for phandle references Alexander Graf
2012-06-23 23:06 ` [Qemu-devel] [PATCH 34/72] dt: temporarily disable subtree creation failure check Alexander Graf
2012-06-23 23:06 ` [Qemu-devel] [PATCH 35/72] dt: add helper for phandle enumeration Alexander Graf
2012-06-23 23:07 ` [Qemu-devel] [PATCH 36/72] dt: add helper for empty dt creation Alexander Graf
2012-06-23 23:07 ` [Qemu-devel] [PATCH 37/72] dt: add helper for phandle allocation Alexander Graf
2012-06-23 23:07 ` [Qemu-devel] [PATCH 38/72] dt: add helper for 64bit cell adds Alexander Graf
2012-06-23 23:07 ` [Qemu-devel] [PATCH 39/72] PPC: e500: require libfdt Alexander Graf
2012-06-23 23:07 ` [Qemu-devel] [PATCH 40/72] PPC: e500: dt: create memory node dynamically Alexander Graf
2012-06-23 23:07 ` [Qemu-devel] [PATCH 41/72] PPC: e500: dt: create /cpus " Alexander Graf
2012-06-23 23:07 ` [Qemu-devel] [PATCH 42/72] PPC: e500: dt: create /hypervisor " Alexander Graf
2012-06-23 23:07 ` [Qemu-devel] [PATCH 43/72] PPC: e500: dt: create / " Alexander Graf
2012-06-23 23:07 ` [Qemu-devel] [PATCH 44/72] PPC: e500: dt: create /chosen " Alexander Graf
2012-06-23 23:07 ` [Qemu-devel] [PATCH 45/72] PPC: e500: dt: create /soc8544 " Alexander Graf
2012-06-23 23:07 ` [Qemu-devel] [PATCH 46/72] PPC: e500: dt: create serial nodes dynamically Alexander Graf
2012-06-23 23:07 ` [Qemu-devel] [PATCH 47/72] PPC: e500: dt: create mpic node dynamically Alexander Graf
2012-06-23 23:07 ` [Qemu-devel] [PATCH 48/72] PPC: e500: dt: create global-utils " Alexander Graf
2012-06-23 23:07 ` [Qemu-devel] [PATCH 49/72] PPC: e500: dt: create pci " Alexander Graf
2012-06-23 23:07 ` [Qemu-devel] [PATCH 50/72] PPC: e500: dt: start with empty device tree Alexander Graf
2012-06-23 23:07 ` [Qemu-devel] [PATCH 51/72] dt: Add -machine dumpdtb option to dump the current dtb Alexander Graf
2012-06-23 23:07 ` [Qemu-devel] [PATCH 52/72] PPC: e500: dt: use 64bit cell helper Alexander Graf
2012-06-23 23:07 ` [Qemu-devel] [PATCH 53/72] PPC: e500: dt: use target_phys_addr_t for ramsize Alexander Graf
2012-06-23 23:07 ` [Qemu-devel] [PATCH 54/72] PPC: e500: enable manual loading of dtb blob Alexander Graf
2012-06-23 23:07 ` [Qemu-devel] [PATCH 55/72] Revert "dt: temporarily disable subtree creation failure check" Alexander Graf
2012-06-23 23:07 ` [Qemu-devel] [PATCH 56/72] PPC: e500: Use new MPIC dt format Alexander Graf
2012-08-08 21:16 ` [Qemu-devel] [Qemu-ppc] " Alexander Graf
2012-08-08 22:40 ` Scott Wood
2012-08-09 20:48 ` Alexander Graf
2012-08-09 20:50 ` Scott Wood
2012-08-09 20:52 ` Alexander Graf
2012-08-09 20:58 ` Scott Wood
2012-08-09 21:01 ` Alexander Graf
2012-08-09 21:11 ` Scott Wood
2012-08-09 21:19 ` Alexander Graf
2012-08-09 21:28 ` Scott Wood
2012-08-09 21:36 ` Alexander Graf
2012-08-09 21:45 ` Scott Wood
2012-08-09 21:48 ` Alexander Graf
2012-08-08 22:40 ` [Qemu-devel] " Peter Maydell
2012-08-08 22:43 ` Peter Maydell
2012-06-23 23:07 ` [Qemu-devel] [PATCH 57/72] PPC: e500: Use new SOC " Alexander Graf
2012-06-23 23:07 ` [Qemu-devel] [PATCH 58/72] PPC: e500: Define addresses as always 64bit Alexander Graf
2012-06-23 23:07 ` [Qemu-devel] [PATCH 59/72] PPC: e500: Extend address/size of / to 64bit Alexander Graf
2012-06-23 23:07 ` [Qemu-devel] [PATCH 60/72] dt: Add global option to set phandle start offset Alexander Graf
2012-06-23 23:07 ` [Qemu-devel] [PATCH 61/72] PPC: e500: Refactor serial dt generation Alexander Graf
2012-06-23 23:07 ` [Qemu-devel] [PATCH 62/72] dt: make setprop argument static Alexander Graf
2012-06-23 23:07 ` [Qemu-devel] [PATCH 63/72] PPC: e500: allow users to set the /compatible property via -machine Alexander Graf
2012-06-23 23:07 ` [Qemu-devel] [PATCH 64/72] uImage: increase the gzip load size Alexander Graf
2012-06-23 23:07 ` [Qemu-devel] [PATCH 65/72] PPC: Add some booke SPR defines Alexander Graf
2012-06-23 23:07 ` [Qemu-devel] [PATCH 66/72] PPC: Add support for MSR_CM Alexander Graf
2012-06-23 23:07 ` [Qemu-devel] [PATCH 67/72] PPC: BookE: Implement EPR SPR Alexander Graf
2012-06-23 23:07 ` [Qemu-devel] [PATCH 68/72] PPC: BookE: Make ivpr selectable by CPU type Alexander Graf
2012-06-23 23:07 ` [Qemu-devel] [PATCH 69/72] PPC: Add e5500 CPU target Alexander Graf
2012-06-23 23:07 ` [Qemu-devel] [PATCH 70/72] PPC: Extract SPR dump generation into its own function Alexander Graf
2012-06-23 23:07 ` [Qemu-devel] [PATCH 71/72] PPC: BookE: Support 32 and 64 bit wide MAS2 Alexander Graf
2012-06-23 23:07 ` [Qemu-devel] [PATCH 72/72] PPC: BookE206: Bump MAS2 to 64bit Alexander Graf
2012-06-24 12:27 ` [Qemu-devel] [PULL 00/72] ppc patch queue 2012-06-24 Blue Swirl
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).