]> git.proxmox.com Git - qemu.git/blobdiff - target-ppc/translate.c
Add image format option in monitor for removable media
[qemu.git] / target-ppc / translate.c
index 817045de8c7f7487e46967f5a78e8e97c5959c2d..19de8695a369cc3f208f6292f2455d49bfcd11d6 100644 (file)
 #include "cpu.h"
 #include "exec-all.h"
 #include "disas.h"
+#include "tcg-op.h"
+#include "qemu-common.h"
+
+#define CPU_SINGLE_STEP 0x1
+#define CPU_BRANCH_STEP 0x2
+#define GDBSTUB_SINGLE_STEP 0x4
 
 /* Include definitions for instructions classes and implementations flags */
 //#define DO_SINGLE_STEP
 //#define PPC_DEBUG_DISAS
 //#define DEBUG_MEMORY_ACCESSES
 //#define DO_PPC_STATISTICS
+//#define OPTIMIZE_FPRF_UPDATE
 
 /*****************************************************************************/
 /* Code translation helpers                                                  */
-#if defined(USE_DIRECT_JUMP)
-#define TBPARAM(x)
-#else
-#define TBPARAM(x) (long)(x)
-#endif
-
-enum {
-#define DEF(s, n, copy_size) INDEX_op_ ## s,
-#include "opc.h"
-#undef DEF
-    NB_OPS,
-};
-
-static uint16_t *gen_opc_ptr;
-static uint32_t *gen_opparam_ptr;
 
-#include "gen-op.h"
+#if defined(OPTIMIZE_FPRF_UPDATE)
+static uint16_t *gen_fprf_buf[OPC_BUF_SIZE];
+static uint16_t **gen_fprf_ptr;
+#endif
 
 static always_inline void gen_set_T0 (target_ulong val)
 {
@@ -115,17 +110,9 @@ static always_inline void func (int n)                                        \
 GEN8(gen_op_load_crf_T0, gen_op_load_crf_T0_crf);
 GEN8(gen_op_load_crf_T1, gen_op_load_crf_T1_crf);
 GEN8(gen_op_store_T0_crf, gen_op_store_T0_crf_crf);
+#if 0 // Unused
 GEN8(gen_op_store_T1_crf, gen_op_store_T1_crf_crf);
-
-/* Floating point condition and status register moves */
-GEN8(gen_op_load_fpscr_T0, gen_op_load_fpscr_T0_fpscr);
-GEN8(gen_op_store_T0_fpscr, gen_op_store_T0_fpscr_fpscr);
-GEN8(gen_op_clear_fpscr, gen_op_clear_fpscr_fpscr);
-static always_inline void gen_op_store_T0_fpscri (int n, uint8_t param)
-{
-    gen_op_set_T0(param);
-    gen_op_store_T0_fpscr(n);
-}
+#endif
 
 /* General purpose registers moves */
 GEN32(gen_op_load_gpr_T0, gen_op_load_gpr_T0_gpr);
@@ -165,9 +152,7 @@ typedef struct DisasContext {
 #endif
     int fpu_enabled;
     int altivec_enabled;
-#if defined(TARGET_PPCEMB)
     int spe_enabled;
-#endif
     ppc_spr_t *spr_cb; /* Needed to check rights for mfspr/mtspr */
     int singlestep_enabled;
     int dcache_line_size;
@@ -199,6 +184,44 @@ static always_inline void gen_set_Rc0 (DisasContext *ctx)
     gen_op_set_Rc0();
 }
 
+static always_inline void gen_reset_fpstatus (void)
+{
+#ifdef CONFIG_SOFTFLOAT
+    gen_op_reset_fpstatus();
+#endif
+}
+
+static always_inline void gen_compute_fprf (int set_fprf, int set_rc)
+{
+    if (set_fprf != 0) {
+        /* This case might be optimized later */
+#if defined(OPTIMIZE_FPRF_UPDATE)
+        *gen_fprf_ptr++ = gen_opc_ptr;
+#endif
+        gen_op_compute_fprf(1);
+        if (unlikely(set_rc))
+            gen_op_store_T0_crf(1);
+        gen_op_float_check_status();
+    } else if (unlikely(set_rc)) {
+        /* We always need to compute fpcc */
+        gen_op_compute_fprf(0);
+        gen_op_store_T0_crf(1);
+        if (set_fprf)
+            gen_op_float_check_status();
+    }
+}
+
+static always_inline void gen_optimize_fprf (void)
+{
+#if defined(OPTIMIZE_FPRF_UPDATE)
+    uint16_t **ptr;
+
+    for (ptr = gen_fprf_buf; ptr != (gen_fprf_ptr - 1); ptr++)
+        *ptr = INDEX_op_nop1;
+    gen_fprf_ptr = gen_fprf_buf;
+#endif
+}
+
 static always_inline void gen_update_nip (DisasContext *ctx, target_ulong nip)
 {
 #if defined(TARGET_PPC64)
@@ -257,9 +280,14 @@ static void gen_##name (DisasContext *ctx);                                   \
 GEN_OPCODE(name, opc1, opc2, opc3, inval, type);                              \
 static void gen_##name (DisasContext *ctx)
 
+#define GEN_HANDLER2(name, onam, opc1, opc2, opc3, inval, type)               \
+static void gen_##name (DisasContext *ctx);                                   \
+GEN_OPCODE2(name, onam, opc1, opc2, opc3, inval, type);                       \
+static void gen_##name (DisasContext *ctx)
+
 typedef struct opcode_t {
     unsigned char opc1, opc2, opc3;
-#if HOST_LONG_BITS == 64 /* Explicitely align to 64 bits */
+#if HOST_LONG_BITS == 64 /* Explicitly align to 64 bits */
     unsigned char pad[5];
 #else
     unsigned char pad[1];
@@ -364,15 +392,15 @@ static always_inline target_ulong MASK (uint32_t start, uint32_t end)
 
 #if defined(TARGET_PPC64)
     if (likely(start == 0)) {
-        ret = (uint64_t)(-1ULL) << (63 - end);
+        ret = UINT64_MAX << (63 - end);
     } else if (likely(end == 63)) {
-        ret = (uint64_t)(-1ULL) >> start;
+        ret = UINT64_MAX >> start;
     }
 #else
     if (likely(start == 0)) {
-        ret = (uint32_t)(-1ULL) << (31  - end);
+        ret = UINT32_MAX << (31  - end);
     } else if (likely(end == 31)) {
-        ret = (uint32_t)(-1ULL) >> start;
+        ret = UINT32_MAX >> start;
     }
 #endif
     else {
@@ -388,109 +416,137 @@ static always_inline target_ulong MASK (uint32_t start, uint32_t end)
 /*****************************************************************************/
 /* PowerPC Instructions types definitions                                    */
 enum {
-    PPC_NONE          = 0x0000000000000000ULL,
+    PPC_NONE           = 0x0000000000000000ULL,
     /* PowerPC base instructions set                                         */
-    PPC_INSNS_BASE    = 0x0000000000000001ULL,
-    /* integer operations instructions                                       */
+    PPC_INSNS_BASE     = 0x0000000000000001ULL,
+    /*   integer operations instructions                                     */
 #define PPC_INTEGER PPC_INSNS_BASE
-    /* flow control instructions                                             */
+    /*   flow control instructions                                           */
 #define PPC_FLOW    PPC_INSNS_BASE
-    /* virtual memory instructions                                           */
+    /*   virtual memory instructions                                         */
 #define PPC_MEM     PPC_INSNS_BASE
-    /* ld/st with reservation instructions                                   */
+    /*   ld/st with reservation instructions                                 */
 #define PPC_RES     PPC_INSNS_BASE
-    /* cache control instructions                                            */
-#define PPC_CACHE   PPC_INSNS_BASE
-    /* spr/msr access instructions                                           */
+    /*   spr/msr access instructions                                         */
 #define PPC_MISC    PPC_INSNS_BASE
-    /* Optional floating point instructions                                  */
-    PPC_FLOAT         = 0x0000000000000002ULL,
-    PPC_FLOAT_FSQRT   = 0x0000000000000004ULL,
-    PPC_FLOAT_FRES    = 0x0000000000000008ULL,
-    PPC_FLOAT_FRSQRTE = 0x0000000000000010ULL,
-    PPC_FLOAT_FSEL    = 0x0000000000000020ULL,
-    PPC_FLOAT_STFIWX  = 0x0000000000000040ULL,
-    /* external control instructions                                         */
-    PPC_EXTERN        = 0x0000000000000080ULL,
-    /* segment register access instructions                                  */
-    PPC_SEGMENT       = 0x0000000000000100ULL,
-    /* Optional cache control instruction                                    */
-    PPC_CACHE_DCBA    = 0x0000000000000200ULL,
+    /* Deprecated instruction sets                                           */
+    /*   Original POWER instruction set                                      */
+    PPC_POWER          = 0x0000000000000002ULL,
+    /*   POWER2 instruction set extension                                    */
+    PPC_POWER2         = 0x0000000000000004ULL,
+    /*   Power RTC support                                                   */
+    PPC_POWER_RTC      = 0x0000000000000008ULL,
+    /*   Power-to-PowerPC bridge (601)                                       */
+    PPC_POWER_BR       = 0x0000000000000010ULL,
+    /* 64 bits PowerPC instruction set                                       */
+    PPC_64B            = 0x0000000000000020ULL,
+    /*   New 64 bits extensions (PowerPC 2.0x)                               */
+    PPC_64BX           = 0x0000000000000040ULL,
+    /*   64 bits hypervisor extensions                                       */
+    PPC_64H            = 0x0000000000000080ULL,
+    /*   New wait instruction (PowerPC 2.0x)                                 */
+    PPC_WAIT           = 0x0000000000000100ULL,
+    /*   Time base mftb instruction                                          */
+    PPC_MFTB           = 0x0000000000000200ULL,
+
+    /* Fixed-point unit extensions                                           */
+    /*   PowerPC 602 specific                                                */
+    PPC_602_SPEC       = 0x0000000000000400ULL,
+    /*   isel instruction                                                    */
+    PPC_ISEL           = 0x0000000000000800ULL,
+    /*   popcntb instruction                                                 */
+    PPC_POPCNTB        = 0x0000000000001000ULL,
+    /*   string load / store                                                 */
+    PPC_STRING         = 0x0000000000002000ULL,
+
+    /* Floating-point unit extensions                                        */
+    /*   Optional floating point instructions                                */
+    PPC_FLOAT          = 0x0000000000010000ULL,
+    /* New floating-point extensions (PowerPC 2.0x)                          */
+    PPC_FLOAT_EXT      = 0x0000000000020000ULL,
+    PPC_FLOAT_FSQRT    = 0x0000000000040000ULL,
+    PPC_FLOAT_FRES     = 0x0000000000080000ULL,
+    PPC_FLOAT_FRSQRTE  = 0x0000000000100000ULL,
+    PPC_FLOAT_FRSQRTES = 0x0000000000200000ULL,
+    PPC_FLOAT_FSEL     = 0x0000000000400000ULL,
+    PPC_FLOAT_STFIWX   = 0x0000000000800000ULL,
+
+    /* Vector/SIMD extensions                                                */
+    /*   Altivec support                                                     */
+    PPC_ALTIVEC        = 0x0000000001000000ULL,
+    /*   PowerPC 2.03 SPE extension                                          */
+    PPC_SPE            = 0x0000000002000000ULL,
+    /*   PowerPC 2.03 SPE floating-point extension                           */
+    PPC_SPEFPU         = 0x0000000004000000ULL,
+
     /* Optional memory control instructions                                  */
-    PPC_MEM_TLBIA     = 0x0000000000000400ULL,
-    PPC_MEM_TLBIE     = 0x0000000000000800ULL,
-    PPC_MEM_TLBSYNC   = 0x0000000000001000ULL,
-    /* eieio & sync                                                          */
-    PPC_MEM_SYNC      = 0x0000000000002000ULL,
-    /* PowerPC 6xx TLB management instructions                               */
-    PPC_6xx_TLB       = 0x0000000000004000ULL,
-    /* Altivec support                                                       */
-    PPC_ALTIVEC       = 0x0000000000008000ULL,
-    /* Time base mftb instruction                                            */
-    PPC_MFTB          = 0x0000000000010000ULL,
+    PPC_MEM_TLBIA      = 0x0000000010000000ULL,
+    PPC_MEM_TLBIE      = 0x0000000020000000ULL,
+    PPC_MEM_TLBSYNC    = 0x0000000040000000ULL,
+    /*   sync instruction                                                    */
+    PPC_MEM_SYNC       = 0x0000000080000000ULL,
+    /*   eieio instruction                                                   */
+    PPC_MEM_EIEIO      = 0x0000000100000000ULL,
+
+    /* Cache control instructions                                            */
+    PPC_CACHE          = 0x0000000200000000ULL,
+    /*   icbi instruction                                                    */
+    PPC_CACHE_ICBI     = 0x0000000400000000ULL,
+    /*   dcbz instruction with fixed cache line size                         */
+    PPC_CACHE_DCBZ     = 0x0000000800000000ULL,
+    /*   dcbz instruction with tunable cache line size                       */
+    PPC_CACHE_DCBZT    = 0x0000001000000000ULL,
+    /*   dcba instruction                                                    */
+    PPC_CACHE_DCBA     = 0x0000002000000000ULL,
+    /*   Freescale cache locking instructions                                */
+    PPC_CACHE_LOCK     = 0x0000004000000000ULL,
+
+    /* MMU related extensions                                                */
+    /*   external control instructions                                       */
+    PPC_EXTERN         = 0x0000010000000000ULL,
+    /*   segment register access instructions                                */
+    PPC_SEGMENT        = 0x0000020000000000ULL,
+    /*   PowerPC 6xx TLB management instructions                             */
+    PPC_6xx_TLB        = 0x0000040000000000ULL,
+    /* PowerPC 74xx TLB management instructions                              */
+    PPC_74xx_TLB       = 0x0000080000000000ULL,
+    /*   PowerPC 40x TLB management instructions                             */
+    PPC_40x_TLB        = 0x0000100000000000ULL,
+    /*   segment register access instructions for PowerPC 64 "bridge"        */
+    PPC_SEGMENT_64B    = 0x0000200000000000ULL,
+    /*   SLB management                                                      */
+    PPC_SLBI           = 0x0000400000000000ULL,
+
     /* Embedded PowerPC dedicated instructions                               */
-    PPC_EMB_COMMON    = 0x0000000000020000ULL,
+    PPC_WRTEE          = 0x0001000000000000ULL,
     /* PowerPC 40x exception model                                           */
-    PPC_40x_EXCP      = 0x0000000000040000ULL,
-    /* PowerPC 40x TLB management instructions                               */
-    PPC_40x_TLB       = 0x0000000000080000ULL,
+    PPC_40x_EXCP       = 0x0002000000000000ULL,
     /* PowerPC 405 Mac instructions                                          */
-    PPC_405_MAC       = 0x0000000000100000ULL,
+    PPC_405_MAC        = 0x0004000000000000ULL,
     /* PowerPC 440 specific instructions                                     */
-    PPC_440_SPEC      = 0x0000000000200000ULL,
-    /* Power-to-PowerPC bridge (601)                                         */
-    PPC_POWER_BR      = 0x0000000000400000ULL,
-    /* PowerPC 602 specific                                                  */
-    PPC_602_SPEC      = 0x0000000000800000ULL,
-    /* Deprecated instructions                                               */
-    /* Original POWER instruction set                                        */
-    PPC_POWER         = 0x0000000001000000ULL,
-    /* POWER2 instruction set extension                                      */
-    PPC_POWER2        = 0x0000000002000000ULL,
-    /* Power RTC support                                                     */
-    PPC_POWER_RTC     = 0x0000000004000000ULL,
-    /* 64 bits PowerPC instruction set                                       */
-    PPC_64B           = 0x0000000008000000ULL,
-    /* 64 bits hypervisor extensions                                         */
-    PPC_64H           = 0x0000000010000000ULL,
-    /* segment register access instructions for PowerPC 64 "bridge"          */
-    PPC_SEGMENT_64B   = 0x0000000020000000ULL,
+    PPC_440_SPEC       = 0x0008000000000000ULL,
     /* BookE (embedded) PowerPC specification                                */
-    PPC_BOOKE         = 0x0000000040000000ULL,
-    /* eieio                                                                 */
-    PPC_MEM_EIEIO     = 0x0000000080000000ULL,
-    /* e500 vector instructions                                              */
-    PPC_E500_VECTOR   = 0x0000000100000000ULL,
+    PPC_BOOKE          = 0x0010000000000000ULL,
+    /* mfapidi instruction                                                   */
+    PPC_MFAPIDI        = 0x0020000000000000ULL,
+    /* tlbiva instruction                                                    */
+    PPC_TLBIVA         = 0x0040000000000000ULL,
+    /* tlbivax instruction                                                   */
+    PPC_TLBIVAX        = 0x0080000000000000ULL,
     /* PowerPC 4xx dedicated instructions                                    */
-    PPC_4xx_COMMON    = 0x0000000200000000ULL,
-    /* PowerPC 2.03 specification extensions                                 */
-    PPC_203           = 0x0000000400000000ULL,
-    /* PowerPC 2.03 SPE extension                                            */
-    PPC_SPE           = 0x0000000800000000ULL,
-    /* PowerPC 2.03 SPE floating-point extension                             */
-    PPC_SPEFPU        = 0x0000001000000000ULL,
-    /* SLB management                                                        */
-    PPC_SLBI          = 0x0000002000000000ULL,
+    PPC_4xx_COMMON     = 0x0100000000000000ULL,
     /* PowerPC 40x ibct instructions                                         */
-    PPC_40x_ICBT      = 0x0000004000000000ULL,
-    /* PowerPC 74xx TLB management instructions                              */
-    PPC_74xx_TLB      = 0x0000008000000000ULL,
-    /* More BookE (embedded) instructions...                                 */
-    PPC_BOOKE_EXT     = 0x0000010000000000ULL,
+    PPC_40x_ICBT       = 0x0200000000000000ULL,
     /* rfmci is not implemented in all BookE PowerPC                         */
-    PPC_RFMCI         = 0x0000020000000000ULL,
+    PPC_RFMCI          = 0x0400000000000000ULL,
+    /* rfdi instruction                                                      */
+    PPC_RFDI           = 0x0800000000000000ULL,
+    /* DCR accesses                                                          */
+    PPC_DCR            = 0x1000000000000000ULL,
+    /* DCR extended accesse                                                  */
+    PPC_DCRX           = 0x2000000000000000ULL,
     /* user-mode DCR access, implemented in PowerPC 460                      */
-    PPC_DCRUX         = 0x0000040000000000ULL,
-    /* New floating-point extensions (PowerPC 2.0x)                          */
-    PPC_FLOAT_EXT     = 0x0000080000000000ULL,
-    /* New wait instruction (PowerPC 2.0x)                                   */
-    PPC_WAIT          = 0x0000100000000000ULL,
-    /* New 64 bits extensions (PowerPC 2.0x)                                 */
-    PPC_64BX          = 0x0000200000000000ULL,
-    /* dcbz instruction with fixed cache line size                           */
-    PPC_CACHE_DCBZ    = 0x0000400000000000ULL,
-    /* dcbz instruction with tunable cache line size                         */
-    PPC_CACHE_DCBZT   = 0x0000800000000000ULL,
+    PPC_DCRUX          = 0x4000000000000000ULL,
 };
 
 /*****************************************************************************/
@@ -523,6 +579,20 @@ OPCODES_SECTION opcode_t opc_##name = {                                       \
     },                                                                        \
     .oname = stringify(name),                                                 \
 }
+#define GEN_OPCODE2(name, onam, op1, op2, op3, invl, _typ)                    \
+OPCODES_SECTION opcode_t opc_##name = {                                       \
+    .opc1 = op1,                                                              \
+    .opc2 = op2,                                                              \
+    .opc3 = op3,                                                              \
+    .pad  = { 0, },                                                           \
+    .handler = {                                                              \
+        .inval   = invl,                                                      \
+        .type = _typ,                                                         \
+        .handler = &gen_##name,                                               \
+        .oname = onam,                                                        \
+    },                                                                        \
+    .oname = onam,                                                            \
+}
 #else
 #define GEN_OPCODE(name, op1, op2, op3, invl, _typ)                           \
 OPCODES_SECTION opcode_t opc_##name = {                                       \
@@ -537,6 +607,19 @@ OPCODES_SECTION opcode_t opc_##name = {                                       \
     },                                                                        \
     .oname = stringify(name),                                                 \
 }
+#define GEN_OPCODE2(name, onam, op1, op2, op3, invl, _typ)                    \
+OPCODES_SECTION opcode_t opc_##name = {                                       \
+    .opc1 = op1,                                                              \
+    .opc2 = op2,                                                              \
+    .opc3 = op3,                                                              \
+    .pad  = { 0, },                                                           \
+    .handler = {                                                              \
+        .inval   = invl,                                                      \
+        .type = _typ,                                                         \
+        .handler = &gen_##name,                                               \
+    },                                                                        \
+    .oname = onam,                                                            \
+}
 #endif
 
 #define GEN_OPCODE_MARK(name)                                                 \
@@ -819,17 +902,17 @@ GEN_INT_ARITH1_64 (neg,    0x1F, 0x08, 0x03, PPC_INTEGER);
 /* subf   subf.   subfo   subfo.   */
 static always_inline void gen_op_subfo (void)
 {
-    gen_op_move_T2_T0();
+    gen_op_moven_T2_T0();
     gen_op_subf();
-    gen_op_check_subfo();
+    gen_op_check_addo();
 }
 #if defined(TARGET_PPC64)
 #define gen_op_subf_64 gen_op_subf
 static always_inline void gen_op_subfo_64 (void)
 {
-    gen_op_move_T2_T0();
+    gen_op_moven_T2_T0();
     gen_op_subf();
-    gen_op_check_subfo_64();
+    gen_op_check_addo_64();
 }
 #endif
 GEN_INT_ARITH2_64 (subf,   0x1F, 0x08, 0x01, PPC_INTEGER);
@@ -841,10 +924,10 @@ static always_inline void gen_op_subfc (void)
 }
 static always_inline void gen_op_subfco (void)
 {
-    gen_op_move_T2_T0();
+    gen_op_moven_T2_T0();
     gen_op_subf();
     gen_op_check_subfc();
-    gen_op_check_subfo();
+    gen_op_check_addo();
 }
 #if defined(TARGET_PPC64)
 static always_inline void gen_op_subfc_64 (void)
@@ -854,27 +937,27 @@ static always_inline void gen_op_subfc_64 (void)
 }
 static always_inline void gen_op_subfco_64 (void)
 {
-    gen_op_move_T2_T0();
+    gen_op_moven_T2_T0();
     gen_op_subf();
     gen_op_check_subfc_64();
-    gen_op_check_subfo_64();
+    gen_op_check_addo_64();
 }
 #endif
 GEN_INT_ARITH2_64 (subfc,  0x1F, 0x08, 0x00, PPC_INTEGER);
 /* subfe  subfe.  subfeo  subfeo.  */
 static always_inline void gen_op_subfeo (void)
 {
-    gen_op_move_T2_T0();
+    gen_op_moven_T2_T0();
     gen_op_subfe();
-    gen_op_check_subfo();
+    gen_op_check_addo();
 }
 #if defined(TARGET_PPC64)
 #define gen_op_subfe_64 gen_op_subfe
 static always_inline void gen_op_subfeo_64 (void)
 {
-    gen_op_move_T2_T0();
+    gen_op_moven_T2_T0();
     gen_op_subfe_64();
-    gen_op_check_subfo_64();
+    gen_op_check_addo_64();
 }
 #endif
 GEN_INT_ARITH2_64 (subfe,  0x1F, 0x08, 0x04, PPC_INTEGER);
@@ -918,7 +1001,7 @@ GEN_HANDLER(addic, 0x0C, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
     gen_op_store_T0_gpr(rD(ctx->opcode));
 }
 /* addic. */
-GEN_HANDLER(addic_, 0x0D, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
+GEN_HANDLER2(addic_, "addic.", 0x0D, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
 {
     target_long simm = SIMM(ctx->opcode);
 
@@ -1040,7 +1123,7 @@ GEN_HANDLER(cmpli, 0x0A, 0xFF, 0xFF, 0x00400000, PPC_INTEGER)
 }
 
 /* isel (PowerPC 2.03 specification) */
-GEN_HANDLER(isel, 0x1F, 0x0F, 0x00, 0x00000001, PPC_203)
+GEN_HANDLER(isel, 0x1F, 0x0F, 0xFF, 0x00000001, PPC_ISEL)
 {
     uint32_t bi = rC(ctx->opcode);
     uint32_t mask;
@@ -1087,7 +1170,7 @@ GEN_LOGICAL2(and, 0x00, PPC_INTEGER);
 /* andc & andc. */
 GEN_LOGICAL2(andc, 0x01, PPC_INTEGER);
 /* andi. */
-GEN_HANDLER(andi_, 0x1C, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
+GEN_HANDLER2(andi_, "andi.", 0x1C, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
 {
     gen_op_load_gpr_T0(rS(ctx->opcode));
     gen_op_andi_T0(UIMM(ctx->opcode));
@@ -1095,7 +1178,7 @@ GEN_HANDLER(andi_, 0x1C, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
     gen_set_Rc0(ctx);
 }
 /* andis. */
-GEN_HANDLER(andis_, 0x1D, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
+GEN_HANDLER2(andis_, "andis.", 0x1D, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
 {
     gen_op_load_gpr_T0(rS(ctx->opcode));
     gen_op_andi_T0(UIMM(ctx->opcode) << 16);
@@ -1171,14 +1254,12 @@ GEN_HANDLER(or, 0x1F, 0x1C, 0x0D, 0x00000000, PPC_INTEGER)
                 gen_op_store_pri(6);
             }
             break;
-#if defined(TARGET_PPC64H)
         case 7:
             if (ctx->supervisor > 1) {
                 /* Set process priority to very high */
                 gen_op_store_pri(7);
             }
             break;
-#endif
 #endif
         default:
             /* nop */
@@ -1265,7 +1346,7 @@ GEN_HANDLER(xoris, 0x1B, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
 }
 
 /* popcntb : PowerPC 2.03 specification */
-GEN_HANDLER(popcntb, 0x1F, 0x03, 0x03, 0x0000F801, PPC_203)
+GEN_HANDLER(popcntb, 0x1F, 0x03, 0x03, 0x0000F801, PPC_POPCNTB)
 {
     gen_op_load_gpr_T0(rS(ctx->opcode));
 #if defined(TARGET_PPC64)
@@ -1385,28 +1466,32 @@ GEN_HANDLER(rlwnm, 0x17, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
 
 #if defined(TARGET_PPC64)
 #define GEN_PPC64_R2(name, opc1, opc2)                                        \
-GEN_HANDLER(name##0, opc1, opc2, 0xFF, 0x00000000, PPC_64B)                   \
+GEN_HANDLER2(name##0, stringify(name), opc1, opc2, 0xFF, 0x00000000, PPC_64B) \
 {                                                                             \
     gen_##name(ctx, 0);                                                       \
 }                                                                             \
-GEN_HANDLER(name##1, opc1, opc2 | 0x10, 0xFF, 0x00000000, PPC_64B)            \
+GEN_HANDLER2(name##1, stringify(name), opc1, opc2 | 0x10, 0xFF, 0x00000000,   \
+             PPC_64B)                                                         \
 {                                                                             \
     gen_##name(ctx, 1);                                                       \
 }
 #define GEN_PPC64_R4(name, opc1, opc2)                                        \
-GEN_HANDLER(name##0, opc1, opc2, 0xFF, 0x00000000, PPC_64B)                   \
+GEN_HANDLER2(name##0, stringify(name), opc1, opc2, 0xFF, 0x00000000, PPC_64B) \
 {                                                                             \
     gen_##name(ctx, 0, 0);                                                    \
 }                                                                             \
-GEN_HANDLER(name##1, opc1, opc2 | 0x01, 0xFF, 0x00000000, PPC_64B)            \
+GEN_HANDLER2(name##1, stringify(name), opc1, opc2 | 0x01, 0xFF, 0x00000000,   \
+             PPC_64B)                                                         \
 {                                                                             \
     gen_##name(ctx, 0, 1);                                                    \
 }                                                                             \
-GEN_HANDLER(name##2, opc1, opc2 | 0x10, 0xFF, 0x00000000, PPC_64B)            \
+GEN_HANDLER2(name##2, stringify(name), opc1, opc2 | 0x10, 0xFF, 0x00000000,   \
+             PPC_64B)                                                         \
 {                                                                             \
     gen_##name(ctx, 1, 0);                                                    \
 }                                                                             \
-GEN_HANDLER(name##3, opc1, opc2 | 0x11, 0xFF, 0x00000000, PPC_64B)            \
+GEN_HANDLER2(name##3, stringify(name), opc1, opc2 | 0x11, 0xFF, 0x00000000,   \
+             PPC_64B)                                                         \
 {                                                                             \
     gen_##name(ctx, 1, 1);                                                    \
 }
@@ -1523,17 +1608,15 @@ GEN_PPC64_R2(rldcr, 0x1E, 0x09);
 static always_inline void gen_rldimi (DisasContext *ctx, int mbn, int shn)
 {
     uint64_t mask;
-    uint32_t sh, mb;
+    uint32_t sh, mb, me;
 
     sh = SH(ctx->opcode) | (shn << 5);
     mb = MB(ctx->opcode) | (mbn << 5);
+    me = 63 - sh;
     if (likely(sh == 0)) {
         if (likely(mb == 0)) {
             gen_op_load_gpr_T0(rS(ctx->opcode));
             goto do_store;
-        } else if (likely(mb == 63)) {
-            gen_op_load_gpr_T0(rA(ctx->opcode));
-            goto do_store;
         }
         gen_op_load_gpr_T0(rS(ctx->opcode));
         gen_op_load_gpr_T1(rA(ctx->opcode));
@@ -1543,7 +1626,7 @@ static always_inline void gen_rldimi (DisasContext *ctx, int mbn, int shn)
     gen_op_load_gpr_T1(rA(ctx->opcode));
     gen_op_rotli64_T0(sh);
  do_mask:
-    mask = MASK(mb, 63 - sh);
+    mask = MASK(mb, me);
     gen_andi_T0_64(ctx, mask);
     gen_andi_T1_64(ctx, ~mask);
     gen_op_or();
@@ -1606,11 +1689,11 @@ static always_inline void gen_sradi (DisasContext *ctx, int n)
     if (unlikely(Rc(ctx->opcode) != 0))
         gen_set_Rc0(ctx);
 }
-GEN_HANDLER(sradi0, 0x1F, 0x1A, 0x19, 0x00000000, PPC_64B)
+GEN_HANDLER2(sradi0, "sradi", 0x1F, 0x1A, 0x19, 0x00000000, PPC_64B)
 {
     gen_sradi(ctx, 0);
 }
-GEN_HANDLER(sradi1, 0x1F, 0x1B, 0x19, 0x00000000, PPC_64B)
+GEN_HANDLER2(sradi1, "sradi", 0x1F, 0x1B, 0x19, 0x00000000, PPC_64B)
 {
     gen_sradi(ctx, 1);
 }
@@ -1619,124 +1702,127 @@ __GEN_LOGICAL2(srd, 0x1B, 0x10, PPC_64B);
 #endif
 
 /***                       Floating-Point arithmetic                       ***/
-#define _GEN_FLOAT_ACB(name, op, op1, op2, isfloat, type)                     \
+#define _GEN_FLOAT_ACB(name, op, op1, op2, isfloat, set_fprf, type)           \
 GEN_HANDLER(f##name, op1, op2, 0xFF, 0x00000000, type)                        \
 {                                                                             \
     if (unlikely(!ctx->fpu_enabled)) {                                        \
         GEN_EXCP_NO_FP(ctx);                                                  \
         return;                                                               \
     }                                                                         \
-    gen_op_reset_scrfx();                                                     \
     gen_op_load_fpr_FT0(rA(ctx->opcode));                                     \
     gen_op_load_fpr_FT1(rC(ctx->opcode));                                     \
     gen_op_load_fpr_FT2(rB(ctx->opcode));                                     \
+    gen_reset_fpstatus();                                                     \
     gen_op_f##op();                                                           \
     if (isfloat) {                                                            \
         gen_op_frsp();                                                        \
     }                                                                         \
     gen_op_store_FT0_fpr(rD(ctx->opcode));                                    \
-    if (unlikely(Rc(ctx->opcode) != 0))                                       \
-        gen_op_set_Rc1();                                                     \
+    gen_compute_fprf(set_fprf, Rc(ctx->opcode) != 0);                         \
 }
 
-#define GEN_FLOAT_ACB(name, op2, type)                                        \
-_GEN_FLOAT_ACB(name, name, 0x3F, op2, 0, type);                               \
-_GEN_FLOAT_ACB(name##s, name, 0x3B, op2, 1, type);
+#define GEN_FLOAT_ACB(name, op2, set_fprf, type)                              \
+_GEN_FLOAT_ACB(name, name, 0x3F, op2, 0, set_fprf, type);                     \
+_GEN_FLOAT_ACB(name##s, name, 0x3B, op2, 1, set_fprf, type);
 
-#define _GEN_FLOAT_AB(name, op, op1, op2, inval, isfloat)                     \
-GEN_HANDLER(f##name, op1, op2, 0xFF, inval, PPC_FLOAT)                        \
+#define _GEN_FLOAT_AB(name, op, op1, op2, inval, isfloat, set_fprf, type)     \
+GEN_HANDLER(f##name, op1, op2, 0xFF, inval, type)                             \
 {                                                                             \
     if (unlikely(!ctx->fpu_enabled)) {                                        \
         GEN_EXCP_NO_FP(ctx);                                                  \
         return;                                                               \
     }                                                                         \
-    gen_op_reset_scrfx();                                                     \
     gen_op_load_fpr_FT0(rA(ctx->opcode));                                     \
     gen_op_load_fpr_FT1(rB(ctx->opcode));                                     \
+    gen_reset_fpstatus();                                                     \
     gen_op_f##op();                                                           \
     if (isfloat) {                                                            \
         gen_op_frsp();                                                        \
     }                                                                         \
     gen_op_store_FT0_fpr(rD(ctx->opcode));                                    \
-    if (unlikely(Rc(ctx->opcode) != 0))                                       \
-        gen_op_set_Rc1();                                                     \
+    gen_compute_fprf(set_fprf, Rc(ctx->opcode) != 0);                         \
 }
-#define GEN_FLOAT_AB(name, op2, inval)                                        \
-_GEN_FLOAT_AB(name, name, 0x3F, op2, inval, 0);                               \
-_GEN_FLOAT_AB(name##s, name, 0x3B, op2, inval, 1);
+#define GEN_FLOAT_AB(name, op2, inval, set_fprf, type)                        \
+_GEN_FLOAT_AB(name, name, 0x3F, op2, inval, 0, set_fprf, type);               \
+_GEN_FLOAT_AB(name##s, name, 0x3B, op2, inval, 1, set_fprf, type);
 
-#define _GEN_FLOAT_AC(name, op, op1, op2, inval, isfloat)                     \
-GEN_HANDLER(f##name, op1, op2, 0xFF, inval, PPC_FLOAT)                        \
+#define _GEN_FLOAT_AC(name, op, op1, op2, inval, isfloat, set_fprf, type)     \
+GEN_HANDLER(f##name, op1, op2, 0xFF, inval, type)                             \
 {                                                                             \
     if (unlikely(!ctx->fpu_enabled)) {                                        \
         GEN_EXCP_NO_FP(ctx);                                                  \
         return;                                                               \
     }                                                                         \
-    gen_op_reset_scrfx();                                                     \
     gen_op_load_fpr_FT0(rA(ctx->opcode));                                     \
     gen_op_load_fpr_FT1(rC(ctx->opcode));                                     \
+    gen_reset_fpstatus();                                                     \
     gen_op_f##op();                                                           \
     if (isfloat) {                                                            \
         gen_op_frsp();                                                        \
     }                                                                         \
     gen_op_store_FT0_fpr(rD(ctx->opcode));                                    \
-    if (unlikely(Rc(ctx->opcode) != 0))                                       \
-        gen_op_set_Rc1();                                                     \
+    gen_compute_fprf(set_fprf, Rc(ctx->opcode) != 0);                         \
 }
-#define GEN_FLOAT_AC(name, op2, inval)                                        \
-_GEN_FLOAT_AC(name, name, 0x3F, op2, inval, 0);                               \
-_GEN_FLOAT_AC(name##s, name, 0x3B, op2, inval, 1);
+#define GEN_FLOAT_AC(name, op2, inval, set_fprf, type)                        \
+_GEN_FLOAT_AC(name, name, 0x3F, op2, inval, 0, set_fprf, type);               \
+_GEN_FLOAT_AC(name##s, name, 0x3B, op2, inval, 1, set_fprf, type);
 
-#define GEN_FLOAT_B(name, op2, op3, type)                                     \
+#define GEN_FLOAT_B(name, op2, op3, set_fprf, type)                           \
 GEN_HANDLER(f##name, 0x3F, op2, op3, 0x001F0000, type)                        \
 {                                                                             \
     if (unlikely(!ctx->fpu_enabled)) {                                        \
         GEN_EXCP_NO_FP(ctx);                                                  \
         return;                                                               \
     }                                                                         \
-    gen_op_reset_scrfx();                                                     \
     gen_op_load_fpr_FT0(rB(ctx->opcode));                                     \
+    gen_reset_fpstatus();                                                     \
     gen_op_f##name();                                                         \
     gen_op_store_FT0_fpr(rD(ctx->opcode));                                    \
-    if (unlikely(Rc(ctx->opcode) != 0))                                       \
-        gen_op_set_Rc1();                                                     \
+    gen_compute_fprf(set_fprf, Rc(ctx->opcode) != 0);                         \
 }
 
-#define GEN_FLOAT_BS(name, op1, op2, type)                                    \
+#define GEN_FLOAT_BS(name, op1, op2, set_fprf, type)                          \
 GEN_HANDLER(f##name, op1, op2, 0xFF, 0x001F07C0, type)                        \
 {                                                                             \
     if (unlikely(!ctx->fpu_enabled)) {                                        \
         GEN_EXCP_NO_FP(ctx);                                                  \
         return;                                                               \
     }                                                                         \
-    gen_op_reset_scrfx();                                                     \
     gen_op_load_fpr_FT0(rB(ctx->opcode));                                     \
+    gen_reset_fpstatus();                                                     \
     gen_op_f##name();                                                         \
     gen_op_store_FT0_fpr(rD(ctx->opcode));                                    \
-    if (unlikely(Rc(ctx->opcode) != 0))                                       \
-        gen_op_set_Rc1();                                                     \
+    gen_compute_fprf(set_fprf, Rc(ctx->opcode) != 0);                         \
 }
 
 /* fadd - fadds */
-GEN_FLOAT_AB(add, 0x15, 0x000007C0);
+GEN_FLOAT_AB(add, 0x15, 0x000007C0, 1, PPC_FLOAT);
 /* fdiv - fdivs */
-GEN_FLOAT_AB(div, 0x12, 0x000007C0);
+GEN_FLOAT_AB(div, 0x12, 0x000007C0, 1, PPC_FLOAT);
 /* fmul - fmuls */
-GEN_FLOAT_AC(mul, 0x19, 0x0000F800);
+GEN_FLOAT_AC(mul, 0x19, 0x0000F800, 1, PPC_FLOAT);
 
 /* fre */
-GEN_FLOAT_BS(re, 0x3F, 0x18, PPC_FLOAT_EXT);
+GEN_FLOAT_BS(re, 0x3F, 0x18, 1, PPC_FLOAT_EXT);
 
 /* fres */
-GEN_FLOAT_BS(res, 0x3B, 0x18, PPC_FLOAT_FRES);
+GEN_FLOAT_BS(res, 0x3B, 0x18, 1, PPC_FLOAT_FRES);
 
 /* frsqrte */
-GEN_FLOAT_BS(rsqrte, 0x3F, 0x1A, PPC_FLOAT_FRSQRTE);
+GEN_FLOAT_BS(rsqrte, 0x3F, 0x1A, 1, PPC_FLOAT_FRSQRTE);
+
+/* frsqrtes */
+static always_inline void gen_op_frsqrtes (void)
+{
+    gen_op_frsqrte();
+    gen_op_frsp();
+}
+GEN_FLOAT_BS(rsqrtes, 0x3B, 0x1A, 1, PPC_FLOAT_FRSQRTES);
 
 /* fsel */
-_GEN_FLOAT_ACB(sel, sel, 0x3F, 0x17, 0, PPC_FLOAT_FSEL);
+_GEN_FLOAT_ACB(sel, sel, 0x3F, 0x17, 0, 0, PPC_FLOAT_FSEL);
 /* fsub - fsubs */
-GEN_FLOAT_AB(sub, 0x14, 0x000007C0);
+GEN_FLOAT_AB(sub, 0x14, 0x000007C0, 1, PPC_FLOAT);
 /* Optional: */
 /* fsqrt */
 GEN_HANDLER(fsqrt, 0x3F, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_FSQRT)
@@ -1745,12 +1831,11 @@ GEN_HANDLER(fsqrt, 0x3F, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_FSQRT)
         GEN_EXCP_NO_FP(ctx);
         return;
     }
-    gen_op_reset_scrfx();
     gen_op_load_fpr_FT0(rB(ctx->opcode));
+    gen_reset_fpstatus();
     gen_op_fsqrt();
     gen_op_store_FT0_fpr(rD(ctx->opcode));
-    if (unlikely(Rc(ctx->opcode) != 0))
-        gen_op_set_Rc1();
+    gen_compute_fprf(1, Rc(ctx->opcode) != 0);
 }
 
 GEN_HANDLER(fsqrts, 0x3B, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_FSQRT)
@@ -1759,49 +1844,48 @@ GEN_HANDLER(fsqrts, 0x3B, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_FSQRT)
         GEN_EXCP_NO_FP(ctx);
         return;
     }
-    gen_op_reset_scrfx();
     gen_op_load_fpr_FT0(rB(ctx->opcode));
+    gen_reset_fpstatus();
     gen_op_fsqrt();
     gen_op_frsp();
     gen_op_store_FT0_fpr(rD(ctx->opcode));
-    if (unlikely(Rc(ctx->opcode) != 0))
-        gen_op_set_Rc1();
+    gen_compute_fprf(1, Rc(ctx->opcode) != 0);
 }
 
 /***                     Floating-Point multiply-and-add                   ***/
 /* fmadd - fmadds */
-GEN_FLOAT_ACB(madd, 0x1D, PPC_FLOAT);
+GEN_FLOAT_ACB(madd, 0x1D, 1, PPC_FLOAT);
 /* fmsub - fmsubs */
-GEN_FLOAT_ACB(msub, 0x1C, PPC_FLOAT);
+GEN_FLOAT_ACB(msub, 0x1C, 1, PPC_FLOAT);
 /* fnmadd - fnmadds */
-GEN_FLOAT_ACB(nmadd, 0x1F, PPC_FLOAT);
+GEN_FLOAT_ACB(nmadd, 0x1F, 1, PPC_FLOAT);
 /* fnmsub - fnmsubs */
-GEN_FLOAT_ACB(nmsub, 0x1E, PPC_FLOAT);
+GEN_FLOAT_ACB(nmsub, 0x1E, 1, PPC_FLOAT);
 
 /***                     Floating-Point round & convert                    ***/
 /* fctiw */
-GEN_FLOAT_B(ctiw, 0x0E, 0x00, PPC_FLOAT);
+GEN_FLOAT_B(ctiw, 0x0E, 0x00, 0, PPC_FLOAT);
 /* fctiwz */
-GEN_FLOAT_B(ctiwz, 0x0F, 0x00, PPC_FLOAT);
+GEN_FLOAT_B(ctiwz, 0x0F, 0x00, 0, PPC_FLOAT);
 /* frsp */
-GEN_FLOAT_B(rsp, 0x0C, 0x00, PPC_FLOAT);
+GEN_FLOAT_B(rsp, 0x0C, 0x00, 1, PPC_FLOAT);
 #if defined(TARGET_PPC64)
 /* fcfid */
-GEN_FLOAT_B(cfid, 0x0E, 0x1A, PPC_64B);
+GEN_FLOAT_B(cfid, 0x0E, 0x1A, 1, PPC_64B);
 /* fctid */
-GEN_FLOAT_B(ctid, 0x0E, 0x19, PPC_64B);
+GEN_FLOAT_B(ctid, 0x0E, 0x19, 0, PPC_64B);
 /* fctidz */
-GEN_FLOAT_B(ctidz, 0x0F, 0x19, PPC_64B);
+GEN_FLOAT_B(ctidz, 0x0F, 0x19, 0, PPC_64B);
 #endif
 
 /* frin */
-GEN_FLOAT_B(rin, 0x08, 0x0C, PPC_FLOAT_EXT);
+GEN_FLOAT_B(rin, 0x08, 0x0C, 1, PPC_FLOAT_EXT);
 /* friz */
-GEN_FLOAT_B(riz, 0x08, 0x0D, PPC_FLOAT_EXT);
+GEN_FLOAT_B(riz, 0x08, 0x0D, 1, PPC_FLOAT_EXT);
 /* frip */
-GEN_FLOAT_B(rip, 0x08, 0x0E, PPC_FLOAT_EXT);
+GEN_FLOAT_B(rip, 0x08, 0x0E, 1, PPC_FLOAT_EXT);
 /* frim */
-GEN_FLOAT_B(rim, 0x08, 0x0F, PPC_FLOAT_EXT);
+GEN_FLOAT_B(rim, 0x08, 0x0F, 1, PPC_FLOAT_EXT);
 
 /***                         Floating-Point compare                        ***/
 /* fcmpo */
@@ -1811,11 +1895,12 @@ GEN_HANDLER(fcmpo, 0x3F, 0x00, 0x01, 0x00600001, PPC_FLOAT)
         GEN_EXCP_NO_FP(ctx);
         return;
     }
-    gen_op_reset_scrfx();
     gen_op_load_fpr_FT0(rA(ctx->opcode));
     gen_op_load_fpr_FT1(rB(ctx->opcode));
+    gen_reset_fpstatus();
     gen_op_fcmpo();
     gen_op_store_T0_crf(crfD(ctx->opcode));
+    gen_op_float_check_status();
 }
 
 /* fcmpu */
@@ -1825,47 +1910,54 @@ GEN_HANDLER(fcmpu, 0x3F, 0x00, 0x00, 0x00600001, PPC_FLOAT)
         GEN_EXCP_NO_FP(ctx);
         return;
     }
-    gen_op_reset_scrfx();
     gen_op_load_fpr_FT0(rA(ctx->opcode));
     gen_op_load_fpr_FT1(rB(ctx->opcode));
+    gen_reset_fpstatus();
     gen_op_fcmpu();
     gen_op_store_T0_crf(crfD(ctx->opcode));
+    gen_op_float_check_status();
 }
 
 /***                         Floating-point move                           ***/
 /* fabs */
-GEN_FLOAT_B(abs, 0x08, 0x08, PPC_FLOAT);
+/* XXX: beware that fabs never checks for NaNs nor update FPSCR */
+GEN_FLOAT_B(abs, 0x08, 0x08, 0, PPC_FLOAT);
 
 /* fmr  - fmr. */
+/* XXX: beware that fmr never checks for NaNs nor update FPSCR */
 GEN_HANDLER(fmr, 0x3F, 0x08, 0x02, 0x001F0000, PPC_FLOAT)
 {
     if (unlikely(!ctx->fpu_enabled)) {
         GEN_EXCP_NO_FP(ctx);
         return;
     }
-    gen_op_reset_scrfx();
     gen_op_load_fpr_FT0(rB(ctx->opcode));
     gen_op_store_FT0_fpr(rD(ctx->opcode));
-    if (unlikely(Rc(ctx->opcode) != 0))
-        gen_op_set_Rc1();
+    gen_compute_fprf(0, Rc(ctx->opcode) != 0);
 }
 
 /* fnabs */
-GEN_FLOAT_B(nabs, 0x08, 0x04, PPC_FLOAT);
+/* XXX: beware that fnabs never checks for NaNs nor update FPSCR */
+GEN_FLOAT_B(nabs, 0x08, 0x04, 0, PPC_FLOAT);
 /* fneg */
-GEN_FLOAT_B(neg, 0x08, 0x01, PPC_FLOAT);
+/* XXX: beware that fneg never checks for NaNs nor update FPSCR */
+GEN_FLOAT_B(neg, 0x08, 0x01, 0, PPC_FLOAT);
 
 /***                  Floating-Point status & ctrl register                ***/
 /* mcrfs */
 GEN_HANDLER(mcrfs, 0x3F, 0x00, 0x02, 0x0063F801, PPC_FLOAT)
 {
+    int bfa;
+
     if (unlikely(!ctx->fpu_enabled)) {
         GEN_EXCP_NO_FP(ctx);
         return;
     }
-    gen_op_load_fpscr_T0(crfS(ctx->opcode));
+    gen_optimize_fprf();
+    bfa = 4 * (7 - crfS(ctx->opcode));
+    gen_op_load_fpscr_T0(bfa);
     gen_op_store_T0_crf(crfD(ctx->opcode));
-    gen_op_clear_fpscr(crfS(ctx->opcode));
+    gen_op_fpscr_resetbit(~(0xF << bfa));
 }
 
 /* mffs */
@@ -1875,10 +1967,11 @@ GEN_HANDLER(mffs, 0x3F, 0x07, 0x12, 0x001FF800, PPC_FLOAT)
         GEN_EXCP_NO_FP(ctx);
         return;
     }
-    gen_op_load_fpscr();
+    gen_optimize_fprf();
+    gen_reset_fpstatus();
+    gen_op_load_fpscr_FT0();
     gen_op_store_FT0_fpr(rD(ctx->opcode));
-    if (unlikely(Rc(ctx->opcode) != 0))
-        gen_op_set_Rc1();
+    gen_compute_fprf(0, Rc(ctx->opcode) != 0);
 }
 
 /* mtfsb0 */
@@ -1890,12 +1983,15 @@ GEN_HANDLER(mtfsb0, 0x3F, 0x06, 0x02, 0x001FF800, PPC_FLOAT)
         GEN_EXCP_NO_FP(ctx);
         return;
     }
-    crb = crbD(ctx->opcode) >> 2;
-    gen_op_load_fpscr_T0(crb);
-    gen_op_andi_T0(~(1 << (crbD(ctx->opcode) & 0x03)));
-    gen_op_store_T0_fpscr(crb);
-    if (unlikely(Rc(ctx->opcode) != 0))
-        gen_op_set_Rc1();
+    crb = 32 - (crbD(ctx->opcode) >> 2);
+    gen_optimize_fprf();
+    gen_reset_fpstatus();
+    if (likely(crb != 30 && crb != 29))
+        gen_op_fpscr_resetbit(~(1 << crb));
+    if (unlikely(Rc(ctx->opcode) != 0)) {
+        gen_op_load_fpcc();
+        gen_op_set_Rc0();
+    }
 }
 
 /* mtfsb1 */
@@ -1907,12 +2003,18 @@ GEN_HANDLER(mtfsb1, 0x3F, 0x06, 0x01, 0x001FF800, PPC_FLOAT)
         GEN_EXCP_NO_FP(ctx);
         return;
     }
-    crb = crbD(ctx->opcode) >> 2;
-    gen_op_load_fpscr_T0(crb);
-    gen_op_ori(1 << (crbD(ctx->opcode) & 0x03));
-    gen_op_store_T0_fpscr(crb);
-    if (unlikely(Rc(ctx->opcode) != 0))
-        gen_op_set_Rc1();
+    crb = 32 - (crbD(ctx->opcode) >> 2);
+    gen_optimize_fprf();
+    gen_reset_fpstatus();
+    /* XXX: we pretend we can only do IEEE floating-point computations */
+    if (likely(crb != FPSCR_FEX && crb != FPSCR_VX && crb != FPSCR_NI))
+        gen_op_fpscr_setbit(crb);
+    if (unlikely(Rc(ctx->opcode) != 0)) {
+        gen_op_load_fpcc();
+        gen_op_set_Rc0();
+    }
+    /* We can raise a differed exception */
+    gen_op_float_check_status();
 }
 
 /* mtfsf */
@@ -1922,22 +2024,39 @@ GEN_HANDLER(mtfsf, 0x3F, 0x07, 0x16, 0x02010000, PPC_FLOAT)
         GEN_EXCP_NO_FP(ctx);
         return;
     }
+    gen_optimize_fprf();
     gen_op_load_fpr_FT0(rB(ctx->opcode));
+    gen_reset_fpstatus();
     gen_op_store_fpscr(FM(ctx->opcode));
-    if (unlikely(Rc(ctx->opcode) != 0))
-        gen_op_set_Rc1();
+    if (unlikely(Rc(ctx->opcode) != 0)) {
+        gen_op_load_fpcc();
+        gen_op_set_Rc0();
+    }
+    /* We can raise a differed exception */
+    gen_op_float_check_status();
 }
 
 /* mtfsfi */
 GEN_HANDLER(mtfsfi, 0x3F, 0x06, 0x04, 0x006f0800, PPC_FLOAT)
 {
+    int bf, sh;
+
     if (unlikely(!ctx->fpu_enabled)) {
         GEN_EXCP_NO_FP(ctx);
         return;
     }
-    gen_op_store_T0_fpscri(crbD(ctx->opcode) >> 2, FPIMM(ctx->opcode));
-    if (unlikely(Rc(ctx->opcode) != 0))
-        gen_op_set_Rc1();
+    bf = crbD(ctx->opcode) >> 2;
+    sh = 7 - bf;
+    gen_optimize_fprf();
+    gen_op_set_FT0(FPIMM(ctx->opcode) << (4 * sh));
+    gen_reset_fpstatus();
+    gen_op_store_fpscr(1 << sh);
+    if (unlikely(Rc(ctx->opcode) != 0)) {
+        gen_op_load_fpcc();
+        gen_op_set_Rc0();
+    }
+    /* We can raise a differed exception */
+    gen_op_float_check_status();
 }
 
 /***                           Addressing modes                            ***/
@@ -1986,136 +2105,64 @@ static always_inline void gen_addr_register (DisasContext *ctx)
 #endif
 }
 
-/***                             Integer load                              ***/
-#define op_ldst(name)        (*gen_op_##name[ctx->mem_idx])()
+#if defined(TARGET_PPC64)
+#define _GEN_MEM_FUNCS(name, mode)                                            \
+    &gen_op_##name##_##mode,                                                  \
+    &gen_op_##name##_le_##mode,                                               \
+    &gen_op_##name##_64_##mode,                                               \
+    &gen_op_##name##_le_64_##mode
+#else
+#define _GEN_MEM_FUNCS(name, mode)                                            \
+    &gen_op_##name##_##mode,                                                  \
+    &gen_op_##name##_le_##mode
+#endif
 #if defined(CONFIG_USER_ONLY)
 #if defined(TARGET_PPC64)
-/* User mode only - 64 bits */
-#define OP_LD_TABLE(width)                                                    \
-static GenOpFunc *gen_op_l##width[] = {                                       \
-    &gen_op_l##width##_raw,                                                   \
-    &gen_op_l##width##_le_raw,                                                \
-    &gen_op_l##width##_64_raw,                                                \
-    &gen_op_l##width##_le_64_raw,                                             \
-};
-#define OP_ST_TABLE(width)                                                    \
-static GenOpFunc *gen_op_st##width[] = {                                      \
-    &gen_op_st##width##_raw,                                                  \
-    &gen_op_st##width##_le_raw,                                               \
-    &gen_op_st##width##_64_raw,                                               \
-    &gen_op_st##width##_le_64_raw,                                            \
-};
-/* Byte access routine are endian safe */
-#define gen_op_stb_le_64_raw gen_op_stb_64_raw
-#define gen_op_lbz_le_64_raw gen_op_lbz_64_raw
+#define NB_MEM_FUNCS 4
 #else
-/* User mode only - 32 bits */
-#define OP_LD_TABLE(width)                                                    \
-static GenOpFunc *gen_op_l##width[] = {                                       \
-    &gen_op_l##width##_raw,                                                   \
-    &gen_op_l##width##_le_raw,                                                \
-};
-#define OP_ST_TABLE(width)                                                    \
-static GenOpFunc *gen_op_st##width[] = {                                      \
-    &gen_op_st##width##_raw,                                                  \
-    &gen_op_st##width##_le_raw,                                               \
-};
+#define NB_MEM_FUNCS 2
 #endif
-/* Byte access routine are endian safe */
-#define gen_op_stb_le_raw gen_op_stb_raw
-#define gen_op_lbz_le_raw gen_op_lbz_raw
+#define GEN_MEM_FUNCS(name)                                                   \
+    _GEN_MEM_FUNCS(name, raw)
 #else
 #if defined(TARGET_PPC64)
-#if defined(TARGET_PPC64H)
-/* Full system - 64 bits with hypervisor mode */
-#define OP_LD_TABLE(width)                                                    \
-static GenOpFunc *gen_op_l##width[] = {                                       \
-    &gen_op_l##width##_user,                                                  \
-    &gen_op_l##width##_le_user,                                               \
-    &gen_op_l##width##_64_user,                                               \
-    &gen_op_l##width##_le_64_user,                                            \
-    &gen_op_l##width##_kernel,                                                \
-    &gen_op_l##width##_le_kernel,                                             \
-    &gen_op_l##width##_64_kernel,                                             \
-    &gen_op_l##width##_le_64_kernel,                                          \
-    &gen_op_l##width##_hypv,                                                  \
-    &gen_op_l##width##_le_hypv,                                               \
-    &gen_op_l##width##_64_hypv,                                               \
-    &gen_op_l##width##_le_64_hypv,                                            \
-};
-#define OP_ST_TABLE(width)                                                    \
-static GenOpFunc *gen_op_st##width[] = {                                      \
-    &gen_op_st##width##_user,                                                 \
-    &gen_op_st##width##_le_user,                                              \
-    &gen_op_st##width##_64_user,                                              \
-    &gen_op_st##width##_le_64_user,                                           \
-    &gen_op_st##width##_kernel,                                               \
-    &gen_op_st##width##_le_kernel,                                            \
-    &gen_op_st##width##_64_kernel,                                            \
-    &gen_op_st##width##_le_64_kernel,                                         \
-    &gen_op_st##width##_hypv,                                                 \
-    &gen_op_st##width##_le_hypv,                                              \
-    &gen_op_st##width##_64_hypv,                                              \
-    &gen_op_st##width##_le_64_hypv,                                           \
-};
-/* Byte access routine are endian safe */
-#define gen_op_stb_le_hypv      gen_op_stb_64_hypv
-#define gen_op_lbz_le_hypv      gen_op_lbz_64_hypv
-#define gen_op_stb_le_64_hypv   gen_op_stb_64_hypv
-#define gen_op_lbz_le_64_hypv   gen_op_lbz_64_hypv
+#define NB_MEM_FUNCS 12
 #else
-/* Full system - 64 bits */
-#define OP_LD_TABLE(width)                                                    \
-static GenOpFunc *gen_op_l##width[] = {                                       \
-    &gen_op_l##width##_user,                                                  \
-    &gen_op_l##width##_le_user,                                               \
-    &gen_op_l##width##_64_user,                                               \
-    &gen_op_l##width##_le_64_user,                                            \
-    &gen_op_l##width##_kernel,                                                \
-    &gen_op_l##width##_le_kernel,                                             \
-    &gen_op_l##width##_64_kernel,                                             \
-    &gen_op_l##width##_le_64_kernel,                                          \
-};
-#define OP_ST_TABLE(width)                                                    \
-static GenOpFunc *gen_op_st##width[] = {                                      \
-    &gen_op_st##width##_user,                                                 \
-    &gen_op_st##width##_le_user,                                              \
-    &gen_op_st##width##_64_user,                                              \
-    &gen_op_st##width##_le_64_user,                                           \
-    &gen_op_st##width##_kernel,                                               \
-    &gen_op_st##width##_le_kernel,                                            \
-    &gen_op_st##width##_64_kernel,                                            \
-    &gen_op_st##width##_le_64_kernel,                                         \
-};
+#define NB_MEM_FUNCS 6
 #endif
+#define GEN_MEM_FUNCS(name)                                                   \
+    _GEN_MEM_FUNCS(name, user),                                               \
+    _GEN_MEM_FUNCS(name, kernel),                                             \
+    _GEN_MEM_FUNCS(name, hypv)
+#endif
+
+/***                             Integer load                              ***/
+#define op_ldst(name)        (*gen_op_##name[ctx->mem_idx])()
 /* Byte access routine are endian safe */
-#define gen_op_stb_le_64_user   gen_op_stb_64_user
+#define gen_op_lbz_le_raw       gen_op_lbz_raw
+#define gen_op_lbz_le_user      gen_op_lbz_user
+#define gen_op_lbz_le_kernel    gen_op_lbz_kernel
+#define gen_op_lbz_le_hypv      gen_op_lbz_hypv
+#define gen_op_lbz_le_64_raw    gen_op_lbz_64_raw
 #define gen_op_lbz_le_64_user   gen_op_lbz_64_user
-#define gen_op_stb_le_64_kernel gen_op_stb_64_kernel
 #define gen_op_lbz_le_64_kernel gen_op_lbz_64_kernel
-#else
-/* Full system - 32 bits */
+#define gen_op_lbz_le_64_hypv   gen_op_lbz_64_hypv
+#define gen_op_stb_le_raw       gen_op_stb_raw
+#define gen_op_stb_le_user      gen_op_stb_user
+#define gen_op_stb_le_kernel    gen_op_stb_kernel
+#define gen_op_stb_le_hypv      gen_op_stb_hypv
+#define gen_op_stb_le_64_raw    gen_op_stb_64_raw
+#define gen_op_stb_le_64_user   gen_op_stb_64_user
+#define gen_op_stb_le_64_kernel gen_op_stb_64_kernel
+#define gen_op_stb_le_64_hypv   gen_op_stb_64_hypv
 #define OP_LD_TABLE(width)                                                    \
-static GenOpFunc *gen_op_l##width[] = {                                       \
-    &gen_op_l##width##_user,                                                  \
-    &gen_op_l##width##_le_user,                                               \
-    &gen_op_l##width##_kernel,                                                \
-    &gen_op_l##width##_le_kernel,                                             \
+static GenOpFunc *gen_op_l##width[NB_MEM_FUNCS] = {                           \
+    GEN_MEM_FUNCS(l##width),                                                  \
 };
 #define OP_ST_TABLE(width)                                                    \
-static GenOpFunc *gen_op_st##width[] = {                                      \
-    &gen_op_st##width##_user,                                                 \
-    &gen_op_st##width##_le_user,                                              \
-    &gen_op_st##width##_kernel,                                               \
-    &gen_op_st##width##_le_kernel,                                            \
+static GenOpFunc *gen_op_st##width[NB_MEM_FUNCS] = {                          \
+    GEN_MEM_FUNCS(st##width),                                                 \
 };
-#endif
-/* Byte access routine are endian safe */
-#define gen_op_stb_le_user   gen_op_stb_user
-#define gen_op_lbz_le_user   gen_op_lbz_user
-#define gen_op_stb_le_kernel gen_op_stb_kernel
-#define gen_op_lbz_le_kernel gen_op_lbz_kernel
-#endif
 
 #define GEN_LD(width, opc, type)                                              \
 GEN_HANDLER(l##width, opc, 0xFF, 0xFF, 0x00000000, type)                      \
@@ -2370,75 +2417,12 @@ GEN_STX(wbr, 0x16, 0x14, PPC_INTEGER);
 
 /***                    Integer load and store multiple                    ***/
 #define op_ldstm(name, reg) (*gen_op_##name[ctx->mem_idx])(reg)
-#if defined(CONFIG_USER_ONLY)
-/* User-mode only */
-static GenOpFunc1 *gen_op_lmw[] = {
-    &gen_op_lmw_raw,
-    &gen_op_lmw_le_raw,
-#if defined(TARGET_PPC64)
-    &gen_op_lmw_64_raw,
-    &gen_op_lmw_le_64_raw,
-#endif
-};
-static GenOpFunc1 *gen_op_stmw[] = {
-    &gen_op_stmw_raw,
-    &gen_op_stmw_le_raw,
-#if defined(TARGET_PPC64)
-    &gen_op_stmw_64_raw,
-    &gen_op_stmw_le_64_raw,
-#endif
+static GenOpFunc1 *gen_op_lmw[NB_MEM_FUNCS] = {
+    GEN_MEM_FUNCS(lmw),
 };
-#else
-#if defined(TARGET_PPC64)
-/* Full system - 64 bits mode */
-static GenOpFunc1 *gen_op_lmw[] = {
-    &gen_op_lmw_user,
-    &gen_op_lmw_le_user,
-    &gen_op_lmw_64_user,
-    &gen_op_lmw_le_64_user,
-    &gen_op_lmw_kernel,
-    &gen_op_lmw_le_kernel,
-    &gen_op_lmw_64_kernel,
-    &gen_op_lmw_le_64_kernel,
-#if defined(TARGET_PPC64H)
-    &gen_op_lmw_hypv,
-    &gen_op_lmw_le_hypv,
-    &gen_op_lmw_64_hypv,
-    &gen_op_lmw_le_64_hypv,
-#endif
+static GenOpFunc1 *gen_op_stmw[NB_MEM_FUNCS] = {
+    GEN_MEM_FUNCS(stmw),
 };
-static GenOpFunc1 *gen_op_stmw[] = {
-    &gen_op_stmw_user,
-    &gen_op_stmw_le_user,
-    &gen_op_stmw_64_user,
-    &gen_op_stmw_le_64_user,
-    &gen_op_stmw_kernel,
-    &gen_op_stmw_le_kernel,
-    &gen_op_stmw_64_kernel,
-    &gen_op_stmw_le_64_kernel,
-#if defined(TARGET_PPC64H)
-    &gen_op_stmw_hypv,
-    &gen_op_stmw_le_hypv,
-    &gen_op_stmw_64_hypv,
-    &gen_op_stmw_le_64_hypv,
-#endif
-};
-#else
-/* Full system - 32 bits mode */
-static GenOpFunc1 *gen_op_lmw[] = {
-    &gen_op_lmw_user,
-    &gen_op_lmw_le_user,
-    &gen_op_lmw_kernel,
-    &gen_op_lmw_le_kernel,
-};
-static GenOpFunc1 *gen_op_stmw[] = {
-    &gen_op_stmw_user,
-    &gen_op_stmw_le_user,
-    &gen_op_stmw_kernel,
-    &gen_op_stmw_le_kernel,
-};
-#endif
-#endif
 
 /* lmw */
 GEN_HANDLER(lmw, 0x2E, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
@@ -2461,105 +2445,40 @@ GEN_HANDLER(stmw, 0x2F, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
 /***                    Integer load and store strings                     ***/
 #define op_ldsts(name, start) (*gen_op_##name[ctx->mem_idx])(start)
 #define op_ldstsx(name, rd, ra, rb) (*gen_op_##name[ctx->mem_idx])(rd, ra, rb)
-#if defined(CONFIG_USER_ONLY)
-/* User-mode only */
-static GenOpFunc1 *gen_op_lswi[] = {
-    &gen_op_lswi_raw,
-    &gen_op_lswi_le_raw,
-#if defined(TARGET_PPC64)
-    &gen_op_lswi_64_raw,
-    &gen_op_lswi_le_64_raw,
-#endif
-};
-static GenOpFunc3 *gen_op_lswx[] = {
-    &gen_op_lswx_raw,
-    &gen_op_lswx_le_raw,
-#if defined(TARGET_PPC64)
-    &gen_op_lswx_64_raw,
-    &gen_op_lswx_le_64_raw,
-#endif
-};
-static GenOpFunc1 *gen_op_stsw[] = {
-    &gen_op_stsw_raw,
-    &gen_op_stsw_le_raw,
-#if defined(TARGET_PPC64)
-    &gen_op_stsw_64_raw,
-    &gen_op_stsw_le_64_raw,
-#endif
+/* string load & stores are by definition endian-safe */
+#define gen_op_lswi_le_raw       gen_op_lswi_raw
+#define gen_op_lswi_le_user      gen_op_lswi_user
+#define gen_op_lswi_le_kernel    gen_op_lswi_kernel
+#define gen_op_lswi_le_hypv      gen_op_lswi_hypv
+#define gen_op_lswi_le_64_raw    gen_op_lswi_raw
+#define gen_op_lswi_le_64_user   gen_op_lswi_user
+#define gen_op_lswi_le_64_kernel gen_op_lswi_kernel
+#define gen_op_lswi_le_64_hypv   gen_op_lswi_hypv
+static GenOpFunc1 *gen_op_lswi[NB_MEM_FUNCS] = {
+    GEN_MEM_FUNCS(lswi),
 };
-#else
-#if defined(TARGET_PPC64)
-/* Full system - 64 bits mode */
-static GenOpFunc1 *gen_op_lswi[] = {
-    &gen_op_lswi_user,
-    &gen_op_lswi_le_user,
-    &gen_op_lswi_64_user,
-    &gen_op_lswi_le_64_user,
-    &gen_op_lswi_kernel,
-    &gen_op_lswi_le_kernel,
-    &gen_op_lswi_64_kernel,
-    &gen_op_lswi_le_64_kernel,
-#if defined(TARGET_PPC64H)
-    &gen_op_lswi_hypv,
-    &gen_op_lswi_le_hypv,
-    &gen_op_lswi_64_hypv,
-    &gen_op_lswi_le_64_hypv,
-#endif
-};
-static GenOpFunc3 *gen_op_lswx[] = {
-    &gen_op_lswx_user,
-    &gen_op_lswx_le_user,
-    &gen_op_lswx_64_user,
-    &gen_op_lswx_le_64_user,
-    &gen_op_lswx_kernel,
-    &gen_op_lswx_le_kernel,
-    &gen_op_lswx_64_kernel,
-    &gen_op_lswx_le_64_kernel,
-#if defined(TARGET_PPC64H)
-    &gen_op_lswx_hypv,
-    &gen_op_lswx_le_hypv,
-    &gen_op_lswx_64_hypv,
-    &gen_op_lswx_le_64_hypv,
-#endif
-};
-static GenOpFunc1 *gen_op_stsw[] = {
-    &gen_op_stsw_user,
-    &gen_op_stsw_le_user,
-    &gen_op_stsw_64_user,
-    &gen_op_stsw_le_64_user,
-    &gen_op_stsw_kernel,
-    &gen_op_stsw_le_kernel,
-    &gen_op_stsw_64_kernel,
-    &gen_op_stsw_le_64_kernel,
-#if defined(TARGET_PPC64H)
-    &gen_op_stsw_hypv,
-    &gen_op_stsw_le_hypv,
-    &gen_op_stsw_64_hypv,
-    &gen_op_stsw_le_64_hypv,
-#endif
+#define gen_op_lswx_le_raw       gen_op_lswx_raw
+#define gen_op_lswx_le_user      gen_op_lswx_user
+#define gen_op_lswx_le_kernel    gen_op_lswx_kernel
+#define gen_op_lswx_le_hypv      gen_op_lswx_hypv
+#define gen_op_lswx_le_64_raw    gen_op_lswx_raw
+#define gen_op_lswx_le_64_user   gen_op_lswx_user
+#define gen_op_lswx_le_64_kernel gen_op_lswx_kernel
+#define gen_op_lswx_le_64_hypv   gen_op_lswx_hypv
+static GenOpFunc3 *gen_op_lswx[NB_MEM_FUNCS] = {
+    GEN_MEM_FUNCS(lswx),
 };
-#else
-/* Full system - 32 bits mode */
-static GenOpFunc1 *gen_op_lswi[] = {
-    &gen_op_lswi_user,
-    &gen_op_lswi_le_user,
-    &gen_op_lswi_kernel,
-    &gen_op_lswi_le_kernel,
-};
-static GenOpFunc3 *gen_op_lswx[] = {
-    &gen_op_lswx_user,
-    &gen_op_lswx_le_user,
-    &gen_op_lswx_kernel,
-    &gen_op_lswx_le_kernel,
+#define gen_op_stsw_le_raw       gen_op_stsw_raw
+#define gen_op_stsw_le_user      gen_op_stsw_user
+#define gen_op_stsw_le_kernel    gen_op_stsw_kernel
+#define gen_op_stsw_le_hypv      gen_op_stsw_hypv
+#define gen_op_stsw_le_64_raw    gen_op_stsw_raw
+#define gen_op_stsw_le_64_user   gen_op_stsw_user
+#define gen_op_stsw_le_64_kernel gen_op_stsw_kernel
+#define gen_op_stsw_le_64_hypv   gen_op_stsw_hypv
+static GenOpFunc1 *gen_op_stsw[NB_MEM_FUNCS] = {
+    GEN_MEM_FUNCS(stsw),
 };
-static GenOpFunc1 *gen_op_stsw[] = {
-    &gen_op_stsw_user,
-    &gen_op_stsw_le_user,
-    &gen_op_stsw_kernel,
-    &gen_op_stsw_le_kernel,
-};
-#endif
-#endif
 
 /* lswi */
 /* PowerPC32 specification says we must generate an exception if
@@ -2567,7 +2486,7 @@ static GenOpFunc1 *gen_op_stsw[] = {
  * In an other hand, IBM says this is valid, but rA won't be loaded.
  * For now, I'll follow the spec...
  */
-GEN_HANDLER(lswi, 0x1F, 0x15, 0x12, 0x00000001, PPC_INTEGER)
+GEN_HANDLER(lswi, 0x1F, 0x15, 0x12, 0x00000001, PPC_STRING)
 {
     int nb = NB(ctx->opcode);
     int start = rD(ctx->opcode);
@@ -2592,7 +2511,7 @@ GEN_HANDLER(lswi, 0x1F, 0x15, 0x12, 0x00000001, PPC_INTEGER)
 }
 
 /* lswx */
-GEN_HANDLER(lswx, 0x1F, 0x15, 0x10, 0x00000001, PPC_INTEGER)
+GEN_HANDLER(lswx, 0x1F, 0x15, 0x10, 0x00000001, PPC_STRING)
 {
     int ra = rA(ctx->opcode);
     int rb = rB(ctx->opcode);
@@ -2608,7 +2527,7 @@ GEN_HANDLER(lswx, 0x1F, 0x15, 0x10, 0x00000001, PPC_INTEGER)
 }
 
 /* stswi */
-GEN_HANDLER(stswi, 0x1F, 0x15, 0x16, 0x00000001, PPC_INTEGER)
+GEN_HANDLER(stswi, 0x1F, 0x15, 0x16, 0x00000001, PPC_STRING)
 {
     int nb = NB(ctx->opcode);
 
@@ -2622,7 +2541,7 @@ GEN_HANDLER(stswi, 0x1F, 0x15, 0x16, 0x00000001, PPC_INTEGER)
 }
 
 /* stswx */
-GEN_HANDLER(stswx, 0x1F, 0x15, 0x14, 0x00000001, PPC_INTEGER)
+GEN_HANDLER(stswx, 0x1F, 0x15, 0x14, 0x00000001, PPC_STRING)
 {
     /* NIP cannot be restored if the memory exception comes from an helper */
     gen_update_nip(ctx, ctx->nip - 4);
@@ -2645,75 +2564,12 @@ GEN_HANDLER(isync, 0x13, 0x16, 0x04, 0x03FFF801, PPC_MEM)
 
 #define op_lwarx() (*gen_op_lwarx[ctx->mem_idx])()
 #define op_stwcx() (*gen_op_stwcx[ctx->mem_idx])()
-#if defined(CONFIG_USER_ONLY)
-/* User-mode only */
-static GenOpFunc *gen_op_lwarx[] = {
-    &gen_op_lwarx_raw,
-    &gen_op_lwarx_le_raw,
-#if defined(TARGET_PPC64)
-    &gen_op_lwarx_64_raw,
-    &gen_op_lwarx_le_64_raw,
-#endif
-};
-static GenOpFunc *gen_op_stwcx[] = {
-    &gen_op_stwcx_raw,
-    &gen_op_stwcx_le_raw,
-#if defined(TARGET_PPC64)
-    &gen_op_stwcx_64_raw,
-    &gen_op_stwcx_le_64_raw,
-#endif
-};
-#else
-#if defined(TARGET_PPC64)
-/* Full system - 64 bits mode */
-static GenOpFunc *gen_op_lwarx[] = {
-    &gen_op_lwarx_user,
-    &gen_op_lwarx_le_user,
-    &gen_op_lwarx_64_user,
-    &gen_op_lwarx_le_64_user,
-    &gen_op_lwarx_kernel,
-    &gen_op_lwarx_le_kernel,
-    &gen_op_lwarx_64_kernel,
-    &gen_op_lwarx_le_64_kernel,
-#if defined(TARGET_PPC64H)
-    &gen_op_lwarx_hypv,
-    &gen_op_lwarx_le_hypv,
-    &gen_op_lwarx_64_hypv,
-    &gen_op_lwarx_le_64_hypv,
-#endif
-};
-static GenOpFunc *gen_op_stwcx[] = {
-    &gen_op_stwcx_user,
-    &gen_op_stwcx_le_user,
-    &gen_op_stwcx_64_user,
-    &gen_op_stwcx_le_64_user,
-    &gen_op_stwcx_kernel,
-    &gen_op_stwcx_le_kernel,
-    &gen_op_stwcx_64_kernel,
-    &gen_op_stwcx_le_64_kernel,
-#if defined(TARGET_PPC64H)
-    &gen_op_stwcx_hypv,
-    &gen_op_stwcx_le_hypv,
-    &gen_op_stwcx_64_hypv,
-    &gen_op_stwcx_le_64_hypv,
-#endif
+static GenOpFunc *gen_op_lwarx[NB_MEM_FUNCS] = {
+    GEN_MEM_FUNCS(lwarx),
 };
-#else
-/* Full system - 32 bits mode */
-static GenOpFunc *gen_op_lwarx[] = {
-    &gen_op_lwarx_user,
-    &gen_op_lwarx_le_user,
-    &gen_op_lwarx_kernel,
-    &gen_op_lwarx_le_kernel,
+static GenOpFunc *gen_op_stwcx[NB_MEM_FUNCS] = {
+    GEN_MEM_FUNCS(stwcx),
 };
-static GenOpFunc *gen_op_stwcx[] = {
-    &gen_op_stwcx_user,
-    &gen_op_stwcx_le_user,
-    &gen_op_stwcx_kernel,
-    &gen_op_stwcx_le_kernel,
-};
-#endif
-#endif
 
 /* lwarx */
 GEN_HANDLER(lwarx, 0x1F, 0x14, 0x00, 0x00000001, PPC_RES)
@@ -2726,7 +2582,7 @@ GEN_HANDLER(lwarx, 0x1F, 0x14, 0x00, 0x00000001, PPC_RES)
 }
 
 /* stwcx. */
-GEN_HANDLER(stwcx_, 0x1F, 0x16, 0x04, 0x00000000, PPC_RES)
+GEN_HANDLER2(stwcx_, "stwcx.", 0x1F, 0x16, 0x04, 0x00000000, PPC_RES)
 {
     /* NIP cannot be restored if the memory exception comes from an helper */
     gen_update_nip(ctx, ctx->nip - 4);
@@ -2738,55 +2594,12 @@ GEN_HANDLER(stwcx_, 0x1F, 0x16, 0x04, 0x00000000, PPC_RES)
 #if defined(TARGET_PPC64)
 #define op_ldarx() (*gen_op_ldarx[ctx->mem_idx])()
 #define op_stdcx() (*gen_op_stdcx[ctx->mem_idx])()
-#if defined(CONFIG_USER_ONLY)
-/* User-mode only */
-static GenOpFunc *gen_op_ldarx[] = {
-    &gen_op_ldarx_raw,
-    &gen_op_ldarx_le_raw,
-    &gen_op_ldarx_64_raw,
-    &gen_op_ldarx_le_64_raw,
-};
-static GenOpFunc *gen_op_stdcx[] = {
-    &gen_op_stdcx_raw,
-    &gen_op_stdcx_le_raw,
-    &gen_op_stdcx_64_raw,
-    &gen_op_stdcx_le_64_raw,
+static GenOpFunc *gen_op_ldarx[NB_MEM_FUNCS] = {
+    GEN_MEM_FUNCS(ldarx),
 };
-#else
-/* Full system */
-static GenOpFunc *gen_op_ldarx[] = {
-    &gen_op_ldarx_user,
-    &gen_op_ldarx_le_user,
-    &gen_op_ldarx_64_user,
-    &gen_op_ldarx_le_64_user,
-    &gen_op_ldarx_kernel,
-    &gen_op_ldarx_le_kernel,
-    &gen_op_ldarx_64_kernel,
-    &gen_op_ldarx_le_64_kernel,
-#if defined(TARGET_PPC64H)
-    &gen_op_ldarx_hypv,
-    &gen_op_ldarx_le_hypv,
-    &gen_op_ldarx_64_hypv,
-    &gen_op_ldarx_le_64_hypv,
-#endif
+static GenOpFunc *gen_op_stdcx[NB_MEM_FUNCS] = {
+    GEN_MEM_FUNCS(stdcx),
 };
-static GenOpFunc *gen_op_stdcx[] = {
-    &gen_op_stdcx_user,
-    &gen_op_stdcx_le_user,
-    &gen_op_stdcx_64_user,
-    &gen_op_stdcx_le_64_user,
-    &gen_op_stdcx_kernel,
-    &gen_op_stdcx_le_kernel,
-    &gen_op_stdcx_64_kernel,
-    &gen_op_stdcx_le_64_kernel,
-#if defined(TARGET_PPC64H)
-    &gen_op_stdcx_hypv,
-    &gen_op_stdcx_le_hypv,
-    &gen_op_stdcx_64_hypv,
-    &gen_op_stdcx_le_64_hypv,
-#endif
-};
-#endif
 
 /* ldarx */
 GEN_HANDLER(ldarx, 0x1F, 0x14, 0x02, 0x00000001, PPC_64B)
@@ -2799,7 +2612,7 @@ GEN_HANDLER(ldarx, 0x1F, 0x14, 0x02, 0x00000001, PPC_64B)
 }
 
 /* stdcx. */
-GEN_HANDLER(stdcx_, 0x1F, 0x16, 0x06, 0x00000000, PPC_64B)
+GEN_HANDLER2(stdcx_, "stdcx.", 0x1F, 0x16, 0x06, 0x00000000, PPC_64B)
 {
     /* NIP cannot be restored if the memory exception comes from an helper */
     gen_update_nip(ctx, ctx->nip - 4);
@@ -2966,8 +2779,8 @@ GEN_STFS(fs, 0x14, PPC_FLOAT);
 
 /* Optional: */
 /* stfiwx */
-OP_ST_TABLE(fiwx);
-GEN_STXF(fiwx, 0x17, 0x1E, PPC_FLOAT_STFIWX);
+OP_ST_TABLE(fiw);
+GEN_STXF(fiw, 0x17, 0x1E, PPC_FLOAT_STFIWX);
 
 /***                                Branch                                 ***/
 static always_inline void gen_goto_tb (DisasContext *ctx, int n,
@@ -2975,11 +2788,9 @@ static always_inline void gen_goto_tb (DisasContext *ctx, int n,
 {
     TranslationBlock *tb;
     tb = ctx->tb;
-    if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) {
-        if (n == 0)
-            gen_op_goto_tb0(TBPARAM(tb));
-        else
-            gen_op_goto_tb1(TBPARAM(tb));
+    if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK) &&
+        likely(!ctx->singlestep_enabled)) {
+        tcg_gen_goto_tb(n);
         gen_set_T1(dest);
 #if defined(TARGET_PPC64)
         if (ctx->sf_mode)
@@ -2987,10 +2798,7 @@ static always_inline void gen_goto_tb (DisasContext *ctx, int n,
         else
 #endif
             gen_op_b_T1();
-        gen_op_set_T0((long)tb + n);
-        if (ctx->singlestep_enabled)
-            gen_op_debug();
-        gen_op_exit_tb();
+        tcg_gen_exit_tb((long)tb + n);
     } else {
         gen_set_T1(dest);
 #if defined(TARGET_PPC64)
@@ -2999,10 +2807,21 @@ static always_inline void gen_goto_tb (DisasContext *ctx, int n,
         else
 #endif
             gen_op_b_T1();
-        gen_op_reset_T0();
-        if (ctx->singlestep_enabled)
-            gen_op_debug();
-        gen_op_exit_tb();
+        if (unlikely(ctx->singlestep_enabled)) {
+            if ((ctx->singlestep_enabled &
+                 (CPU_BRANCH_STEP | CPU_SINGLE_STEP)) &&
+                ctx->exception == POWERPC_EXCP_BRANCH) {
+                target_ulong tmp = ctx->nip;
+                ctx->nip = dest;
+                GEN_EXCP(ctx, POWERPC_EXCP_TRACE, 0);
+                ctx->nip = tmp;
+            }
+            if (ctx->singlestep_enabled & GDBSTUB_SINGLE_STEP) {
+                gen_update_nip(ctx, dest);
+                gen_op_debug();
+            }
+        }
+        tcg_gen_exit_tb(0);
     }
 }
 
@@ -3021,6 +2840,7 @@ GEN_HANDLER(b, 0x12, 0xFF, 0xFF, 0x00000000, PPC_FLOW)
 {
     target_ulong li, target;
 
+    ctx->exception = POWERPC_EXCP_BRANCH;
     /* sign extend LI */
 #if defined(TARGET_PPC64)
     if (ctx->sf_mode)
@@ -3039,7 +2859,6 @@ GEN_HANDLER(b, 0x12, 0xFF, 0xFF, 0x00000000, PPC_FLOW)
     if (LK(ctx->opcode))
         gen_setlr(ctx, ctx->nip);
     gen_goto_tb(ctx, 0, target);
-    ctx->exception = POWERPC_EXCP_BRANCH;
 }
 
 #define BCOND_IM  0
@@ -3054,6 +2873,7 @@ static always_inline void gen_bcond (DisasContext *ctx, int type)
     uint32_t bi = BI(ctx->opcode);
     uint32_t mask;
 
+    ctx->exception = POWERPC_EXCP_BRANCH;
     if ((bo & 0x4) == 0)
         gen_op_dec_ctr();
     switch(type) {
@@ -3103,7 +2923,7 @@ static always_inline void gen_bcond (DisasContext *ctx, int type)
         case 6:
             if (type == BCOND_IM) {
                 gen_goto_tb(ctx, 0, target);
-                goto out;
+                return;
             } else {
 #if defined(TARGET_PPC64)
                 if (ctx->sf_mode)
@@ -3111,7 +2931,6 @@ static always_inline void gen_bcond (DisasContext *ctx, int type)
                 else
 #endif
                     gen_op_b_T1();
-                gen_op_reset_T0();
                 goto no_test;
             }
             break;
@@ -3182,14 +3001,13 @@ static always_inline void gen_bcond (DisasContext *ctx, int type)
         else
 #endif
             gen_op_btest_T1(ctx->nip);
-        gen_op_reset_T0();
     no_test:
-        if (ctx->singlestep_enabled)
+        if (ctx->singlestep_enabled & GDBSTUB_SINGLE_STEP) {
+            gen_update_nip(ctx, ctx->nip);
             gen_op_debug();
-        gen_op_exit_tb();
+        }
+        tcg_gen_exit_tb(0);
     }
- out:
-    ctx->exception = POWERPC_EXCP_BRANCH;
 }
 
 GEN_HANDLER(bc, 0x10, 0xFF, 0xFF, 0x00000000, PPC_FLOW)
@@ -3211,15 +3029,27 @@ GEN_HANDLER(bclr, 0x13, 0x10, 0x00, 0x00000000, PPC_FLOW)
 #define GEN_CRLOGIC(op, opc)                                                  \
 GEN_HANDLER(cr##op, 0x13, 0x01, opc, 0x00000001, PPC_INTEGER)                 \
 {                                                                             \
+    uint8_t bitmask;                                                          \
+    int sh;                                                                   \
     gen_op_load_crf_T0(crbA(ctx->opcode) >> 2);                               \
-    gen_op_getbit_T0(3 - (crbA(ctx->opcode) & 0x03));                         \
+    sh = (crbD(ctx->opcode) & 0x03) - (crbA(ctx->opcode) & 0x03);             \
+    if (sh > 0)                                                               \
+        gen_op_srli_T0(sh);                                                   \
+    else if (sh < 0)                                                          \
+        gen_op_sli_T0(-sh);                                                   \
     gen_op_load_crf_T1(crbB(ctx->opcode) >> 2);                               \
-    gen_op_getbit_T1(3 - (crbB(ctx->opcode) & 0x03));                         \
+    sh = (crbD(ctx->opcode) & 0x03) - (crbB(ctx->opcode) & 0x03);             \
+    if (sh > 0)                                                               \
+        gen_op_srli_T1(sh);                                                   \
+    else if (sh < 0)                                                          \
+        gen_op_sli_T1(-sh);                                                   \
     gen_op_##op();                                                            \
+    bitmask = 1 << (3 - (crbD(ctx->opcode) & 0x03));                          \
+    gen_op_andi_T0(bitmask);                                                  \
     gen_op_load_crf_T1(crbD(ctx->opcode) >> 2);                               \
-    gen_op_setcrfbit(~(1 << (3 - (crbD(ctx->opcode) & 0x03))),                \
-                     3 - (crbD(ctx->opcode) & 0x03));                         \
-    gen_op_store_T1_crf(crbD(ctx->opcode) >> 2);                              \
+    gen_op_andi_T1(~bitmask);                                                 \
+    gen_op_or();                                                              \
+    gen_op_store_T0_crf(crbD(ctx->opcode) >> 2);                              \
 }
 
 /* crand */
@@ -3277,10 +3107,8 @@ GEN_HANDLER(rfid, 0x13, 0x12, 0x00, 0x03FF8001, PPC_64B)
     GEN_SYNC(ctx);
 #endif
 }
-#endif
 
-#if defined(TARGET_PPC64H)
-GEN_HANDLER(hrfid, 0x13, 0x12, 0x08, 0x03FF8001, PPC_64B)
+GEN_HANDLER(hrfid, 0x13, 0x12, 0x08, 0x03FF8001, PPC_64H)
 {
 #if defined(CONFIG_USER_ONLY)
     GEN_EXCP_PRIVOPC(ctx);
@@ -3395,8 +3223,8 @@ GEN_HANDLER(mfmsr, 0x1F, 0x13, 0x02, 0x001FF801, PPC_MISC)
 #endif
 }
 
-#if 0
-#define SPR_NOACCESS ((void *)(-1))
+#if 1
+#define SPR_NOACCESS ((void *)(-1UL))
 #else
 static void spr_noaccess (void *opaque, int sprn)
 {
@@ -3413,12 +3241,9 @@ static always_inline void gen_op_mfspr (DisasContext *ctx)
     uint32_t sprn = SPR(ctx->opcode);
 
 #if !defined(CONFIG_USER_ONLY)
-#if defined(TARGET_PPC64H)
     if (ctx->supervisor == 2)
         read_cb = ctx->spr_cb[sprn].hea_read;
-    else
-#endif
-    if (ctx->supervisor)
+    else if (ctx->supervisor)
         read_cb = ctx->spr_cb[sprn].oea_read;
     else
 #endif
@@ -3429,20 +3254,28 @@ static always_inline void gen_op_mfspr (DisasContext *ctx)
             gen_op_store_T0_gpr(rD(ctx->opcode));
         } else {
             /* Privilege exception */
-            if (loglevel != 0) {
-                fprintf(logfile, "Trying to read privileged spr %d %03x\n",
-                        sprn, sprn);
+            /* This is a hack to avoid warnings when running Linux:
+             * this OS breaks the PowerPC virtualisation model,
+             * allowing userland application to read the PVR
+             */
+            if (sprn != SPR_PVR) {
+                if (loglevel != 0) {
+                    fprintf(logfile, "Trying to read privileged spr %d %03x at "
+                            ADDRX "\n", sprn, sprn, ctx->nip);
+                }
+                printf("Trying to read privileged spr %d %03x at " ADDRX "\n",
+                       sprn, sprn, ctx->nip);
             }
-            printf("Trying to read privileged spr %d %03x\n", sprn, sprn);
             GEN_EXCP_PRIVREG(ctx);
         }
     } else {
         /* Not defined */
         if (loglevel != 0) {
-            fprintf(logfile, "Trying to read invalid spr %d %03x\n",
-                    sprn, sprn);
+            fprintf(logfile, "Trying to read invalid spr %d %03x at "
+                    ADDRX "\n", sprn, sprn, ctx->nip);
         }
-        printf("Trying to read invalid spr %d %03x\n", sprn, sprn);
+        printf("Trying to read invalid spr %d %03x at " ADDRX "\n",
+               sprn, sprn, ctx->nip);
         GEN_EXCP(ctx, POWERPC_EXCP_PROGRAM,
                  POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_SPR);
     }
@@ -3545,12 +3378,9 @@ GEN_HANDLER(mtspr, 0x1F, 0x13, 0x0E, 0x00000001, PPC_MISC)
     uint32_t sprn = SPR(ctx->opcode);
 
 #if !defined(CONFIG_USER_ONLY)
-#if defined(TARGET_PPC64H)
     if (ctx->supervisor == 2)
         write_cb = ctx->spr_cb[sprn].hea_write;
-    else
-#endif
-    if (ctx->supervisor)
+    else if (ctx->supervisor)
         write_cb = ctx->spr_cb[sprn].oea_write;
     else
 #endif
@@ -3562,32 +3392,31 @@ GEN_HANDLER(mtspr, 0x1F, 0x13, 0x0E, 0x00000001, PPC_MISC)
         } else {
             /* Privilege exception */
             if (loglevel != 0) {
-                fprintf(logfile, "Trying to write privileged spr %d %03x\n",
-                        sprn, sprn);
+                fprintf(logfile, "Trying to write privileged spr %d %03x at "
+                        ADDRX "\n", sprn, sprn, ctx->nip);
             }
-            printf("Trying to write privileged spr %d %03x\n", sprn, sprn);
+            printf("Trying to write privileged spr %d %03x at " ADDRX "\n",
+                   sprn, sprn, ctx->nip);
             GEN_EXCP_PRIVREG(ctx);
         }
     } else {
         /* Not defined */
         if (loglevel != 0) {
-            fprintf(logfile, "Trying to write invalid spr %d %03x\n",
-                    sprn, sprn);
+            fprintf(logfile, "Trying to write invalid spr %d %03x at "
+                    ADDRX "\n", sprn, sprn, ctx->nip);
         }
-        printf("Trying to write invalid spr %d %03x\n", sprn, sprn);
+        printf("Trying to write invalid spr %d %03x at " ADDRX "\n",
+               sprn, sprn, ctx->nip);
         GEN_EXCP(ctx, POWERPC_EXCP_PROGRAM,
                  POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_SPR);
     }
 }
 
 /***                         Cache management                              ***/
-/* For now, all those will be implemented as nop:
- * this is valid, regarding the PowerPC specs...
- * We just have to flush tb while invalidating instruction cache lines...
- */
 /* dcbf */
 GEN_HANDLER(dcbf, 0x1F, 0x16, 0x02, 0x03C00001, PPC_CACHE)
 {
+    /* XXX: specification says this is treated as a load by the MMU */
     gen_addr_reg_index(ctx);
     op_ldst(lbz);
 }
@@ -3604,7 +3433,7 @@ GEN_HANDLER(dcbi, 0x1F, 0x16, 0x0E, 0x03E00001, PPC_CACHE)
     }
     gen_addr_reg_index(ctx);
     /* XXX: specification says this should be treated as a store by the MMU */
-    //op_ldst(lbz);
+    op_ldst(lbz);
     op_ldst(stb);
 #endif
 }
@@ -3637,141 +3466,56 @@ GEN_HANDLER(dcbtst, 0x1F, 0x16, 0x07, 0x02000001, PPC_CACHE)
 
 /* dcbz */
 #define op_dcbz(n) (*gen_op_dcbz[n][ctx->mem_idx])()
-#if defined(CONFIG_USER_ONLY)
-/* User-mode only */
-static GenOpFunc *gen_op_dcbz[4][4] = {
+static GenOpFunc *gen_op_dcbz[4][NB_MEM_FUNCS] = {
+    /* 32 bytes cache line size */
     {
-        &gen_op_dcbz_l32_raw,
-        &gen_op_dcbz_l32_raw,
-#if defined(TARGET_PPC64)
-        &gen_op_dcbz_l32_64_raw,
-        &gen_op_dcbz_l32_64_raw,
-#endif
+#define gen_op_dcbz_l32_le_raw        gen_op_dcbz_l32_raw
+#define gen_op_dcbz_l32_le_user       gen_op_dcbz_l32_user
+#define gen_op_dcbz_l32_le_kernel     gen_op_dcbz_l32_kernel
+#define gen_op_dcbz_l32_le_hypv       gen_op_dcbz_l32_hypv
+#define gen_op_dcbz_l32_le_64_raw     gen_op_dcbz_l32_64_raw
+#define gen_op_dcbz_l32_le_64_user    gen_op_dcbz_l32_64_user
+#define gen_op_dcbz_l32_le_64_kernel  gen_op_dcbz_l32_64_kernel
+#define gen_op_dcbz_l32_le_64_hypv    gen_op_dcbz_l32_64_hypv
+        GEN_MEM_FUNCS(dcbz_l32),
     },
+    /* 64 bytes cache line size */
     {
-        &gen_op_dcbz_l64_raw,
-        &gen_op_dcbz_l64_raw,
-#if defined(TARGET_PPC64)
-        &gen_op_dcbz_l64_64_raw,
-        &gen_op_dcbz_l64_64_raw,
-#endif
+#define gen_op_dcbz_l64_le_raw        gen_op_dcbz_l64_raw
+#define gen_op_dcbz_l64_le_user       gen_op_dcbz_l64_user
+#define gen_op_dcbz_l64_le_kernel     gen_op_dcbz_l64_kernel
+#define gen_op_dcbz_l64_le_hypv       gen_op_dcbz_l64_hypv
+#define gen_op_dcbz_l64_le_64_raw     gen_op_dcbz_l64_64_raw
+#define gen_op_dcbz_l64_le_64_user    gen_op_dcbz_l64_64_user
+#define gen_op_dcbz_l64_le_64_kernel  gen_op_dcbz_l64_64_kernel
+#define gen_op_dcbz_l64_le_64_hypv    gen_op_dcbz_l64_64_hypv
+        GEN_MEM_FUNCS(dcbz_l64),
     },
+    /* 128 bytes cache line size */
     {
-        &gen_op_dcbz_l128_raw,
-        &gen_op_dcbz_l128_raw,
-#if defined(TARGET_PPC64)
-        &gen_op_dcbz_l128_64_raw,
-        &gen_op_dcbz_l128_64_raw,
-#endif
+#define gen_op_dcbz_l128_le_raw       gen_op_dcbz_l128_raw
+#define gen_op_dcbz_l128_le_user      gen_op_dcbz_l128_user
+#define gen_op_dcbz_l128_le_kernel    gen_op_dcbz_l128_kernel
+#define gen_op_dcbz_l128_le_hypv      gen_op_dcbz_l128_hypv
+#define gen_op_dcbz_l128_le_64_raw    gen_op_dcbz_l128_64_raw
+#define gen_op_dcbz_l128_le_64_user   gen_op_dcbz_l128_64_user
+#define gen_op_dcbz_l128_le_64_kernel gen_op_dcbz_l128_64_kernel
+#define gen_op_dcbz_l128_le_64_hypv   gen_op_dcbz_l128_64_hypv
+        GEN_MEM_FUNCS(dcbz_l128),
     },
+    /* tunable cache line size */
     {
-        &gen_op_dcbz_raw,
-        &gen_op_dcbz_raw,
-#if defined(TARGET_PPC64)
-        &gen_op_dcbz_64_raw,
-        &gen_op_dcbz_64_raw,
-#endif
+#define gen_op_dcbz_le_raw            gen_op_dcbz_raw
+#define gen_op_dcbz_le_user           gen_op_dcbz_user
+#define gen_op_dcbz_le_kernel         gen_op_dcbz_kernel
+#define gen_op_dcbz_le_hypv           gen_op_dcbz_hypv
+#define gen_op_dcbz_le_64_raw         gen_op_dcbz_64_raw
+#define gen_op_dcbz_le_64_user        gen_op_dcbz_64_user
+#define gen_op_dcbz_le_64_kernel      gen_op_dcbz_64_kernel
+#define gen_op_dcbz_le_64_hypv        gen_op_dcbz_64_hypv
+        GEN_MEM_FUNCS(dcbz),
     },
 };
-#else
-#if defined(TARGET_PPC64)
-/* Full system - 64 bits mode */
-static GenOpFunc *gen_op_dcbz[4][12] = {
-    {
-        &gen_op_dcbz_l32_user,
-        &gen_op_dcbz_l32_user,
-        &gen_op_dcbz_l32_64_user,
-        &gen_op_dcbz_l32_64_user,
-        &gen_op_dcbz_l32_kernel,
-        &gen_op_dcbz_l32_kernel,
-        &gen_op_dcbz_l32_64_kernel,
-        &gen_op_dcbz_l32_64_kernel,
-#if defined(TARGET_PPC64H)
-        &gen_op_dcbz_l32_hypv,
-        &gen_op_dcbz_l32_hypv,
-        &gen_op_dcbz_l32_64_hypv,
-        &gen_op_dcbz_l32_64_hypv,
-#endif
-    },
-    {
-        &gen_op_dcbz_l64_user,
-        &gen_op_dcbz_l64_user,
-        &gen_op_dcbz_l64_64_user,
-        &gen_op_dcbz_l64_64_user,
-        &gen_op_dcbz_l64_kernel,
-        &gen_op_dcbz_l64_kernel,
-        &gen_op_dcbz_l64_64_kernel,
-        &gen_op_dcbz_l64_64_kernel,
-#if defined(TARGET_PPC64H)
-        &gen_op_dcbz_l64_hypv,
-        &gen_op_dcbz_l64_hypv,
-        &gen_op_dcbz_l64_64_hypv,
-        &gen_op_dcbz_l64_64_hypv,
-#endif
-    },
-    {
-        &gen_op_dcbz_l128_user,
-        &gen_op_dcbz_l128_user,
-        &gen_op_dcbz_l128_64_user,
-        &gen_op_dcbz_l128_64_user,
-        &gen_op_dcbz_l128_kernel,
-        &gen_op_dcbz_l128_kernel,
-        &gen_op_dcbz_l128_64_kernel,
-        &gen_op_dcbz_l128_64_kernel,
-#if defined(TARGET_PPC64H)
-        &gen_op_dcbz_l128_hypv,
-        &gen_op_dcbz_l128_hypv,
-        &gen_op_dcbz_l128_64_hypv,
-        &gen_op_dcbz_l128_64_hypv,
-#endif
-    },
-    {
-        &gen_op_dcbz_user,
-        &gen_op_dcbz_user,
-        &gen_op_dcbz_64_user,
-        &gen_op_dcbz_64_user,
-        &gen_op_dcbz_kernel,
-        &gen_op_dcbz_kernel,
-        &gen_op_dcbz_64_kernel,
-        &gen_op_dcbz_64_kernel,
-#if defined(TARGET_PPC64H)
-        &gen_op_dcbz_hypv,
-        &gen_op_dcbz_hypv,
-        &gen_op_dcbz_64_hypv,
-        &gen_op_dcbz_64_hypv,
-#endif
-    },
-};
-#else
-/* Full system - 32 bits mode */
-static GenOpFunc *gen_op_dcbz[4][4] = {
-    {
-        &gen_op_dcbz_l32_user,
-        &gen_op_dcbz_l32_user,
-        &gen_op_dcbz_l32_kernel,
-        &gen_op_dcbz_l32_kernel,
-    },
-    {
-        &gen_op_dcbz_l64_user,
-        &gen_op_dcbz_l64_user,
-        &gen_op_dcbz_l64_kernel,
-        &gen_op_dcbz_l64_kernel,
-    },
-    {
-        &gen_op_dcbz_l128_user,
-        &gen_op_dcbz_l128_user,
-        &gen_op_dcbz_l128_kernel,
-        &gen_op_dcbz_l128_kernel,
-    },
-    {
-        &gen_op_dcbz_user,
-        &gen_op_dcbz_user,
-        &gen_op_dcbz_kernel,
-        &gen_op_dcbz_kernel,
-    },
-};
-#endif
-#endif
 
 static always_inline void handler_dcbz (DisasContext *ctx,
                                         int dcache_line_size)
@@ -3802,7 +3546,7 @@ GEN_HANDLER(dcbz, 0x1F, 0x16, 0x1F, 0x03E00001, PPC_CACHE_DCBZ)
     gen_op_check_reservation();
 }
 
-GEN_HANDLER(dcbz_970, 0x1F, 0x16, 0x1F, 0x03C00001, PPC_CACHE_DCBZT)
+GEN_HANDLER2(dcbz_970, "dcbz", 0x1F, 0x16, 0x1F, 0x03C00001, PPC_CACHE_DCBZT)
 {
     gen_addr_reg_index(ctx);
     if (ctx->opcode & 0x00200000)
@@ -3814,47 +3558,19 @@ GEN_HANDLER(dcbz_970, 0x1F, 0x16, 0x1F, 0x03C00001, PPC_CACHE_DCBZT)
 
 /* icbi */
 #define op_icbi() (*gen_op_icbi[ctx->mem_idx])()
-#if defined(CONFIG_USER_ONLY)
-/* User-mode only */
-static GenOpFunc *gen_op_icbi[] = {
-    &gen_op_icbi_raw,
-    &gen_op_icbi_raw,
-#if defined(TARGET_PPC64)
-    &gen_op_icbi_64_raw,
-    &gen_op_icbi_64_raw,
-#endif
-};
-#else
-/* Full system - 64 bits mode */
-#if defined(TARGET_PPC64)
-static GenOpFunc *gen_op_icbi[] = {
-    &gen_op_icbi_user,
-    &gen_op_icbi_user,
-    &gen_op_icbi_64_user,
-    &gen_op_icbi_64_user,
-    &gen_op_icbi_kernel,
-    &gen_op_icbi_kernel,
-    &gen_op_icbi_64_kernel,
-    &gen_op_icbi_64_kernel,
-#if defined(TARGET_PPC64H)
-    &gen_op_icbi_hypv,
-    &gen_op_icbi_hypv,
-    &gen_op_icbi_64_hypv,
-    &gen_op_icbi_64_hypv,
-#endif
+#define gen_op_icbi_le_raw       gen_op_icbi_raw
+#define gen_op_icbi_le_user      gen_op_icbi_user
+#define gen_op_icbi_le_kernel    gen_op_icbi_kernel
+#define gen_op_icbi_le_hypv      gen_op_icbi_hypv
+#define gen_op_icbi_le_64_raw    gen_op_icbi_64_raw
+#define gen_op_icbi_le_64_user   gen_op_icbi_64_user
+#define gen_op_icbi_le_64_kernel gen_op_icbi_64_kernel
+#define gen_op_icbi_le_64_hypv   gen_op_icbi_64_hypv
+static GenOpFunc *gen_op_icbi[NB_MEM_FUNCS] = {
+    GEN_MEM_FUNCS(icbi),
 };
-#else
-/* Full system - 32 bits mode */
-static GenOpFunc *gen_op_icbi[] = {
-    &gen_op_icbi_user,
-    &gen_op_icbi_user,
-    &gen_op_icbi_kernel,
-    &gen_op_icbi_kernel,
-};
-#endif
-#endif
 
-GEN_HANDLER(icbi, 0x1F, 0x16, 0x1E, 0x03E00001, PPC_CACHE)
+GEN_HANDLER(icbi, 0x1F, 0x16, 0x1E, 0x03E00001, PPC_CACHE_ICBI)
 {
     /* NIP cannot be restored if the memory exception comes from an helper */
     gen_update_nip(ctx, ctx->nip - 4);
@@ -3943,7 +3659,7 @@ GEN_HANDLER(mtsrin, 0x1F, 0x12, 0x07, 0x001F0001, PPC_SEGMENT)
 #if defined(TARGET_PPC64)
 /* Specific implementation for PowerPC 64 "bridge" emulation using SLB */
 /* mfsr */
-GEN_HANDLER(mfsr_64b, 0x1F, 0x13, 0x12, 0x0010F801, PPC_SEGMENT_64B)
+GEN_HANDLER2(mfsr_64b, "mfsr", 0x1F, 0x13, 0x12, 0x0010F801, PPC_SEGMENT_64B)
 {
 #if defined(CONFIG_USER_ONLY)
     GEN_EXCP_PRIVREG(ctx);
@@ -3959,7 +3675,8 @@ GEN_HANDLER(mfsr_64b, 0x1F, 0x13, 0x12, 0x0010F801, PPC_SEGMENT_64B)
 }
 
 /* mfsrin */
-GEN_HANDLER(mfsrin_64b, 0x1F, 0x13, 0x14, 0x001F0001, PPC_SEGMENT_64B)
+GEN_HANDLER2(mfsrin_64b, "mfsrin", 0x1F, 0x13, 0x14, 0x001F0001,
+             PPC_SEGMENT_64B)
 {
 #if defined(CONFIG_USER_ONLY)
     GEN_EXCP_PRIVREG(ctx);
@@ -3976,7 +3693,7 @@ GEN_HANDLER(mfsrin_64b, 0x1F, 0x13, 0x14, 0x001F0001, PPC_SEGMENT_64B)
 }
 
 /* mtsr */
-GEN_HANDLER(mtsr_64b, 0x1F, 0x12, 0x06, 0x0010F801, PPC_SEGMENT_64B)
+GEN_HANDLER2(mtsr_64b, "mtsr", 0x1F, 0x12, 0x06, 0x0010F801, PPC_SEGMENT_64B)
 {
 #if defined(CONFIG_USER_ONLY)
     GEN_EXCP_PRIVREG(ctx);
@@ -3992,7 +3709,8 @@ GEN_HANDLER(mtsr_64b, 0x1F, 0x12, 0x06, 0x0010F801, PPC_SEGMENT_64B)
 }
 
 /* mtsrin */
-GEN_HANDLER(mtsrin_64b, 0x1F, 0x12, 0x07, 0x001F0001, PPC_SEGMENT_64B)
+GEN_HANDLER2(mtsrin_64b, "mtsrin", 0x1F, 0x12, 0x07, 0x001F0001,
+             PPC_SEGMENT_64B)
 {
 #if defined(CONFIG_USER_ONLY)
     GEN_EXCP_PRIVREG(ctx);
@@ -4018,8 +3736,6 @@ GEN_HANDLER(tlbia, 0x1F, 0x12, 0x0B, 0x03FFFC01, PPC_MEM_TLBIA)
     GEN_EXCP_PRIVOPC(ctx);
 #else
     if (unlikely(!ctx->supervisor)) {
-        if (loglevel != 0)
-            fprintf(logfile, "%s: ! supervisor\n", __func__);
         GEN_EXCP_PRIVOPC(ctx);
         return;
     }
@@ -4072,8 +3788,6 @@ GEN_HANDLER(slbia, 0x1F, 0x12, 0x0F, 0x03FFFC01, PPC_SLBI)
     GEN_EXCP_PRIVOPC(ctx);
 #else
     if (unlikely(!ctx->supervisor)) {
-        if (loglevel != 0)
-            fprintf(logfile, "%s: ! supervisor\n", __func__);
         GEN_EXCP_PRIVOPC(ctx);
         return;
     }
@@ -4101,75 +3815,12 @@ GEN_HANDLER(slbie, 0x1F, 0x12, 0x0D, 0x03FF0001, PPC_SLBI)
 /* Optional: */
 #define op_eciwx() (*gen_op_eciwx[ctx->mem_idx])()
 #define op_ecowx() (*gen_op_ecowx[ctx->mem_idx])()
-#if defined(CONFIG_USER_ONLY)
-/* User-mode only */
-static GenOpFunc *gen_op_eciwx[] = {
-    &gen_op_eciwx_raw,
-    &gen_op_eciwx_le_raw,
-#if defined(TARGET_PPC64)
-    &gen_op_eciwx_64_raw,
-    &gen_op_eciwx_le_64_raw,
-#endif
-};
-static GenOpFunc *gen_op_ecowx[] = {
-    &gen_op_ecowx_raw,
-    &gen_op_ecowx_le_raw,
-#if defined(TARGET_PPC64)
-    &gen_op_ecowx_64_raw,
-    &gen_op_ecowx_le_64_raw,
-#endif
-};
-#else
-#if defined(TARGET_PPC64)
-/* Full system - 64 bits mode */
-static GenOpFunc *gen_op_eciwx[] = {
-    &gen_op_eciwx_user,
-    &gen_op_eciwx_le_user,
-    &gen_op_eciwx_64_user,
-    &gen_op_eciwx_le_64_user,
-    &gen_op_eciwx_kernel,
-    &gen_op_eciwx_le_kernel,
-    &gen_op_eciwx_64_kernel,
-    &gen_op_eciwx_le_64_kernel,
-#if defined(TARGET_PPC64H)
-    &gen_op_eciwx_hypv,
-    &gen_op_eciwx_le_hypv,
-    &gen_op_eciwx_64_hypv,
-    &gen_op_eciwx_le_64_hypv,
-#endif
-};
-static GenOpFunc *gen_op_ecowx[] = {
-    &gen_op_ecowx_user,
-    &gen_op_ecowx_le_user,
-    &gen_op_ecowx_64_user,
-    &gen_op_ecowx_le_64_user,
-    &gen_op_ecowx_kernel,
-    &gen_op_ecowx_le_kernel,
-    &gen_op_ecowx_64_kernel,
-    &gen_op_ecowx_le_64_kernel,
-#if defined(TARGET_PPC64H)
-    &gen_op_ecowx_hypv,
-    &gen_op_ecowx_le_hypv,
-    &gen_op_ecowx_64_hypv,
-    &gen_op_ecowx_le_64_hypv,
-#endif
+static GenOpFunc *gen_op_eciwx[NB_MEM_FUNCS] = {
+    GEN_MEM_FUNCS(eciwx),
 };
-#else
-/* Full system - 32 bits mode */
-static GenOpFunc *gen_op_eciwx[] = {
-    &gen_op_eciwx_user,
-    &gen_op_eciwx_le_user,
-    &gen_op_eciwx_kernel,
-    &gen_op_eciwx_le_kernel,
+static GenOpFunc *gen_op_ecowx[NB_MEM_FUNCS] = {
+    GEN_MEM_FUNCS(ecowx),
 };
-static GenOpFunc *gen_op_ecowx[] = {
-    &gen_op_ecowx_user,
-    &gen_op_ecowx_le_user,
-    &gen_op_ecowx_kernel,
-    &gen_op_ecowx_le_kernel,
-};
-#endif
-#endif
 
 /* eciwx */
 GEN_HANDLER(eciwx, 0x1F, 0x16, 0x0D, 0x00000001, PPC_EXTERN)
@@ -4215,6 +3866,7 @@ GEN_HANDLER(clcs, 0x1F, 0x10, 0x13, 0x0000F800, PPC_POWER_BR)
 {
     gen_op_load_gpr_T0(rA(ctx->opcode));
     gen_op_POWER_clcs();
+    /* Rc=1 sets CR0 to an undefined state */
     gen_op_store_T0_gpr(rD(ctx->opcode));
 }
 
@@ -4293,22 +3945,26 @@ GEN_HANDLER(dozi, 0x09, 0xFF, 0xFF, 0x00000000, PPC_POWER_BR)
     gen_op_store_T0_gpr(rD(ctx->opcode));
 }
 
-/* As lscbx load from memory byte after byte, it's always endian safe */
+/* As lscbx load from memory byte after byte, it's always endian safe.
+ * Original POWER is 32 bits only, define 64 bits ops as 32 bits ones
+ */
 #define op_POWER_lscbx(start, ra, rb)                                         \
 (*gen_op_POWER_lscbx[ctx->mem_idx])(start, ra, rb)
-#if defined(CONFIG_USER_ONLY)
-static GenOpFunc3 *gen_op_POWER_lscbx[] = {
-    &gen_op_POWER_lscbx_raw,
-    &gen_op_POWER_lscbx_raw,
-};
-#else
-static GenOpFunc3 *gen_op_POWER_lscbx[] = {
-    &gen_op_POWER_lscbx_user,
-    &gen_op_POWER_lscbx_user,
-    &gen_op_POWER_lscbx_kernel,
-    &gen_op_POWER_lscbx_kernel,
+#define gen_op_POWER_lscbx_64_raw       gen_op_POWER_lscbx_raw
+#define gen_op_POWER_lscbx_64_user      gen_op_POWER_lscbx_user
+#define gen_op_POWER_lscbx_64_kernel    gen_op_POWER_lscbx_kernel
+#define gen_op_POWER_lscbx_64_hypv      gen_op_POWER_lscbx_hypv
+#define gen_op_POWER_lscbx_le_raw       gen_op_POWER_lscbx_raw
+#define gen_op_POWER_lscbx_le_user      gen_op_POWER_lscbx_user
+#define gen_op_POWER_lscbx_le_kernel    gen_op_POWER_lscbx_kernel
+#define gen_op_POWER_lscbx_le_hypv      gen_op_POWER_lscbx_hypv
+#define gen_op_POWER_lscbx_le_64_raw    gen_op_POWER_lscbx_raw
+#define gen_op_POWER_lscbx_le_64_user   gen_op_POWER_lscbx_user
+#define gen_op_POWER_lscbx_le_64_kernel gen_op_POWER_lscbx_kernel
+#define gen_op_POWER_lscbx_le_64_hypv   gen_op_POWER_lscbx_hypv
+static GenOpFunc3 *gen_op_POWER_lscbx[NB_MEM_FUNCS] = {
+    GEN_MEM_FUNCS(POWER_lscbx),
 };
-#endif
 
 /* lscbx - lscbx. */
 GEN_HANDLER(lscbx, 0x1F, 0x15, 0x08, 0x00000000, PPC_POWER_BR)
@@ -4622,7 +4278,7 @@ GEN_HANDLER(mfrom, 0x1F, 0x09, 0x08, 0x03E0F801, PPC_602_SPEC)
 
 /* 602 - 603 - G2 TLB management */
 /* tlbld */
-GEN_HANDLER(tlbld_6xx, 0x1F, 0x12, 0x1E, 0x03FF0001, PPC_6xx_TLB)
+GEN_HANDLER2(tlbld_6xx, "tlbld", 0x1F, 0x12, 0x1E, 0x03FF0001, PPC_6xx_TLB)
 {
 #if defined(CONFIG_USER_ONLY)
     GEN_EXCP_PRIVOPC(ctx);
@@ -4637,7 +4293,7 @@ GEN_HANDLER(tlbld_6xx, 0x1F, 0x12, 0x1E, 0x03FF0001, PPC_6xx_TLB)
 }
 
 /* tlbli */
-GEN_HANDLER(tlbli_6xx, 0x1F, 0x12, 0x1F, 0x03FF0001, PPC_6xx_TLB)
+GEN_HANDLER2(tlbli_6xx, "tlbli", 0x1F, 0x12, 0x1F, 0x03FF0001, PPC_6xx_TLB)
 {
 #if defined(CONFIG_USER_ONLY)
     GEN_EXCP_PRIVOPC(ctx);
@@ -4653,7 +4309,7 @@ GEN_HANDLER(tlbli_6xx, 0x1F, 0x12, 0x1F, 0x03FF0001, PPC_6xx_TLB)
 
 /* 74xx TLB management */
 /* tlbld */
-GEN_HANDLER(tlbld_74xx, 0x1F, 0x12, 0x1E, 0x03FF0001, PPC_74xx_TLB)
+GEN_HANDLER2(tlbld_74xx, "tlbld", 0x1F, 0x12, 0x1E, 0x03FF0001, PPC_74xx_TLB)
 {
 #if defined(CONFIG_USER_ONLY)
     GEN_EXCP_PRIVOPC(ctx);
@@ -4668,7 +4324,7 @@ GEN_HANDLER(tlbld_74xx, 0x1F, 0x12, 0x1E, 0x03FF0001, PPC_74xx_TLB)
 }
 
 /* tlbli */
-GEN_HANDLER(tlbli_74xx, 0x1F, 0x12, 0x1F, 0x03FF0001, PPC_74xx_TLB)
+GEN_HANDLER2(tlbli_74xx, "tlbli", 0x1F, 0x12, 0x1F, 0x03FF0001, PPC_74xx_TLB)
 {
 #if defined(CONFIG_USER_ONLY)
     GEN_EXCP_PRIVOPC(ctx);
@@ -4762,31 +4418,31 @@ GEN_HANDLER(rfsvc, 0x13, 0x12, 0x02, 0x03FFF0001, PPC_POWER)
 
 /* POWER2 specific instructions */
 /* Quad manipulation (load/store two floats at a time) */
+/* Original POWER2 is 32 bits only, define 64 bits ops as 32 bits ones */
 #define op_POWER2_lfq() (*gen_op_POWER2_lfq[ctx->mem_idx])()
 #define op_POWER2_stfq() (*gen_op_POWER2_stfq[ctx->mem_idx])()
-#if defined(CONFIG_USER_ONLY)
-static GenOpFunc *gen_op_POWER2_lfq[] = {
-    &gen_op_POWER2_lfq_le_raw,
-    &gen_op_POWER2_lfq_raw,
-};
-static GenOpFunc *gen_op_POWER2_stfq[] = {
-    &gen_op_POWER2_stfq_le_raw,
-    &gen_op_POWER2_stfq_raw,
+#define gen_op_POWER2_lfq_64_raw        gen_op_POWER2_lfq_raw
+#define gen_op_POWER2_lfq_64_user       gen_op_POWER2_lfq_user
+#define gen_op_POWER2_lfq_64_kernel     gen_op_POWER2_lfq_kernel
+#define gen_op_POWER2_lfq_64_hypv       gen_op_POWER2_lfq_hypv
+#define gen_op_POWER2_lfq_le_64_raw     gen_op_POWER2_lfq_le_raw
+#define gen_op_POWER2_lfq_le_64_user    gen_op_POWER2_lfq_le_user
+#define gen_op_POWER2_lfq_le_64_kernel  gen_op_POWER2_lfq_le_kernel
+#define gen_op_POWER2_lfq_le_64_hypv    gen_op_POWER2_lfq_le_hypv
+#define gen_op_POWER2_stfq_64_raw       gen_op_POWER2_stfq_raw
+#define gen_op_POWER2_stfq_64_user      gen_op_POWER2_stfq_user
+#define gen_op_POWER2_stfq_64_kernel    gen_op_POWER2_stfq_kernel
+#define gen_op_POWER2_stfq_64_hypv      gen_op_POWER2_stfq_hypv
+#define gen_op_POWER2_stfq_le_64_raw    gen_op_POWER2_stfq_le_raw
+#define gen_op_POWER2_stfq_le_64_user   gen_op_POWER2_stfq_le_user
+#define gen_op_POWER2_stfq_le_64_kernel gen_op_POWER2_stfq_le_kernel
+#define gen_op_POWER2_stfq_le_64_hypv   gen_op_POWER2_stfq_le_hypv
+static GenOpFunc *gen_op_POWER2_lfq[NB_MEM_FUNCS] = {
+    GEN_MEM_FUNCS(POWER2_lfq),
 };
-#else
-static GenOpFunc *gen_op_POWER2_lfq[] = {
-    &gen_op_POWER2_lfq_le_user,
-    &gen_op_POWER2_lfq_user,
-    &gen_op_POWER2_lfq_le_kernel,
-    &gen_op_POWER2_lfq_kernel,
-};
-static GenOpFunc *gen_op_POWER2_stfq[] = {
-    &gen_op_POWER2_stfq_le_user,
-    &gen_op_POWER2_stfq_user,
-    &gen_op_POWER2_stfq_le_kernel,
-    &gen_op_POWER2_stfq_kernel,
+static GenOpFunc *gen_op_POWER2_stfq[NB_MEM_FUNCS] = {
+    GEN_MEM_FUNCS(POWER2_stfq),
 };
-#endif
 
 /* lfq */
 GEN_HANDLER(lfq, 0x38, 0xFF, 0xFF, 0x00000003, PPC_POWER2)
@@ -4894,14 +4550,14 @@ GEN_HANDLER(stfqx, 0x1F, 0x17, 0x1C, 0x00000001, PPC_POWER2)
 
 /* BookE specific instructions */
 /* XXX: not implemented on 440 ? */
-GEN_HANDLER(mfapidi, 0x1F, 0x13, 0x08, 0x0000F801, PPC_BOOKE_EXT)
+GEN_HANDLER(mfapidi, 0x1F, 0x13, 0x08, 0x0000F801, PPC_MFAPIDI)
 {
     /* XXX: TODO */
     GEN_EXCP_INVAL(ctx);
 }
 
 /* XXX: not implemented on 440 ? */
-GEN_HANDLER(tlbiva, 0x1F, 0x12, 0x18, 0x03FFF801, PPC_BOOKE_EXT)
+GEN_HANDLER(tlbiva, 0x1F, 0x12, 0x18, 0x03FFF801, PPC_TLBIVA)
 {
 #if defined(CONFIG_USER_ONLY)
     GEN_EXCP_PRIVOPC(ctx);
@@ -4985,7 +4641,7 @@ static always_inline void gen_405_mulladd_insn (DisasContext *ctx,
     if (opc3 & 0x10) {
         /* Check overflow */
         if (opc3 & 0x01)
-            gen_op_405_check_ov();
+            gen_op_check_addo();
         else
             gen_op_405_check_ovu();
     }
@@ -5097,7 +4753,7 @@ GEN_MAC_HANDLER(mullhw, 0x08, 0x0D);
 GEN_MAC_HANDLER(mullhwu, 0x08, 0x0C);
 
 /* mfdcr */
-GEN_HANDLER(mfdcr, 0x1F, 0x03, 0x0A, 0x00000001, PPC_EMB_COMMON)
+GEN_HANDLER(mfdcr, 0x1F, 0x03, 0x0A, 0x00000001, PPC_DCR)
 {
 #if defined(CONFIG_USER_ONLY)
     GEN_EXCP_PRIVREG(ctx);
@@ -5115,7 +4771,7 @@ GEN_HANDLER(mfdcr, 0x1F, 0x03, 0x0A, 0x00000001, PPC_EMB_COMMON)
 }
 
 /* mtdcr */
-GEN_HANDLER(mtdcr, 0x1F, 0x03, 0x0E, 0x00000001, PPC_EMB_COMMON)
+GEN_HANDLER(mtdcr, 0x1F, 0x03, 0x0E, 0x00000001, PPC_DCR)
 {
 #if defined(CONFIG_USER_ONLY)
     GEN_EXCP_PRIVREG(ctx);
@@ -5134,7 +4790,7 @@ GEN_HANDLER(mtdcr, 0x1F, 0x03, 0x0E, 0x00000001, PPC_EMB_COMMON)
 
 /* mfdcrx */
 /* XXX: not implemented on 440 ? */
-GEN_HANDLER(mfdcrx, 0x1F, 0x03, 0x08, 0x00000000, PPC_BOOKE_EXT)
+GEN_HANDLER(mfdcrx, 0x1F, 0x03, 0x08, 0x00000000, PPC_DCRX)
 {
 #if defined(CONFIG_USER_ONLY)
     GEN_EXCP_PRIVREG(ctx);
@@ -5152,7 +4808,7 @@ GEN_HANDLER(mfdcrx, 0x1F, 0x03, 0x08, 0x00000000, PPC_BOOKE_EXT)
 
 /* mtdcrx */
 /* XXX: not implemented on 440 ? */
-GEN_HANDLER(mtdcrx, 0x1F, 0x03, 0x0C, 0x00000000, PPC_BOOKE_EXT)
+GEN_HANDLER(mtdcrx, 0x1F, 0x03, 0x0C, 0x00000000, PPC_DCRX)
 {
 #if defined(CONFIG_USER_ONLY)
     GEN_EXCP_PRIVREG(ctx);
@@ -5217,7 +4873,7 @@ GEN_HANDLER(dcread, 0x1F, 0x06, 0x0F, 0x00000001, PPC_4xx_COMMON)
 }
 
 /* icbt */
-GEN_HANDLER(icbt_40x, 0x1F, 0x06, 0x08, 0x03E00001, PPC_40x_ICBT)
+GEN_HANDLER2(icbt_40x, "icbt", 0x1F, 0x06, 0x08, 0x03E00001, PPC_40x_ICBT)
 {
     /* interpreted as no-op */
     /* XXX: specification say this is treated as a load by the MMU
@@ -5254,7 +4910,7 @@ GEN_HANDLER(icread, 0x1F, 0x06, 0x1F, 0x03E00001, PPC_4xx_COMMON)
 }
 
 /* rfci (supervisor only) */
-GEN_HANDLER(rfci_40x, 0x13, 0x13, 0x01, 0x03FF8001, PPC_40x_EXCP)
+GEN_HANDLER2(rfci_40x, "rfci", 0x13, 0x13, 0x01, 0x03FF8001, PPC_40x_EXCP)
 {
 #if defined(CONFIG_USER_ONLY)
     GEN_EXCP_PRIVOPC(ctx);
@@ -5286,7 +4942,7 @@ GEN_HANDLER(rfci, 0x13, 0x13, 0x01, 0x03FF8001, PPC_BOOKE)
 
 /* BookE specific */
 /* XXX: not implemented on 440 ? */
-GEN_HANDLER(rfdi, 0x13, 0x07, 0x01, 0x03FF8001, PPC_BOOKE_EXT)
+GEN_HANDLER(rfdi, 0x13, 0x07, 0x01, 0x03FF8001, PPC_RFDI)
 {
 #if defined(CONFIG_USER_ONLY)
     GEN_EXCP_PRIVOPC(ctx);
@@ -5319,7 +4975,7 @@ GEN_HANDLER(rfmci, 0x13, 0x06, 0x01, 0x03FF8001, PPC_RFMCI)
 
 /* TLB management - PowerPC 405 implementation */
 /* tlbre */
-GEN_HANDLER(tlbre_40x, 0x1F, 0x12, 0x1D, 0x00000001, PPC_40x_TLB)
+GEN_HANDLER2(tlbre_40x, "tlbre", 0x1F, 0x12, 0x1D, 0x00000001, PPC_40x_TLB)
 {
 #if defined(CONFIG_USER_ONLY)
     GEN_EXCP_PRIVOPC(ctx);
@@ -5347,7 +5003,7 @@ GEN_HANDLER(tlbre_40x, 0x1F, 0x12, 0x1D, 0x00000001, PPC_40x_TLB)
 }
 
 /* tlbsx - tlbsx. */
-GEN_HANDLER(tlbsx_40x, 0x1F, 0x12, 0x1C, 0x00000000, PPC_40x_TLB)
+GEN_HANDLER2(tlbsx_40x, "tlbsx", 0x1F, 0x12, 0x1C, 0x00000000, PPC_40x_TLB)
 {
 #if defined(CONFIG_USER_ONLY)
     GEN_EXCP_PRIVOPC(ctx);
@@ -5365,7 +5021,7 @@ GEN_HANDLER(tlbsx_40x, 0x1F, 0x12, 0x1C, 0x00000000, PPC_40x_TLB)
 }
 
 /* tlbwe */
-GEN_HANDLER(tlbwe_40x, 0x1F, 0x12, 0x1E, 0x00000001, PPC_40x_TLB)
+GEN_HANDLER2(tlbwe_40x, "tlbwe", 0x1F, 0x12, 0x1E, 0x00000001, PPC_40x_TLB)
 {
 #if defined(CONFIG_USER_ONLY)
     GEN_EXCP_PRIVOPC(ctx);
@@ -5394,7 +5050,7 @@ GEN_HANDLER(tlbwe_40x, 0x1F, 0x12, 0x1E, 0x00000001, PPC_40x_TLB)
 
 /* TLB management - PowerPC 440 implementation */
 /* tlbre */
-GEN_HANDLER(tlbre_440, 0x1F, 0x12, 0x1D, 0x00000001, PPC_BOOKE)
+GEN_HANDLER2(tlbre_440, "tlbre", 0x1F, 0x12, 0x1D, 0x00000001, PPC_BOOKE)
 {
 #if defined(CONFIG_USER_ONLY)
     GEN_EXCP_PRIVOPC(ctx);
@@ -5419,7 +5075,7 @@ GEN_HANDLER(tlbre_440, 0x1F, 0x12, 0x1D, 0x00000001, PPC_BOOKE)
 }
 
 /* tlbsx - tlbsx. */
-GEN_HANDLER(tlbsx_440, 0x1F, 0x12, 0x1C, 0x00000000, PPC_BOOKE)
+GEN_HANDLER2(tlbsx_440, "tlbsx", 0x1F, 0x12, 0x1C, 0x00000000, PPC_BOOKE)
 {
 #if defined(CONFIG_USER_ONLY)
     GEN_EXCP_PRIVOPC(ctx);
@@ -5437,7 +5093,7 @@ GEN_HANDLER(tlbsx_440, 0x1F, 0x12, 0x1C, 0x00000000, PPC_BOOKE)
 }
 
 /* tlbwe */
-GEN_HANDLER(tlbwe_440, 0x1F, 0x12, 0x1E, 0x00000001, PPC_BOOKE)
+GEN_HANDLER2(tlbwe_440, "tlbwe", 0x1F, 0x12, 0x1E, 0x00000001, PPC_BOOKE)
 {
 #if defined(CONFIG_USER_ONLY)
     GEN_EXCP_PRIVOPC(ctx);
@@ -5462,7 +5118,7 @@ GEN_HANDLER(tlbwe_440, 0x1F, 0x12, 0x1E, 0x00000001, PPC_BOOKE)
 }
 
 /* wrtee */
-GEN_HANDLER(wrtee, 0x1F, 0x03, 0x04, 0x000FFC01, PPC_EMB_COMMON)
+GEN_HANDLER(wrtee, 0x1F, 0x03, 0x04, 0x000FFC01, PPC_WRTEE)
 {
 #if defined(CONFIG_USER_ONLY)
     GEN_EXCP_PRIVOPC(ctx);
@@ -5481,7 +5137,7 @@ GEN_HANDLER(wrtee, 0x1F, 0x03, 0x04, 0x000FFC01, PPC_EMB_COMMON)
 }
 
 /* wrteei */
-GEN_HANDLER(wrteei, 0x1F, 0x03, 0x05, 0x000EFC01, PPC_EMB_COMMON)
+GEN_HANDLER(wrteei, 0x1F, 0x03, 0x05, 0x000EFC01, PPC_WRTEE)
 {
 #if defined(CONFIG_USER_ONLY)
     GEN_EXCP_PRIVOPC(ctx);
@@ -5527,7 +5183,7 @@ GEN_HANDLER(msync, 0x1F, 0x16, 0x12, 0x03FFF801, PPC_BOOKE)
 }
 
 /* icbt */
-GEN_HANDLER(icbt_440, 0x1F, 0x16, 0x00, 0x03E00001, PPC_BOOKE)
+GEN_HANDLER2(icbt_440, "icbt", 0x1F, 0x16, 0x00, 0x03E00001, PPC_BOOKE)
 {
     /* interpreted as no-op */
     /* XXX: specification say this is treated as a load by the MMU
@@ -5548,111 +5204,14 @@ GEN32(gen_op_store_A2_avr, gen_op_store_A2_avr_avr);
 #endif
 
 #define op_vr_ldst(name)        (*gen_op_##name[ctx->mem_idx])()
-#if defined(CONFIG_USER_ONLY)
-#if defined(TARGET_PPC64)
-/* User-mode only - 64 bits mode */
 #define OP_VR_LD_TABLE(name)                                                  \
-static GenOpFunc *gen_op_vr_l##name[] = {                                     \
-    &gen_op_vr_l##name##_raw,                                                 \
-    &gen_op_vr_l##name##_le_raw,                                              \
-    &gen_op_vr_l##name##_64_raw,                                              \
-    &gen_op_vr_l##name##_le_64_raw,                                           \
+static GenOpFunc *gen_op_vr_l##name[NB_MEM_FUNCS] = {                         \
+    GEN_MEM_FUNCS(vr_l##name),                                                \
 };
 #define OP_VR_ST_TABLE(name)                                                  \
-static GenOpFunc *gen_op_vr_st##name[] = {                                    \
-    &gen_op_vr_st##name##_raw,                                                \
-    &gen_op_vr_st##name##_le_raw,                                             \
-    &gen_op_vr_st##name##_64_raw,                                             \
-    &gen_op_vr_st##name##_le_64_raw,                                          \
-};
-#else /* defined(TARGET_PPC64) */
-/* User-mode only - 32 bits mode */
-#define OP_VR_LD_TABLE(name)                                                  \
-static GenOpFunc *gen_op_vr_l##name[] = {                                     \
-    &gen_op_vr_l##name##_raw,                                                 \
-    &gen_op_vr_l##name##_le_raw,                                              \
+static GenOpFunc *gen_op_vr_st##name[NB_MEM_FUNCS] = {                        \
+    GEN_MEM_FUNCS(vr_st##name),                                               \
 };
-#define OP_VR_ST_TABLE(name)                                                  \
-static GenOpFunc *gen_op_vr_st##name[] = {                                    \
-    &gen_op_vr_st##name##_raw,                                                \
-    &gen_op_vr_st##name##_le_raw,                                             \
-};
-#endif /* defined(TARGET_PPC64) */
-#else /* defined(CONFIG_USER_ONLY) */
-#if defined(TARGET_PPC64H)
-/* Full system with hypervisor mode */
-#define OP_VR_LD_TABLE(name)                                                  \
-static GenOpFunc *gen_op_vr_l##name[] = {                                     \
-    &gen_op_vr_l##name##_user,                                                \
-    &gen_op_vr_l##name##_le_user,                                             \
-    &gen_op_vr_l##name##_64_user,                                             \
-    &gen_op_vr_l##name##_le_64_user,                                          \
-    &gen_op_vr_l##name##_kernel,                                              \
-    &gen_op_vr_l##name##_le_kernel,                                           \
-    &gen_op_vr_l##name##_64_kernel,                                           \
-    &gen_op_vr_l##name##_le_64_kernel,                                        \
-    &gen_op_vr_l##name##_hypv,                                                \
-    &gen_op_vr_l##name##_le_hypv,                                             \
-    &gen_op_vr_l##name##_64_hypv,                                             \
-    &gen_op_vr_l##name##_le_64_hypv,                                          \
-};
-#define OP_VR_ST_TABLE(name)                                                  \
-static GenOpFunc *gen_op_vr_st##name[] = {                                    \
-    &gen_op_vr_st##name##_user,                                               \
-    &gen_op_vr_st##name##_le_user,                                            \
-    &gen_op_vr_st##name##_64_user,                                            \
-    &gen_op_vr_st##name##_le_64_user,                                         \
-    &gen_op_vr_st##name##_kernel,                                             \
-    &gen_op_vr_st##name##_le_kernel,                                          \
-    &gen_op_vr_st##name##_64_kernel,                                          \
-    &gen_op_vr_st##name##_le_64_kernel,                                       \
-    &gen_op_vr_st##name##_hypv,                                               \
-    &gen_op_vr_st##name##_le_hypv,                                            \
-    &gen_op_vr_st##name##_64_hypv,                                            \
-    &gen_op_vr_st##name##_le_64_hypv,                                         \
-};
-#elif defined(TARGET_PPC64)
-/* Full system - 64 bits mode */
-#define OP_VR_LD_TABLE(name)                                                  \
-static GenOpFunc *gen_op_vr_l##name[] = {                                     \
-    &gen_op_vr_l##name##_user,                                                \
-    &gen_op_vr_l##name##_le_user,                                             \
-    &gen_op_vr_l##name##_64_user,                                             \
-    &gen_op_vr_l##name##_le_64_user,                                          \
-    &gen_op_vr_l##name##_kernel,                                              \
-    &gen_op_vr_l##name##_le_kernel,                                           \
-    &gen_op_vr_l##name##_64_kernel,                                           \
-    &gen_op_vr_l##name##_le_64_kernel,                                        \
-};
-#define OP_VR_ST_TABLE(name)                                                  \
-static GenOpFunc *gen_op_vr_st##name[] = {                                    \
-    &gen_op_vr_st##name##_user,                                               \
-    &gen_op_vr_st##name##_le_user,                                            \
-    &gen_op_vr_st##name##_64_user,                                            \
-    &gen_op_vr_st##name##_le_64_user,                                         \
-    &gen_op_vr_st##name##_kernel,                                             \
-    &gen_op_vr_st##name##_le_kernel,                                          \
-    &gen_op_vr_st##name##_64_kernel,                                          \
-    &gen_op_vr_st##name##_le_64_kernel,                                       \
-};
-#else /* defined(TARGET_PPC64) */
-/* Full system - 32 bits mode */
-#define OP_VR_LD_TABLE(name)                                                  \
-static GenOpFunc *gen_op_vr_l##name[] = {                                     \
-    &gen_op_vr_l##name##_user,                                                \
-    &gen_op_vr_l##name##_le_user,                                             \
-    &gen_op_vr_l##name##_kernel,                                              \
-    &gen_op_vr_l##name##_le_kernel,                                           \
-};
-#define OP_VR_ST_TABLE(name)                                                  \
-static GenOpFunc *gen_op_vr_st##name[] = {                                    \
-    &gen_op_vr_st##name##_user,                                               \
-    &gen_op_vr_st##name##_le_user,                                            \
-    &gen_op_vr_st##name##_kernel,                                             \
-    &gen_op_vr_st##name##_le_kernel,                                          \
-};
-#endif /* defined(TARGET_PPC64) */
-#endif /* defined(CONFIG_USER_ONLY) */
 
 #define GEN_VR_LDX(name, opc2, opc3)                                          \
 GEN_HANDLER(l##name, 0x1F, opc2, opc3, 0x00000001, PPC_ALTIVEC)               \
@@ -5690,10 +5249,10 @@ GEN_VR_STX(vx, 0x07, 0x07);
 #define gen_op_vr_stvxl gen_op_vr_stvx
 GEN_VR_STX(vxl, 0x07, 0x0F);
 
-#if defined(TARGET_PPCEMB)
 /***                           SPE extension                               ***/
-
 /* Register moves */
+#if !defined(TARGET_PPC64)
+
 GEN32(gen_op_load_gpr64_T0, gen_op_load_gpr64_T0_gpr);
 GEN32(gen_op_load_gpr64_T1, gen_op_load_gpr64_T1_gpr);
 #if 0 // unused
@@ -5706,6 +5265,23 @@ GEN32(gen_op_store_T1_gpr64, gen_op_store_T1_gpr64_gpr);
 GEN32(gen_op_store_T2_gpr64, gen_op_store_T2_gpr64_gpr);
 #endif
 
+#else /* !defined(TARGET_PPC64) */
+
+/* No specific load/store functions: GPRs are already 64 bits */
+#define gen_op_load_gpr64_T0 gen_op_load_gpr_T0
+#define gen_op_load_gpr64_T1 gen_op_load_gpr_T1
+#if 0 // unused
+#define gen_op_load_gpr64_T2 gen_op_load_gpr_T2
+#endif
+
+#define gen_op_store_T0_gpr64 gen_op_store_T0_gpr
+#define gen_op_store_T1_gpr64 gen_op_store_T1_gpr
+#if 0 // unused
+#define gen_op_store_T2_gpr64 gen_op_store_T2_gpr
+#endif
+
+#endif /* !defined(TARGET_PPC64) */
+
 #define GEN_SPE(name0, name1, opc2, opc3, inval, type)                        \
 GEN_HANDLER(name0##_##name1, 0x04, opc2, opc3, inval, type)                   \
 {                                                                             \
@@ -5736,111 +5312,14 @@ static always_inline void gen_addr_spe_imm_index (DisasContext *ctx, int sh)
 }
 
 #define op_spe_ldst(name)        (*gen_op_##name[ctx->mem_idx])()
-#if defined(CONFIG_USER_ONLY)
-#if defined(TARGET_PPC64)
-/* User-mode only - 64 bits mode */
-#define OP_SPE_LD_TABLE(name)                                                 \
-static GenOpFunc *gen_op_spe_l##name[] = {                                    \
-    &gen_op_spe_l##name##_raw,                                                \
-    &gen_op_spe_l##name##_le_raw,                                             \
-    &gen_op_spe_l##name##_64_raw,                                             \
-    &gen_op_spe_l##name##_le_64_raw,                                          \
-};
-#define OP_SPE_ST_TABLE(name)                                                 \
-static GenOpFunc *gen_op_spe_st##name[] = {                                   \
-    &gen_op_spe_st##name##_raw,                                               \
-    &gen_op_spe_st##name##_le_raw,                                            \
-    &gen_op_spe_st##name##_64_raw,                                            \
-    &gen_op_spe_st##name##_le_64_raw,                                         \
-};
-#else /* defined(TARGET_PPC64) */
-/* User-mode only - 32 bits mode */
-#define OP_SPE_LD_TABLE(name)                                                 \
-static GenOpFunc *gen_op_spe_l##name[] = {                                    \
-    &gen_op_spe_l##name##_raw,                                                \
-    &gen_op_spe_l##name##_le_raw,                                             \
-};
-#define OP_SPE_ST_TABLE(name)                                                 \
-static GenOpFunc *gen_op_spe_st##name[] = {                                   \
-    &gen_op_spe_st##name##_raw,                                               \
-    &gen_op_spe_st##name##_le_raw,                                            \
-};
-#endif /* defined(TARGET_PPC64) */
-#else /* defined(CONFIG_USER_ONLY) */
-#if defined(TARGET_PPC64H)
-/* Full system with hypervisor mode */
-#define OP_SPE_LD_TABLE(name)                                                 \
-static GenOpFunc *gen_op_spe_l##name[] = {                                    \
-    &gen_op_spe_l##name##_user,                                               \
-    &gen_op_spe_l##name##_le_user,                                            \
-    &gen_op_spe_l##name##_64_user,                                            \
-    &gen_op_spe_l##name##_le_64_user,                                         \
-    &gen_op_spe_l##name##_kernel,                                             \
-    &gen_op_spe_l##name##_le_kernel,                                          \
-    &gen_op_spe_l##name##_64_kernel,                                          \
-    &gen_op_spe_l##name##_le_64_kernel,                                       \
-    &gen_op_spe_l##name##_hypv,                                               \
-    &gen_op_spe_l##name##_le_hypv,                                            \
-    &gen_op_spe_l##name##_64_hypv,                                            \
-    &gen_op_spe_l##name##_le_64_hypv,                                         \
-};
-#define OP_SPE_ST_TABLE(name)                                                 \
-static GenOpFunc *gen_op_spe_st##name[] = {                                   \
-    &gen_op_spe_st##name##_user,                                              \
-    &gen_op_spe_st##name##_le_user,                                           \
-    &gen_op_spe_st##name##_64_user,                                           \
-    &gen_op_spe_st##name##_le_64_user,                                        \
-    &gen_op_spe_st##name##_kernel,                                            \
-    &gen_op_spe_st##name##_le_kernel,                                         \
-    &gen_op_spe_st##name##_64_kernel,                                         \
-    &gen_op_spe_st##name##_le_64_kernel,                                      \
-    &gen_op_spe_st##name##_hypv,                                              \
-    &gen_op_spe_st##name##_le_hypv,                                           \
-    &gen_op_spe_st##name##_64_hypv,                                           \
-    &gen_op_spe_st##name##_le_64_hypv,                                        \
-};
-#elif defined(TARGET_PPC64)
-/* Full system - 64 bits mode */
-#define OP_SPE_LD_TABLE(name)                                                 \
-static GenOpFunc *gen_op_spe_l##name[] = {                                    \
-    &gen_op_spe_l##name##_user,                                               \
-    &gen_op_spe_l##name##_le_user,                                            \
-    &gen_op_spe_l##name##_64_user,                                            \
-    &gen_op_spe_l##name##_le_64_user,                                         \
-    &gen_op_spe_l##name##_kernel,                                             \
-    &gen_op_spe_l##name##_le_kernel,                                          \
-    &gen_op_spe_l##name##_64_kernel,                                          \
-    &gen_op_spe_l##name##_le_64_kernel,                                       \
-};
-#define OP_SPE_ST_TABLE(name)                                                 \
-static GenOpFunc *gen_op_spe_st##name[] = {                                   \
-    &gen_op_spe_st##name##_user,                                              \
-    &gen_op_spe_st##name##_le_user,                                           \
-    &gen_op_spe_st##name##_64_user,                                           \
-    &gen_op_spe_st##name##_le_64_user,                                        \
-    &gen_op_spe_st##name##_kernel,                                            \
-    &gen_op_spe_st##name##_le_kernel,                                         \
-    &gen_op_spe_st##name##_64_kernel,                                         \
-    &gen_op_spe_st##name##_le_64_kernel,                                      \
-};
-#else /* defined(TARGET_PPC64) */
-/* Full system - 32 bits mode */
 #define OP_SPE_LD_TABLE(name)                                                 \
-static GenOpFunc *gen_op_spe_l##name[] = {                                    \
-    &gen_op_spe_l##name##_user,                                               \
-    &gen_op_spe_l##name##_le_user,                                            \
-    &gen_op_spe_l##name##_kernel,                                             \
-    &gen_op_spe_l##name##_le_kernel,                                          \
+static GenOpFunc *gen_op_spe_l##name[NB_MEM_FUNCS] = {                        \
+    GEN_MEM_FUNCS(spe_l##name),                                               \
 };
 #define OP_SPE_ST_TABLE(name)                                                 \
-static GenOpFunc *gen_op_spe_st##name[] = {                                   \
-    &gen_op_spe_st##name##_user,                                              \
-    &gen_op_spe_st##name##_le_user,                                           \
-    &gen_op_spe_st##name##_kernel,                                            \
-    &gen_op_spe_st##name##_le_kernel,                                         \
+static GenOpFunc *gen_op_spe_st##name[NB_MEM_FUNCS] = {                       \
+    GEN_MEM_FUNCS(spe_st##name),                                              \
 };
-#endif /* defined(TARGET_PPC64) */
-#endif /* defined(CONFIG_USER_ONLY) */
 
 #define GEN_SPE_LD(name, sh)                                                  \
 static always_inline void gen_evl##name (DisasContext *ctx)                   \
@@ -5974,10 +5453,10 @@ GEN_SPEOP_ARITH1(evcntlsw);
 static always_inline void gen_brinc (DisasContext *ctx)
 {
     /* Note: brinc is usable even if SPE is disabled */
-    gen_op_load_gpr64_T0(rA(ctx->opcode));
-    gen_op_load_gpr64_T1(rB(ctx->opcode));
+    gen_op_load_gpr_T0(rA(ctx->opcode));
+    gen_op_load_gpr_T1(rB(ctx->opcode));
     gen_op_brinc();
-    gen_op_store_T0_gpr64(rD(ctx->opcode));
+    gen_op_store_T0_gpr(rD(ctx->opcode));
 }
 
 #define GEN_SPEOP_ARITH_IMM2(name)                                            \
@@ -6079,19 +5558,19 @@ static always_inline void gen_evsel (DisasContext *ctx)
     gen_op_store_T0_gpr64(rD(ctx->opcode));
 }
 
-GEN_HANDLER(evsel0, 0x04, 0x1c, 0x09, 0x00000000, PPC_SPE)
+GEN_HANDLER2(evsel0, "evsel", 0x04, 0x1c, 0x09, 0x00000000, PPC_SPE)
 {
     gen_evsel(ctx);
 }
-GEN_HANDLER(evsel1, 0x04, 0x1d, 0x09, 0x00000000, PPC_SPE)
+GEN_HANDLER2(evsel1, "evsel", 0x04, 0x1d, 0x09, 0x00000000, PPC_SPE)
 {
     gen_evsel(ctx);
 }
-GEN_HANDLER(evsel2, 0x04, 0x1e, 0x09, 0x00000000, PPC_SPE)
+GEN_HANDLER2(evsel2, "evsel", 0x04, 0x1e, 0x09, 0x00000000, PPC_SPE)
 {
     gen_evsel(ctx);
 }
-GEN_HANDLER(evsel3, 0x04, 0x1f, 0x09, 0x00000000, PPC_SPE)
+GEN_HANDLER2(evsel3, "evsel", 0x04, 0x1f, 0x09, 0x00000000, PPC_SPE)
 {
     gen_evsel(ctx);
 }
@@ -6101,33 +5580,38 @@ GEN_HANDLER(evsel3, 0x04, 0x1f, 0x09, 0x00000000, PPC_SPE)
 /* In that case, we already have 64 bits load & stores
  * so, spe_ldd is equivalent to ld and spe_std is equivalent to std
  */
-#if defined(CONFIG_USER_ONLY)
-#define gen_op_spe_ldd_raw gen_op_ld_raw
-#define gen_op_spe_ldd_64_raw gen_op_ld_64_raw
-#define gen_op_spe_ldd_le_raw gen_op_ld_le_raw
-#define gen_op_spe_ldd_le_64_raw gen_op_ld_le_64_raw
-#define gen_op_spe_stdd_raw gen_op_ld_raw
-#define gen_op_spe_stdd_64_raw gen_op_std_64_raw
-#define gen_op_spe_stdd_le_raw gen_op_std_le_raw
-#define gen_op_spe_stdd_le_64_raw gen_op_std_le_64_raw
-#else /* defined(CONFIG_USER_ONLY) */
-#define gen_op_spe_ldd_kernel gen_op_ld_kernel
-#define gen_op_spe_ldd_64_kernel gen_op_ld_64_kernel
-#define gen_op_spe_ldd_le_kernel gen_op_ld_kernel
-#define gen_op_spe_ldd_le_64_kernel gen_op_ld_64_kernel
-#define gen_op_spe_ldd_user gen_op_ld_user
-#define gen_op_spe_ldd_64_user gen_op_ld_64_user
-#define gen_op_spe_ldd_le_user gen_op_ld_le_user
-#define gen_op_spe_ldd_le_64_user gen_op_ld_le_64_user
-#define gen_op_spe_stdd_kernel gen_op_std_kernel
-#define gen_op_spe_stdd_64_kernel gen_op_std_64_kernel
-#define gen_op_spe_stdd_le_kernel gen_op_std_kernel
-#define gen_op_spe_stdd_le_64_kernel gen_op_std_64_kernel
-#define gen_op_spe_stdd_user gen_op_std_user
-#define gen_op_spe_stdd_64_user gen_op_std_64_user
-#define gen_op_spe_stdd_le_user gen_op_std_le_user
-#define gen_op_spe_stdd_le_64_user gen_op_std_le_64_user
-#endif /* defined(CONFIG_USER_ONLY) */
+#define gen_op_spe_ldd_raw           gen_op_ld_raw
+#define gen_op_spe_ldd_user          gen_op_ld_user
+#define gen_op_spe_ldd_kernel        gen_op_ld_kernel
+#define gen_op_spe_ldd_hypv          gen_op_ld_hypv
+#define gen_op_spe_ldd_64_raw        gen_op_ld_64_raw
+#define gen_op_spe_ldd_64_user       gen_op_ld_64_user
+#define gen_op_spe_ldd_64_kernel     gen_op_ld_64_kernel
+#define gen_op_spe_ldd_64_hypv       gen_op_ld_64_hypv
+#define gen_op_spe_ldd_le_raw        gen_op_ld_le_raw
+#define gen_op_spe_ldd_le_user       gen_op_ld_le_user
+#define gen_op_spe_ldd_le_kernel     gen_op_ld_le_kernel
+#define gen_op_spe_ldd_le_hypv       gen_op_ld_le_hypv
+#define gen_op_spe_ldd_le_64_raw     gen_op_ld_le_64_raw
+#define gen_op_spe_ldd_le_64_user    gen_op_ld_le_64_user
+#define gen_op_spe_ldd_le_64_kernel  gen_op_ld_le_64_kernel
+#define gen_op_spe_ldd_le_64_hypv    gen_op_ld_le_64_hypv
+#define gen_op_spe_stdd_raw          gen_op_std_raw
+#define gen_op_spe_stdd_user         gen_op_std_user
+#define gen_op_spe_stdd_kernel       gen_op_std_kernel
+#define gen_op_spe_stdd_hypv         gen_op_std_hypv
+#define gen_op_spe_stdd_64_raw       gen_op_std_64_raw
+#define gen_op_spe_stdd_64_user      gen_op_std_64_user
+#define gen_op_spe_stdd_64_kernel    gen_op_std_64_kernel
+#define gen_op_spe_stdd_64_hypv      gen_op_std_64_hypv
+#define gen_op_spe_stdd_le_raw       gen_op_std_le_raw
+#define gen_op_spe_stdd_le_user      gen_op_std_le_user
+#define gen_op_spe_stdd_le_kernel    gen_op_std_le_kernel
+#define gen_op_spe_stdd_le_hypv      gen_op_std_le_hypv
+#define gen_op_spe_stdd_le_64_raw    gen_op_std_le_64_raw
+#define gen_op_spe_stdd_le_64_user   gen_op_std_le_64_user
+#define gen_op_spe_stdd_le_64_kernel gen_op_std_le_64_kernel
+#define gen_op_spe_stdd_le_64_hypv   gen_op_std_le_64_hypv
 #endif /* defined(TARGET_PPC64) */
 GEN_SPEOP_LDST(dd, 3);
 GEN_SPEOP_LDST(dw, 3);
@@ -6139,21 +5623,22 @@ GEN_SPEOP_ST(who, 2);
 
 #if defined(TARGET_PPC64)
 /* In that case, spe_stwwo is equivalent to stw */
-#if defined(CONFIG_USER_ONLY)
-#define gen_op_spe_stwwo_raw gen_op_stw_raw
-#define gen_op_spe_stwwo_le_raw gen_op_stw_le_raw
-#define gen_op_spe_stwwo_64_raw gen_op_stw_64_raw
-#define gen_op_spe_stwwo_le_64_raw gen_op_stw_le_64_raw
-#else
-#define gen_op_spe_stwwo_user gen_op_stw_user
-#define gen_op_spe_stwwo_le_user gen_op_stw_le_user
-#define gen_op_spe_stwwo_64_user gen_op_stw_64_user
-#define gen_op_spe_stwwo_le_64_user gen_op_stw_le_64_user
-#define gen_op_spe_stwwo_kernel gen_op_stw_kernel
-#define gen_op_spe_stwwo_le_kernel gen_op_stw_le_kernel
-#define gen_op_spe_stwwo_64_kernel gen_op_stw_64_kernel
+#define gen_op_spe_stwwo_raw          gen_op_stw_raw
+#define gen_op_spe_stwwo_user         gen_op_stw_user
+#define gen_op_spe_stwwo_kernel       gen_op_stw_kernel
+#define gen_op_spe_stwwo_hypv         gen_op_stw_hypv
+#define gen_op_spe_stwwo_le_raw       gen_op_stw_le_raw
+#define gen_op_spe_stwwo_le_user      gen_op_stw_le_user
+#define gen_op_spe_stwwo_le_kernel    gen_op_stw_le_kernel
+#define gen_op_spe_stwwo_le_hypv      gen_op_stw_le_hypv
+#define gen_op_spe_stwwo_64_raw       gen_op_stw_64_raw
+#define gen_op_spe_stwwo_64_user      gen_op_stw_64_user
+#define gen_op_spe_stwwo_64_kernel    gen_op_stw_64_kernel
+#define gen_op_spe_stwwo_64_hypv      gen_op_stw_64_hypv
+#define gen_op_spe_stwwo_le_64_raw    gen_op_stw_le_64_raw
+#define gen_op_spe_stwwo_le_64_user   gen_op_stw_le_64_user
 #define gen_op_spe_stwwo_le_64_kernel gen_op_stw_le_64_kernel
-#endif
+#define gen_op_spe_stwwo_le_64_hypv   gen_op_stw_le_64_hypv
 #endif
 #define _GEN_OP_SPE_STWWE(suffix)                                             \
 static always_inline void gen_op_spe_stwwe_##suffix (void)                    \
@@ -6189,8 +5674,9 @@ _GEN_OP_SPE_STWWE_LE(suffix)
 #if defined(CONFIG_USER_ONLY)
 GEN_OP_SPE_STWWE(raw);
 #else /* defined(CONFIG_USER_ONLY) */
-GEN_OP_SPE_STWWE(kernel);
 GEN_OP_SPE_STWWE(user);
+GEN_OP_SPE_STWWE(kernel);
+GEN_OP_SPE_STWWE(hypv);
 #endif /* defined(CONFIG_USER_ONLY) */
 GEN_SPEOP_ST(wwe, 2);
 GEN_SPEOP_ST(wwo, 2);
@@ -6240,47 +5726,67 @@ GEN_OP_SPE_LHX(le_64_raw);
 GEN_SPE_LDSPLAT(hhossplat, spe_lhx, le_64_raw);
 #endif
 #else
-GEN_OP_SPE_LHE(kernel);
 GEN_OP_SPE_LHE(user);
-GEN_SPE_LDSPLAT(hhesplat, spe_lhe, kernel);
+GEN_OP_SPE_LHE(kernel);
+GEN_OP_SPE_LHE(hypv);
 GEN_SPE_LDSPLAT(hhesplat, spe_lhe, user);
-GEN_OP_SPE_LHE(le_kernel);
+GEN_SPE_LDSPLAT(hhesplat, spe_lhe, kernel);
+GEN_SPE_LDSPLAT(hhesplat, spe_lhe, hypv);
 GEN_OP_SPE_LHE(le_user);
-GEN_SPE_LDSPLAT(hhesplat, spe_lhe, le_kernel);
+GEN_OP_SPE_LHE(le_kernel);
+GEN_OP_SPE_LHE(le_hypv);
 GEN_SPE_LDSPLAT(hhesplat, spe_lhe, le_user);
-GEN_SPE_LDSPLAT(hhousplat, spe_lh, kernel);
+GEN_SPE_LDSPLAT(hhesplat, spe_lhe, le_kernel);
+GEN_SPE_LDSPLAT(hhesplat, spe_lhe, le_hypv);
 GEN_SPE_LDSPLAT(hhousplat, spe_lh, user);
-GEN_SPE_LDSPLAT(hhousplat, spe_lh, le_kernel);
+GEN_SPE_LDSPLAT(hhousplat, spe_lh, kernel);
+GEN_SPE_LDSPLAT(hhousplat, spe_lh, hypv);
 GEN_SPE_LDSPLAT(hhousplat, spe_lh, le_user);
-GEN_OP_SPE_LHX(kernel);
+GEN_SPE_LDSPLAT(hhousplat, spe_lh, le_kernel);
+GEN_SPE_LDSPLAT(hhousplat, spe_lh, le_hypv);
 GEN_OP_SPE_LHX(user);
-GEN_SPE_LDSPLAT(hhossplat, spe_lhx, kernel);
+GEN_OP_SPE_LHX(kernel);
+GEN_OP_SPE_LHX(hypv);
 GEN_SPE_LDSPLAT(hhossplat, spe_lhx, user);
-GEN_OP_SPE_LHX(le_kernel);
+GEN_SPE_LDSPLAT(hhossplat, spe_lhx, kernel);
+GEN_SPE_LDSPLAT(hhossplat, spe_lhx, hypv);
 GEN_OP_SPE_LHX(le_user);
-GEN_SPE_LDSPLAT(hhossplat, spe_lhx, le_kernel);
+GEN_OP_SPE_LHX(le_kernel);
+GEN_OP_SPE_LHX(le_hypv);
 GEN_SPE_LDSPLAT(hhossplat, spe_lhx, le_user);
+GEN_SPE_LDSPLAT(hhossplat, spe_lhx, le_kernel);
+GEN_SPE_LDSPLAT(hhossplat, spe_lhx, le_hypv);
 #if defined(TARGET_PPC64)
-GEN_OP_SPE_LHE(64_kernel);
 GEN_OP_SPE_LHE(64_user);
-GEN_SPE_LDSPLAT(hhesplat, spe_lhe, 64_kernel);
+GEN_OP_SPE_LHE(64_kernel);
+GEN_OP_SPE_LHE(64_hypv);
 GEN_SPE_LDSPLAT(hhesplat, spe_lhe, 64_user);
-GEN_OP_SPE_LHE(le_64_kernel);
+GEN_SPE_LDSPLAT(hhesplat, spe_lhe, 64_kernel);
+GEN_SPE_LDSPLAT(hhesplat, spe_lhe, 64_hypv);
 GEN_OP_SPE_LHE(le_64_user);
-GEN_SPE_LDSPLAT(hhesplat, spe_lhe, le_64_kernel);
+GEN_OP_SPE_LHE(le_64_kernel);
+GEN_OP_SPE_LHE(le_64_hypv);
 GEN_SPE_LDSPLAT(hhesplat, spe_lhe, le_64_user);
-GEN_SPE_LDSPLAT(hhousplat, spe_lh, 64_kernel);
+GEN_SPE_LDSPLAT(hhesplat, spe_lhe, le_64_kernel);
+GEN_SPE_LDSPLAT(hhesplat, spe_lhe, le_64_hypv);
 GEN_SPE_LDSPLAT(hhousplat, spe_lh, 64_user);
-GEN_SPE_LDSPLAT(hhousplat, spe_lh, le_64_kernel);
+GEN_SPE_LDSPLAT(hhousplat, spe_lh, 64_kernel);
+GEN_SPE_LDSPLAT(hhousplat, spe_lh, 64_hypv);
 GEN_SPE_LDSPLAT(hhousplat, spe_lh, le_64_user);
-GEN_OP_SPE_LHX(64_kernel);
+GEN_SPE_LDSPLAT(hhousplat, spe_lh, le_64_kernel);
+GEN_SPE_LDSPLAT(hhousplat, spe_lh, le_64_hypv);
 GEN_OP_SPE_LHX(64_user);
-GEN_SPE_LDSPLAT(hhossplat, spe_lhx, 64_kernel);
+GEN_OP_SPE_LHX(64_kernel);
+GEN_OP_SPE_LHX(64_hypv);
 GEN_SPE_LDSPLAT(hhossplat, spe_lhx, 64_user);
-GEN_OP_SPE_LHX(le_64_kernel);
+GEN_SPE_LDSPLAT(hhossplat, spe_lhx, 64_kernel);
+GEN_SPE_LDSPLAT(hhossplat, spe_lhx, 64_hypv);
 GEN_OP_SPE_LHX(le_64_user);
-GEN_SPE_LDSPLAT(hhossplat, spe_lhx, le_64_kernel);
+GEN_OP_SPE_LHX(le_64_kernel);
+GEN_OP_SPE_LHX(le_64_hypv);
 GEN_SPE_LDSPLAT(hhossplat, spe_lhx, le_64_user);
+GEN_SPE_LDSPLAT(hhossplat, spe_lhx, le_64_kernel);
+GEN_SPE_LDSPLAT(hhossplat, spe_lhx, le_64_hypv);
 #endif
 #endif
 GEN_SPEOP_LD(hhesplat, 1);
@@ -6467,7 +5973,7 @@ GEN_SPEOP_COMP(efststlt);
 GEN_SPEOP_COMP(efststeq);
 
 /* Opcodes definitions */
-GEN_SPE(efsadd,         efssub,        0x00, 0x0A, 0x00000000, PPC_SPEFPU); //
+GEN_SPE(efsadd,         efssub,        0x00, 0x0B, 0x00000000, PPC_SPEFPU); //
 GEN_SPE(efsabs,         efsnabs,       0x02, 0x0B, 0x0000F800, PPC_SPEFPU); //
 GEN_SPE(efsneg,         speundef,      0x03, 0x0B, 0x0000F800, PPC_SPEFPU); //
 GEN_SPE(efsmul,         efsdiv,        0x04, 0x0B, 0x00000000, PPC_SPEFPU); //
@@ -6532,7 +6038,6 @@ GEN_SPE(efdctuiz,       speundef,      0x1C, 0x0B, 0x00180000, PPC_SPEFPU); //
 GEN_SPE(efdctsiz,       speundef,      0x1D, 0x0B, 0x00180000, PPC_SPEFPU); //
 GEN_SPE(efdtstgt,       efdtstlt,      0x1E, 0x0B, 0x00600000, PPC_SPEFPU); //
 GEN_SPE(efdtsteq,       speundef,      0x1F, 0x0B, 0x00600000, PPC_SPEFPU); //
-#endif
 
 /* End opcode list */
 GEN_OPCODE_MARK(end);
@@ -6546,40 +6051,31 @@ void cpu_dump_state (CPUState *env, FILE *f,
                      int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
                      int flags)
 {
-#if defined(TARGET_PPC64) || 1
-#define FILL ""
 #define RGPL  4
 #define RFPL  4
-#else
-#define FILL "        "
-#define RGPL  8
-#define RFPL  4
-#endif
 
     int i;
 
-    cpu_fprintf(f, "NIP " ADDRX " LR " ADDRX " CTR " ADDRX " idx %d\n",
-                env->nip, env->lr, env->ctr, env->mmu_idx);
-    cpu_fprintf(f, "MSR " REGX FILL " XER %08x      "
+    cpu_fprintf(f, "NIP " ADDRX "   LR " ADDRX " CTR " ADDRX " XER %08x\n",
+                env->nip, env->lr, env->ctr, hreg_load_xer(env));
+    cpu_fprintf(f, "MSR " ADDRX " HID0 " ADDRX "  HF " ADDRX " idx %d\n",
+                env->msr, env->spr[SPR_HID0], env->hflags, env->mmu_idx);
 #if !defined(NO_TIMER_DUMP)
-                "TB %08x %08x "
+    cpu_fprintf(f, "TB %08x %08x "
 #if !defined(CONFIG_USER_ONLY)
                 "DECR %08x"
-#endif
 #endif
                 "\n",
-                env->msr, hreg_load_xer(env)
-#if !defined(NO_TIMER_DUMP)
-                , cpu_ppc_load_tbu(env), cpu_ppc_load_tbl(env)
+                cpu_ppc_load_tbu(env), cpu_ppc_load_tbl(env)
 #if !defined(CONFIG_USER_ONLY)
                 , cpu_ppc_load_decr(env)
-#endif
 #endif
                 );
+#endif
     for (i = 0; i < 32; i++) {
         if ((i & (RGPL - 1)) == 0)
             cpu_fprintf(f, "GPR%02d", i);
-        cpu_fprintf(f, " " REGX, (target_ulong)env->gpr[i]);
+        cpu_fprintf(f, " " REGX, ppc_dump_gpr(env, i));
         if ((i & (RGPL - 1)) == (RGPL - 1))
             cpu_fprintf(f, "\n");
     }
@@ -6597,7 +6093,7 @@ void cpu_dump_state (CPUState *env, FILE *f,
             a = 'E';
         cpu_fprintf(f, " %c%c", a, env->crf[i] & 0x01 ? 'O' : ' ');
     }
-    cpu_fprintf(f, " ]             " FILL "RES " REGX "\n", env->reserve);
+    cpu_fprintf(f, " ]             RES " ADDRX "\n", env->reserve);
     for (i = 0; i < 32; i++) {
         if ((i & (RFPL - 1)) == 0)
             cpu_fprintf(f, "FPR%02d", i);
@@ -6606,14 +6102,12 @@ void cpu_dump_state (CPUState *env, FILE *f,
             cpu_fprintf(f, "\n");
     }
 #if !defined(CONFIG_USER_ONLY)
-    cpu_fprintf(f, "SRR0 " REGX " SRR1 " REGX "         " FILL FILL FILL
-                "SDR1 " REGX "\n",
+    cpu_fprintf(f, "SRR0 " ADDRX " SRR1 " ADDRX " SDR1 " ADDRX "\n",
                 env->spr[SPR_SRR0], env->spr[SPR_SRR1], env->sdr1);
 #endif
 
 #undef RGPL
 #undef RFPL
-#undef FILL
 }
 
 void cpu_dump_statistics (CPUState *env, FILE*f,
@@ -6672,15 +6166,14 @@ static always_inline int gen_intermediate_code_internal (CPUState *env,
     opc_handler_t **table, *handler;
     target_ulong pc_start;
     uint16_t *gen_opc_end;
-    int supervisor;
-    int single_step, branch_step;
+    int supervisor, little_endian;
     int j, lj = -1;
 
     pc_start = tb->pc;
-    gen_opc_ptr = gen_opc_buf;
     gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
-    gen_opparam_ptr = gen_opparam_buf;
-    nb_gen_labels = 0;
+#if defined(OPTIMIZE_FPRF_UPDATE)
+    gen_fprf_ptr = gen_fprf_buf;
+#endif
     ctx.nip = pc_start;
     ctx.tb = tb;
     ctx.exception = POWERPC_EXCP_NONE;
@@ -6689,33 +6182,31 @@ static always_inline int gen_intermediate_code_internal (CPUState *env,
 #if !defined(CONFIG_USER_ONLY)
     ctx.supervisor = supervisor;
 #endif
+    little_endian = env->hflags & (1 << MSR_LE) ? 1 : 0;
 #if defined(TARGET_PPC64)
     ctx.sf_mode = msr_sf;
-    ctx.mem_idx = (supervisor << 2) | (msr_sf << 1) | msr_le;
+    ctx.mem_idx = (supervisor << 2) | (msr_sf << 1) | little_endian;
 #else
-    ctx.mem_idx = (supervisor << 1) | msr_le;
+    ctx.mem_idx = (supervisor << 1) | little_endian;
 #endif
     ctx.dcache_line_size = env->dcache_line_size;
     ctx.fpu_enabled = msr_fp;
-#if defined(TARGET_PPCEMB)
     if ((env->flags & POWERPC_FLAG_SPE) && msr_spe)
         ctx.spe_enabled = msr_spe;
     else
         ctx.spe_enabled = 0;
-#endif
     if ((env->flags & POWERPC_FLAG_VRE) && msr_vr)
         ctx.altivec_enabled = msr_vr;
     else
         ctx.altivec_enabled = 0;
     if ((env->flags & POWERPC_FLAG_SE) && msr_se)
-        single_step = 1;
+        ctx.singlestep_enabled = CPU_SINGLE_STEP;
     else
-        single_step = 0;
+        ctx.singlestep_enabled = 0;
     if ((env->flags & POWERPC_FLAG_BE) && msr_be)
-        branch_step = 1;
-    else
-        branch_step = 0;
-    ctx.singlestep_enabled = env->singlestep_enabled || single_step == 1;
+        ctx.singlestep_enabled |= CPU_BRANCH_STEP;
+    if (unlikely(env->singlestep_enabled))
+        ctx.singlestep_enabled |= GDBSTUB_SINGLE_STEP;
 #if defined (DO_SINGLE_STEP) && 0
     /* Single step trace mode */
     msr_se = 1;
@@ -6748,18 +6239,16 @@ static always_inline int gen_intermediate_code_internal (CPUState *env,
                     ctx.nip, supervisor, (int)msr_ir);
         }
 #endif
-        ctx.opcode = ldl_code(ctx.nip);
-        if (msr_le) {
-            ctx.opcode = ((ctx.opcode & 0xFF000000) >> 24) |
-                ((ctx.opcode & 0x00FF0000) >> 8) |
-                ((ctx.opcode & 0x0000FF00) << 8) |
-                ((ctx.opcode & 0x000000FF) << 24);
+        if (unlikely(little_endian)) {
+            ctx.opcode = bswap32(ldl_code(ctx.nip));
+        } else {
+            ctx.opcode = ldl_code(ctx.nip);
         }
 #if defined PPC_DEBUG_DISAS
         if (loglevel & CPU_LOG_TB_IN_ASM) {
             fprintf(logfile, "translate opcode %08x (%02x %02x %02x) (%s)\n",
                     ctx.opcode, opc1(ctx.opcode), opc2(ctx.opcode),
-                    opc3(ctx.opcode), msr_le ? "little" : "big");
+                    opc3(ctx.opcode), little_endian ? "little" : "big");
         }
 #endif
         ctx.nip += 4;
@@ -6777,12 +6266,12 @@ static always_inline int gen_intermediate_code_internal (CPUState *env,
         if (unlikely(handler->handler == &gen_invalid)) {
             if (loglevel != 0) {
                 fprintf(logfile, "invalid/unsupported opcode: "
-                        "%02x - %02x - %02x (%08x) 0x" ADDRX " %d\n",
+                        "%02x - %02x - %02x (%08x) " ADDRX " %d\n",
                         opc1(ctx.opcode), opc2(ctx.opcode),
                         opc3(ctx.opcode), ctx.opcode, ctx.nip - 4, (int)msr_ir);
             } else {
                 printf("invalid/unsupported opcode: "
-                       "%02x - %02x - %02x (%08x) 0x" ADDRX " %d\n",
+                       "%02x - %02x - %02x (%08x) " ADDRX " %d\n",
                        opc1(ctx.opcode), opc2(ctx.opcode),
                        opc3(ctx.opcode), ctx.opcode, ctx.nip - 4, (int)msr_ir);
             }
@@ -6790,13 +6279,13 @@ static always_inline int gen_intermediate_code_internal (CPUState *env,
             if (unlikely((ctx.opcode & handler->inval) != 0)) {
                 if (loglevel != 0) {
                     fprintf(logfile, "invalid bits: %08x for opcode: "
-                            "%02x - %02x - %02x (%08x) 0x" ADDRX "\n",
+                            "%02x - %02x - %02x (%08x) " ADDRX "\n",
                             ctx.opcode & handler->inval, opc1(ctx.opcode),
                             opc2(ctx.opcode), opc3(ctx.opcode),
                             ctx.opcode, ctx.nip - 4);
                 } else {
                     printf("invalid bits: %08x for opcode: "
-                           "%02x - %02x - %02x (%08x) 0x" ADDRX "\n",
+                           "%02x - %02x - %02x (%08x) " ADDRX "\n",
                            ctx.opcode & handler->inval, opc1(ctx.opcode),
                            opc2(ctx.opcode), opc3(ctx.opcode),
                            ctx.opcode, ctx.nip - 4);
@@ -6810,14 +6299,11 @@ static always_inline int gen_intermediate_code_internal (CPUState *env,
         handler->count++;
 #endif
         /* Check trace mode exceptions */
-        if (unlikely(branch_step != 0 &&
-                     ctx.exception == POWERPC_EXCP_BRANCH)) {
-            GEN_EXCP(ctxp, POWERPC_EXCP_TRACE, 0);
-        } else if (unlikely(single_step != 0 &&
-                            (ctx.nip <= 0x100 || ctx.nip > 0xF00 ||
-                             (ctx.nip & 0xFC) != 0x04) &&
-                            ctx.exception != POWERPC_SYSCALL &&
-                            ctx.exception != POWERPC_EXCP_TRAP)) {
+        if (unlikely(ctx.singlestep_enabled & CPU_SINGLE_STEP &&
+                     (ctx.nip <= 0x100 || ctx.nip > 0xF00) &&
+                     ctx.exception != POWERPC_SYSCALL &&
+                     ctx.exception != POWERPC_EXCP_TRAP &&
+                     ctx.exception != POWERPC_EXCP_BRANCH)) {
             GEN_EXCP(ctxp, POWERPC_EXCP_TRACE, 0);
         } else if (unlikely(((ctx.nip & (TARGET_PAGE_SIZE - 1)) == 0) ||
                             (env->singlestep_enabled))) {
@@ -6833,9 +6319,12 @@ static always_inline int gen_intermediate_code_internal (CPUState *env,
     if (ctx.exception == POWERPC_EXCP_NONE) {
         gen_goto_tb(&ctx, 0, ctx.nip);
     } else if (ctx.exception != POWERPC_EXCP_BRANCH) {
-        gen_op_reset_T0();
+        if (unlikely(env->singlestep_enabled)) {
+            gen_update_nip(&ctx, ctx.nip);
+            gen_op_debug();
+        }
         /* Generate the return instruction */
-        gen_op_exit_tb();
+        tcg_gen_exit_tb(0);
     }
     *gen_opc_ptr = INDEX_op_end;
     if (unlikely(search_pc)) {
@@ -6854,16 +6343,11 @@ static always_inline int gen_intermediate_code_internal (CPUState *env,
     if (loglevel & CPU_LOG_TB_IN_ASM) {
         int flags;
         flags = env->bfd_mach;
-        flags |= msr_le << 16;
+        flags |= little_endian << 16;
         fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start));
         target_disas(logfile, pc_start, ctx.nip - pc_start, flags);
         fprintf(logfile, "\n");
     }
-    if (loglevel & CPU_LOG_TB_OP) {
-        fprintf(logfile, "OP:\n");
-        dump_ops(gen_opc_buf, gen_opparam_buf);
-        fprintf(logfile, "\n");
-    }
 #endif
     return 0;
 }
@@ -6877,3 +6361,45 @@ int gen_intermediate_code_pc (CPUState *env, struct TranslationBlock *tb)
 {
     return gen_intermediate_code_internal(env, tb, 1);
 }
+
+void gen_pc_load(CPUState *env, TranslationBlock *tb,
+                unsigned long searched_pc, int pc_pos, void *puc)
+{
+    int type, c;
+    /* for PPC, we need to look at the micro operation to get the
+     * access type */
+    env->nip = gen_opc_pc[pc_pos];
+    c = gen_opc_buf[pc_pos];
+    switch(c) {
+#if defined(CONFIG_USER_ONLY)
+#define CASE3(op)\
+    case INDEX_op_ ## op ## _raw
+#else
+#define CASE3(op)\
+    case INDEX_op_ ## op ## _user:\
+    case INDEX_op_ ## op ## _kernel:\
+    case INDEX_op_ ## op ## _hypv
+#endif
+
+    CASE3(stfd):
+    CASE3(stfs):
+    CASE3(lfd):
+    CASE3(lfs):
+        type = ACCESS_FLOAT;
+        break;
+    CASE3(lwarx):
+        type = ACCESS_RES;
+        break;
+    CASE3(stwcx):
+        type = ACCESS_RES;
+        break;
+    CASE3(eciwx):
+    CASE3(ecowx):
+        type = ACCESS_EXT;
+        break;
+    default:
+        type = ACCESS_INT;
+        break;
+    }
+    env->access_type = type;
+}