summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorBlue Swirl <blauwirbel@gmail.com>2012-06-24 10:48:56 +0000
committerBlue Swirl <blauwirbel@gmail.com>2012-06-24 10:48:56 +0000
commit4e469a438f40a53dc6217fa5c3d456861b00d80c (patch)
tree3eb0db99ac318738016463b56250da6bdfd64d9e
parent959a255dfbe085a47e00fd21c57e87ad4c92719e (diff)
parent960916988b9ec45bb10400d892351f360b4aac96 (diff)
downloadfocaccia-qemu-4e469a438f40a53dc6217fa5c3d456861b00d80c.tar.gz
focaccia-qemu-4e469a438f40a53dc6217fa5c3d456861b00d80c.zip
Merge branch 'ppc-for-upstream' of git://repo.or.cz/qemu/agraf
* 'ppc-for-upstream' of git://repo.or.cz/qemu/agraf: (72 commits)
  PPC: BookE206: Bump MAS2 to 64bit
  PPC: BookE: Support 32 and 64 bit wide MAS2
  PPC: Extract SPR dump generation into its own function
  PPC: Add e5500 CPU target
  PPC: BookE: Make ivpr selectable by CPU type
  PPC: BookE: Implement EPR SPR
  PPC: Add support for MSR_CM
  PPC: Add some booke SPR defines
  uImage: increase the gzip load size
  PPC: e500: allow users to set the /compatible property via -machine
  dt: make setprop argument static
  PPC: e500: Refactor serial dt generation
  dt: Add global option to set phandle start offset
  PPC: e500: Extend address/size of / to 64bit
  PPC: e500: Define addresses as always 64bit
  PPC: e500: Use new SOC dt format
  PPC: e500: Use new MPIC dt format
  Revert "dt: temporarily disable subtree creation failure check"
  PPC: e500: enable manual loading of dtb blob
  PPC: e500: dt: use target_phys_addr_t for ramsize
  ...
-rw-r--r--Makefile1
-rw-r--r--block/raw-posix.c9
-rwxr-xr-xconfigure2
-rw-r--r--cpu-all.h9
-rw-r--r--device_tree.c108
-rw-r--r--device_tree.h22
-rw-r--r--docs/specs/ppc-spapr-hcalls.txt78
-rw-r--r--hw/loader.c4
-rw-r--r--hw/ppc/Makefile.objs2
-rw-r--r--hw/ppce500_mpc8544ds.c283
-rw-r--r--hw/spapr.c46
-rw-r--r--hw/spapr.h3
-rw-r--r--hw/spapr_hcall.c68
-rw-r--r--hw/spapr_vscsi.c4
-rw-r--r--pc-bios/mpc8544ds.dtbbin2028 -> 0 bytes
-rw-r--r--pc-bios/mpc8544ds.dts119
-rw-r--r--qemu-config.c12
-rw-r--r--qemu-log.h4
-rw-r--r--target-ppc/Makefile.objs14
-rw-r--r--target-ppc/cpu.h88
-rw-r--r--target-ppc/excp_helper.c969
-rw-r--r--target-ppc/fpu_helper.c1740
-rw-r--r--target-ppc/helper.c3168
-rw-r--r--target-ppc/helper.h573
-rw-r--r--target-ppc/int_helper.c1564
-rw-r--r--target-ppc/kvm.c208
-rw-r--r--target-ppc/kvm_ppc.h5
-rw-r--r--target-ppc/mem_helper.c295
-rw-r--r--target-ppc/misc_helper.c124
-rw-r--r--target-ppc/mmu_helper.c3326
-rw-r--r--target-ppc/mpic_helper.c35
-rw-r--r--target-ppc/op_helper.c4568
-rw-r--r--target-ppc/timebase_helper.c159
-rw-r--r--target-ppc/translate.c462
-rw-r--r--target-ppc/translate_init.c249
35 files changed, 9858 insertions, 8463 deletions
diff --git a/Makefile b/Makefile
index a7281b02b6..827e1adac3 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/block/raw-posix.c b/block/raw-posix.c
index bf7700a238..0dce089be5 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.
diff --git a/configure b/configure
index b68c0ca194..6128ba7522 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 50c8b62583..9dc249a165 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/device_tree.c b/device_tree.c
index 86a694c955..b366fddeaf 100644
--- a/device_tree.c
+++ b/device_tree.c
@@ -22,9 +22,48 @@
 #include "qemu-common.h"
 #include "device_tree.h"
 #include "hw/loader.h"
+#include "qemu-option.h"
+#include "qemu-config.h"
 
 #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;
@@ -88,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;
 
@@ -117,6 +156,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)
 {
@@ -132,6 +178,59 @@ 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 = qemu_devtree_get_phandle(fdt, target_node_path);
+    return qemu_devtree_setprop_cell(fdt, node_path, property, phandle);
+}
+
+uint32_t qemu_devtree_alloc_phandle(void *fdt)
+{
+    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++;
+}
+
 int qemu_devtree_nop_node(void *fdt, const char *node_path)
 {
     int r;
@@ -151,6 +250,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 +260,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));
diff --git a/device_tree.h b/device_tree.h
index 4378685b7a..2244270b2d 100644
--- a/device_tree.h
+++ b/device_tree.h
@@ -14,15 +14,35 @@
 #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,
-                         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,
+                             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,
+                                 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);
 
+#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__ */
diff --git a/docs/specs/ppc-spapr-hcalls.txt b/docs/specs/ppc-spapr-hcalls.txt
new file mode 100644
index 0000000000..52ba8d42ab
--- /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/loader.c b/hw/loader.c
index 7d64113e7f..33acc2fdab 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)
diff --git a/hw/ppc/Makefile.objs b/hw/ppc/Makefile.objs
index 44a1e8cdab..d18dbaf6cc 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 3eb8a23779..8b9fd83ce1 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
@@ -41,57 +42,150 @@
 
 #define RAM_SIZES_ALIGN            (64UL << 20)
 
-#define MPC8544_CCSRBAR_BASE       0xE0000000
-#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
 {
     uint32_t dt_base;
+    uint32_t dt_size;
     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, 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, 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 < ARRAY_SIZE(tmp); i++) {
+        pci_map[i] = cpu_to_be32(tmp[i]);
+    }
+}
+
+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,
-                                    uint32_t ramsize,
+                                    target_phys_addr_t ramsize,
                                     target_phys_addr_t initrd_base,
                                     target_phys_addr_t initrd_size,
                                     const char *kernel_cmdline)
 {
     int ret = -1;
-#ifdef CONFIG_FDT
-    uint32_t mem_reg_property[] = {0, cpu_to_be32(ramsize)};
-    char *filename;
+    uint64_t mem_reg_property[] = { 0, cpu_to_be64(ramsize) };
     int fdt_size;
     void *fdt;
     uint8_t hypercall[16];
     uint32_t clock_freq = 400000000;
     uint32_t tb_freq = 400000000;
     int i;
+    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];
+    char mpic[128];
+    uint32_t mpic_ph;
+    char gutil[128];
+    char pci[128];
+    uint32_t pci_map[9 * 8];
+    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;
+
+    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;
+        }
+    }
 
-    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE);
-    if (!filename) {
-        goto out;
+    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 = load_device_tree(filename, &fdt_size);
-    g_free(filename);
+
+    fdt = create_device_tree(&fdt_size);
     if (fdt == NULL) {
         goto out;
     }
 
     /* 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_setprop_string(fdt, "/", "model", model);
+    qemu_devtree_setprop(fdt, "/", "compatible", compatible, compatible_len);
+    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");
+    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);
@@ -117,6 +211,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));
@@ -124,11 +219,16 @@ 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--) {
         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) {
@@ -156,39 +256,133 @@ 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");
         }
     }
 
+    qemu_devtree_add_subnode(fdt, "/aliases");
+    /* XXX These should go into their respective devices' code */
+    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,
+                         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 >> 32, MPC8544_CCSRBAR_BASE,
+                               MPC8544_CCSRBAR_SIZE);
+    /* XXX should contain a reasonable value */
+    qemu_devtree_setprop_cell(fdt, soc, "bus-frequency", 0);
+
+    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");
+    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", 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
+     * device it finds in the dt as serial output device. And we generate
+     * devices in reverse order to the dt.
+     */
+    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);
+    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);
+
+    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");
+    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, 0, 0);
+    qemu_devtree_setprop_cells(fdt, pci, "bus-range", 0, 255);
+    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 >> 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);
+    qemu_devtree_setprop_cell(fdt, pci, "#address-cells", 3);
+    qemu_devtree_setprop_string(fdt, "/aliases", "pci0", pci);
+
+done:
+    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;
+    }
     g_free(fdt);
+    ret = fdt_size;
 
 out:
-#endif
 
     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 +414,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,
@@ -275,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);
 
@@ -379,13 +574,12 @@ 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 +587,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()) {
diff --git a/hw/spapr.c b/hw/spapr.c
index d0bddbce95..09a23ff092 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,
@@ -163,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;
@@ -298,6 +333,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 +399,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)));
     }
 
@@ -374,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 654a7a8a34..c75172e0c0 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 94bb504ca6..a5990a9617 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);
diff --git a/hw/spapr_vscsi.c b/hw/spapr_vscsi.c
index 037867ab4f..2f09616dd5 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));
 
diff --git a/pc-bios/mpc8544ds.dtb b/pc-bios/mpc8544ds.dtb
deleted file mode 100644
index c6d302153c..0000000000
--- a/pc-bios/mpc8544ds.dtb
+++ /dev/null
Binary files differdiff --git a/pc-bios/mpc8544ds.dts b/pc-bios/mpc8544ds.dts
deleted file mode 100644
index 7eb31604fc..0000000000
--- a/pc-bios/mpc8544ds.dts
+++ /dev/null
@@ -1,119 +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/;
-/ {
-	model = "MPC8544DS";
-	compatible = "MPC8544DS", "MPC85xxDS";
-	#address-cells = <1>;
-	#size-cells = <1>;
-
-	aliases {
-		serial0 = &serial0;
-		serial1 = &serial1;
-		pci0 = &pci0;
-	};
-
-	cpus {
-		#address-cells = <1>;
-		#size-cells = <0>;
-	};
-
-	memory {
-		device_type = "memory";
-		reg = <0x0 0x0>;	// Filled by U-Boot
-	};
-
-	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";
-			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>;
-			#interrupt-cells = <2>;
-			reg = <0x40000 0x40000>;
-			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 {
-		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>;
-	};
-
-	chosen {
-		linux,stdout-path = "/soc8544@e0000000/serial@4500";
-	};
-
-	hypervisor {
-	};
-};
diff --git a/qemu-config.c b/qemu-config.c
index bb3bff426a..5c3296b8c6 100644
--- a/qemu-config.c
+++ b/qemu-config.c
@@ -583,6 +583,18 @@ 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",
+        }, {
+            .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 */ }
     },
diff --git a/qemu-log.h b/qemu-log.h
index 40f8b7b0c8..2ed19d1578 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)
diff --git a/target-ppc/Makefile.objs b/target-ppc/Makefile.objs
index f78161004e..237a0ed4f7 100644
--- a/target-ppc/Makefile.objs
+++ b/target-ppc/Makefile.objs
@@ -1,6 +1,12 @@
-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)/op_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
+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-y += mem_helper.o
+obj-y += mpic_helper.o
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index 77a28580af..ca2fc2198e 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) */
 };
 
@@ -691,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)
@@ -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;
@@ -1035,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 */
@@ -1117,27 +1149,12 @@ 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);
-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);
 
@@ -1176,19 +1193,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
 
@@ -1387,6 +1396,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)
@@ -1754,6 +1764,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 {
@@ -2182,6 +2213,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
new file mode 100644
index 0000000000..1a593f6f3f
--- /dev/null
+++ b/target-ppc/excp_helper.c
@@ -0,0 +1,969 @@
+/*
+ *  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 "helper.h"
+
+#include "helper_regs.h"
+
+//#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] |= (cpu_ldl_code(env, (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 (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)) {
+            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 */
+
+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);
+#endif
+    env->exception_index = exception;
+    env->error_code = error_code;
+    cpu_loop_exit(env);
+}
+
+void helper_raise_exception(CPUPPCState *env, uint32_t exception)
+{
+    helper_raise_exception_err(env, exception, 0);
+}
+
+#if !defined(CONFIG_USER_ONLY)
+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(env, val);
+    }
+}
+
+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_is_64bit(env, msr)) {
+        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(CPUPPCState *env)
+{
+    do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1],
+           ~((target_ulong)0x783F0000), 1);
+}
+
+#if defined(TARGET_PPC64)
+void helper_rfid(CPUPPCState *env)
+{
+    do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1],
+           ~((target_ulong)0x783F0000), 0);
+}
+
+void helper_hrfid(CPUPPCState *env)
+{
+    do_rfi(env, env->spr[SPR_HSRR0], env->spr[SPR_HSRR1],
+           ~((target_ulong)0x783F0000), 0);
+}
+#endif
+
+/*****************************************************************************/
+/* Embedded PowerPC specific helpers */
+void helper_40x_rfci(CPUPPCState *env)
+{
+    do_rfi(env, env->spr[SPR_40x_SRR2], env->spr[SPR_40x_SRR3],
+           ~((target_ulong)0xFFFF0000), 0);
+}
+
+void helper_rfci(CPUPPCState *env)
+{
+    do_rfi(env, env->spr[SPR_BOOKE_CSRR0], SPR_BOOKE_CSRR1,
+           ~((target_ulong)0x3FFF0000), 0);
+}
+
+void helper_rfdi(CPUPPCState *env)
+{
+    do_rfi(env, env->spr[SPR_BOOKE_DSRR0], SPR_BOOKE_DSRR1,
+           ~((target_ulong)0x3FFF0000), 0);
+}
+
+void helper_rfmci(CPUPPCState *env)
+{
+    do_rfi(env, env->spr[SPR_BOOKE_MCSRR0], SPR_BOOKE_MCSRR1,
+           ~((target_ulong)0x3FFF0000), 0);
+}
+#endif
+
+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(env, POWERPC_EXCP_PROGRAM,
+                                   POWERPC_EXCP_TRAP);
+    }
+}
+
+#if defined(TARGET_PPC64)
+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(env, POWERPC_EXCP_PROGRAM,
+                                   POWERPC_EXCP_TRAP);
+    }
+}
+#endif
+
+#if !defined(CONFIG_USER_ONLY)
+/*****************************************************************************/
+/* PowerPC 601 specific instructions (POWER bridge) */
+
+void helper_rfsvc(CPUPPCState *env)
+{
+    do_rfi(env, 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(CPUPPCState *env, 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/fpu_helper.c b/target-ppc/fpu_helper.c
new file mode 100644
index 0000000000..9d67926209
--- /dev/null
+++ b/target-ppc/fpu_helper.c
@@ -0,0 +1,1740 @@
+/*
+ *  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 "helper.h"
+
+/*****************************************************************************/
+/* Floating point operations helpers */
+uint64_t helper_float32_to_float64(CPUPPCState *env, 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(CPUPPCState *env, 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(CPUPPCState *env, 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(CPUPPCState *env, 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(CPUPPCState *env)
+{
+    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(CPUPPCState *env)
+{
+    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(CPUPPCState *env)
+{
+    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(CPUPPCState *env)
+{
+    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(CPUPPCState *env)
+{
+    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(CPUPPCState *env, 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(env);
+            break;
+        default:
+            break;
+        }
+    }
+}
+
+void helper_fpscr_setbit(CPUPPCState *env, 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;
+            }
+            break;
+        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(env);
+            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(CPUPPCState *env, 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(env);
+}
+
+void helper_float_check_status(CPUPPCState *env)
+{
+    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(env);
+        } else if (status & float_flag_overflow) {
+            float_overflow_excp(env);
+        } else if (status & float_flag_underflow) {
+            float_underflow_excp(env);
+        } else if (status & float_flag_inexact) {
+            float_inexact_excp(env);
+        }
+    }
+}
+
+void helper_reset_fpstatus(CPUPPCState *env)
+{
+    set_float_exception_flags(0, &env->fp_status);
+}
+
+/* fadd - fadd. */
+uint64_t helper_fadd(CPUPPCState *env, 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(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(env, POWERPC_EXCP_FP_VXSNAN);
+        }
+        farg1.d = float64_add(farg1.d, farg2.d, &env->fp_status);
+    }
+
+    return farg1.ll;
+}
+
+/* fsub - fsub. */
+uint64_t helper_fsub(CPUPPCState *env, 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(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(env, POWERPC_EXCP_FP_VXSNAN);
+        }
+        farg1.d = float64_sub(farg1.d, farg2.d, &env->fp_status);
+    }
+
+    return farg1.ll;
+}
+
+/* fmul - fmul. */
+uint64_t helper_fmul(CPUPPCState *env, 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(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(env, POWERPC_EXCP_FP_VXSNAN);
+        }
+        farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
+    }
+
+    return farg1.ll;
+}
+
+/* fdiv - fdiv. */
+uint64_t helper_fdiv(CPUPPCState *env, 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(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(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(env, POWERPC_EXCP_FP_VXSNAN);
+        }
+        farg1.d = float64_div(farg1.d, farg2.d, &env->fp_status);
+    }
+
+    return farg1.ll;
+}
+
+/* fabs */
+uint64_t helper_fabs(CPUPPCState *env, uint64_t arg)
+{
+    CPU_DoubleU farg;
+
+    farg.ll = arg;
+    farg.d = float64_abs(farg.d);
+    return farg.ll;
+}
+
+/* fnabs */
+uint64_t helper_fnabs(CPUPPCState *env, 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(CPUPPCState *env, uint64_t arg)
+{
+    CPU_DoubleU farg;
+
+    farg.ll = arg;
+    farg.d = float64_chs(farg.d);
+    return farg.ll;
+}
+
+/* fctiw - fctiw. */
+uint64_t helper_fctiw(CPUPPCState *env, 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(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(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.
+         *     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(CPUPPCState *env, 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(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(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.
+         *     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(CPUPPCState *env, uint64_t arg)
+{
+    CPU_DoubleU farg;
+
+    farg.d = int64_to_float64(arg, &env->fp_status);
+    return farg.ll;
+}
+
+/* fctid - fctid. */
+uint64_t helper_fctid(CPUPPCState *env, 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(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(env, POWERPC_EXCP_FP_VXCVI);
+    } else {
+        farg.ll = float64_to_int64(farg.d, &env->fp_status);
+    }
+    return farg.ll;
+}
+
+/* fctidz - fctidz. */
+uint64_t helper_fctidz(CPUPPCState *env, 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(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(env, 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(CPUPPCState *env, 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(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(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(env);
+    }
+    return farg.ll;
+}
+
+uint64_t helper_frin(CPUPPCState *env, uint64_t arg)
+{
+    return do_fri(env, arg, float_round_nearest_even);
+}
+
+uint64_t helper_friz(CPUPPCState *env, uint64_t arg)
+{
+    return do_fri(env, arg, float_round_to_zero);
+}
+
+uint64_t helper_frip(CPUPPCState *env, uint64_t arg)
+{
+    return do_fri(env, arg, float_round_up);
+}
+
+uint64_t helper_frim(CPUPPCState *env, uint64_t arg)
+{
+    return do_fri(env, arg, float_round_down);
+}
+
+/* fmadd - fmadd. */
+uint64_t helper_fmadd(CPUPPCState *env, 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(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(env, 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(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);
+            farg1.d = float128_to_float64(ft0_128, &env->fp_status);
+        }
+    }
+
+    return farg1.ll;
+}
+
+/* fmsub - fmsub. */
+uint64_t helper_fmsub(CPUPPCState *env, 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(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(env, 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(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);
+            farg1.d = float128_to_float64(ft0_128, &env->fp_status);
+        }
+    }
+    return farg1.ll;
+}
+
+/* fnmadd - fnmadd. */
+uint64_t helper_fnmadd(CPUPPCState *env, 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(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(env, 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(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);
+            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(CPUPPCState *env, 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(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(env, 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(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);
+            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(CPUPPCState *env, 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(env, 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(CPUPPCState *env, 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(env, POWERPC_EXCP_FP_VXSQRT);
+    } else {
+        if (unlikely(float64_is_signaling_nan(farg.d))) {
+            /* sNaN square root */
+            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN);
+        }
+        farg.d = float64_sqrt(farg.d, &env->fp_status);
+    }
+    return farg.ll;
+}
+
+/* fre - fre. */
+uint64_t helper_fre(CPUPPCState *env, uint64_t arg)
+{
+    CPU_DoubleU farg;
+
+    farg.ll = arg;
+
+    if (unlikely(float64_is_signaling_nan(farg.d))) {
+        /* sNaN reciprocal */
+        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(CPUPPCState *env, 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(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);
+    farg.d = float32_to_float64(f32, &env->fp_status);
+
+    return farg.ll;
+}
+
+/* frsqrte  - frsqrte. */
+uint64_t helper_frsqrte(CPUPPCState *env, 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(env, POWERPC_EXCP_FP_VXSQRT);
+    } else {
+        if (unlikely(float64_is_signaling_nan(farg.d))) {
+            /* sNaN reciprocal square root */
+            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);
+        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(CPUPPCState *env, 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(CPUPPCState *env, 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(env, POWERPC_EXCP_FP_VXSNAN);
+    }
+}
+
+void helper_fcmpo(CPUPPCState *env, 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(env, POWERPC_EXCP_FP_VXSNAN |
+                                  POWERPC_EXCP_FP_VXVC);
+        } else {
+            /* qNaN comparison */
+            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXVC);
+        }
+    }
+}
+
+/* Single-precision floating-point conversions */
+static inline uint32_t efscfsi(CPUPPCState *env, uint32_t val)
+{
+    CPU_FloatU u;
+
+    u.f = int32_to_float32(val, &env->vec_status);
+
+    return u.l;
+}
+
+static inline uint32_t efscfui(CPUPPCState *env, uint32_t val)
+{
+    CPU_FloatU u;
+
+    u.f = uint32_to_float32(val, &env->vec_status);
+
+    return u.l;
+}
+
+static inline int32_t efsctsi(CPUPPCState *env, 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(CPUPPCState *env, 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(CPUPPCState *env, 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(CPUPPCState *env, 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(CPUPPCState *env, 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(CPUPPCState *env, 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(CPUPPCState *env, 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(CPUPPCState *env, 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(CPUPPCState *env, uint32_t val)       \
+    {                                                             \
+        return e##name(env, 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(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);
+/* 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(CPUPPCState *env, 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(CPUPPCState *env, 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(CPUPPCState *env, 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(CPUPPCState *env, 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(CPUPPCState *env, uint32_t op1, uint32_t op2) \
+    {                                                                   \
+        return e##name(env, 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(CPUPPCState *env, uint64_t op1, uint64_t 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);
+/* 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(CPUPPCState *env, 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(CPUPPCState *env, 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(CPUPPCState *env, 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(CPUPPCState *env, uint32_t op1, uint32_t op2)
+{
+    /* XXX: TODO: ignore special values (NaN, infinites, ...) */
+    return efscmplt(env, op1, op2);
+}
+
+static inline uint32_t efststgt(CPUPPCState *env, uint32_t op1, uint32_t op2)
+{
+    /* XXX: TODO: ignore special values (NaN, infinites, ...) */
+    return efscmpgt(env, op1, op2);
+}
+
+static inline uint32_t efststeq(CPUPPCState *env, uint32_t op1, uint32_t op2)
+{
+    /* XXX: TODO: ignore special values (NaN, infinites, ...) */
+    return efscmpeq(env, op1, op2);
+}
+
+#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);
+/* 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(CPUPPCState *env, uint64_t op1, uint64_t op2) \
+    {                                                                   \
+        return evcmp_merge(e##name(env, op1 >> 32, op2 >> 32),          \
+                           e##name(env, 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(CPUPPCState *env, uint32_t val)
+{
+    CPU_DoubleU u;
+
+    u.d = int32_to_float64(val, &env->vec_status);
+
+    return u.ll;
+}
+
+uint64_t helper_efdcfsid(CPUPPCState *env, uint64_t val)
+{
+    CPU_DoubleU u;
+
+    u.d = int64_to_float64(val, &env->vec_status);
+
+    return u.ll;
+}
+
+uint64_t helper_efdcfui(CPUPPCState *env, uint32_t val)
+{
+    CPU_DoubleU u;
+
+    u.d = uint32_to_float64(val, &env->vec_status);
+
+    return u.ll;
+}
+
+uint64_t helper_efdcfuid(CPUPPCState *env, uint64_t val)
+{
+    CPU_DoubleU u;
+
+    u.d = uint64_to_float64(val, &env->vec_status);
+
+    return u.ll;
+}
+
+uint32_t helper_efdctsi(CPUPPCState *env, 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(CPUPPCState *env, 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(CPUPPCState *env, 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(CPUPPCState *env, 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(CPUPPCState *env, 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(CPUPPCState *env, 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(CPUPPCState *env, 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(CPUPPCState *env, 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(CPUPPCState *env, 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(CPUPPCState *env, 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(CPUPPCState *env, 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(CPUPPCState *env, 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(CPUPPCState *env, 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(CPUPPCState *env, 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(CPUPPCState *env, 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(CPUPPCState *env, 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(CPUPPCState *env, 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(CPUPPCState *env, 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(CPUPPCState *env, 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(CPUPPCState *env, uint64_t op1, uint64_t op2)
+{
+    /* XXX: TODO: test special values (NaN, infinites, ...) */
+    return helper_efdtstlt(env, op1, op2);
+}
+
+uint32_t helper_efdcmpgt(CPUPPCState *env, uint64_t op1, uint64_t op2)
+{
+    /* XXX: TODO: test special values (NaN, infinites, ...) */
+    return helper_efdtstgt(env, op1, op2);
+}
+
+uint32_t helper_efdcmpeq(CPUPPCState *env, uint64_t op1, uint64_t op2)
+{
+    /* XXX: TODO: test special values (NaN, infinites, ...) */
+    return helper_efdtsteq(env, op1, op2);
+}
diff --git a/target-ppc/helper.c b/target-ppc/helper.c
index 3f7d8a464f..48b19a7e1d 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
  *
@@ -23,3169 +23,6 @@
 #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 DEBUG_EXCEPTIONS
-//#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
-
-#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 */
-
-#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_virt(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_virt(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_virt(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_pte(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_pte(env, ctx, 1, h, rw, type, target_page_bits);
-#endif
-
-    return _find_pte(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, _prot;
-
-    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) {
-        _prot = tlb->prot & 0xF;
-    } else {
-        _prot = (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 = _prot;
-        if (_prot & PAGE_EXEC) {
-            LOG_SWTLB("%s: good TLB!\n", __func__);
-            return 0;
-        }
-
-        LOG_SWTLB("%s: no PAGE_EXEC: %x\n", __func__, _prot);
-        ret = -3;
-    } else {
-        if (msr_dr != (tlb->attr & 1)) {
-            LOG_SWTLB("%s: AS doesn't match\n", __func__);
-            return -1;
-        }
-
-        *prot = _prot;
-        if ((!rw && _prot & PAGE_READ) || (rw && (_prot & PAGE_WRITE))) {
-            LOG_SWTLB("%s: found TLB!\n", __func__);
-            return 0;
-        }
-
-        LOG_SWTLB("%s: PAGE_READ/WRITE doesn't match: %x\n", __func__, _prot);
-        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 _prot = 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) {
-            _prot |= PAGE_READ;
-        }
-        if (tlb->mas7_3 & MAS3_UW) {
-            _prot |= PAGE_WRITE;
-        }
-        if (tlb->mas7_3 & MAS3_UX) {
-            _prot |= PAGE_EXEC;
-        }
-    } else {
-        if (tlb->mas7_3 & MAS3_SR) {
-            _prot |= PAGE_READ;
-        }
-        if (tlb->mas7_3 & MAS3_SW) {
-            _prot |= PAGE_WRITE;
-        }
-        if (tlb->mas7_3 & MAS3_SX) {
-            _prot |= 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 = _prot;
-        if (_prot & PAGE_EXEC) {
-            LOG_SWTLB("%s: good TLB!\n", __func__);
-            return 0;
-        }
-
-        LOG_SWTLB("%s: no PAGE_EXEC: %x\n", __func__, _prot);
-        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 = _prot;
-        if ((!rw && _prot & PAGE_READ) || (rw && (_prot & PAGE_WRITE))) {
-            LOG_SWTLB("%s: found TLB!\n", __func__);
-            return 0;
-        }
-
-        LOG_SWTLB("%s: PAGE_READ/WRITE doesn't match: %x\n", __func__, _prot);
-        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)
-{
-    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;
@@ -3193,8 +30,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;
diff --git a/target-ppc/helper.h b/target-ppc/helper.h
index 148543a8a1..fd04c063e2 100644
--- a/target-ppc/helper.h
+++ b/target-ppc/helper.h
@@ -1,96 +1,96 @@
 #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
 
-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)
 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)
 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 *
@@ -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,212 +205,213 @@ 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(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_2(mtvscr, void, env, avr);
+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)
+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_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)
-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)
-DEF_HELPER_1(msgclr, void, tl)
+DEF_HELPER_2(msgclr, void, env, tl)
 #endif
 
-DEF_HELPER_3(dlmzb, tl, tl, tl, i32)
-DEF_HELPER_FLAGS_1(clcs, TCG_CALL_CONST | TCG_CALL_PURE, tl, i32)
+DEF_HELPER_4(dlmzb, tl, env, tl, tl, i32)
+DEF_HELPER_FLAGS_2(clcs, TCG_CALL_CONST | TCG_CALL_PURE, tl, env, i32)
 #if !defined(CONFIG_USER_ONLY)
-DEF_HELPER_1(rac, tl, tl)
+DEF_HELPER_2(rac, tl, env, 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)
+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_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)
+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_2(store_asr, void, env, 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_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(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_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)
+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_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_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)
+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/int_helper.c b/target-ppc/int_helper.c
new file mode 100644
index 0000000000..f638b2a07c
--- /dev/null
+++ b/target-ppc/int_helper.c
@@ -0,0 +1,1564 @@
+/*
+ *  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 "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(CPUPPCState *env, 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(CPUPPCState *env, 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(CPUPPCState *env, 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(CPUPPCState *env, 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(CPUPPCState *env, 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(CPUPPCState *env, 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(CPUPPCState *env, 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(CPUPPCState *env, 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(CPUPPCState *env, 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(CPUPPCState *env, 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(CPUPPCState *env, 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(CPUPPCState *env, 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(CPUPPCState *env, 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(CPUPPCState *env, 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(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
+{
+    vcmpbfp_internal(env, r, a, b, 0);
+}
+
+void helper_vcmpbfp_dot(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
+                        ppc_avr_t *b)
+{
+    vcmpbfp_internal(env, r, a, b, 1);
+}
+
+#define VCT(suffix, satcvt, element)                                    \
+    void helper_vct##suffix(CPUPPCState *env, 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(CPUPPCState *env, 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(CPUPPCState *env, 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(CPUPPCState *env, 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(CPUPPCState *env, 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(CPUPPCState *env, 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(CPUPPCState *env, 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(CPUPPCState *env, 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(CPUPPCState *env, 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(CPUPPCState *env, 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(CPUPPCState *env, 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(CPUPPCState *env, 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(CPUPPCState *env, 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(CPUPPCState *env, 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(CPUPPCState *env, 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(CPUPPCState *env, 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(CPUPPCState *env, 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(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(CPUPPCState *env, 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(CPUPPCState *env, 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(CPUPPCState *env, 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(CPUPPCState *env, 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(CPUPPCState *env, 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(CPUPPCState *env, 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(CPUPPCState *env, 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 const 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(CPUPPCState *env, 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/kvm.c b/target-ppc/kvm.c
index c09cc39c78..b6ef72d16b 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 34ecad3e26..e2f8703853 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/mem_helper.c b/target-ppc/mem_helper.c
new file mode 100644
index 0000000000..5b5f1bdd23
--- /dev/null
+++ b/target-ppc/mem_helper.c
@@ -0,0 +1,295 @@
+/*
+ *  PowerPC memory access 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 "host-utils.h"
+#include "helper.h"
+
+#include "helper_regs.h"
+
+#if !defined(CONFIG_USER_ONLY)
+#include "softmmu_exec.h"
+#endif /* !defined(CONFIG_USER_ONLY) */
+
+//#define DEBUG_OP
+
+/*****************************************************************************/
+/* Memory load and stores */
+
+static inline target_ulong addr_add(CPUPPCState *env, target_ulong addr,
+                                    target_long arg)
+{
+#if defined(TARGET_PPC64)
+    if (!msr_is_64bit(env, env->msr)) {
+        return (uint32_t)(addr + arg);
+    } else
+#endif
+    {
+        return addr + arg;
+    }
+}
+
+void helper_lmw(CPUPPCState *env, target_ulong addr, uint32_t reg)
+{
+    for (; reg < 32; reg++) {
+        if (msr_le) {
+            env->gpr[reg] = bswap32(cpu_ldl_data(env, addr));
+        } else {
+            env->gpr[reg] = cpu_ldl_data(env, addr);
+        }
+        addr = addr_add(env, addr, 4);
+    }
+}
+
+void helper_stmw(CPUPPCState *env, target_ulong addr, uint32_t reg)
+{
+    for (; reg < 32; reg++) {
+        if (msr_le) {
+            cpu_stl_data(env, addr, bswap32((uint32_t)env->gpr[reg]));
+        } else {
+            cpu_stl_data(env, addr, (uint32_t)env->gpr[reg]);
+        }
+        addr = addr_add(env, addr, 4);
+    }
+}
+
+void helper_lsw(CPUPPCState *env, target_ulong addr, uint32_t nb, uint32_t reg)
+{
+    int sh;
+
+    for (; nb > 3; nb -= 4) {
+        env->gpr[reg] = cpu_ldl_data(env, addr);
+        reg = (reg + 1) % 32;
+        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] |= cpu_ldub_data(env, addr) << sh;
+            addr = addr_add(env, addr, 1);
+        }
+    }
+}
+/* PPC32 specification says we must generate an exception if
+ * rA is in the range of registers to be loaded.
+ * 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(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) ||
+                     (reg < rb && (reg + xer_bc) > rb))) {
+            helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
+                                       POWERPC_EXCP_INVAL |
+                                       POWERPC_EXCP_INVAL_LSWX);
+        } else {
+            helper_lsw(env, addr, xer_bc, reg);
+        }
+    }
+}
+
+void helper_stsw(CPUPPCState *env, target_ulong addr, uint32_t nb,
+                 uint32_t reg)
+{
+    int sh;
+
+    for (; nb > 3; nb -= 4) {
+        cpu_stl_data(env, addr, env->gpr[reg]);
+        reg = (reg + 1) % 32;
+        addr = addr_add(env, addr, 4);
+    }
+    if (unlikely(nb > 0)) {
+        for (sh = 24; nb > 0; nb--, sh -= 8) {
+            cpu_stb_data(env, addr, (env->gpr[reg] >> sh) & 0xFF);
+            addr = addr_add(env, addr, 1);
+        }
+    }
+}
+
+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) {
+        cpu_stl_data(env, addr + i, 0);
+    }
+    if (env->reserve_addr == addr) {
+        env->reserve_addr = (target_ulong)-1ULL;
+    }
+}
+
+void helper_dcbz(CPUPPCState *env, target_ulong addr)
+{
+    do_dcbz(env, addr, env->dcache_line_size);
+}
+
+void helper_dcbz_970(CPUPPCState *env, target_ulong addr)
+{
+    if (((env->spr[SPR_970_HID5] >> 7) & 0x3) == 1) {
+        do_dcbz(env, addr, 32);
+    } else {
+        do_dcbz(env, addr, env->dcache_line_size);
+    }
+}
+
+void helper_icbi(CPUPPCState *env, target_ulong addr)
+{
+    addr &= ~(env->dcache_line_size - 1);
+    /* Invalidate one cache line :
+     * PowerPC specification says this is to be treated like a load
+     * (not a fetch) by the MMU. To be sure it will be so,
+     * do the load "by hand".
+     */
+    cpu_ldl_data(env, addr);
+}
+
+/* XXX: to be tested */
+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 = 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);
+        }
+        if (unlikely(c == xer_cmp)) {
+            break;
+        }
+        if (likely(d != 0)) {
+            d -= 8;
+        } else {
+            d = 24;
+            reg++;
+            reg = reg & 0x1F;
+        }
+    }
+    return i;
+}
+
+/*****************************************************************************/
+/* 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
+
+#define LVE(name, access, swap, element)                        \
+    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);                      \
+        int sh = sizeof(r->element[0]) >> 1;                    \
+        int index = (addr & 0xf) >> sh;                         \
+                                                                \
+        if (msr_le) {                                           \
+            r->element[LO_IDX ? index : (adjust - index)] =     \
+                swap(access(env, addr));                        \
+        } else {                                                \
+            r->element[LO_IDX ? index : (adjust - index)] =     \
+                access(env, addr);                              \
+        }                                                       \
+    }
+#define I(x) (x)
+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(CPUPPCState *env, 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(env, addr, swap(r->element[LO_IDX ? index :          \
+                                              (adjust - index)]));      \
+        } else {                                                        \
+            access(env, addr, r->element[LO_IDX ? index :               \
+                                         (adjust - index)]);            \
+        }                                                               \
+    }
+#define I(x) (x)
+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
+
+#undef HI_IDX
+#undef LO_IDX
+
+/*****************************************************************************/
+/* Softmmu support */
+#if !defined(CONFIG_USER_ONLY)
+
+#define MMUSUFFIX _mmu
+
+#define SHIFT 0
+#include "softmmu_template.h"
+
+#define SHIFT 1
+#include "softmmu_template.h"
+
+#define SHIFT 2
+#include "softmmu_template.h"
+
+#define SHIFT 3
+#include "softmmu_template.h"
+
+/* try to fill the TLB and return an exception if error. If retaddr is
+   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 *env, target_ulong addr, int is_write, int mmu_idx,
+              uintptr_t retaddr)
+{
+    TranslationBlock *tb;
+    int ret;
+
+    ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, mmu_idx);
+    if (unlikely(ret != 0)) {
+        if (likely(retaddr)) {
+            /* now we have a real cpu fault */
+            tb = tb_find_pc(retaddr);
+            if (likely(tb)) {
+                /* the PC is inside the translated code. It means that we have
+                   a virtual CPU fault */
+                cpu_restore_state(tb, env, retaddr);
+            }
+        }
+        helper_raise_exception_err(env, env->exception_index, env->error_code);
+    }
+}
+#endif /* !CONFIG_USER_ONLY */
diff --git a/target-ppc/misc_helper.c b/target-ppc/misc_helper.c
new file mode 100644
index 0000000000..26edcca2df
--- /dev/null
+++ b/target-ppc/misc_helper.c
@@ -0,0 +1,124 @@
+/*
+ * 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 "helper.h"
+
+#include "helper_regs.h"
+
+/*****************************************************************************/
+/* SPR accesses */
+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(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(CPUPPCState *env, target_ulong val)
+{
+    ppc_store_asr(env, val);
+}
+#endif
+
+void helper_store_sdr1(CPUPPCState *env, target_ulong val)
+{
+    ppc_store_sdr1(env, val);
+}
+
+void helper_store_hid0_601(CPUPPCState *env, 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(CPUPPCState *env, 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(CPUPPCState *env, target_ulong val)
+{
+    store_40x_dbcr0(env, val);
+}
+
+void helper_store_40x_sler(CPUPPCState *env, target_ulong val)
+{
+    store_40x_sler(env, val);
+}
+#endif
+/*****************************************************************************/
+/* PowerPC 601 specific instructions (POWER bridge) */
+
+target_ulong helper_clcs(CPUPPCState *env, 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;
+    }
+}
+
+/*****************************************************************************/
+/* Special registers manipulation */
+
+/* GDBstub can read and write MSR... */
+void ppc_store_msr(CPUPPCState *env, target_ulong value)
+{
+    hreg_store_msr(env, value, 0);
+}
diff --git a/target-ppc/mmu_helper.c b/target-ppc/mmu_helper.c
new file mode 100644
index 0000000000..d2664acef0
--- /dev/null
+++ b/target-ppc/mmu_helper.c
@@ -0,0 +1,3326 @@
+/*
+ *  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 "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__)
+#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);
+}
+
+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;
+
+    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;
+}
+
+/*****************************************************************************/
+/* SPR accesses */
+
+void helper_slbia(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 helper_slbie(CPUPPCState *env, target_ulong addr)
+{
+    ppc_slb_t *slb;
+
+    slb = slb_lookup(env, addr);
+    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;
+}
+
+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];
+
+    if (slot >= env->slb_nr) {
+        return -1;
+    }
+
+    *rt = slb->esid;
+    return 0;
+}
+
+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];
+
+    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 */
+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;
+
+    /* 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 */
+static 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:
+    case POWERPC_MMU_2_06d:
+        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:
+    case POWERPC_MMU_2_06d:
+        /* 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:
+        case POWERPC_MMU_2_06d:
+#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:
+                case POWERPC_MMU_2_06d:
+#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:
+                case POWERPC_MMU_2_06d:
+#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 helper_store_ibatu(CPUPPCState *env, uint32_t 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 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 helper_store_dbatu(CPUPPCState *env, uint32_t 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 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 helper_store_601_batu(CPUPPCState *env, uint32_t 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 helper_store_601_batl(CPUPPCState *env, uint32_t 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:
+    case POWERPC_MMU_2_06d:
+#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:
+    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,
+         *      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);
+    }
+}
+
+/* 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) {
+        /* XXX */
+        return 0;
+    }
+#endif
+    return env->sr[sr_num];
+}
+
+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__,
+            (int)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) */
+
+#if !defined(CONFIG_USER_ONLY)
+/* SLB management */
+#if defined(TARGET_PPC64)
+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,
+                                   POWERPC_EXCP_INVAL);
+    }
+}
+
+target_ulong helper_load_slb_esid(CPUPPCState *env, target_ulong rb)
+{
+    target_ulong rt = 0;
+
+    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(CPUPPCState *env, target_ulong rb)
+{
+    target_ulong rt = 0;
+
+    if (ppc_load_slb_vsid(env, rb, &rt) < 0) {
+        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
+                                   POWERPC_EXCP_INVAL);
+    }
+    return rt;
+}
+#endif /* defined(TARGET_PPC64) */
+
+/* TLB management */
+void helper_tlbia(CPUPPCState *env)
+{
+    ppc_tlb_invalidate_all(env);
+}
+
+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(CPUPPCState *env, 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(CPUPPCState *env, target_ulong EPN)
+{
+    do_6xx_tlb(env, EPN, 0);
+}
+
+void helper_6xx_tlbi(CPUPPCState *env, target_ulong EPN)
+{
+    do_6xx_tlb(env, EPN, 1);
+}
+
+/* PowerPC 74xx software TLB load instructions helpers */
+static void do_74xx_tlb(CPUPPCState *env, 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(CPUPPCState *env, target_ulong EPN)
+{
+    do_74xx_tlb(env, EPN, 0);
+}
+
+void helper_74xx_tlbi(CPUPPCState *env, target_ulong EPN)
+{
+    do_74xx_tlb(env, EPN, 1);
+}
+
+/*****************************************************************************/
+/* PowerPC 601 specific instructions (POWER bridge) */
+
+target_ulong helper_rac(CPUPPCState *env, 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(CPUPPCState *env, 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(CPUPPCState *env, 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(CPUPPCState *env, 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(CPUPPCState *env, 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(CPUPPCState *env, target_ulong address)
+{
+    return ppcemb_tlb_search(env, address, env->spr[SPR_40x_PID]);
+}
+
+/* PowerPC 440 TLB management */
+void helper_440_tlbwe(CPUPPCState *env, 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(CPUPPCState *env, 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(CPUPPCState *env, 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(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(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:
+        /* 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;
+    }
+
+    /* 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 */
+        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(CPUPPCState *env)
+{
+    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(CPUPPCState *env, 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(CPUPPCState *env, 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(CPUPPCState *env, target_ulong address)
+{
+    /* XXX missing LPID handling */
+    booke206_flush_tlb(env, -1, 1);
+}
+
+void helper_booke206_tlbilx1(CPUPPCState *env, 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(CPUPPCState *env, 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(CPUPPCState *env, 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/mpic_helper.c b/target-ppc/mpic_helper.c
new file mode 100644
index 0000000000..2c6a4d30a9
--- /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
diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c
deleted file mode 100644
index 4ef2332a5a..0000000000
--- a/target-ppc/op_helper.c
+++ /dev/null
@@ -1,4568 +0,0 @@
-/*
- *  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 <string.h>
-#include "cpu.h"
-#include "dyngen-exec.h"
-#include "host-utils.h"
-#include "helper.h"
-
-#include "helper_regs.h"
-
-#if !defined(CONFIG_USER_ONLY)
-#include "softmmu_exec.h"
-#endif /* !defined(CONFIG_USER_ONLY) */
-
-//#define DEBUG_OP
-//#define DEBUG_EXCEPTIONS
-//#define DEBUG_SOFTWARE_TLB
-
-#ifdef DEBUG_SOFTWARE_TLB
-#  define LOG_SWTLB(...) qemu_log(__VA_ARGS__)
-#else
-#  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)
-{
-    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]);
-}
-
-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)
-{
-    ppc_store_asr(env, val);
-}
-#endif
-
-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;
-
-    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);
-    }
-}
-
-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);
-}
-
-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);
-}
-
-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
-
-/*****************************************************************************/
-/* Memory load and stores */
-
-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
-#endif
-            return addr + arg;
-}
-
-void helper_lmw (target_ulong addr, uint32_t reg)
-{
-    for (; reg < 32; reg++) {
-        if (msr_le)
-            env->gpr[reg] = bswap32(ldl(addr));
-        else
-            env->gpr[reg] = ldl(addr);
-	addr = addr_add(addr, 4);
-    }
-}
-
-void helper_stmw (target_ulong addr, uint32_t reg)
-{
-    for (; reg < 32; reg++) {
-        if (msr_le)
-            stl(addr, bswap32((uint32_t)env->gpr[reg]));
-        else
-            stl(addr, (uint32_t)env->gpr[reg]);
-	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);
-    }
-    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);
-        }
-    }
-}
-/* PPC32 specification says we must generate an exception if
- * rA is in the range of registers to be loaded.
- * 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)
-{
-    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,
-                                       POWERPC_EXCP_INVAL |
-                                       POWERPC_EXCP_INVAL_LSWX);
-        } else {
-            helper_lsw(addr, xer_bc, reg);
-        }
-    }
-}
-
-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);
-    }
-    if (unlikely(nb > 0)) {
-        for (sh = 24; nb > 0; nb--, sh -= 8) {
-            stb(addr, (env->gpr[reg] >> sh) & 0xFF);
-            addr = addr_add(addr, 1);
-        }
-    }
-}
-
-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);
-    }
-    if (env->reserve_addr == addr)
-        env->reserve_addr = (target_ulong)-1ULL;
-}
-
-void helper_dcbz(target_ulong addr)
-{
-    do_dcbz(addr, env->dcache_line_size);
-}
-
-void helper_dcbz_970(target_ulong addr)
-{
-    if (((env->spr[SPR_970_HID5] >> 7) & 0x3) == 1)
-        do_dcbz(addr, 32);
-    else
-        do_dcbz(addr, env->dcache_line_size);
-}
-
-void helper_icbi(target_ulong addr)
-{
-    addr &= ~(env->dcache_line_size - 1);
-    /* Invalidate one cache line :
-     * PowerPC specification says this is to be treated like a load
-     * (not a fetch) by the MMU. To be sure it will be so,
-     * do the load "by hand".
-     */
-    ldl(addr);
-}
-
-// 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);
-        /* 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))
-            break;
-        if (likely(d != 0)) {
-            d -= 8;
-        } else {
-            d = 24;
-            reg++;
-            reg = reg & 0x1F;
-        }
-    }
-    return i;
-}
-
-/*****************************************************************************/
-/* 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
-
-/*****************************************************************************/
-/* 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(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(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->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);
-        }
-    }
-}
-
-#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) */
-
-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;
-    }
-}
-
-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)
-{
-    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;
-}
-
-void helper_rfsvc (void)
-{
-    do_rfi(env->lr, env->ctr, 0x0000FFFF, 0);
-}
-#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 */
-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)) {
-        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);
-    }
-    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(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,
-                                   POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG);
-    }
-}
-
-#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)
-{
-    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)
-#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
-
-#define LVE(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) {                                            \
-            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)
-LVE(lvehx, lduw, bswap16, u16)
-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)        \
-    {                                                           \
-        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)]); \
-        }                                                               \
-    }
-#define I(x) (x)
-STVE(stvebx, stb, I, u8)
-STVE(stvehx, stw, bswap16, u16)
-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);
-}
-
-/* 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)
-
-#define MMUSUFFIX _mmu
-
-#define SHIFT 0
-#include "softmmu_template.h"
-
-#define SHIFT 1
-#include "softmmu_template.h"
-
-#define SHIFT 2
-#include "softmmu_template.h"
-
-#define SHIFT 3
-#include "softmmu_template.h"
-
-/* try to fill the TLB and return an exception if error. If retaddr is
-   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,
-              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)) {
-            /* now we have a real cpu fault */
-            tb = tb_find_pc(retaddr);
-            if (likely(tb)) {
-                /* the PC is inside the translated code. It means that we have
-                   a virtual CPU fault */
-                cpu_restore_state(tb, env, retaddr);
-            }
-        }
-        helper_raise_exception_err(env->exception_index, env->error_code);
-    }
-    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(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(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(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(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(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);
-}
-
-/* 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 */
diff --git a/target-ppc/timebase_helper.c b/target-ppc/timebase_helper.c
new file mode 100644
index 0000000000..fad738a4af
--- /dev/null
+++ b/target-ppc/timebase_helper.c
@@ -0,0 +1,159 @@
+/*
+ *  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 */
+
+target_ulong helper_load_tbl(CPUPPCState *env)
+{
+    return (target_ulong)cpu_ppc_load_tbl(env);
+}
+
+target_ulong helper_load_tbu(CPUPPCState *env)
+{
+    return cpu_ppc_load_tbu(env);
+}
+
+target_ulong helper_load_atbl(CPUPPCState *env)
+{
+    return (target_ulong)cpu_ppc_load_atbl(env);
+}
+
+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(CPUPPCState *env)
+{
+    return (target_ulong)cpu_ppc_load_purr(env);
+}
+#endif
+
+target_ulong helper_load_601_rtcl(CPUPPCState *env)
+{
+    return cpu_ppc601_load_rtcl(env);
+}
+
+target_ulong helper_load_601_rtcu(CPUPPCState *env)
+{
+    return cpu_ppc601_load_rtcu(env);
+}
+
+#if !defined(CONFIG_USER_ONLY)
+void helper_store_tbl(CPUPPCState *env, target_ulong val)
+{
+    cpu_ppc_store_tbl(env, val);
+}
+
+void helper_store_tbu(CPUPPCState *env, target_ulong val)
+{
+    cpu_ppc_store_tbu(env, val);
+}
+
+void helper_store_atbl(CPUPPCState *env, target_ulong val)
+{
+    cpu_ppc_store_atbl(env, val);
+}
+
+void helper_store_atbu(CPUPPCState *env, target_ulong val)
+{
+    cpu_ppc_store_atbu(env, val);
+}
+
+void helper_store_601_rtcl(CPUPPCState *env, target_ulong val)
+{
+    cpu_ppc601_store_rtcl(env, val);
+}
+
+void helper_store_601_rtcu(CPUPPCState *env, target_ulong val)
+{
+    cpu_ppc601_store_rtcu(env, val);
+}
+
+target_ulong helper_load_decr(CPUPPCState *env)
+{
+    return cpu_ppc_load_decr(env);
+}
+
+void helper_store_decr(CPUPPCState *env, target_ulong val)
+{
+    cpu_ppc_store_decr(env, val);
+}
+
+target_ulong helper_load_40x_pit(CPUPPCState *env)
+{
+    return load_40x_pit(env);
+}
+
+void helper_store_40x_pit(CPUPPCState *env, target_ulong val)
+{
+    store_40x_pit(env, val);
+}
+
+void helper_store_booke_tcr(CPUPPCState *env, target_ulong val)
+{
+    store_booke_tcr(env, val);
+}
+
+void helper_store_booke_tsr(CPUPPCState *env, 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(CPUPPCState *env, 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(CPUPPCState *env, 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);
+    }
+}
diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index cf59765405..73ee74be21 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);
     }
 
@@ -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);
 }
 
@@ -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)]);
@@ -2027,10 +2035,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 +2060,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 +2084,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 +2108,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 +2124,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 +2156,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 +2179,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 +2193,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 +2249,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 +2267,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 +2342,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 +2367,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 +2394,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 +2421,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                            ***/
@@ -2495,7 +2518,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);
@@ -2966,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);
 }
@@ -2982,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);
 }
@@ -3020,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);
@@ -3039,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);
@@ -3061,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);
@@ -3081,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);
@@ -3303,7 +3326,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 +3416,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);
@@ -3662,7 +3685,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 +3702,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 +3717,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 +3745,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 +3757,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 +3769,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 +3781,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 +3959,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 +3997,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);
@@ -4091,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);
 }
 
@@ -4104,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);
 }
 
@@ -4146,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);
 }
 
@@ -4175,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
 }
@@ -4194,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
 }
@@ -4211,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
 }
@@ -4230,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
 }
@@ -4250,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
 }
@@ -4269,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
 }
@@ -4286,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
 }
@@ -4305,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
 }
@@ -4320,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
 }
 
@@ -4333,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
 }
@@ -4347,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
 }
@@ -4366,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
 }
 
@@ -4380,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
 }
 
@@ -4398,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
 }
 
@@ -4434,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
 }
 
@@ -4448,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
@@ -4525,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 */
 }
@@ -4533,7 +4559,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)]);
 }
@@ -4541,7 +4568,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)]);
 }
@@ -4549,7 +4577,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)]);
 }
@@ -4557,7 +4586,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)]);
 }
@@ -4633,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);
@@ -5165,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
 }
 
@@ -5179,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
 }
 
@@ -5195,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
 }
 
@@ -5209,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
 }
 
@@ -5257,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]);
@@ -5276,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
 }
@@ -5290,7 +5320,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
 }
@@ -5454,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
 }
@@ -5687,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
 }
@@ -5706,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
 }
@@ -5724,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
 }
@@ -5742,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
 }
@@ -5752,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 */
 }
 
@@ -5761,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 */
 }
 
@@ -5849,7 +5883,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 +5898,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 +5916,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 +5932,7 @@ static void gen_rfmci(DisasContext *ctx)
         return;
     }
     /* Restore CPU state */
-    gen_helper_rfmci();
+    gen_helper_rfmci(cpu_env);
     gen_sync_exception(ctx);
 #endif
 }
@@ -5917,10 +5951,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);
@@ -5942,7 +5978,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();
@@ -5968,10 +6004,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);
@@ -5998,7 +6036,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;
@@ -6022,7 +6061,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();
@@ -6052,7 +6091,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;
@@ -6076,7 +6116,7 @@ static void gen_tlbre_booke206(DisasContext *ctx)
         return;
     }
 
-    gen_helper_booke206_tlbre();
+    gen_helper_booke206_tlbre(cpu_env);
 #endif
 }
 
@@ -6100,7 +6140,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
 }
 
@@ -6115,7 +6155,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
 }
 
@@ -6133,7 +6173,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
 }
 
@@ -6153,13 +6193,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);
@@ -6220,8 +6260,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);
 }
 
@@ -6258,7 +6298,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
 }
 
@@ -6347,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);                                          \
     }
@@ -6365,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);                                          \
     }
@@ -6440,7 +6480,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);
 }
 
@@ -6479,6 +6519,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);
@@ -6530,41 +6587,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)                         \
@@ -6577,7 +6634,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);                                          \
@@ -6636,20 +6693,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)                                 \
@@ -6685,13 +6758,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)
 {
@@ -6713,7 +6805,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)) {                          \
@@ -6725,9 +6817,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);                                          \
@@ -8008,7 +8100,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);                                                    \
@@ -8023,7 +8115,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);                                                    \
@@ -8037,13 +8129,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)                              \
@@ -8058,7 +8151,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);                                              \
@@ -8075,8 +8168,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)                              \
@@ -8090,7 +8183,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);                                                    \
 }
@@ -8101,28 +8194,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);                                                    \
 }
@@ -8131,7 +8225,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);                                                    \
 }
@@ -8142,7 +8236,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)                                       \
@@ -8157,7 +8251,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);                                                    \
@@ -8169,7 +8263,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)                                            \
@@ -8184,7 +8278,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);                                                    \
 }
@@ -9532,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;
@@ -9589,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),
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index 6f61175e7d..e6580ff27c 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -55,31 +55,50 @@ 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)
+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();
@@ -159,7 +178,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 +190,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 +205,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 +217,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 +227,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 +242,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 +254,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 +264,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
@@ -279,28 +298,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,35 +338,35 @@ 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);
 }
 
 /* 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 +392,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
@@ -382,30 +401,30 @@ 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)
 {
     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);
 }
@@ -421,14 +440,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
@@ -437,36 +456,36 @@ 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)
 {
     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)
 {
-    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
 
@@ -481,7 +500,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);
 }
 
@@ -1371,14 +1390,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
@@ -1591,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);
         }
     }
@@ -2804,7 +2827,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 +2852,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 +4330,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 */
@@ -4424,16 +4447,70 @@ 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 */
 #if !defined(CONFIG_USER_ONLY)
@@ -4447,8 +4524,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 */
@@ -4476,6 +4561,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;
@@ -4491,6 +4577,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 */
@@ -4566,6 +4653,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;
@@ -4575,7 +4678,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);
 }
@@ -4595,6 +4698,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                                  */
@@ -7133,6 +7243,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
@@ -8527,6 +8638,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",
@@ -9928,6 +10042,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");