All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH 01/32] ppc: Fix fault PC reporting for lve*/stve* VMX instructions
@ 2016-07-26 22:20 Benjamin Herrenschmidt
  2016-07-26 22:20 ` [Qemu-devel] [PATCH 02/32] ppc: Provide basic raise_exception_* functions Benjamin Herrenschmidt
                   ` (31 more replies)
  0 siblings, 32 replies; 69+ messages in thread
From: Benjamin Herrenschmidt @ 2016-07-26 22:20 UTC (permalink / raw)
  To: qemu-ppc; +Cc: qemu-devel, david, Benjamin Herrenschmidt

We forgot to do gen_update_nip() for these like we do with other
helpers. Fix this, but in a more efficient way by passing the RA
to the accessors instead so the overhead is only taken on faults.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
 target-ppc/mem_helper.c | 21 +++++++++++----------
 1 file changed, 11 insertions(+), 10 deletions(-)

diff --git a/target-ppc/mem_helper.c b/target-ppc/mem_helper.c
index e4de86b..e4ed377 100644
--- a/target-ppc/mem_helper.c
+++ b/target-ppc/mem_helper.c
@@ -232,16 +232,16 @@ target_ulong helper_lscbx(CPUPPCState *env, target_ulong addr, uint32_t reg,
                                                                 \
         if (needs_byteswap(env)) {                              \
             r->element[LO_IDX ? index : (adjust - index)] =     \
-                swap(access(env, addr));                        \
+                swap(access(env, addr, GETPC()));               \
         } else {                                                \
             r->element[LO_IDX ? index : (adjust - index)] =     \
-                access(env, addr);                              \
+                access(env, addr, GETPC());                     \
         }                                                       \
     }
 #define I(x) (x)
-LVE(lvebx, cpu_ldub_data, I, u8)
-LVE(lvehx, cpu_lduw_data, bswap16, u16)
-LVE(lvewx, cpu_ldl_data, bswap32, u32)
+LVE(lvebx, cpu_ldub_data_ra, I, u8)
+LVE(lvehx, cpu_lduw_data_ra, bswap16, u16)
+LVE(lvewx, cpu_ldl_data_ra, bswap32, u32)
 #undef I
 #undef LVE
 
@@ -259,16 +259,17 @@ LVE(lvewx, cpu_ldl_data, bswap32, u32)
                                                                         \
         if (needs_byteswap(env)) {                                      \
             access(env, addr, swap(r->element[LO_IDX ? index :          \
-                                              (adjust - index)]));      \
+                                              (adjust - index)]),       \
+                        GETPC());                                       \
         } else {                                                        \
             access(env, addr, r->element[LO_IDX ? index :               \
-                                         (adjust - index)]);            \
+                                         (adjust - index)], GETPC());   \
         }                                                               \
     }
 #define I(x) (x)
-STVE(stvebx, cpu_stb_data, I, u8)
-STVE(stvehx, cpu_stw_data, bswap16, u16)
-STVE(stvewx, cpu_stl_data, bswap32, u32)
+STVE(stvebx, cpu_stb_data_ra, I, u8)
+STVE(stvehx, cpu_stw_data_ra, bswap16, u16)
+STVE(stvewx, cpu_stl_data_ra, bswap32, u32)
 #undef I
 #undef LVE
 
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [Qemu-devel] [PATCH 02/32] ppc: Provide basic raise_exception_* functions
  2016-07-26 22:20 [Qemu-devel] [PATCH 01/32] ppc: Fix fault PC reporting for lve*/stve* VMX instructions Benjamin Herrenschmidt
@ 2016-07-26 22:20 ` Benjamin Herrenschmidt
  2016-07-27  1:50   ` David Gibson
  2016-07-26 22:20 ` [Qemu-devel] [PATCH 03/32] ppc: Move classic fp ops out of translate.c Benjamin Herrenschmidt
                   ` (30 subsequent siblings)
  31 siblings, 1 reply; 69+ messages in thread
From: Benjamin Herrenschmidt @ 2016-07-26 22:20 UTC (permalink / raw)
  To: qemu-ppc; +Cc: qemu-devel, david, Benjamin Herrenschmidt

Instead of using the same helpers called from translate.c, let's have
a bunch of functions that take the various argument combinations,
especially the retaddr which will be needed in subsequent patches,
and leave the helpers to be just that, helpers for translate.c

We don't yet convert all users, we'll go through them in subsequent
patches.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
 target-ppc/cpu.h         |  8 ++++++++
 target-ppc/excp_helper.c | 51 ++++++++++++++++++++++++++++++++----------------
 2 files changed, 42 insertions(+), 17 deletions(-)

diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index 5fce1ff..2ee7a5e 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -2295,6 +2295,14 @@ static inline void cpu_get_tb_cpu_state(CPUPPCState *env, target_ulong *pc,
     *flags = env->hflags;
 }
 
+void QEMU_NORETURN raise_exception(CPUPPCState *env, uint32_t exception);
+void QEMU_NORETURN raise_exception_ra(CPUPPCState *env, uint32_t exception,
+                                      uintptr_t raddr);
+void QEMU_NORETURN raise_exception_err(CPUPPCState *env, uint32_t exception,
+                                       uint32_t error_code);
+void QEMU_NORETURN raise_exception_err_ra(CPUPPCState *env, uint32_t exception,
+                                          uint32_t error_code, uintptr_t raddr);
+
 #if !defined(CONFIG_USER_ONLY)
 static inline int booke206_tlbm_id(CPUPPCState *env, ppcmas_tlb_t *tlbm)
 {
diff --git a/target-ppc/excp_helper.c b/target-ppc/excp_helper.c
index d6e1678..f4b115e 100644
--- a/target-ppc/excp_helper.c
+++ b/target-ppc/excp_helper.c
@@ -898,34 +898,53 @@ static void cpu_dump_rfi(target_ulong RA, target_ulong msr)
 /*****************************************************************************/
 /* Exceptions processing helpers */
 
-void helper_raise_exception_err(CPUPPCState *env, uint32_t exception,
-                                uint32_t error_code)
+void raise_exception_err_ra(CPUPPCState *env, uint32_t exception,
+                            uint32_t error_code, uintptr_t raddr)
 {
     CPUState *cs = CPU(ppc_env_get_cpu(env));
 
-#if 0
-    printf("Raise exception %3x code : %d\n", exception, error_code);
-#endif
     cs->exception_index = exception;
     env->error_code = error_code;
-    cpu_loop_exit(cs);
+    cpu_loop_exit_restore(cs, raddr);
+}
+
+void raise_exception_err(CPUPPCState *env, uint32_t exception,
+                         uint32_t error_code)
+{
+    raise_exception_err_ra(env, exception, error_code, 0);
+}
+
+void raise_exception(CPUPPCState *env, uint32_t exception)
+{
+    raise_exception_err_ra(env, exception, 0, 0);
+}
+
+void raise_exception_ra(CPUPPCState *env, uint32_t exception,
+                        uintptr_t raddr)
+{
+    raise_exception_err_ra(env, exception, 0, 0);
+}
+
+void helper_raise_exception_err(CPUPPCState *env, uint32_t exception,
+                                uint32_t error_code)
+{
+    raise_exception_err_ra(env, exception, error_code, 0);
 }
 
 void helper_raise_exception(CPUPPCState *env, uint32_t exception)
 {
-    helper_raise_exception_err(env, exception, 0);
+    raise_exception_err_ra(env, exception, 0, 0);
 }
 
 #if !defined(CONFIG_USER_ONLY)
 void helper_store_msr(CPUPPCState *env, target_ulong val)
 {
-    CPUState *cs;
+    uint32_t excp = hreg_store_msr(env, val, 0);
 
-    val = hreg_store_msr(env, val, 0);
-    if (val != 0) {
-        cs = CPU(ppc_env_get_cpu(env));
+    if (excp != 0) {
+        CPUState *cs = CPU(ppc_env_get_cpu(env));
         cs->interrupt_request |= CPU_INTERRUPT_EXITTB;
-        helper_raise_exception(env, val);
+        raise_exception(env, excp);
     }
 }
 
@@ -951,7 +970,7 @@ void helper_pminsn(CPUPPCState *env, powerpc_pm_insn_t insn)
      * but this doesn't seem to be a problem.
      */
     env->msr |= (1ull << MSR_EE);
-    helper_raise_exception(env, EXCP_HLT);
+    raise_exception(env, EXCP_HLT);
 }
 #endif /* defined(TARGET_PPC64) */
 
@@ -1041,8 +1060,7 @@ void helper_tw(CPUPPCState *env, target_ulong arg1, target_ulong arg2,
                   ((int32_t)arg1 == (int32_t)arg2 && (flags & 0x04)) ||
                   ((uint32_t)arg1 < (uint32_t)arg2 && (flags & 0x02)) ||
                   ((uint32_t)arg1 > (uint32_t)arg2 && (flags & 0x01))))) {
-        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
-                                   POWERPC_EXCP_TRAP);
+        raise_exception_err(env, POWERPC_EXCP_PROGRAM, POWERPC_EXCP_TRAP);
     }
 }
 
@@ -1055,8 +1073,7 @@ void helper_td(CPUPPCState *env, target_ulong arg1, target_ulong arg2,
                   ((int64_t)arg1 == (int64_t)arg2 && (flags & 0x04)) ||
                   ((uint64_t)arg1 < (uint64_t)arg2 && (flags & 0x02)) ||
                   ((uint64_t)arg1 > (uint64_t)arg2 && (flags & 0x01))))) {
-        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
-                                   POWERPC_EXCP_TRAP);
+        raise_exception_err(env, POWERPC_EXCP_PROGRAM, POWERPC_EXCP_TRAP);
     }
 }
 #endif
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [Qemu-devel] [PATCH 03/32] ppc: Move classic fp ops out of translate.c
  2016-07-26 22:20 [Qemu-devel] [PATCH 01/32] ppc: Fix fault PC reporting for lve*/stve* VMX instructions Benjamin Herrenschmidt
  2016-07-26 22:20 ` [Qemu-devel] [PATCH 02/32] ppc: Provide basic raise_exception_* functions Benjamin Herrenschmidt
@ 2016-07-26 22:20 ` Benjamin Herrenschmidt
  2016-07-28 16:02   ` Richard Henderson
  2016-07-26 22:20 ` [Qemu-devel] [PATCH 04/32] ppc: Move embedded spe " Benjamin Herrenschmidt
                   ` (29 subsequent siblings)
  31 siblings, 1 reply; 69+ messages in thread
From: Benjamin Herrenschmidt @ 2016-07-26 22:20 UTC (permalink / raw)
  To: qemu-ppc; +Cc: qemu-devel, david, Benjamin Herrenschmidt

Makes things a bit more manageable

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
 target-ppc/translate.c         | 1205 +---------------------------------------
 target-ppc/translate/fp-impl.c | 1098 ++++++++++++++++++++++++++++++++++++
 target-ppc/translate/fp-ops.c  |  111 ++++
 3 files changed, 1213 insertions(+), 1201 deletions(-)
 create mode 100644 target-ppc/translate/fp-impl.c
 create mode 100644 target-ppc/translate/fp-ops.c

diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index 92030b6..e42f576 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -250,17 +250,6 @@ struct opc_handler_t {
 #endif
 };
 
-static inline void gen_reset_fpstatus(void)
-{
-    gen_helper_reset_fpstatus(cpu_env);
-}
-
-static inline void gen_compute_fprf(TCGv_i64 arg)
-{
-    gen_helper_compute_fprf(cpu_env, arg);
-    gen_helper_float_check_status(cpu_env);
-}
-
 static inline void gen_set_access_type(DisasContext *ctx, int access_type)
 {
     if (ctx->access_type != access_type) {
@@ -2126,602 +2115,6 @@ static void gen_srd(DisasContext *ctx)
 }
 #endif
 
-#if defined(TARGET_PPC64)
-static void gen_set_cr1_from_fpscr(DisasContext *ctx)
-{
-    TCGv_i32 tmp = tcg_temp_new_i32();
-    tcg_gen_trunc_tl_i32(tmp, cpu_fpscr);
-    tcg_gen_shri_i32(cpu_crf[1], tmp, 28);
-    tcg_temp_free_i32(tmp);
-}
-#else
-static void gen_set_cr1_from_fpscr(DisasContext *ctx)
-{
-    tcg_gen_shri_tl(cpu_crf[1], cpu_fpscr, 28);
-}
-#endif
-
-/***                       Floating-Point arithmetic                       ***/
-#define _GEN_FLOAT_ACB(name, op, op1, op2, isfloat, set_fprf, type)           \
-static void gen_f##name(DisasContext *ctx)                                    \
-{                                                                             \
-    if (unlikely(!ctx->fpu_enabled)) {                                        \
-        gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
-        return;                                                               \
-    }                                                                         \
-    /* NIP cannot be restored if the memory exception comes from an helper */ \
-    gen_update_nip(ctx, ctx->nip - 4);                                        \
-    gen_reset_fpstatus();                                                     \
-    gen_helper_f##op(cpu_fpr[rD(ctx->opcode)], cpu_env,                       \
-                     cpu_fpr[rA(ctx->opcode)],                                \
-                     cpu_fpr[rC(ctx->opcode)], cpu_fpr[rB(ctx->opcode)]);     \
-    if (isfloat) {                                                            \
-        gen_helper_frsp(cpu_fpr[rD(ctx->opcode)], cpu_env,                    \
-                        cpu_fpr[rD(ctx->opcode)]);                            \
-    }                                                                         \
-    if (set_fprf) {                                                           \
-        gen_compute_fprf(cpu_fpr[rD(ctx->opcode)]);                           \
-    }                                                                         \
-    if (unlikely(Rc(ctx->opcode) != 0)) {                                     \
-        gen_set_cr1_from_fpscr(ctx);                                          \
-    }                                                                         \
-}
-
-#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, set_fprf, type)     \
-static void gen_f##name(DisasContext *ctx)                                    \
-{                                                                             \
-    if (unlikely(!ctx->fpu_enabled)) {                                        \
-        gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
-        return;                                                               \
-    }                                                                         \
-    /* NIP cannot be restored if the memory exception comes from an helper */ \
-    gen_update_nip(ctx, ctx->nip - 4);                                        \
-    gen_reset_fpstatus();                                                     \
-    gen_helper_f##op(cpu_fpr[rD(ctx->opcode)], cpu_env,                       \
-                     cpu_fpr[rA(ctx->opcode)],                                \
-                     cpu_fpr[rB(ctx->opcode)]);                               \
-    if (isfloat) {                                                            \
-        gen_helper_frsp(cpu_fpr[rD(ctx->opcode)], cpu_env,                    \
-                        cpu_fpr[rD(ctx->opcode)]);                            \
-    }                                                                         \
-    if (set_fprf) {                                                           \
-        gen_compute_fprf(cpu_fpr[rD(ctx->opcode)]);                           \
-    }                                                                         \
-    if (unlikely(Rc(ctx->opcode) != 0)) {                                     \
-        gen_set_cr1_from_fpscr(ctx);                                          \
-    }                                                                         \
-}
-#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, set_fprf, type)     \
-static void gen_f##name(DisasContext *ctx)                                    \
-{                                                                             \
-    if (unlikely(!ctx->fpu_enabled)) {                                        \
-        gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
-        return;                                                               \
-    }                                                                         \
-    /* NIP cannot be restored if the memory exception comes from an helper */ \
-    gen_update_nip(ctx, ctx->nip - 4);                                        \
-    gen_reset_fpstatus();                                                     \
-    gen_helper_f##op(cpu_fpr[rD(ctx->opcode)], cpu_env,                       \
-                     cpu_fpr[rA(ctx->opcode)],                                \
-                     cpu_fpr[rC(ctx->opcode)]);                               \
-    if (isfloat) {                                                            \
-        gen_helper_frsp(cpu_fpr[rD(ctx->opcode)], cpu_env,                    \
-                        cpu_fpr[rD(ctx->opcode)]);                            \
-    }                                                                         \
-    if (set_fprf) {                                                           \
-        gen_compute_fprf(cpu_fpr[rD(ctx->opcode)]);                           \
-    }                                                                         \
-    if (unlikely(Rc(ctx->opcode) != 0)) {                                     \
-        gen_set_cr1_from_fpscr(ctx);                                          \
-    }                                                                         \
-}
-#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, set_fprf, type)                           \
-static void gen_f##name(DisasContext *ctx)                                    \
-{                                                                             \
-    if (unlikely(!ctx->fpu_enabled)) {                                        \
-        gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
-        return;                                                               \
-    }                                                                         \
-    /* NIP cannot be restored if the memory exception comes from an helper */ \
-    gen_update_nip(ctx, ctx->nip - 4);                                        \
-    gen_reset_fpstatus();                                                     \
-    gen_helper_f##name(cpu_fpr[rD(ctx->opcode)], cpu_env,                     \
-                       cpu_fpr[rB(ctx->opcode)]);                             \
-    if (set_fprf) {                                                           \
-        gen_compute_fprf(cpu_fpr[rD(ctx->opcode)]);                           \
-    }                                                                         \
-    if (unlikely(Rc(ctx->opcode) != 0)) {                                     \
-        gen_set_cr1_from_fpscr(ctx);                                          \
-    }                                                                         \
-}
-
-#define GEN_FLOAT_BS(name, op1, op2, set_fprf, type)                          \
-static void gen_f##name(DisasContext *ctx)                                    \
-{                                                                             \
-    if (unlikely(!ctx->fpu_enabled)) {                                        \
-        gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
-        return;                                                               \
-    }                                                                         \
-    /* NIP cannot be restored if the memory exception comes from an helper */ \
-    gen_update_nip(ctx, ctx->nip - 4);                                        \
-    gen_reset_fpstatus();                                                     \
-    gen_helper_f##name(cpu_fpr[rD(ctx->opcode)], cpu_env,                     \
-                       cpu_fpr[rB(ctx->opcode)]);                             \
-    if (set_fprf) {                                                           \
-        gen_compute_fprf(cpu_fpr[rD(ctx->opcode)]);                           \
-    }                                                                         \
-    if (unlikely(Rc(ctx->opcode) != 0)) {                                     \
-        gen_set_cr1_from_fpscr(ctx);                                          \
-    }                                                                         \
-}
-
-/* fadd - fadds */
-GEN_FLOAT_AB(add, 0x15, 0x000007C0, 1, PPC_FLOAT);
-/* fdiv - fdivs */
-GEN_FLOAT_AB(div, 0x12, 0x000007C0, 1, PPC_FLOAT);
-/* fmul - fmuls */
-GEN_FLOAT_AC(mul, 0x19, 0x0000F800, 1, PPC_FLOAT);
-
-/* fre */
-GEN_FLOAT_BS(re, 0x3F, 0x18, 1, PPC_FLOAT_EXT);
-
-/* fres */
-GEN_FLOAT_BS(res, 0x3B, 0x18, 1, PPC_FLOAT_FRES);
-
-/* frsqrte */
-GEN_FLOAT_BS(rsqrte, 0x3F, 0x1A, 1, PPC_FLOAT_FRSQRTE);
-
-/* frsqrtes */
-static void gen_frsqrtes(DisasContext *ctx)
-{
-    if (unlikely(!ctx->fpu_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_FPU);
-        return;
-    }
-    /* NIP cannot be restored if the memory exception comes from an helper */
-    gen_update_nip(ctx, ctx->nip - 4);
-    gen_reset_fpstatus();
-    gen_helper_frsqrte(cpu_fpr[rD(ctx->opcode)], cpu_env,
-                       cpu_fpr[rB(ctx->opcode)]);
-    gen_helper_frsp(cpu_fpr[rD(ctx->opcode)], cpu_env,
-                    cpu_fpr[rD(ctx->opcode)]);
-    gen_compute_fprf(cpu_fpr[rD(ctx->opcode)]);
-    if (unlikely(Rc(ctx->opcode) != 0)) {
-        gen_set_cr1_from_fpscr(ctx);
-    }
-}
-
-/* fsel */
-_GEN_FLOAT_ACB(sel, sel, 0x3F, 0x17, 0, 0, PPC_FLOAT_FSEL);
-/* fsub - fsubs */
-GEN_FLOAT_AB(sub, 0x14, 0x000007C0, 1, PPC_FLOAT);
-/* Optional: */
-
-/* fsqrt */
-static void gen_fsqrt(DisasContext *ctx)
-{
-    if (unlikely(!ctx->fpu_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_FPU);
-        return;
-    }
-    /* NIP cannot be restored if the memory exception comes from an helper */
-    gen_update_nip(ctx, ctx->nip - 4);
-    gen_reset_fpstatus();
-    gen_helper_fsqrt(cpu_fpr[rD(ctx->opcode)], cpu_env,
-                     cpu_fpr[rB(ctx->opcode)]);
-    gen_compute_fprf(cpu_fpr[rD(ctx->opcode)]);
-    if (unlikely(Rc(ctx->opcode) != 0)) {
-        gen_set_cr1_from_fpscr(ctx);
-    }
-}
-
-static void gen_fsqrts(DisasContext *ctx)
-{
-    if (unlikely(!ctx->fpu_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_FPU);
-        return;
-    }
-    /* NIP cannot be restored if the memory exception comes from an helper */
-    gen_update_nip(ctx, ctx->nip - 4);
-    gen_reset_fpstatus();
-    gen_helper_fsqrt(cpu_fpr[rD(ctx->opcode)], cpu_env,
-                     cpu_fpr[rB(ctx->opcode)]);
-    gen_helper_frsp(cpu_fpr[rD(ctx->opcode)], cpu_env,
-                    cpu_fpr[rD(ctx->opcode)]);
-    gen_compute_fprf(cpu_fpr[rD(ctx->opcode)]);
-    if (unlikely(Rc(ctx->opcode) != 0)) {
-        gen_set_cr1_from_fpscr(ctx);
-    }
-}
-
-/***                     Floating-Point multiply-and-add                   ***/
-/* fmadd - fmadds */
-GEN_FLOAT_ACB(madd, 0x1D, 1, PPC_FLOAT);
-/* fmsub - fmsubs */
-GEN_FLOAT_ACB(msub, 0x1C, 1, PPC_FLOAT);
-/* fnmadd - fnmadds */
-GEN_FLOAT_ACB(nmadd, 0x1F, 1, PPC_FLOAT);
-/* fnmsub - fnmsubs */
-GEN_FLOAT_ACB(nmsub, 0x1E, 1, PPC_FLOAT);
-
-/***                     Floating-Point round & convert                    ***/
-/* fctiw */
-GEN_FLOAT_B(ctiw, 0x0E, 0x00, 0, PPC_FLOAT);
-/* fctiwu */
-GEN_FLOAT_B(ctiwu, 0x0E, 0x04, 0, PPC2_FP_CVT_ISA206);
-/* fctiwz */
-GEN_FLOAT_B(ctiwz, 0x0F, 0x00, 0, PPC_FLOAT);
-/* fctiwuz */
-GEN_FLOAT_B(ctiwuz, 0x0F, 0x04, 0, PPC2_FP_CVT_ISA206);
-/* frsp */
-GEN_FLOAT_B(rsp, 0x0C, 0x00, 1, PPC_FLOAT);
-/* fcfid */
-GEN_FLOAT_B(cfid, 0x0E, 0x1A, 1, PPC2_FP_CVT_S64);
-/* fcfids */
-GEN_FLOAT_B(cfids, 0x0E, 0x1A, 0, PPC2_FP_CVT_ISA206);
-/* fcfidu */
-GEN_FLOAT_B(cfidu, 0x0E, 0x1E, 0, PPC2_FP_CVT_ISA206);
-/* fcfidus */
-GEN_FLOAT_B(cfidus, 0x0E, 0x1E, 0, PPC2_FP_CVT_ISA206);
-/* fctid */
-GEN_FLOAT_B(ctid, 0x0E, 0x19, 0, PPC2_FP_CVT_S64);
-/* fctidu */
-GEN_FLOAT_B(ctidu, 0x0E, 0x1D, 0, PPC2_FP_CVT_ISA206);
-/* fctidz */
-GEN_FLOAT_B(ctidz, 0x0F, 0x19, 0, PPC2_FP_CVT_S64);
-/* fctidu */
-GEN_FLOAT_B(ctiduz, 0x0F, 0x1D, 0, PPC2_FP_CVT_ISA206);
-
-/* frin */
-GEN_FLOAT_B(rin, 0x08, 0x0C, 1, PPC_FLOAT_EXT);
-/* friz */
-GEN_FLOAT_B(riz, 0x08, 0x0D, 1, PPC_FLOAT_EXT);
-/* frip */
-GEN_FLOAT_B(rip, 0x08, 0x0E, 1, PPC_FLOAT_EXT);
-/* frim */
-GEN_FLOAT_B(rim, 0x08, 0x0F, 1, PPC_FLOAT_EXT);
-
-static void gen_ftdiv(DisasContext *ctx)
-{
-    if (unlikely(!ctx->fpu_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_FPU);
-        return;
-    }
-    gen_helper_ftdiv(cpu_crf[crfD(ctx->opcode)], cpu_fpr[rA(ctx->opcode)],
-                     cpu_fpr[rB(ctx->opcode)]);
-}
-
-static void gen_ftsqrt(DisasContext *ctx)
-{
-    if (unlikely(!ctx->fpu_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_FPU);
-        return;
-    }
-    gen_helper_ftsqrt(cpu_crf[crfD(ctx->opcode)], cpu_fpr[rB(ctx->opcode)]);
-}
-
-
-
-/***                         Floating-Point compare                        ***/
-
-/* fcmpo */
-static void gen_fcmpo(DisasContext *ctx)
-{
-    TCGv_i32 crf;
-    if (unlikely(!ctx->fpu_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_FPU);
-        return;
-    }
-    /* NIP cannot be restored if the memory exception comes from an helper */
-    gen_update_nip(ctx, ctx->nip - 4);
-    gen_reset_fpstatus();
-    crf = tcg_const_i32(crfD(ctx->opcode));
-    gen_helper_fcmpo(cpu_env, cpu_fpr[rA(ctx->opcode)],
-                     cpu_fpr[rB(ctx->opcode)], crf);
-    tcg_temp_free_i32(crf);
-    gen_helper_float_check_status(cpu_env);
-}
-
-/* fcmpu */
-static void gen_fcmpu(DisasContext *ctx)
-{
-    TCGv_i32 crf;
-    if (unlikely(!ctx->fpu_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_FPU);
-        return;
-    }
-    /* NIP cannot be restored if the memory exception comes from an helper */
-    gen_update_nip(ctx, ctx->nip - 4);
-    gen_reset_fpstatus();
-    crf = tcg_const_i32(crfD(ctx->opcode));
-    gen_helper_fcmpu(cpu_env, cpu_fpr[rA(ctx->opcode)],
-                     cpu_fpr[rB(ctx->opcode)], crf);
-    tcg_temp_free_i32(crf);
-    gen_helper_float_check_status(cpu_env);
-}
-
-/***                         Floating-point move                           ***/
-/* fabs */
-/* XXX: beware that fabs never checks for NaNs nor update FPSCR */
-static void gen_fabs(DisasContext *ctx)
-{
-    if (unlikely(!ctx->fpu_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_FPU);
-        return;
-    }
-    tcg_gen_andi_i64(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rB(ctx->opcode)],
-                     ~(1ULL << 63));
-    if (unlikely(Rc(ctx->opcode))) {
-        gen_set_cr1_from_fpscr(ctx);
-    }
-}
-
-/* fmr  - fmr. */
-/* XXX: beware that fmr never checks for NaNs nor update FPSCR */
-static void gen_fmr(DisasContext *ctx)
-{
-    if (unlikely(!ctx->fpu_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_FPU);
-        return;
-    }
-    tcg_gen_mov_i64(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rB(ctx->opcode)]);
-    if (unlikely(Rc(ctx->opcode))) {
-        gen_set_cr1_from_fpscr(ctx);
-    }
-}
-
-/* fnabs */
-/* XXX: beware that fnabs never checks for NaNs nor update FPSCR */
-static void gen_fnabs(DisasContext *ctx)
-{
-    if (unlikely(!ctx->fpu_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_FPU);
-        return;
-    }
-    tcg_gen_ori_i64(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rB(ctx->opcode)],
-                    1ULL << 63);
-    if (unlikely(Rc(ctx->opcode))) {
-        gen_set_cr1_from_fpscr(ctx);
-    }
-}
-
-/* fneg */
-/* XXX: beware that fneg never checks for NaNs nor update FPSCR */
-static void gen_fneg(DisasContext *ctx)
-{
-    if (unlikely(!ctx->fpu_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_FPU);
-        return;
-    }
-    tcg_gen_xori_i64(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rB(ctx->opcode)],
-                     1ULL << 63);
-    if (unlikely(Rc(ctx->opcode))) {
-        gen_set_cr1_from_fpscr(ctx);
-    }
-}
-
-/* fcpsgn: PowerPC 2.05 specification */
-/* XXX: beware that fcpsgn never checks for NaNs nor update FPSCR */
-static void gen_fcpsgn(DisasContext *ctx)
-{
-    if (unlikely(!ctx->fpu_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_FPU);
-        return;
-    }
-    tcg_gen_deposit_i64(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rA(ctx->opcode)],
-                        cpu_fpr[rB(ctx->opcode)], 0, 63);
-    if (unlikely(Rc(ctx->opcode))) {
-        gen_set_cr1_from_fpscr(ctx);
-    }
-}
-
-static void gen_fmrgew(DisasContext *ctx)
-{
-    TCGv_i64 b0;
-    if (unlikely(!ctx->fpu_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_FPU);
-        return;
-    }
-    b0 = tcg_temp_new_i64();
-    tcg_gen_shri_i64(b0, cpu_fpr[rB(ctx->opcode)], 32);
-    tcg_gen_deposit_i64(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rA(ctx->opcode)],
-                        b0, 0, 32);
-    tcg_temp_free_i64(b0);
-}
-
-static void gen_fmrgow(DisasContext *ctx)
-{
-    if (unlikely(!ctx->fpu_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_FPU);
-        return;
-    }
-    tcg_gen_deposit_i64(cpu_fpr[rD(ctx->opcode)],
-                        cpu_fpr[rB(ctx->opcode)],
-                        cpu_fpr[rA(ctx->opcode)],
-                        32, 32);
-}
-
-/***                  Floating-Point status & ctrl register                ***/
-
-/* mcrfs */
-static void gen_mcrfs(DisasContext *ctx)
-{
-    TCGv tmp = tcg_temp_new();
-    TCGv_i32 tmask;
-    TCGv_i64 tnew_fpscr = tcg_temp_new_i64();
-    int bfa;
-    int nibble;
-    int shift;
-
-    if (unlikely(!ctx->fpu_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_FPU);
-        return;
-    }
-    bfa = crfS(ctx->opcode);
-    nibble = 7 - bfa;
-    shift = 4 * nibble;
-    tcg_gen_shri_tl(tmp, cpu_fpscr, shift);
-    tcg_gen_trunc_tl_i32(cpu_crf[crfD(ctx->opcode)], tmp);
-    tcg_gen_andi_i32(cpu_crf[crfD(ctx->opcode)], cpu_crf[crfD(ctx->opcode)], 0xf);
-    tcg_temp_free(tmp);
-    tcg_gen_extu_tl_i64(tnew_fpscr, cpu_fpscr);
-    /* Only the exception bits (including FX) should be cleared if read */
-    tcg_gen_andi_i64(tnew_fpscr, tnew_fpscr, ~((0xF << shift) & FP_EX_CLEAR_BITS));
-    /* FEX and VX need to be updated, so don't set fpscr directly */
-    tmask = tcg_const_i32(1 << nibble);
-    gen_helper_store_fpscr(cpu_env, tnew_fpscr, tmask);
-    tcg_temp_free_i32(tmask);
-    tcg_temp_free_i64(tnew_fpscr);
-}
-
-/* mffs */
-static void gen_mffs(DisasContext *ctx)
-{
-    if (unlikely(!ctx->fpu_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_FPU);
-        return;
-    }
-    gen_reset_fpstatus();
-    tcg_gen_extu_tl_i64(cpu_fpr[rD(ctx->opcode)], cpu_fpscr);
-    if (unlikely(Rc(ctx->opcode))) {
-        gen_set_cr1_from_fpscr(ctx);
-    }
-}
-
-/* mtfsb0 */
-static void gen_mtfsb0(DisasContext *ctx)
-{
-    uint8_t crb;
-
-    if (unlikely(!ctx->fpu_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_FPU);
-        return;
-    }
-    crb = 31 - crbD(ctx->opcode);
-    gen_reset_fpstatus();
-    if (likely(crb != FPSCR_FEX && crb != FPSCR_VX)) {
-        TCGv_i32 t0;
-        /* NIP cannot be restored if the memory exception comes from an helper */
-        gen_update_nip(ctx, ctx->nip - 4);
-        t0 = tcg_const_i32(crb);
-        gen_helper_fpscr_clrbit(cpu_env, t0);
-        tcg_temp_free_i32(t0);
-    }
-    if (unlikely(Rc(ctx->opcode) != 0)) {
-        tcg_gen_trunc_tl_i32(cpu_crf[1], cpu_fpscr);
-        tcg_gen_shri_i32(cpu_crf[1], cpu_crf[1], FPSCR_OX);
-    }
-}
-
-/* mtfsb1 */
-static void gen_mtfsb1(DisasContext *ctx)
-{
-    uint8_t crb;
-
-    if (unlikely(!ctx->fpu_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_FPU);
-        return;
-    }
-    crb = 31 - crbD(ctx->opcode);
-    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)) {
-        TCGv_i32 t0;
-        /* NIP cannot be restored if the memory exception comes from an helper */
-        gen_update_nip(ctx, ctx->nip - 4);
-        t0 = tcg_const_i32(crb);
-        gen_helper_fpscr_setbit(cpu_env, t0);
-        tcg_temp_free_i32(t0);
-    }
-    if (unlikely(Rc(ctx->opcode) != 0)) {
-        tcg_gen_trunc_tl_i32(cpu_crf[1], cpu_fpscr);
-        tcg_gen_shri_i32(cpu_crf[1], cpu_crf[1], FPSCR_OX);
-    }
-    /* We can raise a differed exception */
-    gen_helper_float_check_status(cpu_env);
-}
-
-/* mtfsf */
-static void gen_mtfsf(DisasContext *ctx)
-{
-    TCGv_i32 t0;
-    int flm, l, w;
-
-    if (unlikely(!ctx->fpu_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_FPU);
-        return;
-    }
-    flm = FPFLM(ctx->opcode);
-    l = FPL(ctx->opcode);
-    w = FPW(ctx->opcode);
-    if (unlikely(w & !(ctx->insns_flags2 & PPC2_ISA205))) {
-        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
-        return;
-    }
-    /* NIP cannot be restored if the memory exception comes from an helper */
-    gen_update_nip(ctx, ctx->nip - 4);
-    gen_reset_fpstatus();
-    if (l) {
-        t0 = tcg_const_i32((ctx->insns_flags2 & PPC2_ISA205) ? 0xffff : 0xff);
-    } else {
-        t0 = tcg_const_i32(flm << (w * 8));
-    }
-    gen_helper_store_fpscr(cpu_env, cpu_fpr[rB(ctx->opcode)], t0);
-    tcg_temp_free_i32(t0);
-    if (unlikely(Rc(ctx->opcode) != 0)) {
-        tcg_gen_trunc_tl_i32(cpu_crf[1], cpu_fpscr);
-        tcg_gen_shri_i32(cpu_crf[1], cpu_crf[1], FPSCR_OX);
-    }
-    /* We can raise a differed exception */
-    gen_helper_float_check_status(cpu_env);
-}
-
-/* mtfsfi */
-static void gen_mtfsfi(DisasContext *ctx)
-{
-    int bf, sh, w;
-    TCGv_i64 t0;
-    TCGv_i32 t1;
-
-    if (unlikely(!ctx->fpu_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_FPU);
-        return;
-    }
-    w = FPW(ctx->opcode);
-    bf = FPBF(ctx->opcode);
-    if (unlikely(w & !(ctx->insns_flags2 & PPC2_ISA205))) {
-        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
-        return;
-    }
-    sh = (8 * w) + 7 - bf;
-    /* NIP cannot be restored if the memory exception comes from an helper */
-    gen_update_nip(ctx, ctx->nip - 4);
-    gen_reset_fpstatus();
-    t0 = tcg_const_i64(((uint64_t)FPIMM(ctx->opcode)) << (4 * sh));
-    t1 = tcg_const_i32(1 << sh);
-    gen_helper_store_fpscr(cpu_env, t0, t1);
-    tcg_temp_free_i64(t0);
-    tcg_temp_free_i32(t1);
-    if (unlikely(Rc(ctx->opcode) != 0)) {
-        tcg_gen_trunc_tl_i32(cpu_crf[1], cpu_fpscr);
-        tcg_gen_shri_i32(cpu_crf[1], cpu_crf[1], FPSCR_OX);
-    }
-    /* We can raise a differed exception */
-    gen_helper_float_check_status(cpu_env);
-}
-
 /***                           Addressing modes                            ***/
 /* Register indirect with immediate index : EA = (rA|0) + SIMM */
 static inline void gen_addr_imm_index(DisasContext *ctx, TCGv EA,
@@ -3666,336 +3059,6 @@ static void gen_rvwinkle(DisasContext *ctx)
 }
 #endif /* #if defined(TARGET_PPC64) */
 
-/***                         Floating-point load                           ***/
-#define GEN_LDF(name, ldop, opc, type)                                        \
-static void glue(gen_, name)(DisasContext *ctx)                                       \
-{                                                                             \
-    TCGv EA;                                                                  \
-    if (unlikely(!ctx->fpu_enabled)) {                                        \
-        gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
-        return;                                                               \
-    }                                                                         \
-    gen_set_access_type(ctx, ACCESS_FLOAT);                                   \
-    EA = tcg_temp_new();                                                      \
-    gen_addr_imm_index(ctx, EA, 0);                                           \
-    gen_qemu_##ldop(ctx, cpu_fpr[rD(ctx->opcode)], EA);                       \
-    tcg_temp_free(EA);                                                        \
-}
-
-#define GEN_LDUF(name, ldop, opc, type)                                       \
-static void glue(gen_, name##u)(DisasContext *ctx)                                    \
-{                                                                             \
-    TCGv EA;                                                                  \
-    if (unlikely(!ctx->fpu_enabled)) {                                        \
-        gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
-        return;                                                               \
-    }                                                                         \
-    if (unlikely(rA(ctx->opcode) == 0)) {                                     \
-        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);                   \
-        return;                                                               \
-    }                                                                         \
-    gen_set_access_type(ctx, ACCESS_FLOAT);                                   \
-    EA = tcg_temp_new();                                                      \
-    gen_addr_imm_index(ctx, EA, 0);                                           \
-    gen_qemu_##ldop(ctx, cpu_fpr[rD(ctx->opcode)], EA);                       \
-    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA);                             \
-    tcg_temp_free(EA);                                                        \
-}
-
-#define GEN_LDUXF(name, ldop, opc, type)                                      \
-static void glue(gen_, name##ux)(DisasContext *ctx)                                   \
-{                                                                             \
-    TCGv EA;                                                                  \
-    if (unlikely(!ctx->fpu_enabled)) {                                        \
-        gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
-        return;                                                               \
-    }                                                                         \
-    if (unlikely(rA(ctx->opcode) == 0)) {                                     \
-        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);                   \
-        return;                                                               \
-    }                                                                         \
-    gen_set_access_type(ctx, ACCESS_FLOAT);                                   \
-    EA = tcg_temp_new();                                                      \
-    gen_addr_reg_index(ctx, EA);                                              \
-    gen_qemu_##ldop(ctx, cpu_fpr[rD(ctx->opcode)], EA);                       \
-    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA);                             \
-    tcg_temp_free(EA);                                                        \
-}
-
-#define GEN_LDXF(name, ldop, opc2, opc3, type)                                \
-static void glue(gen_, name##x)(DisasContext *ctx)                                    \
-{                                                                             \
-    TCGv EA;                                                                  \
-    if (unlikely(!ctx->fpu_enabled)) {                                        \
-        gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
-        return;                                                               \
-    }                                                                         \
-    gen_set_access_type(ctx, ACCESS_FLOAT);                                   \
-    EA = tcg_temp_new();                                                      \
-    gen_addr_reg_index(ctx, EA);                                              \
-    gen_qemu_##ldop(ctx, cpu_fpr[rD(ctx->opcode)], EA);                       \
-    tcg_temp_free(EA);                                                        \
-}
-
-#define GEN_LDFS(name, ldop, op, type)                                        \
-GEN_LDF(name, ldop, op | 0x20, type);                                         \
-GEN_LDUF(name, ldop, op | 0x21, type);                                        \
-GEN_LDUXF(name, ldop, op | 0x01, type);                                       \
-GEN_LDXF(name, ldop, 0x17, op | 0x00, type)
-
-static inline void gen_qemu_ld32fs(DisasContext *ctx, TCGv_i64 arg1, TCGv arg2)
-{
-    TCGv t0 = tcg_temp_new();
-    TCGv_i32 t1 = tcg_temp_new_i32();
-    gen_qemu_ld32u(ctx, t0, arg2);
-    tcg_gen_trunc_tl_i32(t1, t0);
-    tcg_temp_free(t0);
-    gen_helper_float32_to_float64(arg1, cpu_env, t1);
-    tcg_temp_free_i32(t1);
-}
-
- /* lfd lfdu lfdux lfdx */
-GEN_LDFS(lfd, ld64, 0x12, PPC_FLOAT);
- /* lfs lfsu lfsux lfsx */
-GEN_LDFS(lfs, ld32fs, 0x10, PPC_FLOAT);
-
-/* lfdp */
-static void gen_lfdp(DisasContext *ctx)
-{
-    TCGv EA;
-    if (unlikely(!ctx->fpu_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_FPU);
-        return;
-    }
-    gen_set_access_type(ctx, ACCESS_FLOAT);
-    EA = tcg_temp_new();
-    gen_addr_imm_index(ctx, EA, 0);
-    /* We only need to swap high and low halves. gen_qemu_ld64 does necessary
-       64-bit byteswap already. */
-    if (unlikely(ctx->le_mode)) {
-        gen_qemu_ld64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA);
-        tcg_gen_addi_tl(EA, EA, 8);
-        gen_qemu_ld64(ctx, cpu_fpr[rD(ctx->opcode)], EA);
-    } else {
-        gen_qemu_ld64(ctx, cpu_fpr[rD(ctx->opcode)], EA);
-        tcg_gen_addi_tl(EA, EA, 8);
-        gen_qemu_ld64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA);
-    }
-    tcg_temp_free(EA);
-}
-
-/* lfdpx */
-static void gen_lfdpx(DisasContext *ctx)
-{
-    TCGv EA;
-    if (unlikely(!ctx->fpu_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_FPU);
-        return;
-    }
-    gen_set_access_type(ctx, ACCESS_FLOAT);
-    EA = tcg_temp_new();
-    gen_addr_reg_index(ctx, EA);
-    /* We only need to swap high and low halves. gen_qemu_ld64 does necessary
-       64-bit byteswap already. */
-    if (unlikely(ctx->le_mode)) {
-        gen_qemu_ld64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA);
-        tcg_gen_addi_tl(EA, EA, 8);
-        gen_qemu_ld64(ctx, cpu_fpr[rD(ctx->opcode)], EA);
-    } else {
-        gen_qemu_ld64(ctx, cpu_fpr[rD(ctx->opcode)], EA);
-        tcg_gen_addi_tl(EA, EA, 8);
-        gen_qemu_ld64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA);
-    }
-    tcg_temp_free(EA);
-}
-
-/* lfiwax */
-static void gen_lfiwax(DisasContext *ctx)
-{
-    TCGv EA;
-    TCGv t0;
-    if (unlikely(!ctx->fpu_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_FPU);
-        return;
-    }
-    gen_set_access_type(ctx, ACCESS_FLOAT);
-    EA = tcg_temp_new();
-    t0 = tcg_temp_new();
-    gen_addr_reg_index(ctx, EA);
-    gen_qemu_ld32s(ctx, t0, EA);
-    tcg_gen_ext_tl_i64(cpu_fpr[rD(ctx->opcode)], t0);
-    tcg_temp_free(EA);
-    tcg_temp_free(t0);
-}
-
-/* lfiwzx */
-static void gen_lfiwzx(DisasContext *ctx)
-{
-    TCGv EA;
-    if (unlikely(!ctx->fpu_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_FPU);
-        return;
-    }
-    gen_set_access_type(ctx, ACCESS_FLOAT);
-    EA = tcg_temp_new();
-    gen_addr_reg_index(ctx, EA);
-    gen_qemu_ld32u_i64(ctx, cpu_fpr[rD(ctx->opcode)], EA);
-    tcg_temp_free(EA);
-}
-/***                         Floating-point store                          ***/
-#define GEN_STF(name, stop, opc, type)                                        \
-static void glue(gen_, name)(DisasContext *ctx)                                       \
-{                                                                             \
-    TCGv EA;                                                                  \
-    if (unlikely(!ctx->fpu_enabled)) {                                        \
-        gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
-        return;                                                               \
-    }                                                                         \
-    gen_set_access_type(ctx, ACCESS_FLOAT);                                   \
-    EA = tcg_temp_new();                                                      \
-    gen_addr_imm_index(ctx, EA, 0);                                           \
-    gen_qemu_##stop(ctx, cpu_fpr[rS(ctx->opcode)], EA);                       \
-    tcg_temp_free(EA);                                                        \
-}
-
-#define GEN_STUF(name, stop, opc, type)                                       \
-static void glue(gen_, name##u)(DisasContext *ctx)                                    \
-{                                                                             \
-    TCGv EA;                                                                  \
-    if (unlikely(!ctx->fpu_enabled)) {                                        \
-        gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
-        return;                                                               \
-    }                                                                         \
-    if (unlikely(rA(ctx->opcode) == 0)) {                                     \
-        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);                   \
-        return;                                                               \
-    }                                                                         \
-    gen_set_access_type(ctx, ACCESS_FLOAT);                                   \
-    EA = tcg_temp_new();                                                      \
-    gen_addr_imm_index(ctx, EA, 0);                                           \
-    gen_qemu_##stop(ctx, cpu_fpr[rS(ctx->opcode)], EA);                       \
-    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA);                             \
-    tcg_temp_free(EA);                                                        \
-}
-
-#define GEN_STUXF(name, stop, opc, type)                                      \
-static void glue(gen_, name##ux)(DisasContext *ctx)                                   \
-{                                                                             \
-    TCGv EA;                                                                  \
-    if (unlikely(!ctx->fpu_enabled)) {                                        \
-        gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
-        return;                                                               \
-    }                                                                         \
-    if (unlikely(rA(ctx->opcode) == 0)) {                                     \
-        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);                   \
-        return;                                                               \
-    }                                                                         \
-    gen_set_access_type(ctx, ACCESS_FLOAT);                                   \
-    EA = tcg_temp_new();                                                      \
-    gen_addr_reg_index(ctx, EA);                                              \
-    gen_qemu_##stop(ctx, cpu_fpr[rS(ctx->opcode)], EA);                       \
-    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA);                             \
-    tcg_temp_free(EA);                                                        \
-}
-
-#define GEN_STXF(name, stop, opc2, opc3, type)                                \
-static void glue(gen_, name##x)(DisasContext *ctx)                                    \
-{                                                                             \
-    TCGv EA;                                                                  \
-    if (unlikely(!ctx->fpu_enabled)) {                                        \
-        gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
-        return;                                                               \
-    }                                                                         \
-    gen_set_access_type(ctx, ACCESS_FLOAT);                                   \
-    EA = tcg_temp_new();                                                      \
-    gen_addr_reg_index(ctx, EA);                                              \
-    gen_qemu_##stop(ctx, cpu_fpr[rS(ctx->opcode)], EA);                       \
-    tcg_temp_free(EA);                                                        \
-}
-
-#define GEN_STFS(name, stop, op, type)                                        \
-GEN_STF(name, stop, op | 0x20, type);                                         \
-GEN_STUF(name, stop, op | 0x21, type);                                        \
-GEN_STUXF(name, stop, op | 0x01, type);                                       \
-GEN_STXF(name, stop, 0x17, op | 0x00, type)
-
-static inline void gen_qemu_st32fs(DisasContext *ctx, TCGv_i64 arg1, TCGv arg2)
-{
-    TCGv_i32 t0 = tcg_temp_new_i32();
-    TCGv t1 = tcg_temp_new();
-    gen_helper_float64_to_float32(t0, cpu_env, arg1);
-    tcg_gen_extu_i32_tl(t1, t0);
-    tcg_temp_free_i32(t0);
-    gen_qemu_st32(ctx, t1, arg2);
-    tcg_temp_free(t1);
-}
-
-/* stfd stfdu stfdux stfdx */
-GEN_STFS(stfd, st64, 0x16, PPC_FLOAT);
-/* stfs stfsu stfsux stfsx */
-GEN_STFS(stfs, st32fs, 0x14, PPC_FLOAT);
-
-/* stfdp */
-static void gen_stfdp(DisasContext *ctx)
-{
-    TCGv EA;
-    if (unlikely(!ctx->fpu_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_FPU);
-        return;
-    }
-    gen_set_access_type(ctx, ACCESS_FLOAT);
-    EA = tcg_temp_new();
-    gen_addr_imm_index(ctx, EA, 0);
-    /* We only need to swap high and low halves. gen_qemu_st64 does necessary
-       64-bit byteswap already. */
-    if (unlikely(ctx->le_mode)) {
-        gen_qemu_st64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA);
-        tcg_gen_addi_tl(EA, EA, 8);
-        gen_qemu_st64(ctx, cpu_fpr[rD(ctx->opcode)], EA);
-    } else {
-        gen_qemu_st64(ctx, cpu_fpr[rD(ctx->opcode)], EA);
-        tcg_gen_addi_tl(EA, EA, 8);
-        gen_qemu_st64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA);
-    }
-    tcg_temp_free(EA);
-}
-
-/* stfdpx */
-static void gen_stfdpx(DisasContext *ctx)
-{
-    TCGv EA;
-    if (unlikely(!ctx->fpu_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_FPU);
-        return;
-    }
-    gen_set_access_type(ctx, ACCESS_FLOAT);
-    EA = tcg_temp_new();
-    gen_addr_reg_index(ctx, EA);
-    /* We only need to swap high and low halves. gen_qemu_st64 does necessary
-       64-bit byteswap already. */
-    if (unlikely(ctx->le_mode)) {
-        gen_qemu_st64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA);
-        tcg_gen_addi_tl(EA, EA, 8);
-        gen_qemu_st64(ctx, cpu_fpr[rD(ctx->opcode)], EA);
-    } else {
-        gen_qemu_st64(ctx, cpu_fpr[rD(ctx->opcode)], EA);
-        tcg_gen_addi_tl(EA, EA, 8);
-        gen_qemu_st64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA);
-    }
-    tcg_temp_free(EA);
-}
-
-/* Optional: */
-static inline void gen_qemu_st32fiw(DisasContext *ctx, TCGv_i64 arg1, TCGv arg2)
-{
-    TCGv t0 = tcg_temp_new();
-    tcg_gen_trunc_i64_tl(t0, arg1),
-    gen_qemu_st32(ctx, t0, arg2);
-    tcg_temp_free(t0);
-}
-/* stfiwx */
-GEN_STXF(stfiw, st32fiw, 0x17, 0x1E, PPC_FLOAT_STFIWX);
-
 static inline void gen_update_cfar(DisasContext *ctx, target_ulong nip)
 {
 #if defined(TARGET_PPC64)
@@ -5940,142 +5003,9 @@ static void gen_rfsvc(DisasContext *ctx)
 #endif /* defined(CONFIG_USER_ONLY) */
 }
 
-/* svc is not implemented for now */
-
-/* POWER2 specific instructions */
-/* Quad manipulation (load/store two floats at a time) */
-
-/* lfq */
-static void gen_lfq(DisasContext *ctx)
-{
-    int rd = rD(ctx->opcode);
-    TCGv t0;
-    gen_set_access_type(ctx, ACCESS_FLOAT);
-    t0 = tcg_temp_new();
-    gen_addr_imm_index(ctx, t0, 0);
-    gen_qemu_ld64(ctx, cpu_fpr[rd], t0);
-    gen_addr_add(ctx, t0, t0, 8);
-    gen_qemu_ld64(ctx, cpu_fpr[(rd + 1) % 32], t0);
-    tcg_temp_free(t0);
-}
-
-/* lfqu */
-static void gen_lfqu(DisasContext *ctx)
-{
-    int ra = rA(ctx->opcode);
-    int rd = rD(ctx->opcode);
-    TCGv t0, t1;
-    gen_set_access_type(ctx, ACCESS_FLOAT);
-    t0 = tcg_temp_new();
-    t1 = tcg_temp_new();
-    gen_addr_imm_index(ctx, t0, 0);
-    gen_qemu_ld64(ctx, cpu_fpr[rd], t0);
-    gen_addr_add(ctx, t1, t0, 8);
-    gen_qemu_ld64(ctx, cpu_fpr[(rd + 1) % 32], t1);
-    if (ra != 0)
-        tcg_gen_mov_tl(cpu_gpr[ra], t0);
-    tcg_temp_free(t0);
-    tcg_temp_free(t1);
-}
+#include "translate/fp-impl.c"
 
-/* lfqux */
-static void gen_lfqux(DisasContext *ctx)
-{
-    int ra = rA(ctx->opcode);
-    int rd = rD(ctx->opcode);
-    gen_set_access_type(ctx, ACCESS_FLOAT);
-    TCGv t0, t1;
-    t0 = tcg_temp_new();
-    gen_addr_reg_index(ctx, t0);
-    gen_qemu_ld64(ctx, cpu_fpr[rd], t0);
-    t1 = tcg_temp_new();
-    gen_addr_add(ctx, t1, t0, 8);
-    gen_qemu_ld64(ctx, cpu_fpr[(rd + 1) % 32], t1);
-    tcg_temp_free(t1);
-    if (ra != 0)
-        tcg_gen_mov_tl(cpu_gpr[ra], t0);
-    tcg_temp_free(t0);
-}
-
-/* lfqx */
-static void gen_lfqx(DisasContext *ctx)
-{
-    int rd = rD(ctx->opcode);
-    TCGv t0;
-    gen_set_access_type(ctx, ACCESS_FLOAT);
-    t0 = tcg_temp_new();
-    gen_addr_reg_index(ctx, t0);
-    gen_qemu_ld64(ctx, cpu_fpr[rd], t0);
-    gen_addr_add(ctx, t0, t0, 8);
-    gen_qemu_ld64(ctx, cpu_fpr[(rd + 1) % 32], t0);
-    tcg_temp_free(t0);
-}
-
-/* stfq */
-static void gen_stfq(DisasContext *ctx)
-{
-    int rd = rD(ctx->opcode);
-    TCGv t0;
-    gen_set_access_type(ctx, ACCESS_FLOAT);
-    t0 = tcg_temp_new();
-    gen_addr_imm_index(ctx, t0, 0);
-    gen_qemu_st64(ctx, cpu_fpr[rd], t0);
-    gen_addr_add(ctx, t0, t0, 8);
-    gen_qemu_st64(ctx, cpu_fpr[(rd + 1) % 32], t0);
-    tcg_temp_free(t0);
-}
-
-/* stfqu */
-static void gen_stfqu(DisasContext *ctx)
-{
-    int ra = rA(ctx->opcode);
-    int rd = rD(ctx->opcode);
-    TCGv t0, t1;
-    gen_set_access_type(ctx, ACCESS_FLOAT);
-    t0 = tcg_temp_new();
-    gen_addr_imm_index(ctx, t0, 0);
-    gen_qemu_st64(ctx, cpu_fpr[rd], t0);
-    t1 = tcg_temp_new();
-    gen_addr_add(ctx, t1, t0, 8);
-    gen_qemu_st64(ctx, cpu_fpr[(rd + 1) % 32], t1);
-    tcg_temp_free(t1);
-    if (ra != 0)
-        tcg_gen_mov_tl(cpu_gpr[ra], t0);
-    tcg_temp_free(t0);
-}
-
-/* stfqux */
-static void gen_stfqux(DisasContext *ctx)
-{
-    int ra = rA(ctx->opcode);
-    int rd = rD(ctx->opcode);
-    TCGv t0, t1;
-    gen_set_access_type(ctx, ACCESS_FLOAT);
-    t0 = tcg_temp_new();
-    gen_addr_reg_index(ctx, t0);
-    gen_qemu_st64(ctx, cpu_fpr[rd], t0);
-    t1 = tcg_temp_new();
-    gen_addr_add(ctx, t1, t0, 8);
-    gen_qemu_st64(ctx, cpu_fpr[(rd + 1) % 32], t1);
-    tcg_temp_free(t1);
-    if (ra != 0)
-        tcg_gen_mov_tl(cpu_gpr[ra], t0);
-    tcg_temp_free(t0);
-}
-
-/* stfqx */
-static void gen_stfqx(DisasContext *ctx)
-{
-    int rd = rD(ctx->opcode);
-    TCGv t0;
-    gen_set_access_type(ctx, ACCESS_FLOAT);
-    t0 = tcg_temp_new();
-    gen_addr_reg_index(ctx, t0);
-    gen_qemu_st64(ctx, cpu_fpr[rd], t0);
-    gen_addr_add(ctx, t0, t0, 8);
-    gen_qemu_st64(ctx, cpu_fpr[(rd + 1) % 32], t0);
-    tcg_temp_free(t0);
-}
+/* svc is not implemented for now */
 
 /* BookE specific instructions */
 
@@ -9920,24 +8850,6 @@ GEN_HANDLER2(sradi0, "sradi", 0x1F, 0x1A, 0x19, 0x00000000, PPC_64B),
 GEN_HANDLER2(sradi1, "sradi", 0x1F, 0x1B, 0x19, 0x00000000, PPC_64B),
 GEN_HANDLER(srd, 0x1F, 0x1B, 0x10, 0x00000000, PPC_64B),
 #endif
-GEN_HANDLER(frsqrtes, 0x3B, 0x1A, 0xFF, 0x001F07C0, PPC_FLOAT_FRSQRTES),
-GEN_HANDLER(fsqrt, 0x3F, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_FSQRT),
-GEN_HANDLER(fsqrts, 0x3B, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_FSQRT),
-GEN_HANDLER(fcmpo, 0x3F, 0x00, 0x01, 0x00600001, PPC_FLOAT),
-GEN_HANDLER(fcmpu, 0x3F, 0x00, 0x00, 0x00600001, PPC_FLOAT),
-GEN_HANDLER(fabs, 0x3F, 0x08, 0x08, 0x001F0000, PPC_FLOAT),
-GEN_HANDLER(fmr, 0x3F, 0x08, 0x02, 0x001F0000, PPC_FLOAT),
-GEN_HANDLER(fnabs, 0x3F, 0x08, 0x04, 0x001F0000, PPC_FLOAT),
-GEN_HANDLER(fneg, 0x3F, 0x08, 0x01, 0x001F0000, PPC_FLOAT),
-GEN_HANDLER_E(fcpsgn, 0x3F, 0x08, 0x00, 0x00000000, PPC_NONE, PPC2_ISA205),
-GEN_HANDLER_E(fmrgew, 0x3F, 0x06, 0x1E, 0x00000001, PPC_NONE, PPC2_VSX207),
-GEN_HANDLER_E(fmrgow, 0x3F, 0x06, 0x1A, 0x00000001, PPC_NONE, PPC2_VSX207),
-GEN_HANDLER(mcrfs, 0x3F, 0x00, 0x02, 0x0063F801, PPC_FLOAT),
-GEN_HANDLER(mffs, 0x3F, 0x07, 0x12, 0x001FF800, PPC_FLOAT),
-GEN_HANDLER(mtfsb0, 0x3F, 0x06, 0x02, 0x001FF800, PPC_FLOAT),
-GEN_HANDLER(mtfsb1, 0x3F, 0x06, 0x01, 0x001FF800, PPC_FLOAT),
-GEN_HANDLER(mtfsf, 0x3F, 0x07, 0x16, 0x00000000, PPC_FLOAT),
-GEN_HANDLER(mtfsfi, 0x3F, 0x06, 0x04, 0x006e0800, PPC_FLOAT),
 #if defined(TARGET_PPC64)
 GEN_HANDLER(ld, 0x3A, 0xFF, 0xFF, 0x00000000, PPC_64B),
 GEN_HANDLER(lq, 0x38, 0xFF, 0xFF, 0x00000000, PPC_64BX),
@@ -10259,66 +9171,6 @@ GEN_PPC64_R2(rldcr, 0x1E, 0x09),
 GEN_PPC64_R4(rldimi, 0x1E, 0x06),
 #endif
 
-#undef _GEN_FLOAT_ACB
-#undef GEN_FLOAT_ACB
-#undef _GEN_FLOAT_AB
-#undef GEN_FLOAT_AB
-#undef _GEN_FLOAT_AC
-#undef GEN_FLOAT_AC
-#undef GEN_FLOAT_B
-#undef GEN_FLOAT_BS
-#define _GEN_FLOAT_ACB(name, op, op1, op2, isfloat, set_fprf, type)           \
-GEN_HANDLER(f##name, op1, op2, 0xFF, 0x00000000, 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, set_fprf, type)     \
-GEN_HANDLER(f##name, op1, op2, 0xFF, inval, type)
-#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, set_fprf, type)     \
-GEN_HANDLER(f##name, op1, op2, 0xFF, inval, type)
-#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, set_fprf, type)                           \
-GEN_HANDLER(f##name, 0x3F, op2, op3, 0x001F0000, type)
-#define GEN_FLOAT_BS(name, op1, op2, set_fprf, type)                          \
-GEN_HANDLER(f##name, op1, op2, 0xFF, 0x001F07C0, type)
-
-GEN_FLOAT_AB(add, 0x15, 0x000007C0, 1, PPC_FLOAT),
-GEN_FLOAT_AB(div, 0x12, 0x000007C0, 1, PPC_FLOAT),
-GEN_FLOAT_AC(mul, 0x19, 0x0000F800, 1, PPC_FLOAT),
-GEN_FLOAT_BS(re, 0x3F, 0x18, 1, PPC_FLOAT_EXT),
-GEN_FLOAT_BS(res, 0x3B, 0x18, 1, PPC_FLOAT_FRES),
-GEN_FLOAT_BS(rsqrte, 0x3F, 0x1A, 1, PPC_FLOAT_FRSQRTE),
-_GEN_FLOAT_ACB(sel, sel, 0x3F, 0x17, 0, 0, PPC_FLOAT_FSEL),
-GEN_FLOAT_AB(sub, 0x14, 0x000007C0, 1, PPC_FLOAT),
-GEN_FLOAT_ACB(madd, 0x1D, 1, PPC_FLOAT),
-GEN_FLOAT_ACB(msub, 0x1C, 1, PPC_FLOAT),
-GEN_FLOAT_ACB(nmadd, 0x1F, 1, PPC_FLOAT),
-GEN_FLOAT_ACB(nmsub, 0x1E, 1, PPC_FLOAT),
-GEN_HANDLER_E(ftdiv, 0x3F, 0x00, 0x04, 1, PPC_NONE, PPC2_FP_TST_ISA206),
-GEN_HANDLER_E(ftsqrt, 0x3F, 0x00, 0x05, 1, PPC_NONE, PPC2_FP_TST_ISA206),
-GEN_FLOAT_B(ctiw, 0x0E, 0x00, 0, PPC_FLOAT),
-GEN_HANDLER_E(fctiwu, 0x3F, 0x0E, 0x04, 0, PPC_NONE, PPC2_FP_CVT_ISA206),
-GEN_FLOAT_B(ctiwz, 0x0F, 0x00, 0, PPC_FLOAT),
-GEN_HANDLER_E(fctiwuz, 0x3F, 0x0F, 0x04, 0, PPC_NONE, PPC2_FP_CVT_ISA206),
-GEN_FLOAT_B(rsp, 0x0C, 0x00, 1, PPC_FLOAT),
-GEN_HANDLER_E(fcfid, 0x3F, 0x0E, 0x1A, 0x001F0000, PPC_NONE, PPC2_FP_CVT_S64),
-GEN_HANDLER_E(fcfids, 0x3B, 0x0E, 0x1A, 0, PPC_NONE, PPC2_FP_CVT_ISA206),
-GEN_HANDLER_E(fcfidu, 0x3F, 0x0E, 0x1E, 0, PPC_NONE, PPC2_FP_CVT_ISA206),
-GEN_HANDLER_E(fcfidus, 0x3B, 0x0E, 0x1E, 0, PPC_NONE, PPC2_FP_CVT_ISA206),
-GEN_HANDLER_E(fctid, 0x3F, 0x0E, 0x19, 0x001F0000, PPC_NONE, PPC2_FP_CVT_S64),
-GEN_HANDLER_E(fctidu, 0x3F, 0x0E, 0x1D, 0, PPC_NONE, PPC2_FP_CVT_ISA206),
-GEN_HANDLER_E(fctidz, 0x3F, 0x0F, 0x19, 0x001F0000, PPC_NONE, PPC2_FP_CVT_S64),
-GEN_HANDLER_E(fctiduz, 0x3F, 0x0F, 0x1D, 0, PPC_NONE, PPC2_FP_CVT_ISA206),
-GEN_FLOAT_B(rin, 0x08, 0x0C, 1, PPC_FLOAT_EXT),
-GEN_FLOAT_B(riz, 0x08, 0x0D, 1, PPC_FLOAT_EXT),
-GEN_FLOAT_B(rip, 0x08, 0x0E, 1, PPC_FLOAT_EXT),
-GEN_FLOAT_B(rim, 0x08, 0x0F, 1, PPC_FLOAT_EXT),
-
 #undef GEN_LD
 #undef GEN_LDU
 #undef GEN_LDUX
@@ -10392,57 +9244,6 @@ GEN_STX_HVRM(stbcix, st8, 0x15, 0x1e, PPC_CILDST)
 GEN_STX(sthbr, st16r, 0x16, 0x1C, PPC_INTEGER)
 GEN_STX(stwbr, st32r, 0x16, 0x14, PPC_INTEGER)
 
-#undef GEN_LDF
-#undef GEN_LDUF
-#undef GEN_LDUXF
-#undef GEN_LDXF
-#undef GEN_LDFS
-#define GEN_LDF(name, ldop, opc, type)                                        \
-GEN_HANDLER(name, opc, 0xFF, 0xFF, 0x00000000, type),
-#define GEN_LDUF(name, ldop, opc, type)                                       \
-GEN_HANDLER(name##u, opc, 0xFF, 0xFF, 0x00000000, type),
-#define GEN_LDUXF(name, ldop, opc, type)                                      \
-GEN_HANDLER(name##ux, 0x1F, 0x17, opc, 0x00000001, type),
-#define GEN_LDXF(name, ldop, opc2, opc3, type)                                \
-GEN_HANDLER(name##x, 0x1F, opc2, opc3, 0x00000001, type),
-#define GEN_LDFS(name, ldop, op, type)                                        \
-GEN_LDF(name, ldop, op | 0x20, type)                                          \
-GEN_LDUF(name, ldop, op | 0x21, type)                                         \
-GEN_LDUXF(name, ldop, op | 0x01, type)                                        \
-GEN_LDXF(name, ldop, 0x17, op | 0x00, type)
-
-GEN_LDFS(lfd, ld64, 0x12, PPC_FLOAT)
-GEN_LDFS(lfs, ld32fs, 0x10, PPC_FLOAT)
-GEN_HANDLER_E(lfiwax, 0x1f, 0x17, 0x1a, 0x00000001, PPC_NONE, PPC2_ISA205),
-GEN_HANDLER_E(lfiwzx, 0x1f, 0x17, 0x1b, 0x1, PPC_NONE, PPC2_FP_CVT_ISA206),
-GEN_HANDLER_E(lfdp, 0x39, 0xFF, 0xFF, 0x00200003, PPC_NONE, PPC2_ISA205),
-GEN_HANDLER_E(lfdpx, 0x1F, 0x17, 0x18, 0x00200001, PPC_NONE, PPC2_ISA205),
-
-#undef GEN_STF
-#undef GEN_STUF
-#undef GEN_STUXF
-#undef GEN_STXF
-#undef GEN_STFS
-#define GEN_STF(name, stop, opc, type)                                        \
-GEN_HANDLER(name, opc, 0xFF, 0xFF, 0x00000000, type),
-#define GEN_STUF(name, stop, opc, type)                                       \
-GEN_HANDLER(name##u, opc, 0xFF, 0xFF, 0x00000000, type),
-#define GEN_STUXF(name, stop, opc, type)                                      \
-GEN_HANDLER(name##ux, 0x1F, 0x17, opc, 0x00000001, type),
-#define GEN_STXF(name, stop, opc2, opc3, type)                                \
-GEN_HANDLER(name##x, 0x1F, opc2, opc3, 0x00000001, type),
-#define GEN_STFS(name, stop, op, type)                                        \
-GEN_STF(name, stop, op | 0x20, type)                                          \
-GEN_STUF(name, stop, op | 0x21, type)                                         \
-GEN_STUXF(name, stop, op | 0x01, type)                                        \
-GEN_STXF(name, stop, 0x17, op | 0x00, type)
-
-GEN_STFS(stfd, st64, 0x16, PPC_FLOAT)
-GEN_STFS(stfs, st32fs, 0x14, PPC_FLOAT)
-GEN_STXF(stfiw, st32fiw, 0x17, 0x1E, PPC_FLOAT_STFIWX)
-GEN_HANDLER_E(stfdp, 0x3D, 0xFF, 0xFF, 0x00200003, PPC_NONE, PPC2_ISA205),
-GEN_HANDLER_E(stfdpx, 0x1F, 0x17, 0x1C, 0x00200001, PPC_NONE, PPC2_ISA205),
-
 #undef GEN_CRLOGIC
 #define GEN_CRLOGIC(name, tcg_op, opc)                                        \
 GEN_HANDLER(name, 0x13, 0x01, opc, 0x00000001, PPC_INTEGER)
@@ -10501,6 +9302,8 @@ GEN_MAC_HANDLER(mulhhwu, 0x08, 0x00),
 GEN_MAC_HANDLER(mullhw, 0x08, 0x0D),
 GEN_MAC_HANDLER(mullhwu, 0x08, 0x0C),
 
+#include "translate/fp-ops.c"
+
 #undef GEN_VR_LDX
 #undef GEN_VR_STX
 #undef GEN_VR_LVE
diff --git a/target-ppc/translate/fp-impl.c b/target-ppc/translate/fp-impl.c
new file mode 100644
index 0000000..2abc386
--- /dev/null
+++ b/target-ppc/translate/fp-impl.c
@@ -0,0 +1,1098 @@
+/*
+ * translate-fp.c
+ *
+ * Standard FPU translation
+ */
+
+static inline void gen_reset_fpstatus(void)
+{
+    gen_helper_reset_fpstatus(cpu_env);
+}
+
+static inline void gen_compute_fprf(TCGv_i64 arg)
+{
+    gen_helper_compute_fprf(cpu_env, arg);
+    gen_helper_float_check_status(cpu_env);
+}
+
+#if defined(TARGET_PPC64)
+static void gen_set_cr1_from_fpscr(DisasContext *ctx)
+{
+    TCGv_i32 tmp = tcg_temp_new_i32();
+    tcg_gen_trunc_tl_i32(tmp, cpu_fpscr);
+    tcg_gen_shri_i32(cpu_crf[1], tmp, 28);
+    tcg_temp_free_i32(tmp);
+}
+#else
+static void gen_set_cr1_from_fpscr(DisasContext *ctx)
+{
+    tcg_gen_shri_tl(cpu_crf[1], cpu_fpscr, 28);
+}
+#endif
+
+/***                       Floating-Point arithmetic                       ***/
+#define _GEN_FLOAT_ACB(name, op, op1, op2, isfloat, set_fprf, type)           \
+static void gen_f##name(DisasContext *ctx)                                    \
+{                                                                             \
+    if (unlikely(!ctx->fpu_enabled)) {                                        \
+        gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
+        return;                                                               \
+    }                                                                         \
+    /* NIP cannot be restored if the memory exception comes from an helper */ \
+    gen_update_nip(ctx, ctx->nip - 4);                                        \
+    gen_reset_fpstatus();                                                     \
+    gen_helper_f##op(cpu_fpr[rD(ctx->opcode)], cpu_env,                       \
+                     cpu_fpr[rA(ctx->opcode)],                                \
+                     cpu_fpr[rC(ctx->opcode)], cpu_fpr[rB(ctx->opcode)]);     \
+    if (isfloat) {                                                            \
+        gen_helper_frsp(cpu_fpr[rD(ctx->opcode)], cpu_env,                    \
+                        cpu_fpr[rD(ctx->opcode)]);                            \
+    }                                                                         \
+    if (set_fprf) {                                                           \
+        gen_compute_fprf(cpu_fpr[rD(ctx->opcode)]);                           \
+    }                                                                         \
+    if (unlikely(Rc(ctx->opcode) != 0)) {                                     \
+        gen_set_cr1_from_fpscr(ctx);                                          \
+    }                                                                         \
+}
+
+#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, set_fprf, type)     \
+static void gen_f##name(DisasContext *ctx)                                    \
+{                                                                             \
+    if (unlikely(!ctx->fpu_enabled)) {                                        \
+        gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
+        return;                                                               \
+    }                                                                         \
+    /* NIP cannot be restored if the memory exception comes from an helper */ \
+    gen_update_nip(ctx, ctx->nip - 4);                                        \
+    gen_reset_fpstatus();                                                     \
+    gen_helper_f##op(cpu_fpr[rD(ctx->opcode)], cpu_env,                       \
+                     cpu_fpr[rA(ctx->opcode)],                                \
+                     cpu_fpr[rB(ctx->opcode)]);                               \
+    if (isfloat) {                                                            \
+        gen_helper_frsp(cpu_fpr[rD(ctx->opcode)], cpu_env,                    \
+                        cpu_fpr[rD(ctx->opcode)]);                            \
+    }                                                                         \
+    if (set_fprf) {                                                           \
+        gen_compute_fprf(cpu_fpr[rD(ctx->opcode)]);                           \
+    }                                                                         \
+    if (unlikely(Rc(ctx->opcode) != 0)) {                                     \
+        gen_set_cr1_from_fpscr(ctx);                                          \
+    }                                                                         \
+}
+#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, set_fprf, type)     \
+static void gen_f##name(DisasContext *ctx)                                    \
+{                                                                             \
+    if (unlikely(!ctx->fpu_enabled)) {                                        \
+        gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
+        return;                                                               \
+    }                                                                         \
+    /* NIP cannot be restored if the memory exception comes from an helper */ \
+    gen_update_nip(ctx, ctx->nip - 4);                                        \
+    gen_reset_fpstatus();                                                     \
+    gen_helper_f##op(cpu_fpr[rD(ctx->opcode)], cpu_env,                       \
+                     cpu_fpr[rA(ctx->opcode)],                                \
+                     cpu_fpr[rC(ctx->opcode)]);                               \
+    if (isfloat) {                                                            \
+        gen_helper_frsp(cpu_fpr[rD(ctx->opcode)], cpu_env,                    \
+                        cpu_fpr[rD(ctx->opcode)]);                            \
+    }                                                                         \
+    if (set_fprf) {                                                           \
+        gen_compute_fprf(cpu_fpr[rD(ctx->opcode)]);                           \
+    }                                                                         \
+    if (unlikely(Rc(ctx->opcode) != 0)) {                                     \
+        gen_set_cr1_from_fpscr(ctx);                                          \
+    }                                                                         \
+}
+#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, set_fprf, type)                           \
+static void gen_f##name(DisasContext *ctx)                                    \
+{                                                                             \
+    if (unlikely(!ctx->fpu_enabled)) {                                        \
+        gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
+        return;                                                               \
+    }                                                                         \
+    /* NIP cannot be restored if the memory exception comes from an helper */ \
+    gen_update_nip(ctx, ctx->nip - 4);                                        \
+    gen_reset_fpstatus();                                                     \
+    gen_helper_f##name(cpu_fpr[rD(ctx->opcode)], cpu_env,                     \
+                       cpu_fpr[rB(ctx->opcode)]);                             \
+    if (set_fprf) {                                                           \
+        gen_compute_fprf(cpu_fpr[rD(ctx->opcode)]);                           \
+    }                                                                         \
+    if (unlikely(Rc(ctx->opcode) != 0)) {                                     \
+        gen_set_cr1_from_fpscr(ctx);                                          \
+    }                                                                         \
+}
+
+#define GEN_FLOAT_BS(name, op1, op2, set_fprf, type)                          \
+static void gen_f##name(DisasContext *ctx)                                    \
+{                                                                             \
+    if (unlikely(!ctx->fpu_enabled)) {                                        \
+        gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
+        return;                                                               \
+    }                                                                         \
+    /* NIP cannot be restored if the memory exception comes from an helper */ \
+    gen_update_nip(ctx, ctx->nip - 4);                                        \
+    gen_reset_fpstatus();                                                     \
+    gen_helper_f##name(cpu_fpr[rD(ctx->opcode)], cpu_env,                     \
+                       cpu_fpr[rB(ctx->opcode)]);                             \
+    if (set_fprf) {                                                           \
+        gen_compute_fprf(cpu_fpr[rD(ctx->opcode)]);                           \
+    }                                                                         \
+    if (unlikely(Rc(ctx->opcode) != 0)) {                                     \
+        gen_set_cr1_from_fpscr(ctx);                                          \
+    }                                                                         \
+}
+
+/* fadd - fadds */
+GEN_FLOAT_AB(add, 0x15, 0x000007C0, 1, PPC_FLOAT);
+/* fdiv - fdivs */
+GEN_FLOAT_AB(div, 0x12, 0x000007C0, 1, PPC_FLOAT);
+/* fmul - fmuls */
+GEN_FLOAT_AC(mul, 0x19, 0x0000F800, 1, PPC_FLOAT);
+
+/* fre */
+GEN_FLOAT_BS(re, 0x3F, 0x18, 1, PPC_FLOAT_EXT);
+
+/* fres */
+GEN_FLOAT_BS(res, 0x3B, 0x18, 1, PPC_FLOAT_FRES);
+
+/* frsqrte */
+GEN_FLOAT_BS(rsqrte, 0x3F, 0x1A, 1, PPC_FLOAT_FRSQRTE);
+
+/* frsqrtes */
+static void gen_frsqrtes(DisasContext *ctx)
+{
+    if (unlikely(!ctx->fpu_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_FPU);
+        return;
+    }
+    /* NIP cannot be restored if the memory exception comes from an helper */
+    gen_update_nip(ctx, ctx->nip - 4);
+    gen_reset_fpstatus();
+    gen_helper_frsqrte(cpu_fpr[rD(ctx->opcode)], cpu_env,
+                       cpu_fpr[rB(ctx->opcode)]);
+    gen_helper_frsp(cpu_fpr[rD(ctx->opcode)], cpu_env,
+                    cpu_fpr[rD(ctx->opcode)]);
+    gen_compute_fprf(cpu_fpr[rD(ctx->opcode)]);
+    if (unlikely(Rc(ctx->opcode) != 0)) {
+        gen_set_cr1_from_fpscr(ctx);
+    }
+}
+
+/* fsel */
+_GEN_FLOAT_ACB(sel, sel, 0x3F, 0x17, 0, 0, PPC_FLOAT_FSEL);
+/* fsub - fsubs */
+GEN_FLOAT_AB(sub, 0x14, 0x000007C0, 1, PPC_FLOAT);
+/* Optional: */
+
+/* fsqrt */
+static void gen_fsqrt(DisasContext *ctx)
+{
+    if (unlikely(!ctx->fpu_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_FPU);
+        return;
+    }
+    /* NIP cannot be restored if the memory exception comes from an helper */
+    gen_update_nip(ctx, ctx->nip - 4);
+    gen_reset_fpstatus();
+    gen_helper_fsqrt(cpu_fpr[rD(ctx->opcode)], cpu_env,
+                     cpu_fpr[rB(ctx->opcode)]);
+    gen_compute_fprf(cpu_fpr[rD(ctx->opcode)]);
+    if (unlikely(Rc(ctx->opcode) != 0)) {
+        gen_set_cr1_from_fpscr(ctx);
+    }
+}
+
+static void gen_fsqrts(DisasContext *ctx)
+{
+    if (unlikely(!ctx->fpu_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_FPU);
+        return;
+    }
+    /* NIP cannot be restored if the memory exception comes from an helper */
+    gen_update_nip(ctx, ctx->nip - 4);
+    gen_reset_fpstatus();
+    gen_helper_fsqrt(cpu_fpr[rD(ctx->opcode)], cpu_env,
+                     cpu_fpr[rB(ctx->opcode)]);
+    gen_helper_frsp(cpu_fpr[rD(ctx->opcode)], cpu_env,
+                    cpu_fpr[rD(ctx->opcode)]);
+    gen_compute_fprf(cpu_fpr[rD(ctx->opcode)]);
+    if (unlikely(Rc(ctx->opcode) != 0)) {
+        gen_set_cr1_from_fpscr(ctx);
+    }
+}
+
+/***                     Floating-Point multiply-and-add                   ***/
+/* fmadd - fmadds */
+GEN_FLOAT_ACB(madd, 0x1D, 1, PPC_FLOAT);
+/* fmsub - fmsubs */
+GEN_FLOAT_ACB(msub, 0x1C, 1, PPC_FLOAT);
+/* fnmadd - fnmadds */
+GEN_FLOAT_ACB(nmadd, 0x1F, 1, PPC_FLOAT);
+/* fnmsub - fnmsubs */
+GEN_FLOAT_ACB(nmsub, 0x1E, 1, PPC_FLOAT);
+
+/***                     Floating-Point round & convert                    ***/
+/* fctiw */
+GEN_FLOAT_B(ctiw, 0x0E, 0x00, 0, PPC_FLOAT);
+/* fctiwu */
+GEN_FLOAT_B(ctiwu, 0x0E, 0x04, 0, PPC2_FP_CVT_ISA206);
+/* fctiwz */
+GEN_FLOAT_B(ctiwz, 0x0F, 0x00, 0, PPC_FLOAT);
+/* fctiwuz */
+GEN_FLOAT_B(ctiwuz, 0x0F, 0x04, 0, PPC2_FP_CVT_ISA206);
+/* frsp */
+GEN_FLOAT_B(rsp, 0x0C, 0x00, 1, PPC_FLOAT);
+/* fcfid */
+GEN_FLOAT_B(cfid, 0x0E, 0x1A, 1, PPC2_FP_CVT_S64);
+/* fcfids */
+GEN_FLOAT_B(cfids, 0x0E, 0x1A, 0, PPC2_FP_CVT_ISA206);
+/* fcfidu */
+GEN_FLOAT_B(cfidu, 0x0E, 0x1E, 0, PPC2_FP_CVT_ISA206);
+/* fcfidus */
+GEN_FLOAT_B(cfidus, 0x0E, 0x1E, 0, PPC2_FP_CVT_ISA206);
+/* fctid */
+GEN_FLOAT_B(ctid, 0x0E, 0x19, 0, PPC2_FP_CVT_S64);
+/* fctidu */
+GEN_FLOAT_B(ctidu, 0x0E, 0x1D, 0, PPC2_FP_CVT_ISA206);
+/* fctidz */
+GEN_FLOAT_B(ctidz, 0x0F, 0x19, 0, PPC2_FP_CVT_S64);
+/* fctidu */
+GEN_FLOAT_B(ctiduz, 0x0F, 0x1D, 0, PPC2_FP_CVT_ISA206);
+
+/* frin */
+GEN_FLOAT_B(rin, 0x08, 0x0C, 1, PPC_FLOAT_EXT);
+/* friz */
+GEN_FLOAT_B(riz, 0x08, 0x0D, 1, PPC_FLOAT_EXT);
+/* frip */
+GEN_FLOAT_B(rip, 0x08, 0x0E, 1, PPC_FLOAT_EXT);
+/* frim */
+GEN_FLOAT_B(rim, 0x08, 0x0F, 1, PPC_FLOAT_EXT);
+
+static void gen_ftdiv(DisasContext *ctx)
+{
+    if (unlikely(!ctx->fpu_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_FPU);
+        return;
+    }
+    gen_helper_ftdiv(cpu_crf[crfD(ctx->opcode)], cpu_fpr[rA(ctx->opcode)],
+                     cpu_fpr[rB(ctx->opcode)]);
+}
+
+static void gen_ftsqrt(DisasContext *ctx)
+{
+    if (unlikely(!ctx->fpu_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_FPU);
+        return;
+    }
+    gen_helper_ftsqrt(cpu_crf[crfD(ctx->opcode)], cpu_fpr[rB(ctx->opcode)]);
+}
+
+
+
+/***                         Floating-Point compare                        ***/
+
+/* fcmpo */
+static void gen_fcmpo(DisasContext *ctx)
+{
+    TCGv_i32 crf;
+    if (unlikely(!ctx->fpu_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_FPU);
+        return;
+    }
+    /* NIP cannot be restored if the memory exception comes from an helper */
+    gen_update_nip(ctx, ctx->nip - 4);
+    gen_reset_fpstatus();
+    crf = tcg_const_i32(crfD(ctx->opcode));
+    gen_helper_fcmpo(cpu_env, cpu_fpr[rA(ctx->opcode)],
+                     cpu_fpr[rB(ctx->opcode)], crf);
+    tcg_temp_free_i32(crf);
+    gen_helper_float_check_status(cpu_env);
+}
+
+/* fcmpu */
+static void gen_fcmpu(DisasContext *ctx)
+{
+    TCGv_i32 crf;
+    if (unlikely(!ctx->fpu_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_FPU);
+        return;
+    }
+    /* NIP cannot be restored if the memory exception comes from an helper */
+    gen_update_nip(ctx, ctx->nip - 4);
+    gen_reset_fpstatus();
+    crf = tcg_const_i32(crfD(ctx->opcode));
+    gen_helper_fcmpu(cpu_env, cpu_fpr[rA(ctx->opcode)],
+                     cpu_fpr[rB(ctx->opcode)], crf);
+    tcg_temp_free_i32(crf);
+    gen_helper_float_check_status(cpu_env);
+}
+
+/***                         Floating-point move                           ***/
+/* fabs */
+/* XXX: beware that fabs never checks for NaNs nor update FPSCR */
+static void gen_fabs(DisasContext *ctx)
+{
+    if (unlikely(!ctx->fpu_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_FPU);
+        return;
+    }
+    tcg_gen_andi_i64(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rB(ctx->opcode)],
+                     ~(1ULL << 63));
+    if (unlikely(Rc(ctx->opcode))) {
+        gen_set_cr1_from_fpscr(ctx);
+    }
+}
+
+/* fmr  - fmr. */
+/* XXX: beware that fmr never checks for NaNs nor update FPSCR */
+static void gen_fmr(DisasContext *ctx)
+{
+    if (unlikely(!ctx->fpu_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_FPU);
+        return;
+    }
+    tcg_gen_mov_i64(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rB(ctx->opcode)]);
+    if (unlikely(Rc(ctx->opcode))) {
+        gen_set_cr1_from_fpscr(ctx);
+    }
+}
+
+/* fnabs */
+/* XXX: beware that fnabs never checks for NaNs nor update FPSCR */
+static void gen_fnabs(DisasContext *ctx)
+{
+    if (unlikely(!ctx->fpu_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_FPU);
+        return;
+    }
+    tcg_gen_ori_i64(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rB(ctx->opcode)],
+                    1ULL << 63);
+    if (unlikely(Rc(ctx->opcode))) {
+        gen_set_cr1_from_fpscr(ctx);
+    }
+}
+
+/* fneg */
+/* XXX: beware that fneg never checks for NaNs nor update FPSCR */
+static void gen_fneg(DisasContext *ctx)
+{
+    if (unlikely(!ctx->fpu_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_FPU);
+        return;
+    }
+    tcg_gen_xori_i64(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rB(ctx->opcode)],
+                     1ULL << 63);
+    if (unlikely(Rc(ctx->opcode))) {
+        gen_set_cr1_from_fpscr(ctx);
+    }
+}
+
+/* fcpsgn: PowerPC 2.05 specification */
+/* XXX: beware that fcpsgn never checks for NaNs nor update FPSCR */
+static void gen_fcpsgn(DisasContext *ctx)
+{
+    if (unlikely(!ctx->fpu_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_FPU);
+        return;
+    }
+    tcg_gen_deposit_i64(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rA(ctx->opcode)],
+                        cpu_fpr[rB(ctx->opcode)], 0, 63);
+    if (unlikely(Rc(ctx->opcode))) {
+        gen_set_cr1_from_fpscr(ctx);
+    }
+}
+
+static void gen_fmrgew(DisasContext *ctx)
+{
+    TCGv_i64 b0;
+    if (unlikely(!ctx->fpu_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_FPU);
+        return;
+    }
+    b0 = tcg_temp_new_i64();
+    tcg_gen_shri_i64(b0, cpu_fpr[rB(ctx->opcode)], 32);
+    tcg_gen_deposit_i64(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rA(ctx->opcode)],
+                        b0, 0, 32);
+    tcg_temp_free_i64(b0);
+}
+
+static void gen_fmrgow(DisasContext *ctx)
+{
+    if (unlikely(!ctx->fpu_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_FPU);
+        return;
+    }
+    tcg_gen_deposit_i64(cpu_fpr[rD(ctx->opcode)],
+                        cpu_fpr[rB(ctx->opcode)],
+                        cpu_fpr[rA(ctx->opcode)],
+                        32, 32);
+}
+
+/***                  Floating-Point status & ctrl register                ***/
+
+/* mcrfs */
+static void gen_mcrfs(DisasContext *ctx)
+{
+    TCGv tmp = tcg_temp_new();
+    TCGv_i32 tmask;
+    TCGv_i64 tnew_fpscr = tcg_temp_new_i64();
+    int bfa;
+    int nibble;
+    int shift;
+
+    if (unlikely(!ctx->fpu_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_FPU);
+        return;
+    }
+    bfa = crfS(ctx->opcode);
+    nibble = 7 - bfa;
+    shift = 4 * nibble;
+    tcg_gen_shri_tl(tmp, cpu_fpscr, shift);
+    tcg_gen_trunc_tl_i32(cpu_crf[crfD(ctx->opcode)], tmp);
+    tcg_gen_andi_i32(cpu_crf[crfD(ctx->opcode)], cpu_crf[crfD(ctx->opcode)], 0xf);
+    tcg_temp_free(tmp);
+    tcg_gen_extu_tl_i64(tnew_fpscr, cpu_fpscr);
+    /* Only the exception bits (including FX) should be cleared if read */
+    tcg_gen_andi_i64(tnew_fpscr, tnew_fpscr, ~((0xF << shift) & FP_EX_CLEAR_BITS));
+    /* FEX and VX need to be updated, so don't set fpscr directly */
+    tmask = tcg_const_i32(1 << nibble);
+    gen_helper_store_fpscr(cpu_env, tnew_fpscr, tmask);
+    tcg_temp_free_i32(tmask);
+    tcg_temp_free_i64(tnew_fpscr);
+}
+
+/* mffs */
+static void gen_mffs(DisasContext *ctx)
+{
+    if (unlikely(!ctx->fpu_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_FPU);
+        return;
+    }
+    gen_reset_fpstatus();
+    tcg_gen_extu_tl_i64(cpu_fpr[rD(ctx->opcode)], cpu_fpscr);
+    if (unlikely(Rc(ctx->opcode))) {
+        gen_set_cr1_from_fpscr(ctx);
+    }
+}
+
+/* mtfsb0 */
+static void gen_mtfsb0(DisasContext *ctx)
+{
+    uint8_t crb;
+
+    if (unlikely(!ctx->fpu_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_FPU);
+        return;
+    }
+    crb = 31 - crbD(ctx->opcode);
+    gen_reset_fpstatus();
+    if (likely(crb != FPSCR_FEX && crb != FPSCR_VX)) {
+        TCGv_i32 t0;
+        /* NIP cannot be restored if the memory exception comes from an helper */
+        gen_update_nip(ctx, ctx->nip - 4);
+        t0 = tcg_const_i32(crb);
+        gen_helper_fpscr_clrbit(cpu_env, t0);
+        tcg_temp_free_i32(t0);
+    }
+    if (unlikely(Rc(ctx->opcode) != 0)) {
+        tcg_gen_trunc_tl_i32(cpu_crf[1], cpu_fpscr);
+        tcg_gen_shri_i32(cpu_crf[1], cpu_crf[1], FPSCR_OX);
+    }
+}
+
+/* mtfsb1 */
+static void gen_mtfsb1(DisasContext *ctx)
+{
+    uint8_t crb;
+
+    if (unlikely(!ctx->fpu_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_FPU);
+        return;
+    }
+    crb = 31 - crbD(ctx->opcode);
+    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)) {
+        TCGv_i32 t0;
+        /* NIP cannot be restored if the memory exception comes from an helper */
+        gen_update_nip(ctx, ctx->nip - 4);
+        t0 = tcg_const_i32(crb);
+        gen_helper_fpscr_setbit(cpu_env, t0);
+        tcg_temp_free_i32(t0);
+    }
+    if (unlikely(Rc(ctx->opcode) != 0)) {
+        tcg_gen_trunc_tl_i32(cpu_crf[1], cpu_fpscr);
+        tcg_gen_shri_i32(cpu_crf[1], cpu_crf[1], FPSCR_OX);
+    }
+    /* We can raise a differed exception */
+    gen_helper_float_check_status(cpu_env);
+}
+
+/* mtfsf */
+static void gen_mtfsf(DisasContext *ctx)
+{
+    TCGv_i32 t0;
+    int flm, l, w;
+
+    if (unlikely(!ctx->fpu_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_FPU);
+        return;
+    }
+    flm = FPFLM(ctx->opcode);
+    l = FPL(ctx->opcode);
+    w = FPW(ctx->opcode);
+    if (unlikely(w & !(ctx->insns_flags2 & PPC2_ISA205))) {
+        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
+        return;
+    }
+    /* NIP cannot be restored if the memory exception comes from an helper */
+    gen_update_nip(ctx, ctx->nip - 4);
+    gen_reset_fpstatus();
+    if (l) {
+        t0 = tcg_const_i32((ctx->insns_flags2 & PPC2_ISA205) ? 0xffff : 0xff);
+    } else {
+        t0 = tcg_const_i32(flm << (w * 8));
+    }
+    gen_helper_store_fpscr(cpu_env, cpu_fpr[rB(ctx->opcode)], t0);
+    tcg_temp_free_i32(t0);
+    if (unlikely(Rc(ctx->opcode) != 0)) {
+        tcg_gen_trunc_tl_i32(cpu_crf[1], cpu_fpscr);
+        tcg_gen_shri_i32(cpu_crf[1], cpu_crf[1], FPSCR_OX);
+    }
+    /* We can raise a differed exception */
+    gen_helper_float_check_status(cpu_env);
+}
+
+/* mtfsfi */
+static void gen_mtfsfi(DisasContext *ctx)
+{
+    int bf, sh, w;
+    TCGv_i64 t0;
+    TCGv_i32 t1;
+
+    if (unlikely(!ctx->fpu_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_FPU);
+        return;
+    }
+    w = FPW(ctx->opcode);
+    bf = FPBF(ctx->opcode);
+    if (unlikely(w & !(ctx->insns_flags2 & PPC2_ISA205))) {
+        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
+        return;
+    }
+    sh = (8 * w) + 7 - bf;
+    /* NIP cannot be restored if the memory exception comes from an helper */
+    gen_update_nip(ctx, ctx->nip - 4);
+    gen_reset_fpstatus();
+    t0 = tcg_const_i64(((uint64_t)FPIMM(ctx->opcode)) << (4 * sh));
+    t1 = tcg_const_i32(1 << sh);
+    gen_helper_store_fpscr(cpu_env, t0, t1);
+    tcg_temp_free_i64(t0);
+    tcg_temp_free_i32(t1);
+    if (unlikely(Rc(ctx->opcode) != 0)) {
+        tcg_gen_trunc_tl_i32(cpu_crf[1], cpu_fpscr);
+        tcg_gen_shri_i32(cpu_crf[1], cpu_crf[1], FPSCR_OX);
+    }
+    /* We can raise a differed exception */
+    gen_helper_float_check_status(cpu_env);
+}
+
+/***                         Floating-point load                           ***/
+#define GEN_LDF(name, ldop, opc, type)                                        \
+static void glue(gen_, name)(DisasContext *ctx)                                       \
+{                                                                             \
+    TCGv EA;                                                                  \
+    if (unlikely(!ctx->fpu_enabled)) {                                        \
+        gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
+        return;                                                               \
+    }                                                                         \
+    gen_set_access_type(ctx, ACCESS_FLOAT);                                   \
+    EA = tcg_temp_new();                                                      \
+    gen_addr_imm_index(ctx, EA, 0);                                           \
+    gen_qemu_##ldop(ctx, cpu_fpr[rD(ctx->opcode)], EA);                       \
+    tcg_temp_free(EA);                                                        \
+}
+
+#define GEN_LDUF(name, ldop, opc, type)                                       \
+static void glue(gen_, name##u)(DisasContext *ctx)                                    \
+{                                                                             \
+    TCGv EA;                                                                  \
+    if (unlikely(!ctx->fpu_enabled)) {                                        \
+        gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
+        return;                                                               \
+    }                                                                         \
+    if (unlikely(rA(ctx->opcode) == 0)) {                                     \
+        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);                   \
+        return;                                                               \
+    }                                                                         \
+    gen_set_access_type(ctx, ACCESS_FLOAT);                                   \
+    EA = tcg_temp_new();                                                      \
+    gen_addr_imm_index(ctx, EA, 0);                                           \
+    gen_qemu_##ldop(ctx, cpu_fpr[rD(ctx->opcode)], EA);                       \
+    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA);                             \
+    tcg_temp_free(EA);                                                        \
+}
+
+#define GEN_LDUXF(name, ldop, opc, type)                                      \
+static void glue(gen_, name##ux)(DisasContext *ctx)                                   \
+{                                                                             \
+    TCGv EA;                                                                  \
+    if (unlikely(!ctx->fpu_enabled)) {                                        \
+        gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
+        return;                                                               \
+    }                                                                         \
+    if (unlikely(rA(ctx->opcode) == 0)) {                                     \
+        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);                   \
+        return;                                                               \
+    }                                                                         \
+    gen_set_access_type(ctx, ACCESS_FLOAT);                                   \
+    EA = tcg_temp_new();                                                      \
+    gen_addr_reg_index(ctx, EA);                                              \
+    gen_qemu_##ldop(ctx, cpu_fpr[rD(ctx->opcode)], EA);                       \
+    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA);                             \
+    tcg_temp_free(EA);                                                        \
+}
+
+#define GEN_LDXF(name, ldop, opc2, opc3, type)                                \
+static void glue(gen_, name##x)(DisasContext *ctx)                                    \
+{                                                                             \
+    TCGv EA;                                                                  \
+    if (unlikely(!ctx->fpu_enabled)) {                                        \
+        gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
+        return;                                                               \
+    }                                                                         \
+    gen_set_access_type(ctx, ACCESS_FLOAT);                                   \
+    EA = tcg_temp_new();                                                      \
+    gen_addr_reg_index(ctx, EA);                                              \
+    gen_qemu_##ldop(ctx, cpu_fpr[rD(ctx->opcode)], EA);                       \
+    tcg_temp_free(EA);                                                        \
+}
+
+#define GEN_LDFS(name, ldop, op, type)                                        \
+GEN_LDF(name, ldop, op | 0x20, type);                                         \
+GEN_LDUF(name, ldop, op | 0x21, type);                                        \
+GEN_LDUXF(name, ldop, op | 0x01, type);                                       \
+GEN_LDXF(name, ldop, 0x17, op | 0x00, type)
+
+static inline void gen_qemu_ld32fs(DisasContext *ctx, TCGv_i64 arg1, TCGv arg2)
+{
+    TCGv t0 = tcg_temp_new();
+    TCGv_i32 t1 = tcg_temp_new_i32();
+    gen_qemu_ld32u(ctx, t0, arg2);
+    tcg_gen_trunc_tl_i32(t1, t0);
+    tcg_temp_free(t0);
+    gen_helper_float32_to_float64(arg1, cpu_env, t1);
+    tcg_temp_free_i32(t1);
+}
+
+ /* lfd lfdu lfdux lfdx */
+GEN_LDFS(lfd, ld64, 0x12, PPC_FLOAT);
+ /* lfs lfsu lfsux lfsx */
+GEN_LDFS(lfs, ld32fs, 0x10, PPC_FLOAT);
+
+/* lfdp */
+static void gen_lfdp(DisasContext *ctx)
+{
+    TCGv EA;
+    if (unlikely(!ctx->fpu_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_FPU);
+        return;
+    }
+    gen_set_access_type(ctx, ACCESS_FLOAT);
+    EA = tcg_temp_new();
+    gen_addr_imm_index(ctx, EA, 0);
+    /* We only need to swap high and low halves. gen_qemu_ld64 does necessary
+       64-bit byteswap already. */
+    if (unlikely(ctx->le_mode)) {
+        gen_qemu_ld64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA);
+        tcg_gen_addi_tl(EA, EA, 8);
+        gen_qemu_ld64(ctx, cpu_fpr[rD(ctx->opcode)], EA);
+    } else {
+        gen_qemu_ld64(ctx, cpu_fpr[rD(ctx->opcode)], EA);
+        tcg_gen_addi_tl(EA, EA, 8);
+        gen_qemu_ld64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA);
+    }
+    tcg_temp_free(EA);
+}
+
+/* lfdpx */
+static void gen_lfdpx(DisasContext *ctx)
+{
+    TCGv EA;
+    if (unlikely(!ctx->fpu_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_FPU);
+        return;
+    }
+    gen_set_access_type(ctx, ACCESS_FLOAT);
+    EA = tcg_temp_new();
+    gen_addr_reg_index(ctx, EA);
+    /* We only need to swap high and low halves. gen_qemu_ld64 does necessary
+       64-bit byteswap already. */
+    if (unlikely(ctx->le_mode)) {
+        gen_qemu_ld64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA);
+        tcg_gen_addi_tl(EA, EA, 8);
+        gen_qemu_ld64(ctx, cpu_fpr[rD(ctx->opcode)], EA);
+    } else {
+        gen_qemu_ld64(ctx, cpu_fpr[rD(ctx->opcode)], EA);
+        tcg_gen_addi_tl(EA, EA, 8);
+        gen_qemu_ld64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA);
+    }
+    tcg_temp_free(EA);
+}
+
+/* lfiwax */
+static void gen_lfiwax(DisasContext *ctx)
+{
+    TCGv EA;
+    TCGv t0;
+    if (unlikely(!ctx->fpu_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_FPU);
+        return;
+    }
+    gen_set_access_type(ctx, ACCESS_FLOAT);
+    EA = tcg_temp_new();
+    t0 = tcg_temp_new();
+    gen_addr_reg_index(ctx, EA);
+    gen_qemu_ld32s(ctx, t0, EA);
+    tcg_gen_ext_tl_i64(cpu_fpr[rD(ctx->opcode)], t0);
+    tcg_temp_free(EA);
+    tcg_temp_free(t0);
+}
+
+/* lfiwzx */
+static void gen_lfiwzx(DisasContext *ctx)
+{
+    TCGv EA;
+    if (unlikely(!ctx->fpu_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_FPU);
+        return;
+    }
+    gen_set_access_type(ctx, ACCESS_FLOAT);
+    EA = tcg_temp_new();
+    gen_addr_reg_index(ctx, EA);
+    gen_qemu_ld32u_i64(ctx, cpu_fpr[rD(ctx->opcode)], EA);
+    tcg_temp_free(EA);
+}
+/***                         Floating-point store                          ***/
+#define GEN_STF(name, stop, opc, type)                                        \
+static void glue(gen_, name)(DisasContext *ctx)                                       \
+{                                                                             \
+    TCGv EA;                                                                  \
+    if (unlikely(!ctx->fpu_enabled)) {                                        \
+        gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
+        return;                                                               \
+    }                                                                         \
+    gen_set_access_type(ctx, ACCESS_FLOAT);                                   \
+    EA = tcg_temp_new();                                                      \
+    gen_addr_imm_index(ctx, EA, 0);                                           \
+    gen_qemu_##stop(ctx, cpu_fpr[rS(ctx->opcode)], EA);                       \
+    tcg_temp_free(EA);                                                        \
+}
+
+#define GEN_STUF(name, stop, opc, type)                                       \
+static void glue(gen_, name##u)(DisasContext *ctx)                                    \
+{                                                                             \
+    TCGv EA;                                                                  \
+    if (unlikely(!ctx->fpu_enabled)) {                                        \
+        gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
+        return;                                                               \
+    }                                                                         \
+    if (unlikely(rA(ctx->opcode) == 0)) {                                     \
+        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);                   \
+        return;                                                               \
+    }                                                                         \
+    gen_set_access_type(ctx, ACCESS_FLOAT);                                   \
+    EA = tcg_temp_new();                                                      \
+    gen_addr_imm_index(ctx, EA, 0);                                           \
+    gen_qemu_##stop(ctx, cpu_fpr[rS(ctx->opcode)], EA);                       \
+    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA);                             \
+    tcg_temp_free(EA);                                                        \
+}
+
+#define GEN_STUXF(name, stop, opc, type)                                      \
+static void glue(gen_, name##ux)(DisasContext *ctx)                                   \
+{                                                                             \
+    TCGv EA;                                                                  \
+    if (unlikely(!ctx->fpu_enabled)) {                                        \
+        gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
+        return;                                                               \
+    }                                                                         \
+    if (unlikely(rA(ctx->opcode) == 0)) {                                     \
+        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);                   \
+        return;                                                               \
+    }                                                                         \
+    gen_set_access_type(ctx, ACCESS_FLOAT);                                   \
+    EA = tcg_temp_new();                                                      \
+    gen_addr_reg_index(ctx, EA);                                              \
+    gen_qemu_##stop(ctx, cpu_fpr[rS(ctx->opcode)], EA);                       \
+    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA);                             \
+    tcg_temp_free(EA);                                                        \
+}
+
+#define GEN_STXF(name, stop, opc2, opc3, type)                                \
+static void glue(gen_, name##x)(DisasContext *ctx)                                    \
+{                                                                             \
+    TCGv EA;                                                                  \
+    if (unlikely(!ctx->fpu_enabled)) {                                        \
+        gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
+        return;                                                               \
+    }                                                                         \
+    gen_set_access_type(ctx, ACCESS_FLOAT);                                   \
+    EA = tcg_temp_new();                                                      \
+    gen_addr_reg_index(ctx, EA);                                              \
+    gen_qemu_##stop(ctx, cpu_fpr[rS(ctx->opcode)], EA);                       \
+    tcg_temp_free(EA);                                                        \
+}
+
+#define GEN_STFS(name, stop, op, type)                                        \
+GEN_STF(name, stop, op | 0x20, type);                                         \
+GEN_STUF(name, stop, op | 0x21, type);                                        \
+GEN_STUXF(name, stop, op | 0x01, type);                                       \
+GEN_STXF(name, stop, 0x17, op | 0x00, type)
+
+static inline void gen_qemu_st32fs(DisasContext *ctx, TCGv_i64 arg1, TCGv arg2)
+{
+    TCGv_i32 t0 = tcg_temp_new_i32();
+    TCGv t1 = tcg_temp_new();
+    gen_helper_float64_to_float32(t0, cpu_env, arg1);
+    tcg_gen_extu_i32_tl(t1, t0);
+    tcg_temp_free_i32(t0);
+    gen_qemu_st32(ctx, t1, arg2);
+    tcg_temp_free(t1);
+}
+
+/* stfd stfdu stfdux stfdx */
+GEN_STFS(stfd, st64, 0x16, PPC_FLOAT);
+/* stfs stfsu stfsux stfsx */
+GEN_STFS(stfs, st32fs, 0x14, PPC_FLOAT);
+
+/* stfdp */
+static void gen_stfdp(DisasContext *ctx)
+{
+    TCGv EA;
+    if (unlikely(!ctx->fpu_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_FPU);
+        return;
+    }
+    gen_set_access_type(ctx, ACCESS_FLOAT);
+    EA = tcg_temp_new();
+    gen_addr_imm_index(ctx, EA, 0);
+    /* We only need to swap high and low halves. gen_qemu_st64 does necessary
+       64-bit byteswap already. */
+    if (unlikely(ctx->le_mode)) {
+        gen_qemu_st64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA);
+        tcg_gen_addi_tl(EA, EA, 8);
+        gen_qemu_st64(ctx, cpu_fpr[rD(ctx->opcode)], EA);
+    } else {
+        gen_qemu_st64(ctx, cpu_fpr[rD(ctx->opcode)], EA);
+        tcg_gen_addi_tl(EA, EA, 8);
+        gen_qemu_st64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA);
+    }
+    tcg_temp_free(EA);
+}
+
+/* stfdpx */
+static void gen_stfdpx(DisasContext *ctx)
+{
+    TCGv EA;
+    if (unlikely(!ctx->fpu_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_FPU);
+        return;
+    }
+    gen_set_access_type(ctx, ACCESS_FLOAT);
+    EA = tcg_temp_new();
+    gen_addr_reg_index(ctx, EA);
+    /* We only need to swap high and low halves. gen_qemu_st64 does necessary
+       64-bit byteswap already. */
+    if (unlikely(ctx->le_mode)) {
+        gen_qemu_st64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA);
+        tcg_gen_addi_tl(EA, EA, 8);
+        gen_qemu_st64(ctx, cpu_fpr[rD(ctx->opcode)], EA);
+    } else {
+        gen_qemu_st64(ctx, cpu_fpr[rD(ctx->opcode)], EA);
+        tcg_gen_addi_tl(EA, EA, 8);
+        gen_qemu_st64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA);
+    }
+    tcg_temp_free(EA);
+}
+
+/* Optional: */
+static inline void gen_qemu_st32fiw(DisasContext *ctx, TCGv_i64 arg1, TCGv arg2)
+{
+    TCGv t0 = tcg_temp_new();
+    tcg_gen_trunc_i64_tl(t0, arg1),
+    gen_qemu_st32(ctx, t0, arg2);
+    tcg_temp_free(t0);
+}
+/* stfiwx */
+GEN_STXF(stfiw, st32fiw, 0x17, 0x1E, PPC_FLOAT_STFIWX);
+
+/* POWER2 specific instructions */
+/* Quad manipulation (load/store two floats at a time) */
+
+/* lfq */
+static void gen_lfq(DisasContext *ctx)
+{
+    int rd = rD(ctx->opcode);
+    TCGv t0;
+    gen_set_access_type(ctx, ACCESS_FLOAT);
+    t0 = tcg_temp_new();
+    gen_addr_imm_index(ctx, t0, 0);
+    gen_qemu_ld64(ctx, cpu_fpr[rd], t0);
+    gen_addr_add(ctx, t0, t0, 8);
+    gen_qemu_ld64(ctx, cpu_fpr[(rd + 1) % 32], t0);
+    tcg_temp_free(t0);
+}
+
+/* lfqu */
+static void gen_lfqu(DisasContext *ctx)
+{
+    int ra = rA(ctx->opcode);
+    int rd = rD(ctx->opcode);
+    TCGv t0, t1;
+    gen_set_access_type(ctx, ACCESS_FLOAT);
+    t0 = tcg_temp_new();
+    t1 = tcg_temp_new();
+    gen_addr_imm_index(ctx, t0, 0);
+    gen_qemu_ld64(ctx, cpu_fpr[rd], t0);
+    gen_addr_add(ctx, t1, t0, 8);
+    gen_qemu_ld64(ctx, cpu_fpr[(rd + 1) % 32], t1);
+    if (ra != 0)
+        tcg_gen_mov_tl(cpu_gpr[ra], t0);
+    tcg_temp_free(t0);
+    tcg_temp_free(t1);
+}
+
+/* lfqux */
+static void gen_lfqux(DisasContext *ctx)
+{
+    int ra = rA(ctx->opcode);
+    int rd = rD(ctx->opcode);
+    gen_set_access_type(ctx, ACCESS_FLOAT);
+    TCGv t0, t1;
+    t0 = tcg_temp_new();
+    gen_addr_reg_index(ctx, t0);
+    gen_qemu_ld64(ctx, cpu_fpr[rd], t0);
+    t1 = tcg_temp_new();
+    gen_addr_add(ctx, t1, t0, 8);
+    gen_qemu_ld64(ctx, cpu_fpr[(rd + 1) % 32], t1);
+    tcg_temp_free(t1);
+    if (ra != 0)
+        tcg_gen_mov_tl(cpu_gpr[ra], t0);
+    tcg_temp_free(t0);
+}
+
+/* lfqx */
+static void gen_lfqx(DisasContext *ctx)
+{
+    int rd = rD(ctx->opcode);
+    TCGv t0;
+    gen_set_access_type(ctx, ACCESS_FLOAT);
+    t0 = tcg_temp_new();
+    gen_addr_reg_index(ctx, t0);
+    gen_qemu_ld64(ctx, cpu_fpr[rd], t0);
+    gen_addr_add(ctx, t0, t0, 8);
+    gen_qemu_ld64(ctx, cpu_fpr[(rd + 1) % 32], t0);
+    tcg_temp_free(t0);
+}
+
+/* stfq */
+static void gen_stfq(DisasContext *ctx)
+{
+    int rd = rD(ctx->opcode);
+    TCGv t0;
+    gen_set_access_type(ctx, ACCESS_FLOAT);
+    t0 = tcg_temp_new();
+    gen_addr_imm_index(ctx, t0, 0);
+    gen_qemu_st64(ctx, cpu_fpr[rd], t0);
+    gen_addr_add(ctx, t0, t0, 8);
+    gen_qemu_st64(ctx, cpu_fpr[(rd + 1) % 32], t0);
+    tcg_temp_free(t0);
+}
+
+/* stfqu */
+static void gen_stfqu(DisasContext *ctx)
+{
+    int ra = rA(ctx->opcode);
+    int rd = rD(ctx->opcode);
+    TCGv t0, t1;
+    gen_set_access_type(ctx, ACCESS_FLOAT);
+    t0 = tcg_temp_new();
+    gen_addr_imm_index(ctx, t0, 0);
+    gen_qemu_st64(ctx, cpu_fpr[rd], t0);
+    t1 = tcg_temp_new();
+    gen_addr_add(ctx, t1, t0, 8);
+    gen_qemu_st64(ctx, cpu_fpr[(rd + 1) % 32], t1);
+    tcg_temp_free(t1);
+    if (ra != 0)
+        tcg_gen_mov_tl(cpu_gpr[ra], t0);
+    tcg_temp_free(t0);
+}
+
+/* stfqux */
+static void gen_stfqux(DisasContext *ctx)
+{
+    int ra = rA(ctx->opcode);
+    int rd = rD(ctx->opcode);
+    TCGv t0, t1;
+    gen_set_access_type(ctx, ACCESS_FLOAT);
+    t0 = tcg_temp_new();
+    gen_addr_reg_index(ctx, t0);
+    gen_qemu_st64(ctx, cpu_fpr[rd], t0);
+    t1 = tcg_temp_new();
+    gen_addr_add(ctx, t1, t0, 8);
+    gen_qemu_st64(ctx, cpu_fpr[(rd + 1) % 32], t1);
+    tcg_temp_free(t1);
+    if (ra != 0)
+        tcg_gen_mov_tl(cpu_gpr[ra], t0);
+    tcg_temp_free(t0);
+}
+
+/* stfqx */
+static void gen_stfqx(DisasContext *ctx)
+{
+    int rd = rD(ctx->opcode);
+    TCGv t0;
+    gen_set_access_type(ctx, ACCESS_FLOAT);
+    t0 = tcg_temp_new();
+    gen_addr_reg_index(ctx, t0);
+    gen_qemu_st64(ctx, cpu_fpr[rd], t0);
+    gen_addr_add(ctx, t0, t0, 8);
+    gen_qemu_st64(ctx, cpu_fpr[(rd + 1) % 32], t0);
+    tcg_temp_free(t0);
+}
+
+#undef _GEN_FLOAT_ACB
+#undef GEN_FLOAT_ACB
+#undef _GEN_FLOAT_AB
+#undef GEN_FLOAT_AB
+#undef _GEN_FLOAT_AC
+#undef GEN_FLOAT_AC
+#undef GEN_FLOAT_B
+#undef GEN_FLOAT_BS
+
+#undef GEN_LDF
+#undef GEN_LDUF
+#undef GEN_LDUXF
+#undef GEN_LDXF
+#undef GEN_LDFS
+
+#undef GEN_STF
+#undef GEN_STUF
+#undef GEN_STUXF
+#undef GEN_STXF
+#undef GEN_STFS
diff --git a/target-ppc/translate/fp-ops.c b/target-ppc/translate/fp-ops.c
new file mode 100644
index 0000000..291a1e6
--- /dev/null
+++ b/target-ppc/translate/fp-ops.c
@@ -0,0 +1,111 @@
+#define _GEN_FLOAT_ACB(name, op, op1, op2, isfloat, set_fprf, type)           \
+GEN_HANDLER(f##name, op1, op2, 0xFF, 0x00000000, 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, set_fprf, type)     \
+GEN_HANDLER(f##name, op1, op2, 0xFF, inval, type)
+#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, set_fprf, type)     \
+GEN_HANDLER(f##name, op1, op2, 0xFF, inval, type)
+#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, set_fprf, type)                           \
+GEN_HANDLER(f##name, 0x3F, op2, op3, 0x001F0000, type)
+#define GEN_FLOAT_BS(name, op1, op2, set_fprf, type)                          \
+GEN_HANDLER(f##name, op1, op2, 0xFF, 0x001F07C0, type)
+
+GEN_FLOAT_AB(add, 0x15, 0x000007C0, 1, PPC_FLOAT),
+GEN_FLOAT_AB(div, 0x12, 0x000007C0, 1, PPC_FLOAT),
+GEN_FLOAT_AC(mul, 0x19, 0x0000F800, 1, PPC_FLOAT),
+GEN_FLOAT_BS(re, 0x3F, 0x18, 1, PPC_FLOAT_EXT),
+GEN_FLOAT_BS(res, 0x3B, 0x18, 1, PPC_FLOAT_FRES),
+GEN_FLOAT_BS(rsqrte, 0x3F, 0x1A, 1, PPC_FLOAT_FRSQRTE),
+_GEN_FLOAT_ACB(sel, sel, 0x3F, 0x17, 0, 0, PPC_FLOAT_FSEL),
+GEN_FLOAT_AB(sub, 0x14, 0x000007C0, 1, PPC_FLOAT),
+GEN_FLOAT_ACB(madd, 0x1D, 1, PPC_FLOAT),
+GEN_FLOAT_ACB(msub, 0x1C, 1, PPC_FLOAT),
+GEN_FLOAT_ACB(nmadd, 0x1F, 1, PPC_FLOAT),
+GEN_FLOAT_ACB(nmsub, 0x1E, 1, PPC_FLOAT),
+GEN_HANDLER_E(ftdiv, 0x3F, 0x00, 0x04, 1, PPC_NONE, PPC2_FP_TST_ISA206),
+GEN_HANDLER_E(ftsqrt, 0x3F, 0x00, 0x05, 1, PPC_NONE, PPC2_FP_TST_ISA206),
+GEN_FLOAT_B(ctiw, 0x0E, 0x00, 0, PPC_FLOAT),
+GEN_HANDLER_E(fctiwu, 0x3F, 0x0E, 0x04, 0, PPC_NONE, PPC2_FP_CVT_ISA206),
+GEN_FLOAT_B(ctiwz, 0x0F, 0x00, 0, PPC_FLOAT),
+GEN_HANDLER_E(fctiwuz, 0x3F, 0x0F, 0x04, 0, PPC_NONE, PPC2_FP_CVT_ISA206),
+GEN_FLOAT_B(rsp, 0x0C, 0x00, 1, PPC_FLOAT),
+GEN_HANDLER_E(fcfid, 0x3F, 0x0E, 0x1A, 0x001F0000, PPC_NONE, PPC2_FP_CVT_S64),
+GEN_HANDLER_E(fcfids, 0x3B, 0x0E, 0x1A, 0, PPC_NONE, PPC2_FP_CVT_ISA206),
+GEN_HANDLER_E(fcfidu, 0x3F, 0x0E, 0x1E, 0, PPC_NONE, PPC2_FP_CVT_ISA206),
+GEN_HANDLER_E(fcfidus, 0x3B, 0x0E, 0x1E, 0, PPC_NONE, PPC2_FP_CVT_ISA206),
+GEN_HANDLER_E(fctid, 0x3F, 0x0E, 0x19, 0x001F0000, PPC_NONE, PPC2_FP_CVT_S64),
+GEN_HANDLER_E(fctidu, 0x3F, 0x0E, 0x1D, 0, PPC_NONE, PPC2_FP_CVT_ISA206),
+GEN_HANDLER_E(fctidz, 0x3F, 0x0F, 0x19, 0x001F0000, PPC_NONE, PPC2_FP_CVT_S64),
+GEN_HANDLER_E(fctiduz, 0x3F, 0x0F, 0x1D, 0, PPC_NONE, PPC2_FP_CVT_ISA206),
+GEN_FLOAT_B(rin, 0x08, 0x0C, 1, PPC_FLOAT_EXT),
+GEN_FLOAT_B(riz, 0x08, 0x0D, 1, PPC_FLOAT_EXT),
+GEN_FLOAT_B(rip, 0x08, 0x0E, 1, PPC_FLOAT_EXT),
+GEN_FLOAT_B(rim, 0x08, 0x0F, 1, PPC_FLOAT_EXT),
+
+#define GEN_LDF(name, ldop, opc, type)                                        \
+GEN_HANDLER(name, opc, 0xFF, 0xFF, 0x00000000, type),
+#define GEN_LDUF(name, ldop, opc, type)                                       \
+GEN_HANDLER(name##u, opc, 0xFF, 0xFF, 0x00000000, type),
+#define GEN_LDUXF(name, ldop, opc, type)                                      \
+GEN_HANDLER(name##ux, 0x1F, 0x17, opc, 0x00000001, type),
+#define GEN_LDXF(name, ldop, opc2, opc3, type)                                \
+GEN_HANDLER(name##x, 0x1F, opc2, opc3, 0x00000001, type),
+#define GEN_LDFS(name, ldop, op, type)                                        \
+GEN_LDF(name, ldop, op | 0x20, type)                                          \
+GEN_LDUF(name, ldop, op | 0x21, type)                                         \
+GEN_LDUXF(name, ldop, op | 0x01, type)                                        \
+GEN_LDXF(name, ldop, 0x17, op | 0x00, type)
+
+GEN_LDFS(lfd, ld64, 0x12, PPC_FLOAT)
+GEN_LDFS(lfs, ld32fs, 0x10, PPC_FLOAT)
+GEN_HANDLER_E(lfiwax, 0x1f, 0x17, 0x1a, 0x00000001, PPC_NONE, PPC2_ISA205),
+GEN_HANDLER_E(lfiwzx, 0x1f, 0x17, 0x1b, 0x1, PPC_NONE, PPC2_FP_CVT_ISA206),
+GEN_HANDLER_E(lfdp, 0x39, 0xFF, 0xFF, 0x00200003, PPC_NONE, PPC2_ISA205),
+GEN_HANDLER_E(lfdpx, 0x1F, 0x17, 0x18, 0x00200001, PPC_NONE, PPC2_ISA205),
+
+#define GEN_STF(name, stop, opc, type)                                        \
+GEN_HANDLER(name, opc, 0xFF, 0xFF, 0x00000000, type),
+#define GEN_STUF(name, stop, opc, type)                                       \
+GEN_HANDLER(name##u, opc, 0xFF, 0xFF, 0x00000000, type),
+#define GEN_STUXF(name, stop, opc, type)                                      \
+GEN_HANDLER(name##ux, 0x1F, 0x17, opc, 0x00000001, type),
+#define GEN_STXF(name, stop, opc2, opc3, type)                                \
+GEN_HANDLER(name##x, 0x1F, opc2, opc3, 0x00000001, type),
+#define GEN_STFS(name, stop, op, type)                                        \
+GEN_STF(name, stop, op | 0x20, type)                                          \
+GEN_STUF(name, stop, op | 0x21, type)                                         \
+GEN_STUXF(name, stop, op | 0x01, type)                                        \
+GEN_STXF(name, stop, 0x17, op | 0x00, type)
+
+GEN_STFS(stfd, st64, 0x16, PPC_FLOAT)
+GEN_STFS(stfs, st32fs, 0x14, PPC_FLOAT)
+GEN_STXF(stfiw, st32fiw, 0x17, 0x1E, PPC_FLOAT_STFIWX)
+GEN_HANDLER_E(stfdp, 0x3D, 0xFF, 0xFF, 0x00200003, PPC_NONE, PPC2_ISA205),
+GEN_HANDLER_E(stfdpx, 0x1F, 0x17, 0x1C, 0x00200001, PPC_NONE, PPC2_ISA205),
+
+GEN_HANDLER(frsqrtes, 0x3B, 0x1A, 0xFF, 0x001F07C0, PPC_FLOAT_FRSQRTES),
+GEN_HANDLER(fsqrt, 0x3F, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_FSQRT),
+GEN_HANDLER(fsqrts, 0x3B, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_FSQRT),
+GEN_HANDLER(fcmpo, 0x3F, 0x00, 0x01, 0x00600001, PPC_FLOAT),
+GEN_HANDLER(fcmpu, 0x3F, 0x00, 0x00, 0x00600001, PPC_FLOAT),
+GEN_HANDLER(fabs, 0x3F, 0x08, 0x08, 0x001F0000, PPC_FLOAT),
+GEN_HANDLER(fmr, 0x3F, 0x08, 0x02, 0x001F0000, PPC_FLOAT),
+GEN_HANDLER(fnabs, 0x3F, 0x08, 0x04, 0x001F0000, PPC_FLOAT),
+GEN_HANDLER(fneg, 0x3F, 0x08, 0x01, 0x001F0000, PPC_FLOAT),
+GEN_HANDLER_E(fcpsgn, 0x3F, 0x08, 0x00, 0x00000000, PPC_NONE, PPC2_ISA205),
+GEN_HANDLER_E(fmrgew, 0x3F, 0x06, 0x1E, 0x00000001, PPC_NONE, PPC2_VSX207),
+GEN_HANDLER_E(fmrgow, 0x3F, 0x06, 0x1A, 0x00000001, PPC_NONE, PPC2_VSX207),
+GEN_HANDLER(mcrfs, 0x3F, 0x00, 0x02, 0x0063F801, PPC_FLOAT),
+GEN_HANDLER(mffs, 0x3F, 0x07, 0x12, 0x001FF800, PPC_FLOAT),
+GEN_HANDLER(mtfsb0, 0x3F, 0x06, 0x02, 0x001FF800, PPC_FLOAT),
+GEN_HANDLER(mtfsb1, 0x3F, 0x06, 0x01, 0x001FF800, PPC_FLOAT),
+GEN_HANDLER(mtfsf, 0x3F, 0x07, 0x16, 0x00000000, PPC_FLOAT),
+GEN_HANDLER(mtfsfi, 0x3F, 0x06, 0x04, 0x006e0800, PPC_FLOAT),
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [Qemu-devel] [PATCH 04/32] ppc: Move embedded spe ops out of translate.c
  2016-07-26 22:20 [Qemu-devel] [PATCH 01/32] ppc: Fix fault PC reporting for lve*/stve* VMX instructions Benjamin Herrenschmidt
  2016-07-26 22:20 ` [Qemu-devel] [PATCH 02/32] ppc: Provide basic raise_exception_* functions Benjamin Herrenschmidt
  2016-07-26 22:20 ` [Qemu-devel] [PATCH 03/32] ppc: Move classic fp ops out of translate.c Benjamin Herrenschmidt
@ 2016-07-26 22:20 ` Benjamin Herrenschmidt
  2016-07-26 22:20 ` [Qemu-devel] [PATCH 05/32] ppc: Move DFP " Benjamin Herrenschmidt
                   ` (28 subsequent siblings)
  31 siblings, 0 replies; 69+ messages in thread
From: Benjamin Herrenschmidt @ 2016-07-26 22:20 UTC (permalink / raw)
  To: qemu-ppc; +Cc: qemu-devel, david, Benjamin Herrenschmidt

Makes things a bit more manageable

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
 target-ppc/translate.c          | 1328 +--------------------------------------
 target-ppc/translate/spe-impl.c | 1229 ++++++++++++++++++++++++++++++++++++
 target-ppc/translate/spe-ops.c  |  106 ++++
 3 files changed, 1337 insertions(+), 1326 deletions(-)
 create mode 100644 target-ppc/translate/spe-impl.c
 create mode 100644 target-ppc/translate/spe-ops.c

diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index e42f576..3b96bed 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -7495,1226 +7495,7 @@ GEN_DFP_T_FPR_I32_Rc(dscliq, rA, DCM)
 GEN_DFP_T_FPR_I32_Rc(dscri, rA, DCM)
 GEN_DFP_T_FPR_I32_Rc(dscriq, rA, DCM)
 
-/***                           SPE extension                               ***/
-/* Register moves */
-
-static inline void gen_evmra(DisasContext *ctx)
-{
-
-    if (unlikely(!ctx->spe_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_SPEU);
-        return;
-    }
-
-    TCGv_i64 tmp = tcg_temp_new_i64();
-
-    /* tmp := rA_lo + rA_hi << 32 */
-    tcg_gen_concat_tl_i64(tmp, cpu_gpr[rA(ctx->opcode)], cpu_gprh[rA(ctx->opcode)]);
-
-    /* spe_acc := tmp */
-    tcg_gen_st_i64(tmp, cpu_env, offsetof(CPUPPCState, spe_acc));
-    tcg_temp_free_i64(tmp);
-
-    /* rD := rA */
-    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
-    tcg_gen_mov_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)]);
-}
-
-static inline void gen_load_gpr64(TCGv_i64 t, int reg)
-{
-    tcg_gen_concat_tl_i64(t, cpu_gpr[reg], cpu_gprh[reg]);
-}
-
-static inline void gen_store_gpr64(int reg, TCGv_i64 t)
-{
-    tcg_gen_extr_i64_tl(cpu_gpr[reg], cpu_gprh[reg], t);
-}
-
-#define GEN_SPE(name0, name1, opc2, opc3, inval0, inval1, type)         \
-static void glue(gen_, name0##_##name1)(DisasContext *ctx)                    \
-{                                                                             \
-    if (Rc(ctx->opcode))                                                      \
-        gen_##name1(ctx);                                                     \
-    else                                                                      \
-        gen_##name0(ctx);                                                     \
-}
-
-/* Handler for undefined SPE opcodes */
-static inline void gen_speundef(DisasContext *ctx)
-{
-    gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
-}
-
-/* SPE logic */
-#define GEN_SPEOP_LOGIC2(name, tcg_op)                                        \
-static inline void gen_##name(DisasContext *ctx)                              \
-{                                                                             \
-    if (unlikely(!ctx->spe_enabled)) {                                        \
-        gen_exception(ctx, POWERPC_EXCP_SPEU);                                \
-        return;                                                               \
-    }                                                                         \
-    tcg_op(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)],                \
-           cpu_gpr[rB(ctx->opcode)]);                                         \
-    tcg_op(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)],              \
-           cpu_gprh[rB(ctx->opcode)]);                                        \
-}
-
-GEN_SPEOP_LOGIC2(evand, tcg_gen_and_tl);
-GEN_SPEOP_LOGIC2(evandc, tcg_gen_andc_tl);
-GEN_SPEOP_LOGIC2(evxor, tcg_gen_xor_tl);
-GEN_SPEOP_LOGIC2(evor, tcg_gen_or_tl);
-GEN_SPEOP_LOGIC2(evnor, tcg_gen_nor_tl);
-GEN_SPEOP_LOGIC2(eveqv, tcg_gen_eqv_tl);
-GEN_SPEOP_LOGIC2(evorc, tcg_gen_orc_tl);
-GEN_SPEOP_LOGIC2(evnand, tcg_gen_nand_tl);
-
-/* SPE logic immediate */
-#define GEN_SPEOP_TCG_LOGIC_IMM2(name, tcg_opi)                               \
-static inline void gen_##name(DisasContext *ctx)                              \
-{                                                                             \
-    TCGv_i32 t0;                                                              \
-    if (unlikely(!ctx->spe_enabled)) {                                        \
-        gen_exception(ctx, POWERPC_EXCP_SPEU);                                \
-        return;                                                               \
-    }                                                                         \
-    t0 = tcg_temp_new_i32();                                                  \
-                                                                              \
-    tcg_gen_trunc_tl_i32(t0, cpu_gpr[rA(ctx->opcode)]);                       \
-    tcg_opi(t0, t0, rB(ctx->opcode));                                         \
-    tcg_gen_extu_i32_tl(cpu_gpr[rD(ctx->opcode)], t0);                        \
-                                                                              \
-    tcg_gen_trunc_tl_i32(t0, cpu_gprh[rA(ctx->opcode)]);                      \
-    tcg_opi(t0, t0, rB(ctx->opcode));                                         \
-    tcg_gen_extu_i32_tl(cpu_gprh[rD(ctx->opcode)], t0);                       \
-                                                                              \
-    tcg_temp_free_i32(t0);                                                    \
-}
-GEN_SPEOP_TCG_LOGIC_IMM2(evslwi, tcg_gen_shli_i32);
-GEN_SPEOP_TCG_LOGIC_IMM2(evsrwiu, tcg_gen_shri_i32);
-GEN_SPEOP_TCG_LOGIC_IMM2(evsrwis, tcg_gen_sari_i32);
-GEN_SPEOP_TCG_LOGIC_IMM2(evrlwi, tcg_gen_rotli_i32);
-
-/* SPE arithmetic */
-#define GEN_SPEOP_ARITH1(name, tcg_op)                                        \
-static inline void gen_##name(DisasContext *ctx)                              \
-{                                                                             \
-    TCGv_i32 t0;                                                              \
-    if (unlikely(!ctx->spe_enabled)) {                                        \
-        gen_exception(ctx, POWERPC_EXCP_SPEU);                                \
-        return;                                                               \
-    }                                                                         \
-    t0 = tcg_temp_new_i32();                                                  \
-                                                                              \
-    tcg_gen_trunc_tl_i32(t0, cpu_gpr[rA(ctx->opcode)]);                       \
-    tcg_op(t0, t0);                                                           \
-    tcg_gen_extu_i32_tl(cpu_gpr[rD(ctx->opcode)], t0);                        \
-                                                                              \
-    tcg_gen_trunc_tl_i32(t0, cpu_gprh[rA(ctx->opcode)]);                      \
-    tcg_op(t0, t0);                                                           \
-    tcg_gen_extu_i32_tl(cpu_gprh[rD(ctx->opcode)], t0);                       \
-                                                                              \
-    tcg_temp_free_i32(t0);                                                    \
-}
-
-static inline void gen_op_evabs(TCGv_i32 ret, TCGv_i32 arg1)
-{
-    TCGLabel *l1 = gen_new_label();
-    TCGLabel *l2 = gen_new_label();
-
-    tcg_gen_brcondi_i32(TCG_COND_GE, arg1, 0, l1);
-    tcg_gen_neg_i32(ret, arg1);
-    tcg_gen_br(l2);
-    gen_set_label(l1);
-    tcg_gen_mov_i32(ret, arg1);
-    gen_set_label(l2);
-}
-GEN_SPEOP_ARITH1(evabs, gen_op_evabs);
-GEN_SPEOP_ARITH1(evneg, tcg_gen_neg_i32);
-GEN_SPEOP_ARITH1(evextsb, tcg_gen_ext8s_i32);
-GEN_SPEOP_ARITH1(evextsh, tcg_gen_ext16s_i32);
-static inline void gen_op_evrndw(TCGv_i32 ret, TCGv_i32 arg1)
-{
-    tcg_gen_addi_i32(ret, arg1, 0x8000);
-    tcg_gen_ext16u_i32(ret, ret);
-}
-GEN_SPEOP_ARITH1(evrndw, gen_op_evrndw);
-GEN_SPEOP_ARITH1(evcntlsw, gen_helper_cntlsw32);
-GEN_SPEOP_ARITH1(evcntlzw, gen_helper_cntlzw32);
-
-#define GEN_SPEOP_ARITH2(name, tcg_op)                                        \
-static inline void gen_##name(DisasContext *ctx)                              \
-{                                                                             \
-    TCGv_i32 t0, t1;                                                          \
-    if (unlikely(!ctx->spe_enabled)) {                                        \
-        gen_exception(ctx, POWERPC_EXCP_SPEU);                                \
-        return;                                                               \
-    }                                                                         \
-    t0 = tcg_temp_new_i32();                                                  \
-    t1 = tcg_temp_new_i32();                                                  \
-                                                                              \
-    tcg_gen_trunc_tl_i32(t0, cpu_gpr[rA(ctx->opcode)]);                       \
-    tcg_gen_trunc_tl_i32(t1, cpu_gpr[rB(ctx->opcode)]);                       \
-    tcg_op(t0, t0, t1);                                                       \
-    tcg_gen_extu_i32_tl(cpu_gpr[rD(ctx->opcode)], t0);                        \
-                                                                              \
-    tcg_gen_trunc_tl_i32(t0, cpu_gprh[rA(ctx->opcode)]);                      \
-    tcg_gen_trunc_tl_i32(t1, cpu_gprh[rB(ctx->opcode)]);                      \
-    tcg_op(t0, t0, t1);                                                       \
-    tcg_gen_extu_i32_tl(cpu_gprh[rD(ctx->opcode)], t0);                       \
-                                                                              \
-    tcg_temp_free_i32(t0);                                                    \
-    tcg_temp_free_i32(t1);                                                    \
-}
-
-static inline void gen_op_evsrwu(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
-{
-    TCGLabel *l1 = gen_new_label();
-    TCGLabel *l2 = gen_new_label();
-    TCGv_i32 t0 = tcg_temp_local_new_i32();
-
-    /* No error here: 6 bits are used */
-    tcg_gen_andi_i32(t0, arg2, 0x3F);
-    tcg_gen_brcondi_i32(TCG_COND_GE, t0, 32, l1);
-    tcg_gen_shr_i32(ret, arg1, t0);
-    tcg_gen_br(l2);
-    gen_set_label(l1);
-    tcg_gen_movi_i32(ret, 0);
-    gen_set_label(l2);
-    tcg_temp_free_i32(t0);
-}
-GEN_SPEOP_ARITH2(evsrwu, gen_op_evsrwu);
-static inline void gen_op_evsrws(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
-{
-    TCGLabel *l1 = gen_new_label();
-    TCGLabel *l2 = gen_new_label();
-    TCGv_i32 t0 = tcg_temp_local_new_i32();
-
-    /* No error here: 6 bits are used */
-    tcg_gen_andi_i32(t0, arg2, 0x3F);
-    tcg_gen_brcondi_i32(TCG_COND_GE, t0, 32, l1);
-    tcg_gen_sar_i32(ret, arg1, t0);
-    tcg_gen_br(l2);
-    gen_set_label(l1);
-    tcg_gen_movi_i32(ret, 0);
-    gen_set_label(l2);
-    tcg_temp_free_i32(t0);
-}
-GEN_SPEOP_ARITH2(evsrws, gen_op_evsrws);
-static inline void gen_op_evslw(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
-{
-    TCGLabel *l1 = gen_new_label();
-    TCGLabel *l2 = gen_new_label();
-    TCGv_i32 t0 = tcg_temp_local_new_i32();
-
-    /* No error here: 6 bits are used */
-    tcg_gen_andi_i32(t0, arg2, 0x3F);
-    tcg_gen_brcondi_i32(TCG_COND_GE, t0, 32, l1);
-    tcg_gen_shl_i32(ret, arg1, t0);
-    tcg_gen_br(l2);
-    gen_set_label(l1);
-    tcg_gen_movi_i32(ret, 0);
-    gen_set_label(l2);
-    tcg_temp_free_i32(t0);
-}
-GEN_SPEOP_ARITH2(evslw, gen_op_evslw);
-static inline void gen_op_evrlw(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
-{
-    TCGv_i32 t0 = tcg_temp_new_i32();
-    tcg_gen_andi_i32(t0, arg2, 0x1F);
-    tcg_gen_rotl_i32(ret, arg1, t0);
-    tcg_temp_free_i32(t0);
-}
-GEN_SPEOP_ARITH2(evrlw, gen_op_evrlw);
-static inline void gen_evmergehi(DisasContext *ctx)
-{
-    if (unlikely(!ctx->spe_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_SPEU);
-        return;
-    }
-    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gprh[rB(ctx->opcode)]);
-    tcg_gen_mov_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)]);
-}
-GEN_SPEOP_ARITH2(evaddw, tcg_gen_add_i32);
-static inline void gen_op_evsubf(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
-{
-    tcg_gen_sub_i32(ret, arg2, arg1);
-}
-GEN_SPEOP_ARITH2(evsubfw, gen_op_evsubf);
-
-/* SPE arithmetic immediate */
-#define GEN_SPEOP_ARITH_IMM2(name, tcg_op)                                    \
-static inline void gen_##name(DisasContext *ctx)                              \
-{                                                                             \
-    TCGv_i32 t0;                                                              \
-    if (unlikely(!ctx->spe_enabled)) {                                        \
-        gen_exception(ctx, POWERPC_EXCP_SPEU);                                \
-        return;                                                               \
-    }                                                                         \
-    t0 = tcg_temp_new_i32();                                                  \
-                                                                              \
-    tcg_gen_trunc_tl_i32(t0, cpu_gpr[rB(ctx->opcode)]);                       \
-    tcg_op(t0, t0, rA(ctx->opcode));                                          \
-    tcg_gen_extu_i32_tl(cpu_gpr[rD(ctx->opcode)], t0);                        \
-                                                                              \
-    tcg_gen_trunc_tl_i32(t0, cpu_gprh[rB(ctx->opcode)]);                      \
-    tcg_op(t0, t0, rA(ctx->opcode));                                          \
-    tcg_gen_extu_i32_tl(cpu_gprh[rD(ctx->opcode)], t0);                       \
-                                                                              \
-    tcg_temp_free_i32(t0);                                                    \
-}
-GEN_SPEOP_ARITH_IMM2(evaddiw, tcg_gen_addi_i32);
-GEN_SPEOP_ARITH_IMM2(evsubifw, tcg_gen_subi_i32);
-
-/* SPE comparison */
-#define GEN_SPEOP_COMP(name, tcg_cond)                                        \
-static inline void gen_##name(DisasContext *ctx)                              \
-{                                                                             \
-    if (unlikely(!ctx->spe_enabled)) {                                        \
-        gen_exception(ctx, POWERPC_EXCP_SPEU);                                \
-        return;                                                               \
-    }                                                                         \
-    TCGLabel *l1 = gen_new_label();                                           \
-    TCGLabel *l2 = gen_new_label();                                           \
-    TCGLabel *l3 = gen_new_label();                                           \
-    TCGLabel *l4 = gen_new_label();                                           \
-                                                                              \
-    tcg_gen_ext32s_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);    \
-    tcg_gen_ext32s_tl(cpu_gpr[rB(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);    \
-    tcg_gen_ext32s_tl(cpu_gprh[rA(ctx->opcode)], cpu_gprh[rA(ctx->opcode)]);  \
-    tcg_gen_ext32s_tl(cpu_gprh[rB(ctx->opcode)], cpu_gprh[rB(ctx->opcode)]);  \
-                                                                              \
-    tcg_gen_brcond_tl(tcg_cond, cpu_gpr[rA(ctx->opcode)],                     \
-                       cpu_gpr[rB(ctx->opcode)], l1);                         \
-    tcg_gen_movi_i32(cpu_crf[crfD(ctx->opcode)], 0);                          \
-    tcg_gen_br(l2);                                                           \
-    gen_set_label(l1);                                                        \
-    tcg_gen_movi_i32(cpu_crf[crfD(ctx->opcode)],                              \
-                     CRF_CL | CRF_CH_OR_CL | CRF_CH_AND_CL);                  \
-    gen_set_label(l2);                                                        \
-    tcg_gen_brcond_tl(tcg_cond, cpu_gprh[rA(ctx->opcode)],                    \
-                       cpu_gprh[rB(ctx->opcode)], l3);                        \
-    tcg_gen_andi_i32(cpu_crf[crfD(ctx->opcode)], cpu_crf[crfD(ctx->opcode)],  \
-                     ~(CRF_CH | CRF_CH_AND_CL));                              \
-    tcg_gen_br(l4);                                                           \
-    gen_set_label(l3);                                                        \
-    tcg_gen_ori_i32(cpu_crf[crfD(ctx->opcode)], cpu_crf[crfD(ctx->opcode)],   \
-                    CRF_CH | CRF_CH_OR_CL);                                   \
-    gen_set_label(l4);                                                        \
-}
-GEN_SPEOP_COMP(evcmpgtu, TCG_COND_GTU);
-GEN_SPEOP_COMP(evcmpgts, TCG_COND_GT);
-GEN_SPEOP_COMP(evcmpltu, TCG_COND_LTU);
-GEN_SPEOP_COMP(evcmplts, TCG_COND_LT);
-GEN_SPEOP_COMP(evcmpeq, TCG_COND_EQ);
-
-/* SPE misc */
-static inline void gen_brinc(DisasContext *ctx)
-{
-    /* Note: brinc is usable even if SPE is disabled */
-    gen_helper_brinc(cpu_gpr[rD(ctx->opcode)],
-                     cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
-}
-static inline void gen_evmergelo(DisasContext *ctx)
-{
-    if (unlikely(!ctx->spe_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_SPEU);
-        return;
-    }
-    tcg_gen_mov_tl(cpu_gprh[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
-    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
-}
-static inline void gen_evmergehilo(DisasContext *ctx)
-{
-    if (unlikely(!ctx->spe_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_SPEU);
-        return;
-    }
-    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
-    tcg_gen_mov_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)]);
-}
-static inline void gen_evmergelohi(DisasContext *ctx)
-{
-    if (unlikely(!ctx->spe_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_SPEU);
-        return;
-    }
-    if (rD(ctx->opcode) == rA(ctx->opcode)) {
-        TCGv tmp = tcg_temp_new();
-        tcg_gen_mov_tl(tmp, cpu_gpr[rA(ctx->opcode)]);
-        tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gprh[rB(ctx->opcode)]);
-        tcg_gen_mov_tl(cpu_gprh[rD(ctx->opcode)], tmp);
-        tcg_temp_free(tmp);
-    } else {
-        tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gprh[rB(ctx->opcode)]);
-        tcg_gen_mov_tl(cpu_gprh[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
-    }
-}
-static inline void gen_evsplati(DisasContext *ctx)
-{
-    uint64_t imm = ((int32_t)(rA(ctx->opcode) << 27)) >> 27;
-
-    tcg_gen_movi_tl(cpu_gpr[rD(ctx->opcode)], imm);
-    tcg_gen_movi_tl(cpu_gprh[rD(ctx->opcode)], imm);
-}
-static inline void gen_evsplatfi(DisasContext *ctx)
-{
-    uint64_t imm = rA(ctx->opcode) << 27;
-
-    tcg_gen_movi_tl(cpu_gpr[rD(ctx->opcode)], imm);
-    tcg_gen_movi_tl(cpu_gprh[rD(ctx->opcode)], imm);
-}
-
-static inline void gen_evsel(DisasContext *ctx)
-{
-    TCGLabel *l1 = gen_new_label();
-    TCGLabel *l2 = gen_new_label();
-    TCGLabel *l3 = gen_new_label();
-    TCGLabel *l4 = gen_new_label();
-    TCGv_i32 t0 = tcg_temp_local_new_i32();
-
-    tcg_gen_andi_i32(t0, cpu_crf[ctx->opcode & 0x07], 1 << 3);
-    tcg_gen_brcondi_i32(TCG_COND_EQ, t0, 0, l1);
-    tcg_gen_mov_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)]);
-    tcg_gen_br(l2);
-    gen_set_label(l1);
-    tcg_gen_mov_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rB(ctx->opcode)]);
-    gen_set_label(l2);
-    tcg_gen_andi_i32(t0, cpu_crf[ctx->opcode & 0x07], 1 << 2);
-    tcg_gen_brcondi_i32(TCG_COND_EQ, t0, 0, l3);
-    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
-    tcg_gen_br(l4);
-    gen_set_label(l3);
-    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
-    gen_set_label(l4);
-    tcg_temp_free_i32(t0);
-}
-
-static void gen_evsel0(DisasContext *ctx)
-{
-    gen_evsel(ctx);
-}
-
-static void gen_evsel1(DisasContext *ctx)
-{
-    gen_evsel(ctx);
-}
-
-static void gen_evsel2(DisasContext *ctx)
-{
-    gen_evsel(ctx);
-}
-
-static void gen_evsel3(DisasContext *ctx)
-{
-    gen_evsel(ctx);
-}
-
-/* Multiply */
-
-static inline void gen_evmwumi(DisasContext *ctx)
-{
-    TCGv_i64 t0, t1;
-
-    if (unlikely(!ctx->spe_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_SPEU);
-        return;
-    }
-
-    t0 = tcg_temp_new_i64();
-    t1 = tcg_temp_new_i64();
-
-    /* t0 := rA; t1 := rB */
-    tcg_gen_extu_tl_i64(t0, cpu_gpr[rA(ctx->opcode)]);
-    tcg_gen_ext32u_i64(t0, t0);
-    tcg_gen_extu_tl_i64(t1, cpu_gpr[rB(ctx->opcode)]);
-    tcg_gen_ext32u_i64(t1, t1);
-
-    tcg_gen_mul_i64(t0, t0, t1);  /* t0 := rA * rB */
-
-    gen_store_gpr64(rD(ctx->opcode), t0); /* rD := t0 */
-
-    tcg_temp_free_i64(t0);
-    tcg_temp_free_i64(t1);
-}
-
-static inline void gen_evmwumia(DisasContext *ctx)
-{
-    TCGv_i64 tmp;
-
-    if (unlikely(!ctx->spe_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_SPEU);
-        return;
-    }
-
-    gen_evmwumi(ctx);            /* rD := rA * rB */
-
-    tmp = tcg_temp_new_i64();
-
-    /* acc := rD */
-    gen_load_gpr64(tmp, rD(ctx->opcode));
-    tcg_gen_st_i64(tmp, cpu_env, offsetof(CPUPPCState, spe_acc));
-    tcg_temp_free_i64(tmp);
-}
-
-static inline void gen_evmwumiaa(DisasContext *ctx)
-{
-    TCGv_i64 acc;
-    TCGv_i64 tmp;
-
-    if (unlikely(!ctx->spe_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_SPEU);
-        return;
-    }
-
-    gen_evmwumi(ctx);           /* rD := rA * rB */
-
-    acc = tcg_temp_new_i64();
-    tmp = tcg_temp_new_i64();
-
-    /* tmp := rD */
-    gen_load_gpr64(tmp, rD(ctx->opcode));
-
-    /* Load acc */
-    tcg_gen_ld_i64(acc, cpu_env, offsetof(CPUPPCState, spe_acc));
-
-    /* acc := tmp + acc */
-    tcg_gen_add_i64(acc, acc, tmp);
-
-    /* Store acc */
-    tcg_gen_st_i64(acc, cpu_env, offsetof(CPUPPCState, spe_acc));
-
-    /* rD := acc */
-    gen_store_gpr64(rD(ctx->opcode), acc);
-
-    tcg_temp_free_i64(acc);
-    tcg_temp_free_i64(tmp);
-}
-
-static inline void gen_evmwsmi(DisasContext *ctx)
-{
-    TCGv_i64 t0, t1;
-
-    if (unlikely(!ctx->spe_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_SPEU);
-        return;
-    }
-
-    t0 = tcg_temp_new_i64();
-    t1 = tcg_temp_new_i64();
-
-    /* t0 := rA; t1 := rB */
-    tcg_gen_extu_tl_i64(t0, cpu_gpr[rA(ctx->opcode)]);
-    tcg_gen_ext32s_i64(t0, t0);
-    tcg_gen_extu_tl_i64(t1, cpu_gpr[rB(ctx->opcode)]);
-    tcg_gen_ext32s_i64(t1, t1);
-
-    tcg_gen_mul_i64(t0, t0, t1);  /* t0 := rA * rB */
-
-    gen_store_gpr64(rD(ctx->opcode), t0); /* rD := t0 */
-
-    tcg_temp_free_i64(t0);
-    tcg_temp_free_i64(t1);
-}
-
-static inline void gen_evmwsmia(DisasContext *ctx)
-{
-    TCGv_i64 tmp;
-
-    gen_evmwsmi(ctx);            /* rD := rA * rB */
-
-    tmp = tcg_temp_new_i64();
-
-    /* acc := rD */
-    gen_load_gpr64(tmp, rD(ctx->opcode));
-    tcg_gen_st_i64(tmp, cpu_env, offsetof(CPUPPCState, spe_acc));
-
-    tcg_temp_free_i64(tmp);
-}
-
-static inline void gen_evmwsmiaa(DisasContext *ctx)
-{
-    TCGv_i64 acc = tcg_temp_new_i64();
-    TCGv_i64 tmp = tcg_temp_new_i64();
-
-    gen_evmwsmi(ctx);           /* rD := rA * rB */
-
-    acc = tcg_temp_new_i64();
-    tmp = tcg_temp_new_i64();
-
-    /* tmp := rD */
-    gen_load_gpr64(tmp, rD(ctx->opcode));
-
-    /* Load acc */
-    tcg_gen_ld_i64(acc, cpu_env, offsetof(CPUPPCState, spe_acc));
-
-    /* acc := tmp + acc */
-    tcg_gen_add_i64(acc, acc, tmp);
-
-    /* Store acc */
-    tcg_gen_st_i64(acc, cpu_env, offsetof(CPUPPCState, spe_acc));
-
-    /* rD := acc */
-    gen_store_gpr64(rD(ctx->opcode), acc);
-
-    tcg_temp_free_i64(acc);
-    tcg_temp_free_i64(tmp);
-}
-
-GEN_SPE(evaddw,      speundef,    0x00, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE); ////
-GEN_SPE(evaddiw,     speundef,    0x01, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE);
-GEN_SPE(evsubfw,     speundef,    0x02, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE); ////
-GEN_SPE(evsubifw,    speundef,    0x03, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE);
-GEN_SPE(evabs,       evneg,       0x04, 0x08, 0x0000F800, 0x0000F800, PPC_SPE); ////
-GEN_SPE(evextsb,     evextsh,     0x05, 0x08, 0x0000F800, 0x0000F800, PPC_SPE); ////
-GEN_SPE(evrndw,      evcntlzw,    0x06, 0x08, 0x0000F800, 0x0000F800, PPC_SPE); ////
-GEN_SPE(evcntlsw,    brinc,       0x07, 0x08, 0x0000F800, 0x00000000, PPC_SPE); //
-GEN_SPE(evmra,       speundef,    0x02, 0x13, 0x0000F800, 0xFFFFFFFF, PPC_SPE);
-GEN_SPE(speundef,    evand,       0x08, 0x08, 0xFFFFFFFF, 0x00000000, PPC_SPE); ////
-GEN_SPE(evandc,      speundef,    0x09, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE); ////
-GEN_SPE(evxor,       evor,        0x0B, 0x08, 0x00000000, 0x00000000, PPC_SPE); ////
-GEN_SPE(evnor,       eveqv,       0x0C, 0x08, 0x00000000, 0x00000000, PPC_SPE); ////
-GEN_SPE(evmwumi,     evmwsmi,     0x0C, 0x11, 0x00000000, 0x00000000, PPC_SPE);
-GEN_SPE(evmwumia,    evmwsmia,    0x1C, 0x11, 0x00000000, 0x00000000, PPC_SPE);
-GEN_SPE(evmwumiaa,   evmwsmiaa,   0x0C, 0x15, 0x00000000, 0x00000000, PPC_SPE);
-GEN_SPE(speundef,    evorc,       0x0D, 0x08, 0xFFFFFFFF, 0x00000000, PPC_SPE); ////
-GEN_SPE(evnand,      speundef,    0x0F, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE); ////
-GEN_SPE(evsrwu,      evsrws,      0x10, 0x08, 0x00000000, 0x00000000, PPC_SPE); ////
-GEN_SPE(evsrwiu,     evsrwis,     0x11, 0x08, 0x00000000, 0x00000000, PPC_SPE);
-GEN_SPE(evslw,       speundef,    0x12, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE); ////
-GEN_SPE(evslwi,      speundef,    0x13, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE);
-GEN_SPE(evrlw,       evsplati,    0x14, 0x08, 0x00000000, 0x0000F800, PPC_SPE); //
-GEN_SPE(evrlwi,      evsplatfi,   0x15, 0x08, 0x00000000, 0x0000F800, PPC_SPE);
-GEN_SPE(evmergehi,   evmergelo,   0x16, 0x08, 0x00000000, 0x00000000, PPC_SPE); ////
-GEN_SPE(evmergehilo, evmergelohi, 0x17, 0x08, 0x00000000, 0x00000000, PPC_SPE); ////
-GEN_SPE(evcmpgtu,    evcmpgts,    0x18, 0x08, 0x00600000, 0x00600000, PPC_SPE); ////
-GEN_SPE(evcmpltu,    evcmplts,    0x19, 0x08, 0x00600000, 0x00600000, PPC_SPE); ////
-GEN_SPE(evcmpeq,     speundef,    0x1A, 0x08, 0x00600000, 0xFFFFFFFF, PPC_SPE); ////
-
-/* SPE load and stores */
-static inline void gen_addr_spe_imm_index(DisasContext *ctx, TCGv EA, int sh)
-{
-    target_ulong uimm = rB(ctx->opcode);
-
-    if (rA(ctx->opcode) == 0) {
-        tcg_gen_movi_tl(EA, uimm << sh);
-    } else {
-        tcg_gen_addi_tl(EA, cpu_gpr[rA(ctx->opcode)], uimm << sh);
-        if (NARROW_MODE(ctx)) {
-            tcg_gen_ext32u_tl(EA, EA);
-        }
-    }
-}
-
-static inline void gen_op_evldd(DisasContext *ctx, TCGv addr)
-{
-    TCGv_i64 t0 = tcg_temp_new_i64();
-    gen_qemu_ld64(ctx, t0, addr);
-    gen_store_gpr64(rD(ctx->opcode), t0);
-    tcg_temp_free_i64(t0);
-}
-
-static inline void gen_op_evldw(DisasContext *ctx, TCGv addr)
-{
-    gen_qemu_ld32u(ctx, cpu_gprh[rD(ctx->opcode)], addr);
-    gen_addr_add(ctx, addr, addr, 4);
-    gen_qemu_ld32u(ctx, cpu_gpr[rD(ctx->opcode)], addr);
-}
-
-static inline void gen_op_evldh(DisasContext *ctx, TCGv addr)
-{
-    TCGv t0 = tcg_temp_new();
-    gen_qemu_ld16u(ctx, t0, addr);
-    tcg_gen_shli_tl(cpu_gprh[rD(ctx->opcode)], t0, 16);
-    gen_addr_add(ctx, addr, addr, 2);
-    gen_qemu_ld16u(ctx, t0, addr);
-    tcg_gen_or_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rD(ctx->opcode)], t0);
-    gen_addr_add(ctx, addr, addr, 2);
-    gen_qemu_ld16u(ctx, t0, addr);
-    tcg_gen_shli_tl(cpu_gprh[rD(ctx->opcode)], t0, 16);
-    gen_addr_add(ctx, addr, addr, 2);
-    gen_qemu_ld16u(ctx, t0, addr);
-    tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], t0);
-    tcg_temp_free(t0);
-}
-
-static inline void gen_op_evlhhesplat(DisasContext *ctx, TCGv addr)
-{
-    TCGv t0 = tcg_temp_new();
-    gen_qemu_ld16u(ctx, t0, addr);
-    tcg_gen_shli_tl(t0, t0, 16);
-    tcg_gen_mov_tl(cpu_gprh[rD(ctx->opcode)], t0);
-    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], t0);
-    tcg_temp_free(t0);
-}
-
-static inline void gen_op_evlhhousplat(DisasContext *ctx, TCGv addr)
-{
-    TCGv t0 = tcg_temp_new();
-    gen_qemu_ld16u(ctx, t0, addr);
-    tcg_gen_mov_tl(cpu_gprh[rD(ctx->opcode)], t0);
-    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], t0);
-    tcg_temp_free(t0);
-}
-
-static inline void gen_op_evlhhossplat(DisasContext *ctx, TCGv addr)
-{
-    TCGv t0 = tcg_temp_new();
-    gen_qemu_ld16s(ctx, t0, addr);
-    tcg_gen_mov_tl(cpu_gprh[rD(ctx->opcode)], t0);
-    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], t0);
-    tcg_temp_free(t0);
-}
-
-static inline void gen_op_evlwhe(DisasContext *ctx, TCGv addr)
-{
-    TCGv t0 = tcg_temp_new();
-    gen_qemu_ld16u(ctx, t0, addr);
-    tcg_gen_shli_tl(cpu_gprh[rD(ctx->opcode)], t0, 16);
-    gen_addr_add(ctx, addr, addr, 2);
-    gen_qemu_ld16u(ctx, t0, addr);
-    tcg_gen_shli_tl(cpu_gpr[rD(ctx->opcode)], t0, 16);
-    tcg_temp_free(t0);
-}
-
-static inline void gen_op_evlwhou(DisasContext *ctx, TCGv addr)
-{
-    gen_qemu_ld16u(ctx, cpu_gprh[rD(ctx->opcode)], addr);
-    gen_addr_add(ctx, addr, addr, 2);
-    gen_qemu_ld16u(ctx, cpu_gpr[rD(ctx->opcode)], addr);
-}
-
-static inline void gen_op_evlwhos(DisasContext *ctx, TCGv addr)
-{
-    gen_qemu_ld16s(ctx, cpu_gprh[rD(ctx->opcode)], addr);
-    gen_addr_add(ctx, addr, addr, 2);
-    gen_qemu_ld16s(ctx, cpu_gpr[rD(ctx->opcode)], addr);
-}
-
-static inline void gen_op_evlwwsplat(DisasContext *ctx, TCGv addr)
-{
-    TCGv t0 = tcg_temp_new();
-    gen_qemu_ld32u(ctx, t0, addr);
-    tcg_gen_mov_tl(cpu_gprh[rD(ctx->opcode)], t0);
-    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], t0);
-    tcg_temp_free(t0);
-}
-
-static inline void gen_op_evlwhsplat(DisasContext *ctx, TCGv addr)
-{
-    TCGv t0 = tcg_temp_new();
-    gen_qemu_ld16u(ctx, t0, addr);
-    tcg_gen_shli_tl(cpu_gprh[rD(ctx->opcode)], t0, 16);
-    tcg_gen_or_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rD(ctx->opcode)], t0);
-    gen_addr_add(ctx, addr, addr, 2);
-    gen_qemu_ld16u(ctx, t0, addr);
-    tcg_gen_shli_tl(cpu_gpr[rD(ctx->opcode)], t0, 16);
-    tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gprh[rD(ctx->opcode)], t0);
-    tcg_temp_free(t0);
-}
-
-static inline void gen_op_evstdd(DisasContext *ctx, TCGv addr)
-{
-    TCGv_i64 t0 = tcg_temp_new_i64();
-    gen_load_gpr64(t0, rS(ctx->opcode));
-    gen_qemu_st64(ctx, t0, addr);
-    tcg_temp_free_i64(t0);
-}
-
-static inline void gen_op_evstdw(DisasContext *ctx, TCGv addr)
-{
-    gen_qemu_st32(ctx, cpu_gprh[rS(ctx->opcode)], addr);
-    gen_addr_add(ctx, addr, addr, 4);
-    gen_qemu_st32(ctx, cpu_gpr[rS(ctx->opcode)], addr);
-}
-
-static inline void gen_op_evstdh(DisasContext *ctx, TCGv addr)
-{
-    TCGv t0 = tcg_temp_new();
-    tcg_gen_shri_tl(t0, cpu_gprh[rS(ctx->opcode)], 16);
-    gen_qemu_st16(ctx, t0, addr);
-    gen_addr_add(ctx, addr, addr, 2);
-    gen_qemu_st16(ctx, cpu_gprh[rS(ctx->opcode)], addr);
-    gen_addr_add(ctx, addr, addr, 2);
-    tcg_gen_shri_tl(t0, cpu_gpr[rS(ctx->opcode)], 16);
-    gen_qemu_st16(ctx, t0, addr);
-    tcg_temp_free(t0);
-    gen_addr_add(ctx, addr, addr, 2);
-    gen_qemu_st16(ctx, cpu_gpr[rS(ctx->opcode)], addr);
-}
-
-static inline void gen_op_evstwhe(DisasContext *ctx, TCGv addr)
-{
-    TCGv t0 = tcg_temp_new();
-    tcg_gen_shri_tl(t0, cpu_gprh[rS(ctx->opcode)], 16);
-    gen_qemu_st16(ctx, t0, addr);
-    gen_addr_add(ctx, addr, addr, 2);
-    tcg_gen_shri_tl(t0, cpu_gpr[rS(ctx->opcode)], 16);
-    gen_qemu_st16(ctx, t0, addr);
-    tcg_temp_free(t0);
-}
-
-static inline void gen_op_evstwho(DisasContext *ctx, TCGv addr)
-{
-    gen_qemu_st16(ctx, cpu_gprh[rS(ctx->opcode)], addr);
-    gen_addr_add(ctx, addr, addr, 2);
-    gen_qemu_st16(ctx, cpu_gpr[rS(ctx->opcode)], addr);
-}
-
-static inline void gen_op_evstwwe(DisasContext *ctx, TCGv addr)
-{
-    gen_qemu_st32(ctx, cpu_gprh[rS(ctx->opcode)], addr);
-}
-
-static inline void gen_op_evstwwo(DisasContext *ctx, TCGv addr)
-{
-    gen_qemu_st32(ctx, cpu_gpr[rS(ctx->opcode)], addr);
-}
-
-#define GEN_SPEOP_LDST(name, opc2, sh)                                        \
-static void glue(gen_, name)(DisasContext *ctx)                                       \
-{                                                                             \
-    TCGv t0;                                                                  \
-    if (unlikely(!ctx->spe_enabled)) {                                        \
-        gen_exception(ctx, POWERPC_EXCP_SPEU);                                \
-        return;                                                               \
-    }                                                                         \
-    gen_set_access_type(ctx, ACCESS_INT);                                     \
-    t0 = tcg_temp_new();                                                      \
-    if (Rc(ctx->opcode)) {                                                    \
-        gen_addr_spe_imm_index(ctx, t0, sh);                                  \
-    } else {                                                                  \
-        gen_addr_reg_index(ctx, t0);                                          \
-    }                                                                         \
-    gen_op_##name(ctx, t0);                                                   \
-    tcg_temp_free(t0);                                                        \
-}
-
-GEN_SPEOP_LDST(evldd, 0x00, 3);
-GEN_SPEOP_LDST(evldw, 0x01, 3);
-GEN_SPEOP_LDST(evldh, 0x02, 3);
-GEN_SPEOP_LDST(evlhhesplat, 0x04, 1);
-GEN_SPEOP_LDST(evlhhousplat, 0x06, 1);
-GEN_SPEOP_LDST(evlhhossplat, 0x07, 1);
-GEN_SPEOP_LDST(evlwhe, 0x08, 2);
-GEN_SPEOP_LDST(evlwhou, 0x0A, 2);
-GEN_SPEOP_LDST(evlwhos, 0x0B, 2);
-GEN_SPEOP_LDST(evlwwsplat, 0x0C, 2);
-GEN_SPEOP_LDST(evlwhsplat, 0x0E, 2);
-
-GEN_SPEOP_LDST(evstdd, 0x10, 3);
-GEN_SPEOP_LDST(evstdw, 0x11, 3);
-GEN_SPEOP_LDST(evstdh, 0x12, 3);
-GEN_SPEOP_LDST(evstwhe, 0x18, 2);
-GEN_SPEOP_LDST(evstwho, 0x1A, 2);
-GEN_SPEOP_LDST(evstwwe, 0x1C, 2);
-GEN_SPEOP_LDST(evstwwo, 0x1E, 2);
-
-/* Multiply and add - TODO */
-#if 0
-GEN_SPE(speundef,       evmhessf,      0x01, 0x10, 0xFFFFFFFF, 0x00000000, PPC_SPE);//
-GEN_SPE(speundef,       evmhossf,      0x03, 0x10, 0xFFFFFFFF, 0x00000000, PPC_SPE);
-GEN_SPE(evmheumi,       evmhesmi,      0x04, 0x10, 0x00000000, 0x00000000, PPC_SPE);
-GEN_SPE(speundef,       evmhesmf,      0x05, 0x10, 0xFFFFFFFF, 0x00000000, PPC_SPE);
-GEN_SPE(evmhoumi,       evmhosmi,      0x06, 0x10, 0x00000000, 0x00000000, PPC_SPE);
-GEN_SPE(speundef,       evmhosmf,      0x07, 0x10, 0xFFFFFFFF, 0x00000000, PPC_SPE);
-GEN_SPE(speundef,       evmhessfa,     0x11, 0x10, 0xFFFFFFFF, 0x00000000, PPC_SPE);
-GEN_SPE(speundef,       evmhossfa,     0x13, 0x10, 0xFFFFFFFF, 0x00000000, PPC_SPE);
-GEN_SPE(evmheumia,      evmhesmia,     0x14, 0x10, 0x00000000, 0x00000000, PPC_SPE);
-GEN_SPE(speundef,       evmhesmfa,     0x15, 0x10, 0xFFFFFFFF, 0x00000000, PPC_SPE);
-GEN_SPE(evmhoumia,      evmhosmia,     0x16, 0x10, 0x00000000, 0x00000000, PPC_SPE);
-GEN_SPE(speundef,       evmhosmfa,     0x17, 0x10, 0xFFFFFFFF, 0x00000000, PPC_SPE);
-
-GEN_SPE(speundef,       evmwhssf,      0x03, 0x11, 0xFFFFFFFF, 0x00000000, PPC_SPE);
-GEN_SPE(evmwlumi,       speundef,      0x04, 0x11, 0x00000000, 0xFFFFFFFF, PPC_SPE);
-GEN_SPE(evmwhumi,       evmwhsmi,      0x06, 0x11, 0x00000000, 0x00000000, PPC_SPE);
-GEN_SPE(speundef,       evmwhsmf,      0x07, 0x11, 0xFFFFFFFF, 0x00000000, PPC_SPE);
-GEN_SPE(speundef,       evmwssf,       0x09, 0x11, 0xFFFFFFFF, 0x00000000, PPC_SPE);
-GEN_SPE(speundef,       evmwsmf,       0x0D, 0x11, 0xFFFFFFFF, 0x00000000, PPC_SPE);
-GEN_SPE(speundef,       evmwhssfa,     0x13, 0x11, 0xFFFFFFFF, 0x00000000, PPC_SPE);
-GEN_SPE(evmwlumia,      speundef,      0x14, 0x11, 0x00000000, 0xFFFFFFFF, PPC_SPE);
-GEN_SPE(evmwhumia,      evmwhsmia,     0x16, 0x11, 0x00000000, 0x00000000, PPC_SPE);
-GEN_SPE(speundef,       evmwhsmfa,     0x17, 0x11, 0xFFFFFFFF, 0x00000000, PPC_SPE);
-GEN_SPE(speundef,       evmwssfa,      0x19, 0x11, 0xFFFFFFFF, 0x00000000, PPC_SPE);
-GEN_SPE(speundef,       evmwsmfa,      0x1D, 0x11, 0xFFFFFFFF, 0x00000000, PPC_SPE);
-
-GEN_SPE(evadduiaaw,     evaddsiaaw,    0x00, 0x13, 0x0000F800, 0x0000F800, PPC_SPE);
-GEN_SPE(evsubfusiaaw,   evsubfssiaaw,  0x01, 0x13, 0x0000F800, 0x0000F800, PPC_SPE);
-GEN_SPE(evaddumiaaw,    evaddsmiaaw,   0x04, 0x13, 0x0000F800, 0x0000F800, PPC_SPE);
-GEN_SPE(evsubfumiaaw,   evsubfsmiaaw,  0x05, 0x13, 0x0000F800, 0x0000F800, PPC_SPE);
-GEN_SPE(evdivws,        evdivwu,       0x06, 0x13, 0x00000000, 0x00000000, PPC_SPE);
-
-GEN_SPE(evmheusiaaw,    evmhessiaaw,   0x00, 0x14, 0x00000000, 0x00000000, PPC_SPE);
-GEN_SPE(speundef,       evmhessfaaw,   0x01, 0x14, 0xFFFFFFFF, 0x00000000, PPC_SPE);
-GEN_SPE(evmhousiaaw,    evmhossiaaw,   0x02, 0x14, 0x00000000, 0x00000000, PPC_SPE);
-GEN_SPE(speundef,       evmhossfaaw,   0x03, 0x14, 0xFFFFFFFF, 0x00000000, PPC_SPE);
-GEN_SPE(evmheumiaaw,    evmhesmiaaw,   0x04, 0x14, 0x00000000, 0x00000000, PPC_SPE);
-GEN_SPE(speundef,       evmhesmfaaw,   0x05, 0x14, 0xFFFFFFFF, 0x00000000, PPC_SPE);
-GEN_SPE(evmhoumiaaw,    evmhosmiaaw,   0x06, 0x14, 0x00000000, 0x00000000, PPC_SPE);
-GEN_SPE(speundef,       evmhosmfaaw,   0x07, 0x14, 0xFFFFFFFF, 0x00000000, PPC_SPE);
-GEN_SPE(evmhegumiaa,    evmhegsmiaa,   0x14, 0x14, 0x00000000, 0x00000000, PPC_SPE);
-GEN_SPE(speundef,       evmhegsmfaa,   0x15, 0x14, 0xFFFFFFFF, 0x00000000, PPC_SPE);
-GEN_SPE(evmhogumiaa,    evmhogsmiaa,   0x16, 0x14, 0x00000000, 0x00000000, PPC_SPE);
-GEN_SPE(speundef,       evmhogsmfaa,   0x17, 0x14, 0xFFFFFFFF, 0x00000000, PPC_SPE);
-
-GEN_SPE(evmwlusiaaw,    evmwlssiaaw,   0x00, 0x15, 0x00000000, 0x00000000, PPC_SPE);
-GEN_SPE(evmwlumiaaw,    evmwlsmiaaw,   0x04, 0x15, 0x00000000, 0x00000000, PPC_SPE);
-GEN_SPE(speundef,       evmwssfaa,     0x09, 0x15, 0xFFFFFFFF, 0x00000000, PPC_SPE);
-GEN_SPE(speundef,       evmwsmfaa,     0x0D, 0x15, 0xFFFFFFFF, 0x00000000, PPC_SPE);
-
-GEN_SPE(evmheusianw,    evmhessianw,   0x00, 0x16, 0x00000000, 0x00000000, PPC_SPE);
-GEN_SPE(speundef,       evmhessfanw,   0x01, 0x16, 0xFFFFFFFF, 0x00000000, PPC_SPE);
-GEN_SPE(evmhousianw,    evmhossianw,   0x02, 0x16, 0x00000000, 0x00000000, PPC_SPE);
-GEN_SPE(speundef,       evmhossfanw,   0x03, 0x16, 0xFFFFFFFF, 0x00000000, PPC_SPE);
-GEN_SPE(evmheumianw,    evmhesmianw,   0x04, 0x16, 0x00000000, 0x00000000, PPC_SPE);
-GEN_SPE(speundef,       evmhesmfanw,   0x05, 0x16, 0xFFFFFFFF, 0x00000000, PPC_SPE);
-GEN_SPE(evmhoumianw,    evmhosmianw,   0x06, 0x16, 0x00000000, 0x00000000, PPC_SPE);
-GEN_SPE(speundef,       evmhosmfanw,   0x07, 0x16, 0xFFFFFFFF, 0x00000000, PPC_SPE);
-GEN_SPE(evmhegumian,    evmhegsmian,   0x14, 0x16, 0x00000000, 0x00000000, PPC_SPE);
-GEN_SPE(speundef,       evmhegsmfan,   0x15, 0x16, 0xFFFFFFFF, 0x00000000, PPC_SPE);
-GEN_SPE(evmhigumian,    evmhigsmian,   0x16, 0x16, 0x00000000, 0x00000000, PPC_SPE);
-GEN_SPE(speundef,       evmhogsmfan,   0x17, 0x16, 0xFFFFFFFF, 0x00000000, PPC_SPE);
-
-GEN_SPE(evmwlusianw,    evmwlssianw,   0x00, 0x17, 0x00000000, 0x00000000, PPC_SPE);
-GEN_SPE(evmwlumianw,    evmwlsmianw,   0x04, 0x17, 0x00000000, 0x00000000, PPC_SPE);
-GEN_SPE(speundef,       evmwssfan,     0x09, 0x17, 0xFFFFFFFF, 0x00000000, PPC_SPE);
-GEN_SPE(evmwumian,      evmwsmian,     0x0C, 0x17, 0x00000000, 0x00000000, PPC_SPE);
-GEN_SPE(speundef,       evmwsmfan,     0x0D, 0x17, 0xFFFFFFFF, 0x00000000, PPC_SPE);
-#endif
-
-/***                      SPE floating-point extension                     ***/
-#define GEN_SPEFPUOP_CONV_32_32(name)                                         \
-static inline void gen_##name(DisasContext *ctx)                              \
-{                                                                             \
-    TCGv_i32 t0 = tcg_temp_new_i32();                                         \
-    tcg_gen_trunc_tl_i32(t0, cpu_gpr[rB(ctx->opcode)]);                       \
-    gen_helper_##name(t0, cpu_env, t0);                                       \
-    tcg_gen_extu_i32_tl(cpu_gpr[rD(ctx->opcode)], t0);                        \
-    tcg_temp_free_i32(t0);                                                    \
-}
-#define GEN_SPEFPUOP_CONV_32_64(name)                                         \
-static inline void gen_##name(DisasContext *ctx)                              \
-{                                                                             \
-    TCGv_i64 t0 = tcg_temp_new_i64();                                         \
-    TCGv_i32 t1 = tcg_temp_new_i32();                                         \
-    gen_load_gpr64(t0, rB(ctx->opcode));                                      \
-    gen_helper_##name(t1, cpu_env, t0);                                       \
-    tcg_gen_extu_i32_tl(cpu_gpr[rD(ctx->opcode)], t1);                        \
-    tcg_temp_free_i64(t0);                                                    \
-    tcg_temp_free_i32(t1);                                                    \
-}
-#define GEN_SPEFPUOP_CONV_64_32(name)                                         \
-static inline void gen_##name(DisasContext *ctx)                              \
-{                                                                             \
-    TCGv_i64 t0 = tcg_temp_new_i64();                                         \
-    TCGv_i32 t1 = tcg_temp_new_i32();                                         \
-    tcg_gen_trunc_tl_i32(t1, cpu_gpr[rB(ctx->opcode)]);                       \
-    gen_helper_##name(t0, cpu_env, t1);                                       \
-    gen_store_gpr64(rD(ctx->opcode), t0);                                     \
-    tcg_temp_free_i64(t0);                                                    \
-    tcg_temp_free_i32(t1);                                                    \
-}
-#define GEN_SPEFPUOP_CONV_64_64(name)                                         \
-static inline void gen_##name(DisasContext *ctx)                              \
-{                                                                             \
-    TCGv_i64 t0 = tcg_temp_new_i64();                                         \
-    gen_load_gpr64(t0, rB(ctx->opcode));                                      \
-    gen_helper_##name(t0, cpu_env, t0);                                       \
-    gen_store_gpr64(rD(ctx->opcode), t0);                                     \
-    tcg_temp_free_i64(t0);                                                    \
-}
-#define GEN_SPEFPUOP_ARITH2_32_32(name)                                       \
-static inline void gen_##name(DisasContext *ctx)                              \
-{                                                                             \
-    TCGv_i32 t0, t1;                                                          \
-    if (unlikely(!ctx->spe_enabled)) {                                        \
-        gen_exception(ctx, POWERPC_EXCP_SPEU);                                \
-        return;                                                               \
-    }                                                                         \
-    t0 = tcg_temp_new_i32();                                                  \
-    t1 = tcg_temp_new_i32();                                                  \
-    tcg_gen_trunc_tl_i32(t0, cpu_gpr[rA(ctx->opcode)]);                       \
-    tcg_gen_trunc_tl_i32(t1, cpu_gpr[rB(ctx->opcode)]);                       \
-    gen_helper_##name(t0, cpu_env, t0, t1);                                   \
-    tcg_gen_extu_i32_tl(cpu_gpr[rD(ctx->opcode)], t0);                        \
-                                                                              \
-    tcg_temp_free_i32(t0);                                                    \
-    tcg_temp_free_i32(t1);                                                    \
-}
-#define GEN_SPEFPUOP_ARITH2_64_64(name)                                       \
-static inline void gen_##name(DisasContext *ctx)                              \
-{                                                                             \
-    TCGv_i64 t0, t1;                                                          \
-    if (unlikely(!ctx->spe_enabled)) {                                        \
-        gen_exception(ctx, POWERPC_EXCP_SPEU);                                \
-        return;                                                               \
-    }                                                                         \
-    t0 = tcg_temp_new_i64();                                                  \
-    t1 = tcg_temp_new_i64();                                                  \
-    gen_load_gpr64(t0, rA(ctx->opcode));                                      \
-    gen_load_gpr64(t1, rB(ctx->opcode));                                      \
-    gen_helper_##name(t0, cpu_env, t0, t1);                                   \
-    gen_store_gpr64(rD(ctx->opcode), t0);                                     \
-    tcg_temp_free_i64(t0);                                                    \
-    tcg_temp_free_i64(t1);                                                    \
-}
-#define GEN_SPEFPUOP_COMP_32(name)                                            \
-static inline void gen_##name(DisasContext *ctx)                              \
-{                                                                             \
-    TCGv_i32 t0, t1;                                                          \
-    if (unlikely(!ctx->spe_enabled)) {                                        \
-        gen_exception(ctx, POWERPC_EXCP_SPEU);                                \
-        return;                                                               \
-    }                                                                         \
-    t0 = tcg_temp_new_i32();                                                  \
-    t1 = tcg_temp_new_i32();                                                  \
-                                                                              \
-    tcg_gen_trunc_tl_i32(t0, cpu_gpr[rA(ctx->opcode)]);                       \
-    tcg_gen_trunc_tl_i32(t1, cpu_gpr[rB(ctx->opcode)]);                       \
-    gen_helper_##name(cpu_crf[crfD(ctx->opcode)], cpu_env, t0, t1);           \
-                                                                              \
-    tcg_temp_free_i32(t0);                                                    \
-    tcg_temp_free_i32(t1);                                                    \
-}
-#define GEN_SPEFPUOP_COMP_64(name)                                            \
-static inline void gen_##name(DisasContext *ctx)                              \
-{                                                                             \
-    TCGv_i64 t0, t1;                                                          \
-    if (unlikely(!ctx->spe_enabled)) {                                        \
-        gen_exception(ctx, POWERPC_EXCP_SPEU);                                \
-        return;                                                               \
-    }                                                                         \
-    t0 = tcg_temp_new_i64();                                                  \
-    t1 = tcg_temp_new_i64();                                                  \
-    gen_load_gpr64(t0, rA(ctx->opcode));                                      \
-    gen_load_gpr64(t1, rB(ctx->opcode));                                      \
-    gen_helper_##name(cpu_crf[crfD(ctx->opcode)], cpu_env, t0, t1);           \
-    tcg_temp_free_i64(t0);                                                    \
-    tcg_temp_free_i64(t1);                                                    \
-}
-
-/* Single precision floating-point vectors operations */
-/* Arithmetic */
-GEN_SPEFPUOP_ARITH2_64_64(evfsadd);
-GEN_SPEFPUOP_ARITH2_64_64(evfssub);
-GEN_SPEFPUOP_ARITH2_64_64(evfsmul);
-GEN_SPEFPUOP_ARITH2_64_64(evfsdiv);
-static inline void gen_evfsabs(DisasContext *ctx)
-{
-    if (unlikely(!ctx->spe_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_SPEU);
-        return;
-    }
-    tcg_gen_andi_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)],
-                    ~0x80000000);
-    tcg_gen_andi_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)],
-                    ~0x80000000);
-}
-static inline void gen_evfsnabs(DisasContext *ctx)
-{
-    if (unlikely(!ctx->spe_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_SPEU);
-        return;
-    }
-    tcg_gen_ori_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)],
-                   0x80000000);
-    tcg_gen_ori_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)],
-                   0x80000000);
-}
-static inline void gen_evfsneg(DisasContext *ctx)
-{
-    if (unlikely(!ctx->spe_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_SPEU);
-        return;
-    }
-    tcg_gen_xori_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)],
-                    0x80000000);
-    tcg_gen_xori_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)],
-                    0x80000000);
-}
-
-/* Conversion */
-GEN_SPEFPUOP_CONV_64_64(evfscfui);
-GEN_SPEFPUOP_CONV_64_64(evfscfsi);
-GEN_SPEFPUOP_CONV_64_64(evfscfuf);
-GEN_SPEFPUOP_CONV_64_64(evfscfsf);
-GEN_SPEFPUOP_CONV_64_64(evfsctui);
-GEN_SPEFPUOP_CONV_64_64(evfsctsi);
-GEN_SPEFPUOP_CONV_64_64(evfsctuf);
-GEN_SPEFPUOP_CONV_64_64(evfsctsf);
-GEN_SPEFPUOP_CONV_64_64(evfsctuiz);
-GEN_SPEFPUOP_CONV_64_64(evfsctsiz);
-
-/* Comparison */
-GEN_SPEFPUOP_COMP_64(evfscmpgt);
-GEN_SPEFPUOP_COMP_64(evfscmplt);
-GEN_SPEFPUOP_COMP_64(evfscmpeq);
-GEN_SPEFPUOP_COMP_64(evfststgt);
-GEN_SPEFPUOP_COMP_64(evfststlt);
-GEN_SPEFPUOP_COMP_64(evfststeq);
-
-/* Opcodes definitions */
-GEN_SPE(evfsadd,   evfssub,   0x00, 0x0A, 0x00000000, 0x00000000, PPC_SPE_SINGLE); //
-GEN_SPE(evfsabs,   evfsnabs,  0x02, 0x0A, 0x0000F800, 0x0000F800, PPC_SPE_SINGLE); //
-GEN_SPE(evfsneg,   speundef,  0x03, 0x0A, 0x0000F800, 0xFFFFFFFF, PPC_SPE_SINGLE); //
-GEN_SPE(evfsmul,   evfsdiv,   0x04, 0x0A, 0x00000000, 0x00000000, PPC_SPE_SINGLE); //
-GEN_SPE(evfscmpgt, evfscmplt, 0x06, 0x0A, 0x00600000, 0x00600000, PPC_SPE_SINGLE); //
-GEN_SPE(evfscmpeq, speundef,  0x07, 0x0A, 0x00600000, 0xFFFFFFFF, PPC_SPE_SINGLE); //
-GEN_SPE(evfscfui,  evfscfsi,  0x08, 0x0A, 0x00180000, 0x00180000, PPC_SPE_SINGLE); //
-GEN_SPE(evfscfuf,  evfscfsf,  0x09, 0x0A, 0x00180000, 0x00180000, PPC_SPE_SINGLE); //
-GEN_SPE(evfsctui,  evfsctsi,  0x0A, 0x0A, 0x00180000, 0x00180000, PPC_SPE_SINGLE); //
-GEN_SPE(evfsctuf,  evfsctsf,  0x0B, 0x0A, 0x00180000, 0x00180000, PPC_SPE_SINGLE); //
-GEN_SPE(evfsctuiz, speundef,  0x0C, 0x0A, 0x00180000, 0xFFFFFFFF, PPC_SPE_SINGLE); //
-GEN_SPE(evfsctsiz, speundef,  0x0D, 0x0A, 0x00180000, 0xFFFFFFFF, PPC_SPE_SINGLE); //
-GEN_SPE(evfststgt, evfststlt, 0x0E, 0x0A, 0x00600000, 0x00600000, PPC_SPE_SINGLE); //
-GEN_SPE(evfststeq, speundef,  0x0F, 0x0A, 0x00600000, 0xFFFFFFFF, PPC_SPE_SINGLE); //
-
-/* Single precision floating-point operations */
-/* Arithmetic */
-GEN_SPEFPUOP_ARITH2_32_32(efsadd);
-GEN_SPEFPUOP_ARITH2_32_32(efssub);
-GEN_SPEFPUOP_ARITH2_32_32(efsmul);
-GEN_SPEFPUOP_ARITH2_32_32(efsdiv);
-static inline void gen_efsabs(DisasContext *ctx)
-{
-    if (unlikely(!ctx->spe_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_SPEU);
-        return;
-    }
-    tcg_gen_andi_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], (target_long)~0x80000000LL);
-}
-static inline void gen_efsnabs(DisasContext *ctx)
-{
-    if (unlikely(!ctx->spe_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_SPEU);
-        return;
-    }
-    tcg_gen_ori_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x80000000);
-}
-static inline void gen_efsneg(DisasContext *ctx)
-{
-    if (unlikely(!ctx->spe_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_SPEU);
-        return;
-    }
-    tcg_gen_xori_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x80000000);
-}
-
-/* Conversion */
-GEN_SPEFPUOP_CONV_32_32(efscfui);
-GEN_SPEFPUOP_CONV_32_32(efscfsi);
-GEN_SPEFPUOP_CONV_32_32(efscfuf);
-GEN_SPEFPUOP_CONV_32_32(efscfsf);
-GEN_SPEFPUOP_CONV_32_32(efsctui);
-GEN_SPEFPUOP_CONV_32_32(efsctsi);
-GEN_SPEFPUOP_CONV_32_32(efsctuf);
-GEN_SPEFPUOP_CONV_32_32(efsctsf);
-GEN_SPEFPUOP_CONV_32_32(efsctuiz);
-GEN_SPEFPUOP_CONV_32_32(efsctsiz);
-GEN_SPEFPUOP_CONV_32_64(efscfd);
-
-/* Comparison */
-GEN_SPEFPUOP_COMP_32(efscmpgt);
-GEN_SPEFPUOP_COMP_32(efscmplt);
-GEN_SPEFPUOP_COMP_32(efscmpeq);
-GEN_SPEFPUOP_COMP_32(efststgt);
-GEN_SPEFPUOP_COMP_32(efststlt);
-GEN_SPEFPUOP_COMP_32(efststeq);
-
-/* Opcodes definitions */
-GEN_SPE(efsadd,   efssub,   0x00, 0x0B, 0x00000000, 0x00000000, PPC_SPE_SINGLE); //
-GEN_SPE(efsabs,   efsnabs,  0x02, 0x0B, 0x0000F800, 0x0000F800, PPC_SPE_SINGLE); //
-GEN_SPE(efsneg,   speundef, 0x03, 0x0B, 0x0000F800, 0xFFFFFFFF, PPC_SPE_SINGLE); //
-GEN_SPE(efsmul,   efsdiv,   0x04, 0x0B, 0x00000000, 0x00000000, PPC_SPE_SINGLE); //
-GEN_SPE(efscmpgt, efscmplt, 0x06, 0x0B, 0x00600000, 0x00600000, PPC_SPE_SINGLE); //
-GEN_SPE(efscmpeq, efscfd,   0x07, 0x0B, 0x00600000, 0x00180000, PPC_SPE_SINGLE); //
-GEN_SPE(efscfui,  efscfsi,  0x08, 0x0B, 0x00180000, 0x00180000, PPC_SPE_SINGLE); //
-GEN_SPE(efscfuf,  efscfsf,  0x09, 0x0B, 0x00180000, 0x00180000, PPC_SPE_SINGLE); //
-GEN_SPE(efsctui,  efsctsi,  0x0A, 0x0B, 0x00180000, 0x00180000, PPC_SPE_SINGLE); //
-GEN_SPE(efsctuf,  efsctsf,  0x0B, 0x0B, 0x00180000, 0x00180000, PPC_SPE_SINGLE); //
-GEN_SPE(efsctuiz, speundef, 0x0C, 0x0B, 0x00180000, 0xFFFFFFFF, PPC_SPE_SINGLE); //
-GEN_SPE(efsctsiz, speundef, 0x0D, 0x0B, 0x00180000, 0xFFFFFFFF, PPC_SPE_SINGLE); //
-GEN_SPE(efststgt, efststlt, 0x0E, 0x0B, 0x00600000, 0x00600000, PPC_SPE_SINGLE); //
-GEN_SPE(efststeq, speundef, 0x0F, 0x0B, 0x00600000, 0xFFFFFFFF, PPC_SPE_SINGLE); //
-
-/* Double precision floating-point operations */
-/* Arithmetic */
-GEN_SPEFPUOP_ARITH2_64_64(efdadd);
-GEN_SPEFPUOP_ARITH2_64_64(efdsub);
-GEN_SPEFPUOP_ARITH2_64_64(efdmul);
-GEN_SPEFPUOP_ARITH2_64_64(efddiv);
-static inline void gen_efdabs(DisasContext *ctx)
-{
-    if (unlikely(!ctx->spe_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_SPEU);
-        return;
-    }
-    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
-    tcg_gen_andi_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)],
-                    ~0x80000000);
-}
-static inline void gen_efdnabs(DisasContext *ctx)
-{
-    if (unlikely(!ctx->spe_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_SPEU);
-        return;
-    }
-    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
-    tcg_gen_ori_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)],
-                   0x80000000);
-}
-static inline void gen_efdneg(DisasContext *ctx)
-{
-    if (unlikely(!ctx->spe_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_SPEU);
-        return;
-    }
-    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
-    tcg_gen_xori_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)],
-                    0x80000000);
-}
-
-/* Conversion */
-GEN_SPEFPUOP_CONV_64_32(efdcfui);
-GEN_SPEFPUOP_CONV_64_32(efdcfsi);
-GEN_SPEFPUOP_CONV_64_32(efdcfuf);
-GEN_SPEFPUOP_CONV_64_32(efdcfsf);
-GEN_SPEFPUOP_CONV_32_64(efdctui);
-GEN_SPEFPUOP_CONV_32_64(efdctsi);
-GEN_SPEFPUOP_CONV_32_64(efdctuf);
-GEN_SPEFPUOP_CONV_32_64(efdctsf);
-GEN_SPEFPUOP_CONV_32_64(efdctuiz);
-GEN_SPEFPUOP_CONV_32_64(efdctsiz);
-GEN_SPEFPUOP_CONV_64_32(efdcfs);
-GEN_SPEFPUOP_CONV_64_64(efdcfuid);
-GEN_SPEFPUOP_CONV_64_64(efdcfsid);
-GEN_SPEFPUOP_CONV_64_64(efdctuidz);
-GEN_SPEFPUOP_CONV_64_64(efdctsidz);
-
-/* Comparison */
-GEN_SPEFPUOP_COMP_64(efdcmpgt);
-GEN_SPEFPUOP_COMP_64(efdcmplt);
-GEN_SPEFPUOP_COMP_64(efdcmpeq);
-GEN_SPEFPUOP_COMP_64(efdtstgt);
-GEN_SPEFPUOP_COMP_64(efdtstlt);
-GEN_SPEFPUOP_COMP_64(efdtsteq);
-
-/* Opcodes definitions */
-GEN_SPE(efdadd,    efdsub,    0x10, 0x0B, 0x00000000, 0x00000000, PPC_SPE_DOUBLE); //
-GEN_SPE(efdcfuid,  efdcfsid,  0x11, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE); //
-GEN_SPE(efdabs,    efdnabs,   0x12, 0x0B, 0x0000F800, 0x0000F800, PPC_SPE_DOUBLE); //
-GEN_SPE(efdneg,    speundef,  0x13, 0x0B, 0x0000F800, 0xFFFFFFFF, PPC_SPE_DOUBLE); //
-GEN_SPE(efdmul,    efddiv,    0x14, 0x0B, 0x00000000, 0x00000000, PPC_SPE_DOUBLE); //
-GEN_SPE(efdctuidz, efdctsidz, 0x15, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE); //
-GEN_SPE(efdcmpgt,  efdcmplt,  0x16, 0x0B, 0x00600000, 0x00600000, PPC_SPE_DOUBLE); //
-GEN_SPE(efdcmpeq,  efdcfs,    0x17, 0x0B, 0x00600000, 0x00180000, PPC_SPE_DOUBLE); //
-GEN_SPE(efdcfui,   efdcfsi,   0x18, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE); //
-GEN_SPE(efdcfuf,   efdcfsf,   0x19, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE); //
-GEN_SPE(efdctui,   efdctsi,   0x1A, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE); //
-GEN_SPE(efdctuf,   efdctsf,   0x1B, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE); //
-GEN_SPE(efdctuiz,  speundef,  0x1C, 0x0B, 0x00180000, 0xFFFFFFFF, PPC_SPE_DOUBLE); //
-GEN_SPE(efdctsiz,  speundef,  0x1D, 0x0B, 0x00180000, 0xFFFFFFFF, PPC_SPE_DOUBLE); //
-GEN_SPE(efdtstgt,  efdtstlt,  0x1E, 0x0B, 0x00600000, 0x00600000, PPC_SPE_DOUBLE); //
-GEN_SPE(efdtsteq,  speundef,  0x1F, 0x0B, 0x00600000, 0xFFFFFFFF, PPC_SPE_DOUBLE); //
+#include "translate/spe-impl.c"
 
 static void gen_tbegin(DisasContext *ctx)
 {
@@ -9055,10 +7836,6 @@ GEN_HANDLER(lvsr, 0x1f, 0x06, 0x01, 0x00000001, PPC_ALTIVEC),
 GEN_HANDLER(mfvscr, 0x04, 0x2, 0x18, 0x001ff800, PPC_ALTIVEC),
 GEN_HANDLER(mtvscr, 0x04, 0x2, 0x19, 0x03ff0000, PPC_ALTIVEC),
 GEN_HANDLER(vmladduhm, 0x04, 0x11, 0xFF, 0x00000000, PPC_ALTIVEC),
-GEN_HANDLER2(evsel0, "evsel", 0x04, 0x1c, 0x09, 0x00000000, PPC_SPE),
-GEN_HANDLER2(evsel1, "evsel", 0x04, 0x1d, 0x09, 0x00000000, PPC_SPE),
-GEN_HANDLER2(evsel2, "evsel", 0x04, 0x1e, 0x09, 0x00000000, PPC_SPE),
-GEN_HANDLER2(evsel3, "evsel", 0x04, 0x1f, 0x09, 0x00000000, PPC_SPE),
 
 #undef GEN_INT_ARITH_ADD
 #undef GEN_INT_ARITH_ADD_CONST
@@ -10002,108 +8779,7 @@ GEN_DFP_Tp_Ap_SH_Rc(dscliq, 0x02, 0x02),
 GEN_DFP_T_A_SH_Rc(dscri, 0x02, 0x03),
 GEN_DFP_Tp_Ap_SH_Rc(dscriq, 0x02, 0x03),
 
-#undef GEN_SPE
-#define GEN_SPE(name0, name1, opc2, opc3, inval0, inval1, type) \
-    GEN_OPCODE_DUAL(name0##_##name1, 0x04, opc2, opc3, inval0, inval1, type, PPC_NONE)
-GEN_SPE(evaddw,      speundef,    0x00, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE),
-GEN_SPE(evaddiw,     speundef,    0x01, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE),
-GEN_SPE(evsubfw,     speundef,    0x02, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE),
-GEN_SPE(evsubifw,    speundef,    0x03, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE),
-GEN_SPE(evabs,       evneg,       0x04, 0x08, 0x0000F800, 0x0000F800, PPC_SPE),
-GEN_SPE(evextsb,     evextsh,     0x05, 0x08, 0x0000F800, 0x0000F800, PPC_SPE),
-GEN_SPE(evrndw,      evcntlzw,    0x06, 0x08, 0x0000F800, 0x0000F800, PPC_SPE),
-GEN_SPE(evcntlsw,    brinc,       0x07, 0x08, 0x0000F800, 0x00000000, PPC_SPE),
-GEN_SPE(evmra,       speundef,    0x02, 0x13, 0x0000F800, 0xFFFFFFFF, PPC_SPE),
-GEN_SPE(speundef,    evand,       0x08, 0x08, 0xFFFFFFFF, 0x00000000, PPC_SPE),
-GEN_SPE(evandc,      speundef,    0x09, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE),
-GEN_SPE(evxor,       evor,        0x0B, 0x08, 0x00000000, 0x00000000, PPC_SPE),
-GEN_SPE(evnor,       eveqv,       0x0C, 0x08, 0x00000000, 0x00000000, PPC_SPE),
-GEN_SPE(evmwumi,     evmwsmi,     0x0C, 0x11, 0x00000000, 0x00000000, PPC_SPE),
-GEN_SPE(evmwumia,    evmwsmia,    0x1C, 0x11, 0x00000000, 0x00000000, PPC_SPE),
-GEN_SPE(evmwumiaa,   evmwsmiaa,   0x0C, 0x15, 0x00000000, 0x00000000, PPC_SPE),
-GEN_SPE(speundef,    evorc,       0x0D, 0x08, 0xFFFFFFFF, 0x00000000, PPC_SPE),
-GEN_SPE(evnand,      speundef,    0x0F, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE),
-GEN_SPE(evsrwu,      evsrws,      0x10, 0x08, 0x00000000, 0x00000000, PPC_SPE),
-GEN_SPE(evsrwiu,     evsrwis,     0x11, 0x08, 0x00000000, 0x00000000, PPC_SPE),
-GEN_SPE(evslw,       speundef,    0x12, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE),
-GEN_SPE(evslwi,      speundef,    0x13, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE),
-GEN_SPE(evrlw,       evsplati,    0x14, 0x08, 0x00000000, 0x0000F800, PPC_SPE),
-GEN_SPE(evrlwi,      evsplatfi,   0x15, 0x08, 0x00000000, 0x0000F800, PPC_SPE),
-GEN_SPE(evmergehi,   evmergelo,   0x16, 0x08, 0x00000000, 0x00000000, PPC_SPE),
-GEN_SPE(evmergehilo, evmergelohi, 0x17, 0x08, 0x00000000, 0x00000000, PPC_SPE),
-GEN_SPE(evcmpgtu,    evcmpgts,    0x18, 0x08, 0x00600000, 0x00600000, PPC_SPE),
-GEN_SPE(evcmpltu,    evcmplts,    0x19, 0x08, 0x00600000, 0x00600000, PPC_SPE),
-GEN_SPE(evcmpeq,     speundef,    0x1A, 0x08, 0x00600000, 0xFFFFFFFF, PPC_SPE),
-
-GEN_SPE(evfsadd,     evfssub,     0x00, 0x0A, 0x00000000, 0x00000000, PPC_SPE_SINGLE),
-GEN_SPE(evfsabs,     evfsnabs,    0x02, 0x0A, 0x0000F800, 0x0000F800, PPC_SPE_SINGLE),
-GEN_SPE(evfsneg,     speundef,    0x03, 0x0A, 0x0000F800, 0xFFFFFFFF, PPC_SPE_SINGLE),
-GEN_SPE(evfsmul,     evfsdiv,     0x04, 0x0A, 0x00000000, 0x00000000, PPC_SPE_SINGLE),
-GEN_SPE(evfscmpgt,   evfscmplt,   0x06, 0x0A, 0x00600000, 0x00600000, PPC_SPE_SINGLE),
-GEN_SPE(evfscmpeq,   speundef,    0x07, 0x0A, 0x00600000, 0xFFFFFFFF, PPC_SPE_SINGLE),
-GEN_SPE(evfscfui,    evfscfsi,    0x08, 0x0A, 0x00180000, 0x00180000, PPC_SPE_SINGLE),
-GEN_SPE(evfscfuf,    evfscfsf,    0x09, 0x0A, 0x00180000, 0x00180000, PPC_SPE_SINGLE),
-GEN_SPE(evfsctui,    evfsctsi,    0x0A, 0x0A, 0x00180000, 0x00180000, PPC_SPE_SINGLE),
-GEN_SPE(evfsctuf,    evfsctsf,    0x0B, 0x0A, 0x00180000, 0x00180000, PPC_SPE_SINGLE),
-GEN_SPE(evfsctuiz,   speundef,    0x0C, 0x0A, 0x00180000, 0xFFFFFFFF, PPC_SPE_SINGLE),
-GEN_SPE(evfsctsiz,   speundef,    0x0D, 0x0A, 0x00180000, 0xFFFFFFFF, PPC_SPE_SINGLE),
-GEN_SPE(evfststgt,   evfststlt,   0x0E, 0x0A, 0x00600000, 0x00600000, PPC_SPE_SINGLE),
-GEN_SPE(evfststeq,   speundef,    0x0F, 0x0A, 0x00600000, 0xFFFFFFFF, PPC_SPE_SINGLE),
-
-GEN_SPE(efsadd,      efssub,      0x00, 0x0B, 0x00000000, 0x00000000, PPC_SPE_SINGLE),
-GEN_SPE(efsabs,      efsnabs,     0x02, 0x0B, 0x0000F800, 0x0000F800, PPC_SPE_SINGLE),
-GEN_SPE(efsneg,      speundef,    0x03, 0x0B, 0x0000F800, 0xFFFFFFFF, PPC_SPE_SINGLE),
-GEN_SPE(efsmul,      efsdiv,      0x04, 0x0B, 0x00000000, 0x00000000, PPC_SPE_SINGLE),
-GEN_SPE(efscmpgt,    efscmplt,    0x06, 0x0B, 0x00600000, 0x00600000, PPC_SPE_SINGLE),
-GEN_SPE(efscmpeq,    efscfd,      0x07, 0x0B, 0x00600000, 0x00180000, PPC_SPE_SINGLE),
-GEN_SPE(efscfui,     efscfsi,     0x08, 0x0B, 0x00180000, 0x00180000, PPC_SPE_SINGLE),
-GEN_SPE(efscfuf,     efscfsf,     0x09, 0x0B, 0x00180000, 0x00180000, PPC_SPE_SINGLE),
-GEN_SPE(efsctui,     efsctsi,     0x0A, 0x0B, 0x00180000, 0x00180000, PPC_SPE_SINGLE),
-GEN_SPE(efsctuf,     efsctsf,     0x0B, 0x0B, 0x00180000, 0x00180000, PPC_SPE_SINGLE),
-GEN_SPE(efsctuiz,    speundef,    0x0C, 0x0B, 0x00180000, 0xFFFFFFFF, PPC_SPE_SINGLE),
-GEN_SPE(efsctsiz,    speundef,    0x0D, 0x0B, 0x00180000, 0xFFFFFFFF, PPC_SPE_SINGLE),
-GEN_SPE(efststgt,    efststlt,    0x0E, 0x0B, 0x00600000, 0x00600000, PPC_SPE_SINGLE),
-GEN_SPE(efststeq,    speundef,    0x0F, 0x0B, 0x00600000, 0xFFFFFFFF, PPC_SPE_SINGLE),
-
-GEN_SPE(efdadd,      efdsub,      0x10, 0x0B, 0x00000000, 0x00000000, PPC_SPE_DOUBLE),
-GEN_SPE(efdcfuid,    efdcfsid,    0x11, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE),
-GEN_SPE(efdabs,      efdnabs,     0x12, 0x0B, 0x0000F800, 0x0000F800, PPC_SPE_DOUBLE),
-GEN_SPE(efdneg,      speundef,    0x13, 0x0B, 0x0000F800, 0xFFFFFFFF, PPC_SPE_DOUBLE),
-GEN_SPE(efdmul,      efddiv,      0x14, 0x0B, 0x00000000, 0x00000000, PPC_SPE_DOUBLE),
-GEN_SPE(efdctuidz,   efdctsidz,   0x15, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE),
-GEN_SPE(efdcmpgt,    efdcmplt,    0x16, 0x0B, 0x00600000, 0x00600000, PPC_SPE_DOUBLE),
-GEN_SPE(efdcmpeq,    efdcfs,      0x17, 0x0B, 0x00600000, 0x00180000, PPC_SPE_DOUBLE),
-GEN_SPE(efdcfui,     efdcfsi,     0x18, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE),
-GEN_SPE(efdcfuf,     efdcfsf,     0x19, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE),
-GEN_SPE(efdctui,     efdctsi,     0x1A, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE),
-GEN_SPE(efdctuf,     efdctsf,     0x1B, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE),
-GEN_SPE(efdctuiz,    speundef,    0x1C, 0x0B, 0x00180000, 0xFFFFFFFF, PPC_SPE_DOUBLE),
-GEN_SPE(efdctsiz,    speundef,    0x1D, 0x0B, 0x00180000, 0xFFFFFFFF, PPC_SPE_DOUBLE),
-GEN_SPE(efdtstgt,    efdtstlt,    0x1E, 0x0B, 0x00600000, 0x00600000, PPC_SPE_DOUBLE),
-GEN_SPE(efdtsteq,    speundef,    0x1F, 0x0B, 0x00600000, 0xFFFFFFFF, PPC_SPE_DOUBLE),
-
-#undef GEN_SPEOP_LDST
-#define GEN_SPEOP_LDST(name, opc2, sh)                                        \
-GEN_HANDLER(name, 0x04, opc2, 0x0C, 0x00000000, PPC_SPE)
-GEN_SPEOP_LDST(evldd, 0x00, 3),
-GEN_SPEOP_LDST(evldw, 0x01, 3),
-GEN_SPEOP_LDST(evldh, 0x02, 3),
-GEN_SPEOP_LDST(evlhhesplat, 0x04, 1),
-GEN_SPEOP_LDST(evlhhousplat, 0x06, 1),
-GEN_SPEOP_LDST(evlhhossplat, 0x07, 1),
-GEN_SPEOP_LDST(evlwhe, 0x08, 2),
-GEN_SPEOP_LDST(evlwhou, 0x0A, 2),
-GEN_SPEOP_LDST(evlwhos, 0x0B, 2),
-GEN_SPEOP_LDST(evlwwsplat, 0x0C, 2),
-GEN_SPEOP_LDST(evlwhsplat, 0x0E, 2),
-
-GEN_SPEOP_LDST(evstdd, 0x10, 3),
-GEN_SPEOP_LDST(evstdw, 0x11, 3),
-GEN_SPEOP_LDST(evstdh, 0x12, 3),
-GEN_SPEOP_LDST(evstwhe, 0x18, 2),
-GEN_SPEOP_LDST(evstwho, 0x1A, 2),
-GEN_SPEOP_LDST(evstwwe, 0x1C, 2),
-GEN_SPEOP_LDST(evstwwo, 0x1E, 2),
+#include "translate/spe-ops.c"
 
 GEN_HANDLER2_E(tbegin, "tbegin", 0x1F, 0x0E, 0x14, 0x01DFF800, \
                PPC_NONE, PPC2_TM),
diff --git a/target-ppc/translate/spe-impl.c b/target-ppc/translate/spe-impl.c
new file mode 100644
index 0000000..0ce403a
--- /dev/null
+++ b/target-ppc/translate/spe-impl.c
@@ -0,0 +1,1229 @@
+/*
+ * translate-spe.c
+ *
+ * Freescale SPE extension translation
+ */
+
+/***                           SPE extension                               ***/
+/* Register moves */
+
+static inline void gen_evmra(DisasContext *ctx)
+{
+
+    if (unlikely(!ctx->spe_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_SPEU);
+        return;
+    }
+
+    TCGv_i64 tmp = tcg_temp_new_i64();
+
+    /* tmp := rA_lo + rA_hi << 32 */
+    tcg_gen_concat_tl_i64(tmp, cpu_gpr[rA(ctx->opcode)], cpu_gprh[rA(ctx->opcode)]);
+
+    /* spe_acc := tmp */
+    tcg_gen_st_i64(tmp, cpu_env, offsetof(CPUPPCState, spe_acc));
+    tcg_temp_free_i64(tmp);
+
+    /* rD := rA */
+    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
+    tcg_gen_mov_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)]);
+}
+
+static inline void gen_load_gpr64(TCGv_i64 t, int reg)
+{
+    tcg_gen_concat_tl_i64(t, cpu_gpr[reg], cpu_gprh[reg]);
+}
+
+static inline void gen_store_gpr64(int reg, TCGv_i64 t)
+{
+    tcg_gen_extr_i64_tl(cpu_gpr[reg], cpu_gprh[reg], t);
+}
+
+#define GEN_SPE(name0, name1, opc2, opc3, inval0, inval1, type)         \
+static void glue(gen_, name0##_##name1)(DisasContext *ctx)                    \
+{                                                                             \
+    if (Rc(ctx->opcode))                                                      \
+        gen_##name1(ctx);                                                     \
+    else                                                                      \
+        gen_##name0(ctx);                                                     \
+}
+
+/* Handler for undefined SPE opcodes */
+static inline void gen_speundef(DisasContext *ctx)
+{
+    gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
+}
+
+/* SPE logic */
+#define GEN_SPEOP_LOGIC2(name, tcg_op)                                        \
+static inline void gen_##name(DisasContext *ctx)                              \
+{                                                                             \
+    if (unlikely(!ctx->spe_enabled)) {                                        \
+        gen_exception(ctx, POWERPC_EXCP_SPEU);                                \
+        return;                                                               \
+    }                                                                         \
+    tcg_op(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)],                \
+           cpu_gpr[rB(ctx->opcode)]);                                         \
+    tcg_op(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)],              \
+           cpu_gprh[rB(ctx->opcode)]);                                        \
+}
+
+GEN_SPEOP_LOGIC2(evand, tcg_gen_and_tl);
+GEN_SPEOP_LOGIC2(evandc, tcg_gen_andc_tl);
+GEN_SPEOP_LOGIC2(evxor, tcg_gen_xor_tl);
+GEN_SPEOP_LOGIC2(evor, tcg_gen_or_tl);
+GEN_SPEOP_LOGIC2(evnor, tcg_gen_nor_tl);
+GEN_SPEOP_LOGIC2(eveqv, tcg_gen_eqv_tl);
+GEN_SPEOP_LOGIC2(evorc, tcg_gen_orc_tl);
+GEN_SPEOP_LOGIC2(evnand, tcg_gen_nand_tl);
+
+/* SPE logic immediate */
+#define GEN_SPEOP_TCG_LOGIC_IMM2(name, tcg_opi)                               \
+static inline void gen_##name(DisasContext *ctx)                              \
+{                                                                             \
+    TCGv_i32 t0;                                                              \
+    if (unlikely(!ctx->spe_enabled)) {                                        \
+        gen_exception(ctx, POWERPC_EXCP_SPEU);                                \
+        return;                                                               \
+    }                                                                         \
+    t0 = tcg_temp_new_i32();                                                  \
+                                                                              \
+    tcg_gen_trunc_tl_i32(t0, cpu_gpr[rA(ctx->opcode)]);                       \
+    tcg_opi(t0, t0, rB(ctx->opcode));                                         \
+    tcg_gen_extu_i32_tl(cpu_gpr[rD(ctx->opcode)], t0);                        \
+                                                                              \
+    tcg_gen_trunc_tl_i32(t0, cpu_gprh[rA(ctx->opcode)]);                      \
+    tcg_opi(t0, t0, rB(ctx->opcode));                                         \
+    tcg_gen_extu_i32_tl(cpu_gprh[rD(ctx->opcode)], t0);                       \
+                                                                              \
+    tcg_temp_free_i32(t0);                                                    \
+}
+GEN_SPEOP_TCG_LOGIC_IMM2(evslwi, tcg_gen_shli_i32);
+GEN_SPEOP_TCG_LOGIC_IMM2(evsrwiu, tcg_gen_shri_i32);
+GEN_SPEOP_TCG_LOGIC_IMM2(evsrwis, tcg_gen_sari_i32);
+GEN_SPEOP_TCG_LOGIC_IMM2(evrlwi, tcg_gen_rotli_i32);
+
+/* SPE arithmetic */
+#define GEN_SPEOP_ARITH1(name, tcg_op)                                        \
+static inline void gen_##name(DisasContext *ctx)                              \
+{                                                                             \
+    TCGv_i32 t0;                                                              \
+    if (unlikely(!ctx->spe_enabled)) {                                        \
+        gen_exception(ctx, POWERPC_EXCP_SPEU);                                \
+        return;                                                               \
+    }                                                                         \
+    t0 = tcg_temp_new_i32();                                                  \
+                                                                              \
+    tcg_gen_trunc_tl_i32(t0, cpu_gpr[rA(ctx->opcode)]);                       \
+    tcg_op(t0, t0);                                                           \
+    tcg_gen_extu_i32_tl(cpu_gpr[rD(ctx->opcode)], t0);                        \
+                                                                              \
+    tcg_gen_trunc_tl_i32(t0, cpu_gprh[rA(ctx->opcode)]);                      \
+    tcg_op(t0, t0);                                                           \
+    tcg_gen_extu_i32_tl(cpu_gprh[rD(ctx->opcode)], t0);                       \
+                                                                              \
+    tcg_temp_free_i32(t0);                                                    \
+}
+
+static inline void gen_op_evabs(TCGv_i32 ret, TCGv_i32 arg1)
+{
+    TCGLabel *l1 = gen_new_label();
+    TCGLabel *l2 = gen_new_label();
+
+    tcg_gen_brcondi_i32(TCG_COND_GE, arg1, 0, l1);
+    tcg_gen_neg_i32(ret, arg1);
+    tcg_gen_br(l2);
+    gen_set_label(l1);
+    tcg_gen_mov_i32(ret, arg1);
+    gen_set_label(l2);
+}
+GEN_SPEOP_ARITH1(evabs, gen_op_evabs);
+GEN_SPEOP_ARITH1(evneg, tcg_gen_neg_i32);
+GEN_SPEOP_ARITH1(evextsb, tcg_gen_ext8s_i32);
+GEN_SPEOP_ARITH1(evextsh, tcg_gen_ext16s_i32);
+static inline void gen_op_evrndw(TCGv_i32 ret, TCGv_i32 arg1)
+{
+    tcg_gen_addi_i32(ret, arg1, 0x8000);
+    tcg_gen_ext16u_i32(ret, ret);
+}
+GEN_SPEOP_ARITH1(evrndw, gen_op_evrndw);
+GEN_SPEOP_ARITH1(evcntlsw, gen_helper_cntlsw32);
+GEN_SPEOP_ARITH1(evcntlzw, gen_helper_cntlzw32);
+
+#define GEN_SPEOP_ARITH2(name, tcg_op)                                        \
+static inline void gen_##name(DisasContext *ctx)                              \
+{                                                                             \
+    TCGv_i32 t0, t1;                                                          \
+    if (unlikely(!ctx->spe_enabled)) {                                        \
+        gen_exception(ctx, POWERPC_EXCP_SPEU);                                \
+        return;                                                               \
+    }                                                                         \
+    t0 = tcg_temp_new_i32();                                                  \
+    t1 = tcg_temp_new_i32();                                                  \
+                                                                              \
+    tcg_gen_trunc_tl_i32(t0, cpu_gpr[rA(ctx->opcode)]);                       \
+    tcg_gen_trunc_tl_i32(t1, cpu_gpr[rB(ctx->opcode)]);                       \
+    tcg_op(t0, t0, t1);                                                       \
+    tcg_gen_extu_i32_tl(cpu_gpr[rD(ctx->opcode)], t0);                        \
+                                                                              \
+    tcg_gen_trunc_tl_i32(t0, cpu_gprh[rA(ctx->opcode)]);                      \
+    tcg_gen_trunc_tl_i32(t1, cpu_gprh[rB(ctx->opcode)]);                      \
+    tcg_op(t0, t0, t1);                                                       \
+    tcg_gen_extu_i32_tl(cpu_gprh[rD(ctx->opcode)], t0);                       \
+                                                                              \
+    tcg_temp_free_i32(t0);                                                    \
+    tcg_temp_free_i32(t1);                                                    \
+}
+
+static inline void gen_op_evsrwu(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
+{
+    TCGLabel *l1 = gen_new_label();
+    TCGLabel *l2 = gen_new_label();
+    TCGv_i32 t0 = tcg_temp_local_new_i32();
+
+    /* No error here: 6 bits are used */
+    tcg_gen_andi_i32(t0, arg2, 0x3F);
+    tcg_gen_brcondi_i32(TCG_COND_GE, t0, 32, l1);
+    tcg_gen_shr_i32(ret, arg1, t0);
+    tcg_gen_br(l2);
+    gen_set_label(l1);
+    tcg_gen_movi_i32(ret, 0);
+    gen_set_label(l2);
+    tcg_temp_free_i32(t0);
+}
+GEN_SPEOP_ARITH2(evsrwu, gen_op_evsrwu);
+static inline void gen_op_evsrws(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
+{
+    TCGLabel *l1 = gen_new_label();
+    TCGLabel *l2 = gen_new_label();
+    TCGv_i32 t0 = tcg_temp_local_new_i32();
+
+    /* No error here: 6 bits are used */
+    tcg_gen_andi_i32(t0, arg2, 0x3F);
+    tcg_gen_brcondi_i32(TCG_COND_GE, t0, 32, l1);
+    tcg_gen_sar_i32(ret, arg1, t0);
+    tcg_gen_br(l2);
+    gen_set_label(l1);
+    tcg_gen_movi_i32(ret, 0);
+    gen_set_label(l2);
+    tcg_temp_free_i32(t0);
+}
+GEN_SPEOP_ARITH2(evsrws, gen_op_evsrws);
+static inline void gen_op_evslw(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
+{
+    TCGLabel *l1 = gen_new_label();
+    TCGLabel *l2 = gen_new_label();
+    TCGv_i32 t0 = tcg_temp_local_new_i32();
+
+    /* No error here: 6 bits are used */
+    tcg_gen_andi_i32(t0, arg2, 0x3F);
+    tcg_gen_brcondi_i32(TCG_COND_GE, t0, 32, l1);
+    tcg_gen_shl_i32(ret, arg1, t0);
+    tcg_gen_br(l2);
+    gen_set_label(l1);
+    tcg_gen_movi_i32(ret, 0);
+    gen_set_label(l2);
+    tcg_temp_free_i32(t0);
+}
+GEN_SPEOP_ARITH2(evslw, gen_op_evslw);
+static inline void gen_op_evrlw(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
+{
+    TCGv_i32 t0 = tcg_temp_new_i32();
+    tcg_gen_andi_i32(t0, arg2, 0x1F);
+    tcg_gen_rotl_i32(ret, arg1, t0);
+    tcg_temp_free_i32(t0);
+}
+GEN_SPEOP_ARITH2(evrlw, gen_op_evrlw);
+static inline void gen_evmergehi(DisasContext *ctx)
+{
+    if (unlikely(!ctx->spe_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_SPEU);
+        return;
+    }
+    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gprh[rB(ctx->opcode)]);
+    tcg_gen_mov_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)]);
+}
+GEN_SPEOP_ARITH2(evaddw, tcg_gen_add_i32);
+static inline void gen_op_evsubf(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
+{
+    tcg_gen_sub_i32(ret, arg2, arg1);
+}
+GEN_SPEOP_ARITH2(evsubfw, gen_op_evsubf);
+
+/* SPE arithmetic immediate */
+#define GEN_SPEOP_ARITH_IMM2(name, tcg_op)                                    \
+static inline void gen_##name(DisasContext *ctx)                              \
+{                                                                             \
+    TCGv_i32 t0;                                                              \
+    if (unlikely(!ctx->spe_enabled)) {                                        \
+        gen_exception(ctx, POWERPC_EXCP_SPEU);                                \
+        return;                                                               \
+    }                                                                         \
+    t0 = tcg_temp_new_i32();                                                  \
+                                                                              \
+    tcg_gen_trunc_tl_i32(t0, cpu_gpr[rB(ctx->opcode)]);                       \
+    tcg_op(t0, t0, rA(ctx->opcode));                                          \
+    tcg_gen_extu_i32_tl(cpu_gpr[rD(ctx->opcode)], t0);                        \
+                                                                              \
+    tcg_gen_trunc_tl_i32(t0, cpu_gprh[rB(ctx->opcode)]);                      \
+    tcg_op(t0, t0, rA(ctx->opcode));                                          \
+    tcg_gen_extu_i32_tl(cpu_gprh[rD(ctx->opcode)], t0);                       \
+                                                                              \
+    tcg_temp_free_i32(t0);                                                    \
+}
+GEN_SPEOP_ARITH_IMM2(evaddiw, tcg_gen_addi_i32);
+GEN_SPEOP_ARITH_IMM2(evsubifw, tcg_gen_subi_i32);
+
+/* SPE comparison */
+#define GEN_SPEOP_COMP(name, tcg_cond)                                        \
+static inline void gen_##name(DisasContext *ctx)                              \
+{                                                                             \
+    if (unlikely(!ctx->spe_enabled)) {                                        \
+        gen_exception(ctx, POWERPC_EXCP_SPEU);                                \
+        return;                                                               \
+    }                                                                         \
+    TCGLabel *l1 = gen_new_label();                                           \
+    TCGLabel *l2 = gen_new_label();                                           \
+    TCGLabel *l3 = gen_new_label();                                           \
+    TCGLabel *l4 = gen_new_label();                                           \
+                                                                              \
+    tcg_gen_ext32s_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);    \
+    tcg_gen_ext32s_tl(cpu_gpr[rB(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);    \
+    tcg_gen_ext32s_tl(cpu_gprh[rA(ctx->opcode)], cpu_gprh[rA(ctx->opcode)]);  \
+    tcg_gen_ext32s_tl(cpu_gprh[rB(ctx->opcode)], cpu_gprh[rB(ctx->opcode)]);  \
+                                                                              \
+    tcg_gen_brcond_tl(tcg_cond, cpu_gpr[rA(ctx->opcode)],                     \
+                       cpu_gpr[rB(ctx->opcode)], l1);                         \
+    tcg_gen_movi_i32(cpu_crf[crfD(ctx->opcode)], 0);                          \
+    tcg_gen_br(l2);                                                           \
+    gen_set_label(l1);                                                        \
+    tcg_gen_movi_i32(cpu_crf[crfD(ctx->opcode)],                              \
+                     CRF_CL | CRF_CH_OR_CL | CRF_CH_AND_CL);                  \
+    gen_set_label(l2);                                                        \
+    tcg_gen_brcond_tl(tcg_cond, cpu_gprh[rA(ctx->opcode)],                    \
+                       cpu_gprh[rB(ctx->opcode)], l3);                        \
+    tcg_gen_andi_i32(cpu_crf[crfD(ctx->opcode)], cpu_crf[crfD(ctx->opcode)],  \
+                     ~(CRF_CH | CRF_CH_AND_CL));                              \
+    tcg_gen_br(l4);                                                           \
+    gen_set_label(l3);                                                        \
+    tcg_gen_ori_i32(cpu_crf[crfD(ctx->opcode)], cpu_crf[crfD(ctx->opcode)],   \
+                    CRF_CH | CRF_CH_OR_CL);                                   \
+    gen_set_label(l4);                                                        \
+}
+GEN_SPEOP_COMP(evcmpgtu, TCG_COND_GTU);
+GEN_SPEOP_COMP(evcmpgts, TCG_COND_GT);
+GEN_SPEOP_COMP(evcmpltu, TCG_COND_LTU);
+GEN_SPEOP_COMP(evcmplts, TCG_COND_LT);
+GEN_SPEOP_COMP(evcmpeq, TCG_COND_EQ);
+
+/* SPE misc */
+static inline void gen_brinc(DisasContext *ctx)
+{
+    /* Note: brinc is usable even if SPE is disabled */
+    gen_helper_brinc(cpu_gpr[rD(ctx->opcode)],
+                     cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
+}
+static inline void gen_evmergelo(DisasContext *ctx)
+{
+    if (unlikely(!ctx->spe_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_SPEU);
+        return;
+    }
+    tcg_gen_mov_tl(cpu_gprh[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
+    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
+}
+static inline void gen_evmergehilo(DisasContext *ctx)
+{
+    if (unlikely(!ctx->spe_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_SPEU);
+        return;
+    }
+    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
+    tcg_gen_mov_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)]);
+}
+static inline void gen_evmergelohi(DisasContext *ctx)
+{
+    if (unlikely(!ctx->spe_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_SPEU);
+        return;
+    }
+    if (rD(ctx->opcode) == rA(ctx->opcode)) {
+        TCGv tmp = tcg_temp_new();
+        tcg_gen_mov_tl(tmp, cpu_gpr[rA(ctx->opcode)]);
+        tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gprh[rB(ctx->opcode)]);
+        tcg_gen_mov_tl(cpu_gprh[rD(ctx->opcode)], tmp);
+        tcg_temp_free(tmp);
+    } else {
+        tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gprh[rB(ctx->opcode)]);
+        tcg_gen_mov_tl(cpu_gprh[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
+    }
+}
+static inline void gen_evsplati(DisasContext *ctx)
+{
+    uint64_t imm = ((int32_t)(rA(ctx->opcode) << 27)) >> 27;
+
+    tcg_gen_movi_tl(cpu_gpr[rD(ctx->opcode)], imm);
+    tcg_gen_movi_tl(cpu_gprh[rD(ctx->opcode)], imm);
+}
+static inline void gen_evsplatfi(DisasContext *ctx)
+{
+    uint64_t imm = rA(ctx->opcode) << 27;
+
+    tcg_gen_movi_tl(cpu_gpr[rD(ctx->opcode)], imm);
+    tcg_gen_movi_tl(cpu_gprh[rD(ctx->opcode)], imm);
+}
+
+static inline void gen_evsel(DisasContext *ctx)
+{
+    TCGLabel *l1 = gen_new_label();
+    TCGLabel *l2 = gen_new_label();
+    TCGLabel *l3 = gen_new_label();
+    TCGLabel *l4 = gen_new_label();
+    TCGv_i32 t0 = tcg_temp_local_new_i32();
+
+    tcg_gen_andi_i32(t0, cpu_crf[ctx->opcode & 0x07], 1 << 3);
+    tcg_gen_brcondi_i32(TCG_COND_EQ, t0, 0, l1);
+    tcg_gen_mov_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)]);
+    tcg_gen_br(l2);
+    gen_set_label(l1);
+    tcg_gen_mov_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rB(ctx->opcode)]);
+    gen_set_label(l2);
+    tcg_gen_andi_i32(t0, cpu_crf[ctx->opcode & 0x07], 1 << 2);
+    tcg_gen_brcondi_i32(TCG_COND_EQ, t0, 0, l3);
+    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
+    tcg_gen_br(l4);
+    gen_set_label(l3);
+    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
+    gen_set_label(l4);
+    tcg_temp_free_i32(t0);
+}
+
+static void gen_evsel0(DisasContext *ctx)
+{
+    gen_evsel(ctx);
+}
+
+static void gen_evsel1(DisasContext *ctx)
+{
+    gen_evsel(ctx);
+}
+
+static void gen_evsel2(DisasContext *ctx)
+{
+    gen_evsel(ctx);
+}
+
+static void gen_evsel3(DisasContext *ctx)
+{
+    gen_evsel(ctx);
+}
+
+/* Multiply */
+
+static inline void gen_evmwumi(DisasContext *ctx)
+{
+    TCGv_i64 t0, t1;
+
+    if (unlikely(!ctx->spe_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_SPEU);
+        return;
+    }
+
+    t0 = tcg_temp_new_i64();
+    t1 = tcg_temp_new_i64();
+
+    /* t0 := rA; t1 := rB */
+    tcg_gen_extu_tl_i64(t0, cpu_gpr[rA(ctx->opcode)]);
+    tcg_gen_ext32u_i64(t0, t0);
+    tcg_gen_extu_tl_i64(t1, cpu_gpr[rB(ctx->opcode)]);
+    tcg_gen_ext32u_i64(t1, t1);
+
+    tcg_gen_mul_i64(t0, t0, t1);  /* t0 := rA * rB */
+
+    gen_store_gpr64(rD(ctx->opcode), t0); /* rD := t0 */
+
+    tcg_temp_free_i64(t0);
+    tcg_temp_free_i64(t1);
+}
+
+static inline void gen_evmwumia(DisasContext *ctx)
+{
+    TCGv_i64 tmp;
+
+    if (unlikely(!ctx->spe_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_SPEU);
+        return;
+    }
+
+    gen_evmwumi(ctx);            /* rD := rA * rB */
+
+    tmp = tcg_temp_new_i64();
+
+    /* acc := rD */
+    gen_load_gpr64(tmp, rD(ctx->opcode));
+    tcg_gen_st_i64(tmp, cpu_env, offsetof(CPUPPCState, spe_acc));
+    tcg_temp_free_i64(tmp);
+}
+
+static inline void gen_evmwumiaa(DisasContext *ctx)
+{
+    TCGv_i64 acc;
+    TCGv_i64 tmp;
+
+    if (unlikely(!ctx->spe_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_SPEU);
+        return;
+    }
+
+    gen_evmwumi(ctx);           /* rD := rA * rB */
+
+    acc = tcg_temp_new_i64();
+    tmp = tcg_temp_new_i64();
+
+    /* tmp := rD */
+    gen_load_gpr64(tmp, rD(ctx->opcode));
+
+    /* Load acc */
+    tcg_gen_ld_i64(acc, cpu_env, offsetof(CPUPPCState, spe_acc));
+
+    /* acc := tmp + acc */
+    tcg_gen_add_i64(acc, acc, tmp);
+
+    /* Store acc */
+    tcg_gen_st_i64(acc, cpu_env, offsetof(CPUPPCState, spe_acc));
+
+    /* rD := acc */
+    gen_store_gpr64(rD(ctx->opcode), acc);
+
+    tcg_temp_free_i64(acc);
+    tcg_temp_free_i64(tmp);
+}
+
+static inline void gen_evmwsmi(DisasContext *ctx)
+{
+    TCGv_i64 t0, t1;
+
+    if (unlikely(!ctx->spe_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_SPEU);
+        return;
+    }
+
+    t0 = tcg_temp_new_i64();
+    t1 = tcg_temp_new_i64();
+
+    /* t0 := rA; t1 := rB */
+    tcg_gen_extu_tl_i64(t0, cpu_gpr[rA(ctx->opcode)]);
+    tcg_gen_ext32s_i64(t0, t0);
+    tcg_gen_extu_tl_i64(t1, cpu_gpr[rB(ctx->opcode)]);
+    tcg_gen_ext32s_i64(t1, t1);
+
+    tcg_gen_mul_i64(t0, t0, t1);  /* t0 := rA * rB */
+
+    gen_store_gpr64(rD(ctx->opcode), t0); /* rD := t0 */
+
+    tcg_temp_free_i64(t0);
+    tcg_temp_free_i64(t1);
+}
+
+static inline void gen_evmwsmia(DisasContext *ctx)
+{
+    TCGv_i64 tmp;
+
+    gen_evmwsmi(ctx);            /* rD := rA * rB */
+
+    tmp = tcg_temp_new_i64();
+
+    /* acc := rD */
+    gen_load_gpr64(tmp, rD(ctx->opcode));
+    tcg_gen_st_i64(tmp, cpu_env, offsetof(CPUPPCState, spe_acc));
+
+    tcg_temp_free_i64(tmp);
+}
+
+static inline void gen_evmwsmiaa(DisasContext *ctx)
+{
+    TCGv_i64 acc = tcg_temp_new_i64();
+    TCGv_i64 tmp = tcg_temp_new_i64();
+
+    gen_evmwsmi(ctx);           /* rD := rA * rB */
+
+    acc = tcg_temp_new_i64();
+    tmp = tcg_temp_new_i64();
+
+    /* tmp := rD */
+    gen_load_gpr64(tmp, rD(ctx->opcode));
+
+    /* Load acc */
+    tcg_gen_ld_i64(acc, cpu_env, offsetof(CPUPPCState, spe_acc));
+
+    /* acc := tmp + acc */
+    tcg_gen_add_i64(acc, acc, tmp);
+
+    /* Store acc */
+    tcg_gen_st_i64(acc, cpu_env, offsetof(CPUPPCState, spe_acc));
+
+    /* rD := acc */
+    gen_store_gpr64(rD(ctx->opcode), acc);
+
+    tcg_temp_free_i64(acc);
+    tcg_temp_free_i64(tmp);
+}
+
+GEN_SPE(evaddw,      speundef,    0x00, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE); ////
+GEN_SPE(evaddiw,     speundef,    0x01, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE);
+GEN_SPE(evsubfw,     speundef,    0x02, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE); ////
+GEN_SPE(evsubifw,    speundef,    0x03, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE);
+GEN_SPE(evabs,       evneg,       0x04, 0x08, 0x0000F800, 0x0000F800, PPC_SPE); ////
+GEN_SPE(evextsb,     evextsh,     0x05, 0x08, 0x0000F800, 0x0000F800, PPC_SPE); ////
+GEN_SPE(evrndw,      evcntlzw,    0x06, 0x08, 0x0000F800, 0x0000F800, PPC_SPE); ////
+GEN_SPE(evcntlsw,    brinc,       0x07, 0x08, 0x0000F800, 0x00000000, PPC_SPE); //
+GEN_SPE(evmra,       speundef,    0x02, 0x13, 0x0000F800, 0xFFFFFFFF, PPC_SPE);
+GEN_SPE(speundef,    evand,       0x08, 0x08, 0xFFFFFFFF, 0x00000000, PPC_SPE); ////
+GEN_SPE(evandc,      speundef,    0x09, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE); ////
+GEN_SPE(evxor,       evor,        0x0B, 0x08, 0x00000000, 0x00000000, PPC_SPE); ////
+GEN_SPE(evnor,       eveqv,       0x0C, 0x08, 0x00000000, 0x00000000, PPC_SPE); ////
+GEN_SPE(evmwumi,     evmwsmi,     0x0C, 0x11, 0x00000000, 0x00000000, PPC_SPE);
+GEN_SPE(evmwumia,    evmwsmia,    0x1C, 0x11, 0x00000000, 0x00000000, PPC_SPE);
+GEN_SPE(evmwumiaa,   evmwsmiaa,   0x0C, 0x15, 0x00000000, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,    evorc,       0x0D, 0x08, 0xFFFFFFFF, 0x00000000, PPC_SPE); ////
+GEN_SPE(evnand,      speundef,    0x0F, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE); ////
+GEN_SPE(evsrwu,      evsrws,      0x10, 0x08, 0x00000000, 0x00000000, PPC_SPE); ////
+GEN_SPE(evsrwiu,     evsrwis,     0x11, 0x08, 0x00000000, 0x00000000, PPC_SPE);
+GEN_SPE(evslw,       speundef,    0x12, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE); ////
+GEN_SPE(evslwi,      speundef,    0x13, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE);
+GEN_SPE(evrlw,       evsplati,    0x14, 0x08, 0x00000000, 0x0000F800, PPC_SPE); //
+GEN_SPE(evrlwi,      evsplatfi,   0x15, 0x08, 0x00000000, 0x0000F800, PPC_SPE);
+GEN_SPE(evmergehi,   evmergelo,   0x16, 0x08, 0x00000000, 0x00000000, PPC_SPE); ////
+GEN_SPE(evmergehilo, evmergelohi, 0x17, 0x08, 0x00000000, 0x00000000, PPC_SPE); ////
+GEN_SPE(evcmpgtu,    evcmpgts,    0x18, 0x08, 0x00600000, 0x00600000, PPC_SPE); ////
+GEN_SPE(evcmpltu,    evcmplts,    0x19, 0x08, 0x00600000, 0x00600000, PPC_SPE); ////
+GEN_SPE(evcmpeq,     speundef,    0x1A, 0x08, 0x00600000, 0xFFFFFFFF, PPC_SPE); ////
+
+/* SPE load and stores */
+static inline void gen_addr_spe_imm_index(DisasContext *ctx, TCGv EA, int sh)
+{
+    target_ulong uimm = rB(ctx->opcode);
+
+    if (rA(ctx->opcode) == 0) {
+        tcg_gen_movi_tl(EA, uimm << sh);
+    } else {
+        tcg_gen_addi_tl(EA, cpu_gpr[rA(ctx->opcode)], uimm << sh);
+        if (NARROW_MODE(ctx)) {
+            tcg_gen_ext32u_tl(EA, EA);
+        }
+    }
+}
+
+static inline void gen_op_evldd(DisasContext *ctx, TCGv addr)
+{
+    TCGv_i64 t0 = tcg_temp_new_i64();
+    gen_qemu_ld64(ctx, t0, addr);
+    gen_store_gpr64(rD(ctx->opcode), t0);
+    tcg_temp_free_i64(t0);
+}
+
+static inline void gen_op_evldw(DisasContext *ctx, TCGv addr)
+{
+    gen_qemu_ld32u(ctx, cpu_gprh[rD(ctx->opcode)], addr);
+    gen_addr_add(ctx, addr, addr, 4);
+    gen_qemu_ld32u(ctx, cpu_gpr[rD(ctx->opcode)], addr);
+}
+
+static inline void gen_op_evldh(DisasContext *ctx, TCGv addr)
+{
+    TCGv t0 = tcg_temp_new();
+    gen_qemu_ld16u(ctx, t0, addr);
+    tcg_gen_shli_tl(cpu_gprh[rD(ctx->opcode)], t0, 16);
+    gen_addr_add(ctx, addr, addr, 2);
+    gen_qemu_ld16u(ctx, t0, addr);
+    tcg_gen_or_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rD(ctx->opcode)], t0);
+    gen_addr_add(ctx, addr, addr, 2);
+    gen_qemu_ld16u(ctx, t0, addr);
+    tcg_gen_shli_tl(cpu_gprh[rD(ctx->opcode)], t0, 16);
+    gen_addr_add(ctx, addr, addr, 2);
+    gen_qemu_ld16u(ctx, t0, addr);
+    tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], t0);
+    tcg_temp_free(t0);
+}
+
+static inline void gen_op_evlhhesplat(DisasContext *ctx, TCGv addr)
+{
+    TCGv t0 = tcg_temp_new();
+    gen_qemu_ld16u(ctx, t0, addr);
+    tcg_gen_shli_tl(t0, t0, 16);
+    tcg_gen_mov_tl(cpu_gprh[rD(ctx->opcode)], t0);
+    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], t0);
+    tcg_temp_free(t0);
+}
+
+static inline void gen_op_evlhhousplat(DisasContext *ctx, TCGv addr)
+{
+    TCGv t0 = tcg_temp_new();
+    gen_qemu_ld16u(ctx, t0, addr);
+    tcg_gen_mov_tl(cpu_gprh[rD(ctx->opcode)], t0);
+    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], t0);
+    tcg_temp_free(t0);
+}
+
+static inline void gen_op_evlhhossplat(DisasContext *ctx, TCGv addr)
+{
+    TCGv t0 = tcg_temp_new();
+    gen_qemu_ld16s(ctx, t0, addr);
+    tcg_gen_mov_tl(cpu_gprh[rD(ctx->opcode)], t0);
+    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], t0);
+    tcg_temp_free(t0);
+}
+
+static inline void gen_op_evlwhe(DisasContext *ctx, TCGv addr)
+{
+    TCGv t0 = tcg_temp_new();
+    gen_qemu_ld16u(ctx, t0, addr);
+    tcg_gen_shli_tl(cpu_gprh[rD(ctx->opcode)], t0, 16);
+    gen_addr_add(ctx, addr, addr, 2);
+    gen_qemu_ld16u(ctx, t0, addr);
+    tcg_gen_shli_tl(cpu_gpr[rD(ctx->opcode)], t0, 16);
+    tcg_temp_free(t0);
+}
+
+static inline void gen_op_evlwhou(DisasContext *ctx, TCGv addr)
+{
+    gen_qemu_ld16u(ctx, cpu_gprh[rD(ctx->opcode)], addr);
+    gen_addr_add(ctx, addr, addr, 2);
+    gen_qemu_ld16u(ctx, cpu_gpr[rD(ctx->opcode)], addr);
+}
+
+static inline void gen_op_evlwhos(DisasContext *ctx, TCGv addr)
+{
+    gen_qemu_ld16s(ctx, cpu_gprh[rD(ctx->opcode)], addr);
+    gen_addr_add(ctx, addr, addr, 2);
+    gen_qemu_ld16s(ctx, cpu_gpr[rD(ctx->opcode)], addr);
+}
+
+static inline void gen_op_evlwwsplat(DisasContext *ctx, TCGv addr)
+{
+    TCGv t0 = tcg_temp_new();
+    gen_qemu_ld32u(ctx, t0, addr);
+    tcg_gen_mov_tl(cpu_gprh[rD(ctx->opcode)], t0);
+    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], t0);
+    tcg_temp_free(t0);
+}
+
+static inline void gen_op_evlwhsplat(DisasContext *ctx, TCGv addr)
+{
+    TCGv t0 = tcg_temp_new();
+    gen_qemu_ld16u(ctx, t0, addr);
+    tcg_gen_shli_tl(cpu_gprh[rD(ctx->opcode)], t0, 16);
+    tcg_gen_or_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rD(ctx->opcode)], t0);
+    gen_addr_add(ctx, addr, addr, 2);
+    gen_qemu_ld16u(ctx, t0, addr);
+    tcg_gen_shli_tl(cpu_gpr[rD(ctx->opcode)], t0, 16);
+    tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gprh[rD(ctx->opcode)], t0);
+    tcg_temp_free(t0);
+}
+
+static inline void gen_op_evstdd(DisasContext *ctx, TCGv addr)
+{
+    TCGv_i64 t0 = tcg_temp_new_i64();
+    gen_load_gpr64(t0, rS(ctx->opcode));
+    gen_qemu_st64(ctx, t0, addr);
+    tcg_temp_free_i64(t0);
+}
+
+static inline void gen_op_evstdw(DisasContext *ctx, TCGv addr)
+{
+    gen_qemu_st32(ctx, cpu_gprh[rS(ctx->opcode)], addr);
+    gen_addr_add(ctx, addr, addr, 4);
+    gen_qemu_st32(ctx, cpu_gpr[rS(ctx->opcode)], addr);
+}
+
+static inline void gen_op_evstdh(DisasContext *ctx, TCGv addr)
+{
+    TCGv t0 = tcg_temp_new();
+    tcg_gen_shri_tl(t0, cpu_gprh[rS(ctx->opcode)], 16);
+    gen_qemu_st16(ctx, t0, addr);
+    gen_addr_add(ctx, addr, addr, 2);
+    gen_qemu_st16(ctx, cpu_gprh[rS(ctx->opcode)], addr);
+    gen_addr_add(ctx, addr, addr, 2);
+    tcg_gen_shri_tl(t0, cpu_gpr[rS(ctx->opcode)], 16);
+    gen_qemu_st16(ctx, t0, addr);
+    tcg_temp_free(t0);
+    gen_addr_add(ctx, addr, addr, 2);
+    gen_qemu_st16(ctx, cpu_gpr[rS(ctx->opcode)], addr);
+}
+
+static inline void gen_op_evstwhe(DisasContext *ctx, TCGv addr)
+{
+    TCGv t0 = tcg_temp_new();
+    tcg_gen_shri_tl(t0, cpu_gprh[rS(ctx->opcode)], 16);
+    gen_qemu_st16(ctx, t0, addr);
+    gen_addr_add(ctx, addr, addr, 2);
+    tcg_gen_shri_tl(t0, cpu_gpr[rS(ctx->opcode)], 16);
+    gen_qemu_st16(ctx, t0, addr);
+    tcg_temp_free(t0);
+}
+
+static inline void gen_op_evstwho(DisasContext *ctx, TCGv addr)
+{
+    gen_qemu_st16(ctx, cpu_gprh[rS(ctx->opcode)], addr);
+    gen_addr_add(ctx, addr, addr, 2);
+    gen_qemu_st16(ctx, cpu_gpr[rS(ctx->opcode)], addr);
+}
+
+static inline void gen_op_evstwwe(DisasContext *ctx, TCGv addr)
+{
+    gen_qemu_st32(ctx, cpu_gprh[rS(ctx->opcode)], addr);
+}
+
+static inline void gen_op_evstwwo(DisasContext *ctx, TCGv addr)
+{
+    gen_qemu_st32(ctx, cpu_gpr[rS(ctx->opcode)], addr);
+}
+
+#define GEN_SPEOP_LDST(name, opc2, sh)                                        \
+static void glue(gen_, name)(DisasContext *ctx)                                       \
+{                                                                             \
+    TCGv t0;                                                                  \
+    if (unlikely(!ctx->spe_enabled)) {                                        \
+        gen_exception(ctx, POWERPC_EXCP_SPEU);                                \
+        return;                                                               \
+    }                                                                         \
+    gen_set_access_type(ctx, ACCESS_INT);                                     \
+    t0 = tcg_temp_new();                                                      \
+    if (Rc(ctx->opcode)) {                                                    \
+        gen_addr_spe_imm_index(ctx, t0, sh);                                  \
+    } else {                                                                  \
+        gen_addr_reg_index(ctx, t0);                                          \
+    }                                                                         \
+    gen_op_##name(ctx, t0);                                                   \
+    tcg_temp_free(t0);                                                        \
+}
+
+GEN_SPEOP_LDST(evldd, 0x00, 3);
+GEN_SPEOP_LDST(evldw, 0x01, 3);
+GEN_SPEOP_LDST(evldh, 0x02, 3);
+GEN_SPEOP_LDST(evlhhesplat, 0x04, 1);
+GEN_SPEOP_LDST(evlhhousplat, 0x06, 1);
+GEN_SPEOP_LDST(evlhhossplat, 0x07, 1);
+GEN_SPEOP_LDST(evlwhe, 0x08, 2);
+GEN_SPEOP_LDST(evlwhou, 0x0A, 2);
+GEN_SPEOP_LDST(evlwhos, 0x0B, 2);
+GEN_SPEOP_LDST(evlwwsplat, 0x0C, 2);
+GEN_SPEOP_LDST(evlwhsplat, 0x0E, 2);
+
+GEN_SPEOP_LDST(evstdd, 0x10, 3);
+GEN_SPEOP_LDST(evstdw, 0x11, 3);
+GEN_SPEOP_LDST(evstdh, 0x12, 3);
+GEN_SPEOP_LDST(evstwhe, 0x18, 2);
+GEN_SPEOP_LDST(evstwho, 0x1A, 2);
+GEN_SPEOP_LDST(evstwwe, 0x1C, 2);
+GEN_SPEOP_LDST(evstwwo, 0x1E, 2);
+
+/* Multiply and add - TODO */
+#if 0
+GEN_SPE(speundef,       evmhessf,      0x01, 0x10, 0xFFFFFFFF, 0x00000000, PPC_SPE);//
+GEN_SPE(speundef,       evmhossf,      0x03, 0x10, 0xFFFFFFFF, 0x00000000, PPC_SPE);
+GEN_SPE(evmheumi,       evmhesmi,      0x04, 0x10, 0x00000000, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhesmf,      0x05, 0x10, 0xFFFFFFFF, 0x00000000, PPC_SPE);
+GEN_SPE(evmhoumi,       evmhosmi,      0x06, 0x10, 0x00000000, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhosmf,      0x07, 0x10, 0xFFFFFFFF, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhessfa,     0x11, 0x10, 0xFFFFFFFF, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhossfa,     0x13, 0x10, 0xFFFFFFFF, 0x00000000, PPC_SPE);
+GEN_SPE(evmheumia,      evmhesmia,     0x14, 0x10, 0x00000000, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhesmfa,     0x15, 0x10, 0xFFFFFFFF, 0x00000000, PPC_SPE);
+GEN_SPE(evmhoumia,      evmhosmia,     0x16, 0x10, 0x00000000, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhosmfa,     0x17, 0x10, 0xFFFFFFFF, 0x00000000, PPC_SPE);
+
+GEN_SPE(speundef,       evmwhssf,      0x03, 0x11, 0xFFFFFFFF, 0x00000000, PPC_SPE);
+GEN_SPE(evmwlumi,       speundef,      0x04, 0x11, 0x00000000, 0xFFFFFFFF, PPC_SPE);
+GEN_SPE(evmwhumi,       evmwhsmi,      0x06, 0x11, 0x00000000, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmwhsmf,      0x07, 0x11, 0xFFFFFFFF, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmwssf,       0x09, 0x11, 0xFFFFFFFF, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmwsmf,       0x0D, 0x11, 0xFFFFFFFF, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmwhssfa,     0x13, 0x11, 0xFFFFFFFF, 0x00000000, PPC_SPE);
+GEN_SPE(evmwlumia,      speundef,      0x14, 0x11, 0x00000000, 0xFFFFFFFF, PPC_SPE);
+GEN_SPE(evmwhumia,      evmwhsmia,     0x16, 0x11, 0x00000000, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmwhsmfa,     0x17, 0x11, 0xFFFFFFFF, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmwssfa,      0x19, 0x11, 0xFFFFFFFF, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmwsmfa,      0x1D, 0x11, 0xFFFFFFFF, 0x00000000, PPC_SPE);
+
+GEN_SPE(evadduiaaw,     evaddsiaaw,    0x00, 0x13, 0x0000F800, 0x0000F800, PPC_SPE);
+GEN_SPE(evsubfusiaaw,   evsubfssiaaw,  0x01, 0x13, 0x0000F800, 0x0000F800, PPC_SPE);
+GEN_SPE(evaddumiaaw,    evaddsmiaaw,   0x04, 0x13, 0x0000F800, 0x0000F800, PPC_SPE);
+GEN_SPE(evsubfumiaaw,   evsubfsmiaaw,  0x05, 0x13, 0x0000F800, 0x0000F800, PPC_SPE);
+GEN_SPE(evdivws,        evdivwu,       0x06, 0x13, 0x00000000, 0x00000000, PPC_SPE);
+
+GEN_SPE(evmheusiaaw,    evmhessiaaw,   0x00, 0x14, 0x00000000, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhessfaaw,   0x01, 0x14, 0xFFFFFFFF, 0x00000000, PPC_SPE);
+GEN_SPE(evmhousiaaw,    evmhossiaaw,   0x02, 0x14, 0x00000000, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhossfaaw,   0x03, 0x14, 0xFFFFFFFF, 0x00000000, PPC_SPE);
+GEN_SPE(evmheumiaaw,    evmhesmiaaw,   0x04, 0x14, 0x00000000, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhesmfaaw,   0x05, 0x14, 0xFFFFFFFF, 0x00000000, PPC_SPE);
+GEN_SPE(evmhoumiaaw,    evmhosmiaaw,   0x06, 0x14, 0x00000000, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhosmfaaw,   0x07, 0x14, 0xFFFFFFFF, 0x00000000, PPC_SPE);
+GEN_SPE(evmhegumiaa,    evmhegsmiaa,   0x14, 0x14, 0x00000000, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhegsmfaa,   0x15, 0x14, 0xFFFFFFFF, 0x00000000, PPC_SPE);
+GEN_SPE(evmhogumiaa,    evmhogsmiaa,   0x16, 0x14, 0x00000000, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhogsmfaa,   0x17, 0x14, 0xFFFFFFFF, 0x00000000, PPC_SPE);
+
+GEN_SPE(evmwlusiaaw,    evmwlssiaaw,   0x00, 0x15, 0x00000000, 0x00000000, PPC_SPE);
+GEN_SPE(evmwlumiaaw,    evmwlsmiaaw,   0x04, 0x15, 0x00000000, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmwssfaa,     0x09, 0x15, 0xFFFFFFFF, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmwsmfaa,     0x0D, 0x15, 0xFFFFFFFF, 0x00000000, PPC_SPE);
+
+GEN_SPE(evmheusianw,    evmhessianw,   0x00, 0x16, 0x00000000, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhessfanw,   0x01, 0x16, 0xFFFFFFFF, 0x00000000, PPC_SPE);
+GEN_SPE(evmhousianw,    evmhossianw,   0x02, 0x16, 0x00000000, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhossfanw,   0x03, 0x16, 0xFFFFFFFF, 0x00000000, PPC_SPE);
+GEN_SPE(evmheumianw,    evmhesmianw,   0x04, 0x16, 0x00000000, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhesmfanw,   0x05, 0x16, 0xFFFFFFFF, 0x00000000, PPC_SPE);
+GEN_SPE(evmhoumianw,    evmhosmianw,   0x06, 0x16, 0x00000000, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhosmfanw,   0x07, 0x16, 0xFFFFFFFF, 0x00000000, PPC_SPE);
+GEN_SPE(evmhegumian,    evmhegsmian,   0x14, 0x16, 0x00000000, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhegsmfan,   0x15, 0x16, 0xFFFFFFFF, 0x00000000, PPC_SPE);
+GEN_SPE(evmhigumian,    evmhigsmian,   0x16, 0x16, 0x00000000, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhogsmfan,   0x17, 0x16, 0xFFFFFFFF, 0x00000000, PPC_SPE);
+
+GEN_SPE(evmwlusianw,    evmwlssianw,   0x00, 0x17, 0x00000000, 0x00000000, PPC_SPE);
+GEN_SPE(evmwlumianw,    evmwlsmianw,   0x04, 0x17, 0x00000000, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmwssfan,     0x09, 0x17, 0xFFFFFFFF, 0x00000000, PPC_SPE);
+GEN_SPE(evmwumian,      evmwsmian,     0x0C, 0x17, 0x00000000, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmwsmfan,     0x0D, 0x17, 0xFFFFFFFF, 0x00000000, PPC_SPE);
+#endif
+
+/***                      SPE floating-point extension                     ***/
+#define GEN_SPEFPUOP_CONV_32_32(name)                                         \
+static inline void gen_##name(DisasContext *ctx)                              \
+{                                                                             \
+    TCGv_i32 t0 = tcg_temp_new_i32();                                         \
+    tcg_gen_trunc_tl_i32(t0, cpu_gpr[rB(ctx->opcode)]);                       \
+    gen_helper_##name(t0, cpu_env, t0);                                       \
+    tcg_gen_extu_i32_tl(cpu_gpr[rD(ctx->opcode)], t0);                        \
+    tcg_temp_free_i32(t0);                                                    \
+}
+#define GEN_SPEFPUOP_CONV_32_64(name)                                         \
+static inline void gen_##name(DisasContext *ctx)                              \
+{                                                                             \
+    TCGv_i64 t0 = tcg_temp_new_i64();                                         \
+    TCGv_i32 t1 = tcg_temp_new_i32();                                         \
+    gen_load_gpr64(t0, rB(ctx->opcode));                                      \
+    gen_helper_##name(t1, cpu_env, t0);                                       \
+    tcg_gen_extu_i32_tl(cpu_gpr[rD(ctx->opcode)], t1);                        \
+    tcg_temp_free_i64(t0);                                                    \
+    tcg_temp_free_i32(t1);                                                    \
+}
+#define GEN_SPEFPUOP_CONV_64_32(name)                                         \
+static inline void gen_##name(DisasContext *ctx)                              \
+{                                                                             \
+    TCGv_i64 t0 = tcg_temp_new_i64();                                         \
+    TCGv_i32 t1 = tcg_temp_new_i32();                                         \
+    tcg_gen_trunc_tl_i32(t1, cpu_gpr[rB(ctx->opcode)]);                       \
+    gen_helper_##name(t0, cpu_env, t1);                                       \
+    gen_store_gpr64(rD(ctx->opcode), t0);                                     \
+    tcg_temp_free_i64(t0);                                                    \
+    tcg_temp_free_i32(t1);                                                    \
+}
+#define GEN_SPEFPUOP_CONV_64_64(name)                                         \
+static inline void gen_##name(DisasContext *ctx)                              \
+{                                                                             \
+    TCGv_i64 t0 = tcg_temp_new_i64();                                         \
+    gen_load_gpr64(t0, rB(ctx->opcode));                                      \
+    gen_helper_##name(t0, cpu_env, t0);                                       \
+    gen_store_gpr64(rD(ctx->opcode), t0);                                     \
+    tcg_temp_free_i64(t0);                                                    \
+}
+#define GEN_SPEFPUOP_ARITH2_32_32(name)                                       \
+static inline void gen_##name(DisasContext *ctx)                              \
+{                                                                             \
+    TCGv_i32 t0, t1;                                                          \
+    if (unlikely(!ctx->spe_enabled)) {                                        \
+        gen_exception(ctx, POWERPC_EXCP_SPEU);                                \
+        return;                                                               \
+    }                                                                         \
+    t0 = tcg_temp_new_i32();                                                  \
+    t1 = tcg_temp_new_i32();                                                  \
+    tcg_gen_trunc_tl_i32(t0, cpu_gpr[rA(ctx->opcode)]);                       \
+    tcg_gen_trunc_tl_i32(t1, cpu_gpr[rB(ctx->opcode)]);                       \
+    gen_helper_##name(t0, cpu_env, t0, t1);                                   \
+    tcg_gen_extu_i32_tl(cpu_gpr[rD(ctx->opcode)], t0);                        \
+                                                                              \
+    tcg_temp_free_i32(t0);                                                    \
+    tcg_temp_free_i32(t1);                                                    \
+}
+#define GEN_SPEFPUOP_ARITH2_64_64(name)                                       \
+static inline void gen_##name(DisasContext *ctx)                              \
+{                                                                             \
+    TCGv_i64 t0, t1;                                                          \
+    if (unlikely(!ctx->spe_enabled)) {                                        \
+        gen_exception(ctx, POWERPC_EXCP_SPEU);                                \
+        return;                                                               \
+    }                                                                         \
+    t0 = tcg_temp_new_i64();                                                  \
+    t1 = tcg_temp_new_i64();                                                  \
+    gen_load_gpr64(t0, rA(ctx->opcode));                                      \
+    gen_load_gpr64(t1, rB(ctx->opcode));                                      \
+    gen_helper_##name(t0, cpu_env, t0, t1);                                   \
+    gen_store_gpr64(rD(ctx->opcode), t0);                                     \
+    tcg_temp_free_i64(t0);                                                    \
+    tcg_temp_free_i64(t1);                                                    \
+}
+#define GEN_SPEFPUOP_COMP_32(name)                                            \
+static inline void gen_##name(DisasContext *ctx)                              \
+{                                                                             \
+    TCGv_i32 t0, t1;                                                          \
+    if (unlikely(!ctx->spe_enabled)) {                                        \
+        gen_exception(ctx, POWERPC_EXCP_SPEU);                                \
+        return;                                                               \
+    }                                                                         \
+    t0 = tcg_temp_new_i32();                                                  \
+    t1 = tcg_temp_new_i32();                                                  \
+                                                                              \
+    tcg_gen_trunc_tl_i32(t0, cpu_gpr[rA(ctx->opcode)]);                       \
+    tcg_gen_trunc_tl_i32(t1, cpu_gpr[rB(ctx->opcode)]);                       \
+    gen_helper_##name(cpu_crf[crfD(ctx->opcode)], cpu_env, t0, t1);           \
+                                                                              \
+    tcg_temp_free_i32(t0);                                                    \
+    tcg_temp_free_i32(t1);                                                    \
+}
+#define GEN_SPEFPUOP_COMP_64(name)                                            \
+static inline void gen_##name(DisasContext *ctx)                              \
+{                                                                             \
+    TCGv_i64 t0, t1;                                                          \
+    if (unlikely(!ctx->spe_enabled)) {                                        \
+        gen_exception(ctx, POWERPC_EXCP_SPEU);                                \
+        return;                                                               \
+    }                                                                         \
+    t0 = tcg_temp_new_i64();                                                  \
+    t1 = tcg_temp_new_i64();                                                  \
+    gen_load_gpr64(t0, rA(ctx->opcode));                                      \
+    gen_load_gpr64(t1, rB(ctx->opcode));                                      \
+    gen_helper_##name(cpu_crf[crfD(ctx->opcode)], cpu_env, t0, t1);           \
+    tcg_temp_free_i64(t0);                                                    \
+    tcg_temp_free_i64(t1);                                                    \
+}
+
+/* Single precision floating-point vectors operations */
+/* Arithmetic */
+GEN_SPEFPUOP_ARITH2_64_64(evfsadd);
+GEN_SPEFPUOP_ARITH2_64_64(evfssub);
+GEN_SPEFPUOP_ARITH2_64_64(evfsmul);
+GEN_SPEFPUOP_ARITH2_64_64(evfsdiv);
+static inline void gen_evfsabs(DisasContext *ctx)
+{
+    if (unlikely(!ctx->spe_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_SPEU);
+        return;
+    }
+    tcg_gen_andi_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)],
+                    ~0x80000000);
+    tcg_gen_andi_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)],
+                    ~0x80000000);
+}
+static inline void gen_evfsnabs(DisasContext *ctx)
+{
+    if (unlikely(!ctx->spe_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_SPEU);
+        return;
+    }
+    tcg_gen_ori_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)],
+                   0x80000000);
+    tcg_gen_ori_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)],
+                   0x80000000);
+}
+static inline void gen_evfsneg(DisasContext *ctx)
+{
+    if (unlikely(!ctx->spe_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_SPEU);
+        return;
+    }
+    tcg_gen_xori_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)],
+                    0x80000000);
+    tcg_gen_xori_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)],
+                    0x80000000);
+}
+
+/* Conversion */
+GEN_SPEFPUOP_CONV_64_64(evfscfui);
+GEN_SPEFPUOP_CONV_64_64(evfscfsi);
+GEN_SPEFPUOP_CONV_64_64(evfscfuf);
+GEN_SPEFPUOP_CONV_64_64(evfscfsf);
+GEN_SPEFPUOP_CONV_64_64(evfsctui);
+GEN_SPEFPUOP_CONV_64_64(evfsctsi);
+GEN_SPEFPUOP_CONV_64_64(evfsctuf);
+GEN_SPEFPUOP_CONV_64_64(evfsctsf);
+GEN_SPEFPUOP_CONV_64_64(evfsctuiz);
+GEN_SPEFPUOP_CONV_64_64(evfsctsiz);
+
+/* Comparison */
+GEN_SPEFPUOP_COMP_64(evfscmpgt);
+GEN_SPEFPUOP_COMP_64(evfscmplt);
+GEN_SPEFPUOP_COMP_64(evfscmpeq);
+GEN_SPEFPUOP_COMP_64(evfststgt);
+GEN_SPEFPUOP_COMP_64(evfststlt);
+GEN_SPEFPUOP_COMP_64(evfststeq);
+
+/* Opcodes definitions */
+GEN_SPE(evfsadd,   evfssub,   0x00, 0x0A, 0x00000000, 0x00000000, PPC_SPE_SINGLE); //
+GEN_SPE(evfsabs,   evfsnabs,  0x02, 0x0A, 0x0000F800, 0x0000F800, PPC_SPE_SINGLE); //
+GEN_SPE(evfsneg,   speundef,  0x03, 0x0A, 0x0000F800, 0xFFFFFFFF, PPC_SPE_SINGLE); //
+GEN_SPE(evfsmul,   evfsdiv,   0x04, 0x0A, 0x00000000, 0x00000000, PPC_SPE_SINGLE); //
+GEN_SPE(evfscmpgt, evfscmplt, 0x06, 0x0A, 0x00600000, 0x00600000, PPC_SPE_SINGLE); //
+GEN_SPE(evfscmpeq, speundef,  0x07, 0x0A, 0x00600000, 0xFFFFFFFF, PPC_SPE_SINGLE); //
+GEN_SPE(evfscfui,  evfscfsi,  0x08, 0x0A, 0x00180000, 0x00180000, PPC_SPE_SINGLE); //
+GEN_SPE(evfscfuf,  evfscfsf,  0x09, 0x0A, 0x00180000, 0x00180000, PPC_SPE_SINGLE); //
+GEN_SPE(evfsctui,  evfsctsi,  0x0A, 0x0A, 0x00180000, 0x00180000, PPC_SPE_SINGLE); //
+GEN_SPE(evfsctuf,  evfsctsf,  0x0B, 0x0A, 0x00180000, 0x00180000, PPC_SPE_SINGLE); //
+GEN_SPE(evfsctuiz, speundef,  0x0C, 0x0A, 0x00180000, 0xFFFFFFFF, PPC_SPE_SINGLE); //
+GEN_SPE(evfsctsiz, speundef,  0x0D, 0x0A, 0x00180000, 0xFFFFFFFF, PPC_SPE_SINGLE); //
+GEN_SPE(evfststgt, evfststlt, 0x0E, 0x0A, 0x00600000, 0x00600000, PPC_SPE_SINGLE); //
+GEN_SPE(evfststeq, speundef,  0x0F, 0x0A, 0x00600000, 0xFFFFFFFF, PPC_SPE_SINGLE); //
+
+/* Single precision floating-point operations */
+/* Arithmetic */
+GEN_SPEFPUOP_ARITH2_32_32(efsadd);
+GEN_SPEFPUOP_ARITH2_32_32(efssub);
+GEN_SPEFPUOP_ARITH2_32_32(efsmul);
+GEN_SPEFPUOP_ARITH2_32_32(efsdiv);
+static inline void gen_efsabs(DisasContext *ctx)
+{
+    if (unlikely(!ctx->spe_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_SPEU);
+        return;
+    }
+    tcg_gen_andi_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], (target_long)~0x80000000LL);
+}
+static inline void gen_efsnabs(DisasContext *ctx)
+{
+    if (unlikely(!ctx->spe_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_SPEU);
+        return;
+    }
+    tcg_gen_ori_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x80000000);
+}
+static inline void gen_efsneg(DisasContext *ctx)
+{
+    if (unlikely(!ctx->spe_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_SPEU);
+        return;
+    }
+    tcg_gen_xori_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x80000000);
+}
+
+/* Conversion */
+GEN_SPEFPUOP_CONV_32_32(efscfui);
+GEN_SPEFPUOP_CONV_32_32(efscfsi);
+GEN_SPEFPUOP_CONV_32_32(efscfuf);
+GEN_SPEFPUOP_CONV_32_32(efscfsf);
+GEN_SPEFPUOP_CONV_32_32(efsctui);
+GEN_SPEFPUOP_CONV_32_32(efsctsi);
+GEN_SPEFPUOP_CONV_32_32(efsctuf);
+GEN_SPEFPUOP_CONV_32_32(efsctsf);
+GEN_SPEFPUOP_CONV_32_32(efsctuiz);
+GEN_SPEFPUOP_CONV_32_32(efsctsiz);
+GEN_SPEFPUOP_CONV_32_64(efscfd);
+
+/* Comparison */
+GEN_SPEFPUOP_COMP_32(efscmpgt);
+GEN_SPEFPUOP_COMP_32(efscmplt);
+GEN_SPEFPUOP_COMP_32(efscmpeq);
+GEN_SPEFPUOP_COMP_32(efststgt);
+GEN_SPEFPUOP_COMP_32(efststlt);
+GEN_SPEFPUOP_COMP_32(efststeq);
+
+/* Opcodes definitions */
+GEN_SPE(efsadd,   efssub,   0x00, 0x0B, 0x00000000, 0x00000000, PPC_SPE_SINGLE); //
+GEN_SPE(efsabs,   efsnabs,  0x02, 0x0B, 0x0000F800, 0x0000F800, PPC_SPE_SINGLE); //
+GEN_SPE(efsneg,   speundef, 0x03, 0x0B, 0x0000F800, 0xFFFFFFFF, PPC_SPE_SINGLE); //
+GEN_SPE(efsmul,   efsdiv,   0x04, 0x0B, 0x00000000, 0x00000000, PPC_SPE_SINGLE); //
+GEN_SPE(efscmpgt, efscmplt, 0x06, 0x0B, 0x00600000, 0x00600000, PPC_SPE_SINGLE); //
+GEN_SPE(efscmpeq, efscfd,   0x07, 0x0B, 0x00600000, 0x00180000, PPC_SPE_SINGLE); //
+GEN_SPE(efscfui,  efscfsi,  0x08, 0x0B, 0x00180000, 0x00180000, PPC_SPE_SINGLE); //
+GEN_SPE(efscfuf,  efscfsf,  0x09, 0x0B, 0x00180000, 0x00180000, PPC_SPE_SINGLE); //
+GEN_SPE(efsctui,  efsctsi,  0x0A, 0x0B, 0x00180000, 0x00180000, PPC_SPE_SINGLE); //
+GEN_SPE(efsctuf,  efsctsf,  0x0B, 0x0B, 0x00180000, 0x00180000, PPC_SPE_SINGLE); //
+GEN_SPE(efsctuiz, speundef, 0x0C, 0x0B, 0x00180000, 0xFFFFFFFF, PPC_SPE_SINGLE); //
+GEN_SPE(efsctsiz, speundef, 0x0D, 0x0B, 0x00180000, 0xFFFFFFFF, PPC_SPE_SINGLE); //
+GEN_SPE(efststgt, efststlt, 0x0E, 0x0B, 0x00600000, 0x00600000, PPC_SPE_SINGLE); //
+GEN_SPE(efststeq, speundef, 0x0F, 0x0B, 0x00600000, 0xFFFFFFFF, PPC_SPE_SINGLE); //
+
+/* Double precision floating-point operations */
+/* Arithmetic */
+GEN_SPEFPUOP_ARITH2_64_64(efdadd);
+GEN_SPEFPUOP_ARITH2_64_64(efdsub);
+GEN_SPEFPUOP_ARITH2_64_64(efdmul);
+GEN_SPEFPUOP_ARITH2_64_64(efddiv);
+static inline void gen_efdabs(DisasContext *ctx)
+{
+    if (unlikely(!ctx->spe_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_SPEU);
+        return;
+    }
+    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
+    tcg_gen_andi_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)],
+                    ~0x80000000);
+}
+static inline void gen_efdnabs(DisasContext *ctx)
+{
+    if (unlikely(!ctx->spe_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_SPEU);
+        return;
+    }
+    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
+    tcg_gen_ori_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)],
+                   0x80000000);
+}
+static inline void gen_efdneg(DisasContext *ctx)
+{
+    if (unlikely(!ctx->spe_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_SPEU);
+        return;
+    }
+    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
+    tcg_gen_xori_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)],
+                    0x80000000);
+}
+
+/* Conversion */
+GEN_SPEFPUOP_CONV_64_32(efdcfui);
+GEN_SPEFPUOP_CONV_64_32(efdcfsi);
+GEN_SPEFPUOP_CONV_64_32(efdcfuf);
+GEN_SPEFPUOP_CONV_64_32(efdcfsf);
+GEN_SPEFPUOP_CONV_32_64(efdctui);
+GEN_SPEFPUOP_CONV_32_64(efdctsi);
+GEN_SPEFPUOP_CONV_32_64(efdctuf);
+GEN_SPEFPUOP_CONV_32_64(efdctsf);
+GEN_SPEFPUOP_CONV_32_64(efdctuiz);
+GEN_SPEFPUOP_CONV_32_64(efdctsiz);
+GEN_SPEFPUOP_CONV_64_32(efdcfs);
+GEN_SPEFPUOP_CONV_64_64(efdcfuid);
+GEN_SPEFPUOP_CONV_64_64(efdcfsid);
+GEN_SPEFPUOP_CONV_64_64(efdctuidz);
+GEN_SPEFPUOP_CONV_64_64(efdctsidz);
+
+/* Comparison */
+GEN_SPEFPUOP_COMP_64(efdcmpgt);
+GEN_SPEFPUOP_COMP_64(efdcmplt);
+GEN_SPEFPUOP_COMP_64(efdcmpeq);
+GEN_SPEFPUOP_COMP_64(efdtstgt);
+GEN_SPEFPUOP_COMP_64(efdtstlt);
+GEN_SPEFPUOP_COMP_64(efdtsteq);
+
+/* Opcodes definitions */
+GEN_SPE(efdadd,    efdsub,    0x10, 0x0B, 0x00000000, 0x00000000, PPC_SPE_DOUBLE); //
+GEN_SPE(efdcfuid,  efdcfsid,  0x11, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE); //
+GEN_SPE(efdabs,    efdnabs,   0x12, 0x0B, 0x0000F800, 0x0000F800, PPC_SPE_DOUBLE); //
+GEN_SPE(efdneg,    speundef,  0x13, 0x0B, 0x0000F800, 0xFFFFFFFF, PPC_SPE_DOUBLE); //
+GEN_SPE(efdmul,    efddiv,    0x14, 0x0B, 0x00000000, 0x00000000, PPC_SPE_DOUBLE); //
+GEN_SPE(efdctuidz, efdctsidz, 0x15, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE); //
+GEN_SPE(efdcmpgt,  efdcmplt,  0x16, 0x0B, 0x00600000, 0x00600000, PPC_SPE_DOUBLE); //
+GEN_SPE(efdcmpeq,  efdcfs,    0x17, 0x0B, 0x00600000, 0x00180000, PPC_SPE_DOUBLE); //
+GEN_SPE(efdcfui,   efdcfsi,   0x18, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE); //
+GEN_SPE(efdcfuf,   efdcfsf,   0x19, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE); //
+GEN_SPE(efdctui,   efdctsi,   0x1A, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE); //
+GEN_SPE(efdctuf,   efdctsf,   0x1B, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE); //
+GEN_SPE(efdctuiz,  speundef,  0x1C, 0x0B, 0x00180000, 0xFFFFFFFF, PPC_SPE_DOUBLE); //
+GEN_SPE(efdctsiz,  speundef,  0x1D, 0x0B, 0x00180000, 0xFFFFFFFF, PPC_SPE_DOUBLE); //
+GEN_SPE(efdtstgt,  efdtstlt,  0x1E, 0x0B, 0x00600000, 0x00600000, PPC_SPE_DOUBLE); //
+GEN_SPE(efdtsteq,  speundef,  0x1F, 0x0B, 0x00600000, 0xFFFFFFFF, PPC_SPE_DOUBLE); //
+
+#undef GEN_SPE
+#undef GEN_SPEOP_LDST
diff --git a/target-ppc/translate/spe-ops.c b/target-ppc/translate/spe-ops.c
new file mode 100644
index 0000000..f9885e9
--- /dev/null
+++ b/target-ppc/translate/spe-ops.c
@@ -0,0 +1,106 @@
+GEN_HANDLER2(evsel0, "evsel", 0x04, 0x1c, 0x09, 0x00000000, PPC_SPE),
+GEN_HANDLER2(evsel1, "evsel", 0x04, 0x1d, 0x09, 0x00000000, PPC_SPE),
+GEN_HANDLER2(evsel2, "evsel", 0x04, 0x1e, 0x09, 0x00000000, PPC_SPE),
+GEN_HANDLER2(evsel3, "evsel", 0x04, 0x1f, 0x09, 0x00000000, PPC_SPE),
+
+#define GEN_SPE(name0, name1, opc2, opc3, inval0, inval1, type) \
+    GEN_OPCODE_DUAL(name0##_##name1, 0x04, opc2, opc3, inval0, inval1, type, PPC_NONE)
+GEN_SPE(evaddw,      speundef,    0x00, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE),
+GEN_SPE(evaddiw,     speundef,    0x01, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE),
+GEN_SPE(evsubfw,     speundef,    0x02, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE),
+GEN_SPE(evsubifw,    speundef,    0x03, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE),
+GEN_SPE(evabs,       evneg,       0x04, 0x08, 0x0000F800, 0x0000F800, PPC_SPE),
+GEN_SPE(evextsb,     evextsh,     0x05, 0x08, 0x0000F800, 0x0000F800, PPC_SPE),
+GEN_SPE(evrndw,      evcntlzw,    0x06, 0x08, 0x0000F800, 0x0000F800, PPC_SPE),
+GEN_SPE(evcntlsw,    brinc,       0x07, 0x08, 0x0000F800, 0x00000000, PPC_SPE),
+GEN_SPE(evmra,       speundef,    0x02, 0x13, 0x0000F800, 0xFFFFFFFF, PPC_SPE),
+GEN_SPE(speundef,    evand,       0x08, 0x08, 0xFFFFFFFF, 0x00000000, PPC_SPE),
+GEN_SPE(evandc,      speundef,    0x09, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE),
+GEN_SPE(evxor,       evor,        0x0B, 0x08, 0x00000000, 0x00000000, PPC_SPE),
+GEN_SPE(evnor,       eveqv,       0x0C, 0x08, 0x00000000, 0x00000000, PPC_SPE),
+GEN_SPE(evmwumi,     evmwsmi,     0x0C, 0x11, 0x00000000, 0x00000000, PPC_SPE),
+GEN_SPE(evmwumia,    evmwsmia,    0x1C, 0x11, 0x00000000, 0x00000000, PPC_SPE),
+GEN_SPE(evmwumiaa,   evmwsmiaa,   0x0C, 0x15, 0x00000000, 0x00000000, PPC_SPE),
+GEN_SPE(speundef,    evorc,       0x0D, 0x08, 0xFFFFFFFF, 0x00000000, PPC_SPE),
+GEN_SPE(evnand,      speundef,    0x0F, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE),
+GEN_SPE(evsrwu,      evsrws,      0x10, 0x08, 0x00000000, 0x00000000, PPC_SPE),
+GEN_SPE(evsrwiu,     evsrwis,     0x11, 0x08, 0x00000000, 0x00000000, PPC_SPE),
+GEN_SPE(evslw,       speundef,    0x12, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE),
+GEN_SPE(evslwi,      speundef,    0x13, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE),
+GEN_SPE(evrlw,       evsplati,    0x14, 0x08, 0x00000000, 0x0000F800, PPC_SPE),
+GEN_SPE(evrlwi,      evsplatfi,   0x15, 0x08, 0x00000000, 0x0000F800, PPC_SPE),
+GEN_SPE(evmergehi,   evmergelo,   0x16, 0x08, 0x00000000, 0x00000000, PPC_SPE),
+GEN_SPE(evmergehilo, evmergelohi, 0x17, 0x08, 0x00000000, 0x00000000, PPC_SPE),
+GEN_SPE(evcmpgtu,    evcmpgts,    0x18, 0x08, 0x00600000, 0x00600000, PPC_SPE),
+GEN_SPE(evcmpltu,    evcmplts,    0x19, 0x08, 0x00600000, 0x00600000, PPC_SPE),
+GEN_SPE(evcmpeq,     speundef,    0x1A, 0x08, 0x00600000, 0xFFFFFFFF, PPC_SPE),
+
+GEN_SPE(evfsadd,     evfssub,     0x00, 0x0A, 0x00000000, 0x00000000, PPC_SPE_SINGLE),
+GEN_SPE(evfsabs,     evfsnabs,    0x02, 0x0A, 0x0000F800, 0x0000F800, PPC_SPE_SINGLE),
+GEN_SPE(evfsneg,     speundef,    0x03, 0x0A, 0x0000F800, 0xFFFFFFFF, PPC_SPE_SINGLE),
+GEN_SPE(evfsmul,     evfsdiv,     0x04, 0x0A, 0x00000000, 0x00000000, PPC_SPE_SINGLE),
+GEN_SPE(evfscmpgt,   evfscmplt,   0x06, 0x0A, 0x00600000, 0x00600000, PPC_SPE_SINGLE),
+GEN_SPE(evfscmpeq,   speundef,    0x07, 0x0A, 0x00600000, 0xFFFFFFFF, PPC_SPE_SINGLE),
+GEN_SPE(evfscfui,    evfscfsi,    0x08, 0x0A, 0x00180000, 0x00180000, PPC_SPE_SINGLE),
+GEN_SPE(evfscfuf,    evfscfsf,    0x09, 0x0A, 0x00180000, 0x00180000, PPC_SPE_SINGLE),
+GEN_SPE(evfsctui,    evfsctsi,    0x0A, 0x0A, 0x00180000, 0x00180000, PPC_SPE_SINGLE),
+GEN_SPE(evfsctuf,    evfsctsf,    0x0B, 0x0A, 0x00180000, 0x00180000, PPC_SPE_SINGLE),
+GEN_SPE(evfsctuiz,   speundef,    0x0C, 0x0A, 0x00180000, 0xFFFFFFFF, PPC_SPE_SINGLE),
+GEN_SPE(evfsctsiz,   speundef,    0x0D, 0x0A, 0x00180000, 0xFFFFFFFF, PPC_SPE_SINGLE),
+GEN_SPE(evfststgt,   evfststlt,   0x0E, 0x0A, 0x00600000, 0x00600000, PPC_SPE_SINGLE),
+GEN_SPE(evfststeq,   speundef,    0x0F, 0x0A, 0x00600000, 0xFFFFFFFF, PPC_SPE_SINGLE),
+
+GEN_SPE(efsadd,      efssub,      0x00, 0x0B, 0x00000000, 0x00000000, PPC_SPE_SINGLE),
+GEN_SPE(efsabs,      efsnabs,     0x02, 0x0B, 0x0000F800, 0x0000F800, PPC_SPE_SINGLE),
+GEN_SPE(efsneg,      speundef,    0x03, 0x0B, 0x0000F800, 0xFFFFFFFF, PPC_SPE_SINGLE),
+GEN_SPE(efsmul,      efsdiv,      0x04, 0x0B, 0x00000000, 0x00000000, PPC_SPE_SINGLE),
+GEN_SPE(efscmpgt,    efscmplt,    0x06, 0x0B, 0x00600000, 0x00600000, PPC_SPE_SINGLE),
+GEN_SPE(efscmpeq,    efscfd,      0x07, 0x0B, 0x00600000, 0x00180000, PPC_SPE_SINGLE),
+GEN_SPE(efscfui,     efscfsi,     0x08, 0x0B, 0x00180000, 0x00180000, PPC_SPE_SINGLE),
+GEN_SPE(efscfuf,     efscfsf,     0x09, 0x0B, 0x00180000, 0x00180000, PPC_SPE_SINGLE),
+GEN_SPE(efsctui,     efsctsi,     0x0A, 0x0B, 0x00180000, 0x00180000, PPC_SPE_SINGLE),
+GEN_SPE(efsctuf,     efsctsf,     0x0B, 0x0B, 0x00180000, 0x00180000, PPC_SPE_SINGLE),
+GEN_SPE(efsctuiz,    speundef,    0x0C, 0x0B, 0x00180000, 0xFFFFFFFF, PPC_SPE_SINGLE),
+GEN_SPE(efsctsiz,    speundef,    0x0D, 0x0B, 0x00180000, 0xFFFFFFFF, PPC_SPE_SINGLE),
+GEN_SPE(efststgt,    efststlt,    0x0E, 0x0B, 0x00600000, 0x00600000, PPC_SPE_SINGLE),
+GEN_SPE(efststeq,    speundef,    0x0F, 0x0B, 0x00600000, 0xFFFFFFFF, PPC_SPE_SINGLE),
+
+GEN_SPE(efdadd,      efdsub,      0x10, 0x0B, 0x00000000, 0x00000000, PPC_SPE_DOUBLE),
+GEN_SPE(efdcfuid,    efdcfsid,    0x11, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE),
+GEN_SPE(efdabs,      efdnabs,     0x12, 0x0B, 0x0000F800, 0x0000F800, PPC_SPE_DOUBLE),
+GEN_SPE(efdneg,      speundef,    0x13, 0x0B, 0x0000F800, 0xFFFFFFFF, PPC_SPE_DOUBLE),
+GEN_SPE(efdmul,      efddiv,      0x14, 0x0B, 0x00000000, 0x00000000, PPC_SPE_DOUBLE),
+GEN_SPE(efdctuidz,   efdctsidz,   0x15, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE),
+GEN_SPE(efdcmpgt,    efdcmplt,    0x16, 0x0B, 0x00600000, 0x00600000, PPC_SPE_DOUBLE),
+GEN_SPE(efdcmpeq,    efdcfs,      0x17, 0x0B, 0x00600000, 0x00180000, PPC_SPE_DOUBLE),
+GEN_SPE(efdcfui,     efdcfsi,     0x18, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE),
+GEN_SPE(efdcfuf,     efdcfsf,     0x19, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE),
+GEN_SPE(efdctui,     efdctsi,     0x1A, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE),
+GEN_SPE(efdctuf,     efdctsf,     0x1B, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE),
+GEN_SPE(efdctuiz,    speundef,    0x1C, 0x0B, 0x00180000, 0xFFFFFFFF, PPC_SPE_DOUBLE),
+GEN_SPE(efdctsiz,    speundef,    0x1D, 0x0B, 0x00180000, 0xFFFFFFFF, PPC_SPE_DOUBLE),
+GEN_SPE(efdtstgt,    efdtstlt,    0x1E, 0x0B, 0x00600000, 0x00600000, PPC_SPE_DOUBLE),
+GEN_SPE(efdtsteq,    speundef,    0x1F, 0x0B, 0x00600000, 0xFFFFFFFF, PPC_SPE_DOUBLE),
+
+#define GEN_SPEOP_LDST(name, opc2, sh)                                        \
+GEN_HANDLER(name, 0x04, opc2, 0x0C, 0x00000000, PPC_SPE)
+GEN_SPEOP_LDST(evldd, 0x00, 3),
+GEN_SPEOP_LDST(evldw, 0x01, 3),
+GEN_SPEOP_LDST(evldh, 0x02, 3),
+GEN_SPEOP_LDST(evlhhesplat, 0x04, 1),
+GEN_SPEOP_LDST(evlhhousplat, 0x06, 1),
+GEN_SPEOP_LDST(evlhhossplat, 0x07, 1),
+GEN_SPEOP_LDST(evlwhe, 0x08, 2),
+GEN_SPEOP_LDST(evlwhou, 0x0A, 2),
+GEN_SPEOP_LDST(evlwhos, 0x0B, 2),
+GEN_SPEOP_LDST(evlwwsplat, 0x0C, 2),
+GEN_SPEOP_LDST(evlwhsplat, 0x0E, 2),
+
+GEN_SPEOP_LDST(evstdd, 0x10, 3),
+GEN_SPEOP_LDST(evstdw, 0x11, 3),
+GEN_SPEOP_LDST(evstdh, 0x12, 3),
+GEN_SPEOP_LDST(evstwhe, 0x18, 2),
+GEN_SPEOP_LDST(evstwho, 0x1A, 2),
+GEN_SPEOP_LDST(evstwwe, 0x1C, 2),
+GEN_SPEOP_LDST(evstwwo, 0x1E, 2),
+
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [Qemu-devel] [PATCH 05/32] ppc: Move DFP ops out of translate.c
  2016-07-26 22:20 [Qemu-devel] [PATCH 01/32] ppc: Fix fault PC reporting for lve*/stve* VMX instructions Benjamin Herrenschmidt
                   ` (2 preceding siblings ...)
  2016-07-26 22:20 ` [Qemu-devel] [PATCH 04/32] ppc: Move embedded spe " Benjamin Herrenschmidt
@ 2016-07-26 22:20 ` Benjamin Herrenschmidt
  2016-07-26 22:21 ` [Qemu-devel] [PATCH 06/32] ppc: Move VMX " Benjamin Herrenschmidt
                   ` (27 subsequent siblings)
  31 siblings, 0 replies; 69+ messages in thread
From: Benjamin Herrenschmidt @ 2016-07-26 22:20 UTC (permalink / raw)
  To: qemu-ppc; +Cc: qemu-devel, david, Benjamin Herrenschmidt

Makes things a bit more manageable

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
 target-ppc/translate.c          | 365 +---------------------------------------
 target-ppc/translate/dfp-impl.c | 212 +++++++++++++++++++++++
 target-ppc/translate/dfp-ops.c  | 151 +++++++++++++++++
 3 files changed, 365 insertions(+), 363 deletions(-)
 create mode 100644 target-ppc/translate/dfp-impl.c
 create mode 100644 target-ppc/translate/dfp-ops.c

diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index 3b96bed..ee45673 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -7290,210 +7290,7 @@ static void gen_xxsldwi(DisasContext *ctx)
     tcg_temp_free_i64(xtl);
 }
 
-/*** Decimal Floating Point ***/
-
-static inline TCGv_ptr gen_fprp_ptr(int reg)
-{
-    TCGv_ptr r = tcg_temp_new_ptr();
-    tcg_gen_addi_ptr(r, cpu_env, offsetof(CPUPPCState, fpr[reg]));
-    return r;
-}
-
-#define GEN_DFP_T_A_B_Rc(name)                   \
-static void gen_##name(DisasContext *ctx)        \
-{                                                \
-    TCGv_ptr rd, ra, rb;                         \
-    if (unlikely(!ctx->fpu_enabled)) {           \
-        gen_exception(ctx, POWERPC_EXCP_FPU);    \
-        return;                                  \
-    }                                            \
-    gen_update_nip(ctx, ctx->nip - 4);           \
-    rd = gen_fprp_ptr(rD(ctx->opcode));          \
-    ra = gen_fprp_ptr(rA(ctx->opcode));          \
-    rb = gen_fprp_ptr(rB(ctx->opcode));          \
-    gen_helper_##name(cpu_env, rd, ra, rb);      \
-    if (unlikely(Rc(ctx->opcode) != 0)) {        \
-        gen_set_cr1_from_fpscr(ctx);             \
-    }                                            \
-    tcg_temp_free_ptr(rd);                       \
-    tcg_temp_free_ptr(ra);                       \
-    tcg_temp_free_ptr(rb);                       \
-}
-
-#define GEN_DFP_BF_A_B(name)                      \
-static void gen_##name(DisasContext *ctx)         \
-{                                                 \
-    TCGv_ptr ra, rb;                              \
-    if (unlikely(!ctx->fpu_enabled)) {            \
-        gen_exception(ctx, POWERPC_EXCP_FPU);     \
-        return;                                   \
-    }                                             \
-    gen_update_nip(ctx, ctx->nip - 4);            \
-    ra = gen_fprp_ptr(rA(ctx->opcode));           \
-    rb = gen_fprp_ptr(rB(ctx->opcode));           \
-    gen_helper_##name(cpu_crf[crfD(ctx->opcode)], \
-                      cpu_env, ra, rb);           \
-    tcg_temp_free_ptr(ra);                        \
-    tcg_temp_free_ptr(rb);                        \
-}
-
-#define GEN_DFP_BF_A_DCM(name)                    \
-static void gen_##name(DisasContext *ctx)         \
-{                                                 \
-    TCGv_ptr ra;                                  \
-    TCGv_i32 dcm;                                 \
-    if (unlikely(!ctx->fpu_enabled)) {            \
-        gen_exception(ctx, POWERPC_EXCP_FPU);     \
-        return;                                   \
-    }                                             \
-    gen_update_nip(ctx, ctx->nip - 4);            \
-    ra = gen_fprp_ptr(rA(ctx->opcode));           \
-    dcm = tcg_const_i32(DCM(ctx->opcode));        \
-    gen_helper_##name(cpu_crf[crfD(ctx->opcode)], \
-                      cpu_env, ra, dcm);          \
-    tcg_temp_free_ptr(ra);                        \
-    tcg_temp_free_i32(dcm);                       \
-}
-
-#define GEN_DFP_T_B_U32_U32_Rc(name, u32f1, u32f2)    \
-static void gen_##name(DisasContext *ctx)             \
-{                                                     \
-    TCGv_ptr rt, rb;                                  \
-    TCGv_i32 u32_1, u32_2;                            \
-    if (unlikely(!ctx->fpu_enabled)) {                \
-        gen_exception(ctx, POWERPC_EXCP_FPU);         \
-        return;                                       \
-    }                                                 \
-    gen_update_nip(ctx, ctx->nip - 4);                \
-    rt = gen_fprp_ptr(rD(ctx->opcode));               \
-    rb = gen_fprp_ptr(rB(ctx->opcode));               \
-    u32_1 = tcg_const_i32(u32f1(ctx->opcode));        \
-    u32_2 = tcg_const_i32(u32f2(ctx->opcode));        \
-    gen_helper_##name(cpu_env, rt, rb, u32_1, u32_2); \
-    if (unlikely(Rc(ctx->opcode) != 0)) {             \
-        gen_set_cr1_from_fpscr(ctx);                  \
-    }                                                 \
-    tcg_temp_free_ptr(rt);                            \
-    tcg_temp_free_ptr(rb);                            \
-    tcg_temp_free_i32(u32_1);                         \
-    tcg_temp_free_i32(u32_2);                         \
-}
-
-#define GEN_DFP_T_A_B_I32_Rc(name, i32fld)       \
-static void gen_##name(DisasContext *ctx)        \
-{                                                \
-    TCGv_ptr rt, ra, rb;                         \
-    TCGv_i32 i32;                                \
-    if (unlikely(!ctx->fpu_enabled)) {           \
-        gen_exception(ctx, POWERPC_EXCP_FPU);    \
-        return;                                  \
-    }                                            \
-    gen_update_nip(ctx, ctx->nip - 4);           \
-    rt = gen_fprp_ptr(rD(ctx->opcode));          \
-    ra = gen_fprp_ptr(rA(ctx->opcode));          \
-    rb = gen_fprp_ptr(rB(ctx->opcode));          \
-    i32 = tcg_const_i32(i32fld(ctx->opcode));    \
-    gen_helper_##name(cpu_env, rt, ra, rb, i32); \
-    if (unlikely(Rc(ctx->opcode) != 0)) {        \
-        gen_set_cr1_from_fpscr(ctx);             \
-    }                                            \
-    tcg_temp_free_ptr(rt);                       \
-    tcg_temp_free_ptr(rb);                       \
-    tcg_temp_free_ptr(ra);                       \
-    tcg_temp_free_i32(i32);                      \
-    }
-
-#define GEN_DFP_T_B_Rc(name)                     \
-static void gen_##name(DisasContext *ctx)        \
-{                                                \
-    TCGv_ptr rt, rb;                             \
-    if (unlikely(!ctx->fpu_enabled)) {           \
-        gen_exception(ctx, POWERPC_EXCP_FPU);    \
-        return;                                  \
-    }                                            \
-    gen_update_nip(ctx, ctx->nip - 4);           \
-    rt = gen_fprp_ptr(rD(ctx->opcode));          \
-    rb = gen_fprp_ptr(rB(ctx->opcode));          \
-    gen_helper_##name(cpu_env, rt, rb);          \
-    if (unlikely(Rc(ctx->opcode) != 0)) {        \
-        gen_set_cr1_from_fpscr(ctx);             \
-    }                                            \
-    tcg_temp_free_ptr(rt);                       \
-    tcg_temp_free_ptr(rb);                       \
-    }
-
-#define GEN_DFP_T_FPR_I32_Rc(name, fprfld, i32fld) \
-static void gen_##name(DisasContext *ctx)          \
-{                                                  \
-    TCGv_ptr rt, rs;                               \
-    TCGv_i32 i32;                                  \
-    if (unlikely(!ctx->fpu_enabled)) {             \
-        gen_exception(ctx, POWERPC_EXCP_FPU);      \
-        return;                                    \
-    }                                              \
-    gen_update_nip(ctx, ctx->nip - 4);             \
-    rt = gen_fprp_ptr(rD(ctx->opcode));            \
-    rs = gen_fprp_ptr(fprfld(ctx->opcode));        \
-    i32 = tcg_const_i32(i32fld(ctx->opcode));      \
-    gen_helper_##name(cpu_env, rt, rs, i32);       \
-    if (unlikely(Rc(ctx->opcode) != 0)) {          \
-        gen_set_cr1_from_fpscr(ctx);               \
-    }                                              \
-    tcg_temp_free_ptr(rt);                         \
-    tcg_temp_free_ptr(rs);                         \
-    tcg_temp_free_i32(i32);                        \
-}
-
-GEN_DFP_T_A_B_Rc(dadd)
-GEN_DFP_T_A_B_Rc(daddq)
-GEN_DFP_T_A_B_Rc(dsub)
-GEN_DFP_T_A_B_Rc(dsubq)
-GEN_DFP_T_A_B_Rc(dmul)
-GEN_DFP_T_A_B_Rc(dmulq)
-GEN_DFP_T_A_B_Rc(ddiv)
-GEN_DFP_T_A_B_Rc(ddivq)
-GEN_DFP_BF_A_B(dcmpu)
-GEN_DFP_BF_A_B(dcmpuq)
-GEN_DFP_BF_A_B(dcmpo)
-GEN_DFP_BF_A_B(dcmpoq)
-GEN_DFP_BF_A_DCM(dtstdc)
-GEN_DFP_BF_A_DCM(dtstdcq)
-GEN_DFP_BF_A_DCM(dtstdg)
-GEN_DFP_BF_A_DCM(dtstdgq)
-GEN_DFP_BF_A_B(dtstex)
-GEN_DFP_BF_A_B(dtstexq)
-GEN_DFP_BF_A_B(dtstsf)
-GEN_DFP_BF_A_B(dtstsfq)
-GEN_DFP_T_B_U32_U32_Rc(dquai, SIMM5, RMC)
-GEN_DFP_T_B_U32_U32_Rc(dquaiq, SIMM5, RMC)
-GEN_DFP_T_A_B_I32_Rc(dqua, RMC)
-GEN_DFP_T_A_B_I32_Rc(dquaq, RMC)
-GEN_DFP_T_A_B_I32_Rc(drrnd, RMC)
-GEN_DFP_T_A_B_I32_Rc(drrndq, RMC)
-GEN_DFP_T_B_U32_U32_Rc(drintx, FPW, RMC)
-GEN_DFP_T_B_U32_U32_Rc(drintxq, FPW, RMC)
-GEN_DFP_T_B_U32_U32_Rc(drintn, FPW, RMC)
-GEN_DFP_T_B_U32_U32_Rc(drintnq, FPW, RMC)
-GEN_DFP_T_B_Rc(dctdp)
-GEN_DFP_T_B_Rc(dctqpq)
-GEN_DFP_T_B_Rc(drsp)
-GEN_DFP_T_B_Rc(drdpq)
-GEN_DFP_T_B_Rc(dcffix)
-GEN_DFP_T_B_Rc(dcffixq)
-GEN_DFP_T_B_Rc(dctfix)
-GEN_DFP_T_B_Rc(dctfixq)
-GEN_DFP_T_FPR_I32_Rc(ddedpd, rB, SP)
-GEN_DFP_T_FPR_I32_Rc(ddedpdq, rB, SP)
-GEN_DFP_T_FPR_I32_Rc(denbcd, rB, SP)
-GEN_DFP_T_FPR_I32_Rc(denbcdq, rB, SP)
-GEN_DFP_T_B_Rc(dxex)
-GEN_DFP_T_B_Rc(dxexq)
-GEN_DFP_T_A_B_Rc(diex)
-GEN_DFP_T_A_B_Rc(diexq)
-GEN_DFP_T_FPR_I32_Rc(dscli, rA, DCM)
-GEN_DFP_T_FPR_I32_Rc(dscliq, rA, DCM)
-GEN_DFP_T_FPR_I32_Rc(dscri, rA, DCM)
-GEN_DFP_T_FPR_I32_Rc(dscriq, rA, DCM)
+#include "translate/dfp-impl.c"
 
 #include "translate/spe-impl.c"
 
@@ -8619,165 +8416,7 @@ GEN_XXSEL_ROW(0x1F)
 
 GEN_XX3FORM_DM(xxpermdi, 0x08, 0x01),
 
-#undef GEN_DFP_T_A_B_Rc
-#undef GEN_DFP_BF_A_B
-#undef GEN_DFP_BF_A_DCM
-#undef GEN_DFP_T_B_U32_U32_Rc
-#undef GEN_DFP_T_A_B_I32_Rc
-#undef GEN_DFP_T_B_Rc
-#undef GEN_DFP_T_FPR_I32_Rc
-
-#define _GEN_DFP_LONG(name, op1, op2, mask) \
-GEN_HANDLER_E(name, 0x3B, op1, op2, mask, PPC_NONE, PPC2_DFP)
-
-#define _GEN_DFP_LONGx2(name, op1, op2, mask) \
-GEN_HANDLER_E(name, 0x3B, op1, 0x00 | op2, mask, PPC_NONE, PPC2_DFP), \
-GEN_HANDLER_E(name, 0x3B, op1, 0x10 | op2, mask, PPC_NONE, PPC2_DFP)
-
-#define _GEN_DFP_LONGx4(name, op1, op2, mask) \
-GEN_HANDLER_E(name, 0x3B, op1, 0x00 | op2, mask, PPC_NONE, PPC2_DFP), \
-GEN_HANDLER_E(name, 0x3B, op1, 0x08 | op2, mask, PPC_NONE, PPC2_DFP), \
-GEN_HANDLER_E(name, 0x3B, op1, 0x10 | op2, mask, PPC_NONE, PPC2_DFP), \
-GEN_HANDLER_E(name, 0x3B, op1, 0x18 | op2, mask, PPC_NONE, PPC2_DFP)
-
-#define _GEN_DFP_QUAD(name, op1, op2, mask) \
-GEN_HANDLER_E(name, 0x3F, op1, op2, mask, PPC_NONE, PPC2_DFP)
-
-#define _GEN_DFP_QUADx2(name, op1, op2, mask) \
-GEN_HANDLER_E(name, 0x3F, op1, 0x00 | op2, mask, PPC_NONE, PPC2_DFP), \
-GEN_HANDLER_E(name, 0x3F, op1, 0x10 | op2, mask, PPC_NONE, PPC2_DFP)
-
-#define _GEN_DFP_QUADx4(name, op1, op2, mask)                         \
-GEN_HANDLER_E(name, 0x3F, op1, 0x00 | op2, mask, PPC_NONE, PPC2_DFP), \
-GEN_HANDLER_E(name, 0x3F, op1, 0x08 | op2, mask, PPC_NONE, PPC2_DFP), \
-GEN_HANDLER_E(name, 0x3F, op1, 0x10 | op2, mask, PPC_NONE, PPC2_DFP), \
-GEN_HANDLER_E(name, 0x3F, op1, 0x18 | op2, mask, PPC_NONE, PPC2_DFP)
-
-#define GEN_DFP_T_A_B_Rc(name, op1, op2) \
-_GEN_DFP_LONG(name, op1, op2, 0x00000000)
-
-#define GEN_DFP_Tp_Ap_Bp_Rc(name, op1, op2) \
-_GEN_DFP_QUAD(name, op1, op2, 0x00210800)
-
-#define GEN_DFP_Tp_A_Bp_Rc(name, op1, op2) \
-_GEN_DFP_QUAD(name, op1, op2, 0x00200800)
-
-#define GEN_DFP_T_B_Rc(name, op1, op2) \
-_GEN_DFP_LONG(name, op1, op2, 0x001F0000)
-
-#define GEN_DFP_Tp_Bp_Rc(name, op1, op2) \
-_GEN_DFP_QUAD(name, op1, op2, 0x003F0800)
-
-#define GEN_DFP_Tp_B_Rc(name, op1, op2) \
-_GEN_DFP_QUAD(name, op1, op2, 0x003F0000)
-
-#define GEN_DFP_T_Bp_Rc(name, op1, op2) \
-_GEN_DFP_QUAD(name, op1, op2, 0x001F0800)
-
-#define GEN_DFP_BF_A_B(name, op1, op2) \
-_GEN_DFP_LONG(name, op1, op2, 0x00000001)
-
-#define GEN_DFP_BF_Ap_Bp(name, op1, op2) \
-_GEN_DFP_QUAD(name, op1, op2, 0x00610801)
-
-#define GEN_DFP_BF_A_Bp(name, op1, op2) \
-_GEN_DFP_QUAD(name, op1, op2, 0x00600801)
-
-#define GEN_DFP_BF_A_DCM(name, op1, op2) \
-_GEN_DFP_LONGx2(name, op1, op2, 0x00600001)
-
-#define GEN_DFP_BF_Ap_DCM(name, op1, op2) \
-_GEN_DFP_QUADx2(name, op1, op2, 0x00610001)
-
-#define GEN_DFP_T_A_B_RMC_Rc(name, op1, op2) \
-_GEN_DFP_LONGx4(name, op1, op2, 0x00000000)
-
-#define GEN_DFP_Tp_Ap_Bp_RMC_Rc(name, op1, op2) \
-_GEN_DFP_QUADx4(name, op1, op2, 0x02010800)
-
-#define GEN_DFP_Tp_A_Bp_RMC_Rc(name, op1, op2) \
-_GEN_DFP_QUADx4(name, op1, op2, 0x02000800)
-
-#define GEN_DFP_TE_T_B_RMC_Rc(name, op1, op2) \
-_GEN_DFP_LONGx4(name, op1, op2, 0x00000000)
-
-#define GEN_DFP_TE_Tp_Bp_RMC_Rc(name, op1, op2) \
-_GEN_DFP_QUADx4(name, op1, op2, 0x00200800)
-
-#define GEN_DFP_R_T_B_RMC_Rc(name, op1, op2) \
-_GEN_DFP_LONGx4(name, op1, op2, 0x001E0000)
-
-#define GEN_DFP_R_Tp_Bp_RMC_Rc(name, op1, op2) \
-_GEN_DFP_QUADx4(name, op1, op2, 0x003E0800)
-
-#define GEN_DFP_SP_T_B_Rc(name, op1, op2) \
-_GEN_DFP_LONG(name, op1, op2, 0x00070000)
-
-#define GEN_DFP_SP_Tp_Bp_Rc(name, op1, op2) \
-_GEN_DFP_QUAD(name, op1, op2, 0x00270800)
-
-#define GEN_DFP_S_T_B_Rc(name, op1, op2) \
-_GEN_DFP_LONG(name, op1, op2, 0x000F0000)
-
-#define GEN_DFP_S_Tp_Bp_Rc(name, op1, op2) \
-_GEN_DFP_QUAD(name, op1, op2, 0x002F0800)
-
-#define GEN_DFP_T_A_SH_Rc(name, op1, op2) \
-_GEN_DFP_LONGx2(name, op1, op2, 0x00000000)
-
-#define GEN_DFP_Tp_Ap_SH_Rc(name, op1, op2) \
-_GEN_DFP_QUADx2(name, op1, op2, 0x00210000)
-
-GEN_DFP_T_A_B_Rc(dadd, 0x02, 0x00),
-GEN_DFP_Tp_Ap_Bp_Rc(daddq, 0x02, 0x00),
-GEN_DFP_T_A_B_Rc(dsub, 0x02, 0x10),
-GEN_DFP_Tp_Ap_Bp_Rc(dsubq, 0x02, 0x10),
-GEN_DFP_T_A_B_Rc(dmul, 0x02, 0x01),
-GEN_DFP_Tp_Ap_Bp_Rc(dmulq, 0x02, 0x01),
-GEN_DFP_T_A_B_Rc(ddiv, 0x02, 0x11),
-GEN_DFP_Tp_Ap_Bp_Rc(ddivq, 0x02, 0x11),
-GEN_DFP_BF_A_B(dcmpu, 0x02, 0x14),
-GEN_DFP_BF_Ap_Bp(dcmpuq, 0x02, 0x14),
-GEN_DFP_BF_A_B(dcmpo, 0x02, 0x04),
-GEN_DFP_BF_Ap_Bp(dcmpoq, 0x02, 0x04),
-GEN_DFP_BF_A_DCM(dtstdc, 0x02, 0x06),
-GEN_DFP_BF_Ap_DCM(dtstdcq, 0x02, 0x06),
-GEN_DFP_BF_A_DCM(dtstdg, 0x02, 0x07),
-GEN_DFP_BF_Ap_DCM(dtstdgq, 0x02, 0x07),
-GEN_DFP_BF_A_B(dtstex, 0x02, 0x05),
-GEN_DFP_BF_Ap_Bp(dtstexq, 0x02, 0x05),
-GEN_DFP_BF_A_B(dtstsf, 0x02, 0x15),
-GEN_DFP_BF_A_Bp(dtstsfq, 0x02, 0x15),
-GEN_DFP_TE_T_B_RMC_Rc(dquai, 0x03, 0x02),
-GEN_DFP_TE_Tp_Bp_RMC_Rc(dquaiq, 0x03, 0x02),
-GEN_DFP_T_A_B_RMC_Rc(dqua, 0x03, 0x00),
-GEN_DFP_Tp_Ap_Bp_RMC_Rc(dquaq, 0x03, 0x00),
-GEN_DFP_T_A_B_RMC_Rc(drrnd, 0x03, 0x01),
-GEN_DFP_Tp_A_Bp_RMC_Rc(drrndq, 0x03, 0x01),
-GEN_DFP_R_T_B_RMC_Rc(drintx, 0x03, 0x03),
-GEN_DFP_R_Tp_Bp_RMC_Rc(drintxq, 0x03, 0x03),
-GEN_DFP_R_T_B_RMC_Rc(drintn, 0x03, 0x07),
-GEN_DFP_R_Tp_Bp_RMC_Rc(drintnq, 0x03, 0x07),
-GEN_DFP_T_B_Rc(dctdp, 0x02, 0x08),
-GEN_DFP_Tp_B_Rc(dctqpq, 0x02, 0x08),
-GEN_DFP_T_B_Rc(drsp, 0x02, 0x18),
-GEN_DFP_Tp_Bp_Rc(drdpq, 0x02, 0x18),
-GEN_DFP_T_B_Rc(dcffix, 0x02, 0x19),
-GEN_DFP_Tp_B_Rc(dcffixq, 0x02, 0x19),
-GEN_DFP_T_B_Rc(dctfix, 0x02, 0x09),
-GEN_DFP_T_Bp_Rc(dctfixq, 0x02, 0x09),
-GEN_DFP_SP_T_B_Rc(ddedpd, 0x02, 0x0a),
-GEN_DFP_SP_Tp_Bp_Rc(ddedpdq, 0x02, 0x0a),
-GEN_DFP_S_T_B_Rc(denbcd, 0x02, 0x1a),
-GEN_DFP_S_Tp_Bp_Rc(denbcdq, 0x02, 0x1a),
-GEN_DFP_T_B_Rc(dxex, 0x02, 0x0b),
-GEN_DFP_T_Bp_Rc(dxexq, 0x02, 0x0b),
-GEN_DFP_T_A_B_Rc(diex, 0x02, 0x1b),
-GEN_DFP_Tp_A_Bp_Rc(diexq, 0x02, 0x1b),
-GEN_DFP_T_A_SH_Rc(dscli, 0x02, 0x02),
-GEN_DFP_Tp_Ap_SH_Rc(dscliq, 0x02, 0x02),
-GEN_DFP_T_A_SH_Rc(dscri, 0x02, 0x03),
-GEN_DFP_Tp_Ap_SH_Rc(dscriq, 0x02, 0x03),
+#include "translate/dfp-ops.c"
 
 #include "translate/spe-ops.c"
 
diff --git a/target-ppc/translate/dfp-impl.c b/target-ppc/translate/dfp-impl.c
new file mode 100644
index 0000000..bf59951
--- /dev/null
+++ b/target-ppc/translate/dfp-impl.c
@@ -0,0 +1,212 @@
+/*** Decimal Floating Point ***/
+
+static inline TCGv_ptr gen_fprp_ptr(int reg)
+{
+    TCGv_ptr r = tcg_temp_new_ptr();
+    tcg_gen_addi_ptr(r, cpu_env, offsetof(CPUPPCState, fpr[reg]));
+    return r;
+}
+
+#define GEN_DFP_T_A_B_Rc(name)                   \
+static void gen_##name(DisasContext *ctx)        \
+{                                                \
+    TCGv_ptr rd, ra, rb;                         \
+    if (unlikely(!ctx->fpu_enabled)) {           \
+        gen_exception(ctx, POWERPC_EXCP_FPU);    \
+        return;                                  \
+    }                                            \
+    gen_update_nip(ctx, ctx->nip - 4);           \
+    rd = gen_fprp_ptr(rD(ctx->opcode));          \
+    ra = gen_fprp_ptr(rA(ctx->opcode));          \
+    rb = gen_fprp_ptr(rB(ctx->opcode));          \
+    gen_helper_##name(cpu_env, rd, ra, rb);      \
+    if (unlikely(Rc(ctx->opcode) != 0)) {        \
+        gen_set_cr1_from_fpscr(ctx);             \
+    }                                            \
+    tcg_temp_free_ptr(rd);                       \
+    tcg_temp_free_ptr(ra);                       \
+    tcg_temp_free_ptr(rb);                       \
+}
+
+#define GEN_DFP_BF_A_B(name)                      \
+static void gen_##name(DisasContext *ctx)         \
+{                                                 \
+    TCGv_ptr ra, rb;                              \
+    if (unlikely(!ctx->fpu_enabled)) {            \
+        gen_exception(ctx, POWERPC_EXCP_FPU);     \
+        return;                                   \
+    }                                             \
+    gen_update_nip(ctx, ctx->nip - 4);            \
+    ra = gen_fprp_ptr(rA(ctx->opcode));           \
+    rb = gen_fprp_ptr(rB(ctx->opcode));           \
+    gen_helper_##name(cpu_crf[crfD(ctx->opcode)], \
+                      cpu_env, ra, rb);           \
+    tcg_temp_free_ptr(ra);                        \
+    tcg_temp_free_ptr(rb);                        \
+}
+
+#define GEN_DFP_BF_A_DCM(name)                    \
+static void gen_##name(DisasContext *ctx)         \
+{                                                 \
+    TCGv_ptr ra;                                  \
+    TCGv_i32 dcm;                                 \
+    if (unlikely(!ctx->fpu_enabled)) {            \
+        gen_exception(ctx, POWERPC_EXCP_FPU);     \
+        return;                                   \
+    }                                             \
+    gen_update_nip(ctx, ctx->nip - 4);            \
+    ra = gen_fprp_ptr(rA(ctx->opcode));           \
+    dcm = tcg_const_i32(DCM(ctx->opcode));        \
+    gen_helper_##name(cpu_crf[crfD(ctx->opcode)], \
+                      cpu_env, ra, dcm);          \
+    tcg_temp_free_ptr(ra);                        \
+    tcg_temp_free_i32(dcm);                       \
+}
+
+#define GEN_DFP_T_B_U32_U32_Rc(name, u32f1, u32f2)    \
+static void gen_##name(DisasContext *ctx)             \
+{                                                     \
+    TCGv_ptr rt, rb;                                  \
+    TCGv_i32 u32_1, u32_2;                            \
+    if (unlikely(!ctx->fpu_enabled)) {                \
+        gen_exception(ctx, POWERPC_EXCP_FPU);         \
+        return;                                       \
+    }                                                 \
+    gen_update_nip(ctx, ctx->nip - 4);                \
+    rt = gen_fprp_ptr(rD(ctx->opcode));               \
+    rb = gen_fprp_ptr(rB(ctx->opcode));               \
+    u32_1 = tcg_const_i32(u32f1(ctx->opcode));        \
+    u32_2 = tcg_const_i32(u32f2(ctx->opcode));        \
+    gen_helper_##name(cpu_env, rt, rb, u32_1, u32_2); \
+    if (unlikely(Rc(ctx->opcode) != 0)) {             \
+        gen_set_cr1_from_fpscr(ctx);                  \
+    }                                                 \
+    tcg_temp_free_ptr(rt);                            \
+    tcg_temp_free_ptr(rb);                            \
+    tcg_temp_free_i32(u32_1);                         \
+    tcg_temp_free_i32(u32_2);                         \
+}
+
+#define GEN_DFP_T_A_B_I32_Rc(name, i32fld)       \
+static void gen_##name(DisasContext *ctx)        \
+{                                                \
+    TCGv_ptr rt, ra, rb;                         \
+    TCGv_i32 i32;                                \
+    if (unlikely(!ctx->fpu_enabled)) {           \
+        gen_exception(ctx, POWERPC_EXCP_FPU);    \
+        return;                                  \
+    }                                            \
+    gen_update_nip(ctx, ctx->nip - 4);           \
+    rt = gen_fprp_ptr(rD(ctx->opcode));          \
+    ra = gen_fprp_ptr(rA(ctx->opcode));          \
+    rb = gen_fprp_ptr(rB(ctx->opcode));          \
+    i32 = tcg_const_i32(i32fld(ctx->opcode));    \
+    gen_helper_##name(cpu_env, rt, ra, rb, i32); \
+    if (unlikely(Rc(ctx->opcode) != 0)) {        \
+        gen_set_cr1_from_fpscr(ctx);             \
+    }                                            \
+    tcg_temp_free_ptr(rt);                       \
+    tcg_temp_free_ptr(rb);                       \
+    tcg_temp_free_ptr(ra);                       \
+    tcg_temp_free_i32(i32);                      \
+    }
+
+#define GEN_DFP_T_B_Rc(name)                     \
+static void gen_##name(DisasContext *ctx)        \
+{                                                \
+    TCGv_ptr rt, rb;                             \
+    if (unlikely(!ctx->fpu_enabled)) {           \
+        gen_exception(ctx, POWERPC_EXCP_FPU);    \
+        return;                                  \
+    }                                            \
+    gen_update_nip(ctx, ctx->nip - 4);           \
+    rt = gen_fprp_ptr(rD(ctx->opcode));          \
+    rb = gen_fprp_ptr(rB(ctx->opcode));          \
+    gen_helper_##name(cpu_env, rt, rb);          \
+    if (unlikely(Rc(ctx->opcode) != 0)) {        \
+        gen_set_cr1_from_fpscr(ctx);             \
+    }                                            \
+    tcg_temp_free_ptr(rt);                       \
+    tcg_temp_free_ptr(rb);                       \
+    }
+
+#define GEN_DFP_T_FPR_I32_Rc(name, fprfld, i32fld) \
+static void gen_##name(DisasContext *ctx)          \
+{                                                  \
+    TCGv_ptr rt, rs;                               \
+    TCGv_i32 i32;                                  \
+    if (unlikely(!ctx->fpu_enabled)) {             \
+        gen_exception(ctx, POWERPC_EXCP_FPU);      \
+        return;                                    \
+    }                                              \
+    gen_update_nip(ctx, ctx->nip - 4);             \
+    rt = gen_fprp_ptr(rD(ctx->opcode));            \
+    rs = gen_fprp_ptr(fprfld(ctx->opcode));        \
+    i32 = tcg_const_i32(i32fld(ctx->opcode));      \
+    gen_helper_##name(cpu_env, rt, rs, i32);       \
+    if (unlikely(Rc(ctx->opcode) != 0)) {          \
+        gen_set_cr1_from_fpscr(ctx);               \
+    }                                              \
+    tcg_temp_free_ptr(rt);                         \
+    tcg_temp_free_ptr(rs);                         \
+    tcg_temp_free_i32(i32);                        \
+}
+
+GEN_DFP_T_A_B_Rc(dadd)
+GEN_DFP_T_A_B_Rc(daddq)
+GEN_DFP_T_A_B_Rc(dsub)
+GEN_DFP_T_A_B_Rc(dsubq)
+GEN_DFP_T_A_B_Rc(dmul)
+GEN_DFP_T_A_B_Rc(dmulq)
+GEN_DFP_T_A_B_Rc(ddiv)
+GEN_DFP_T_A_B_Rc(ddivq)
+GEN_DFP_BF_A_B(dcmpu)
+GEN_DFP_BF_A_B(dcmpuq)
+GEN_DFP_BF_A_B(dcmpo)
+GEN_DFP_BF_A_B(dcmpoq)
+GEN_DFP_BF_A_DCM(dtstdc)
+GEN_DFP_BF_A_DCM(dtstdcq)
+GEN_DFP_BF_A_DCM(dtstdg)
+GEN_DFP_BF_A_DCM(dtstdgq)
+GEN_DFP_BF_A_B(dtstex)
+GEN_DFP_BF_A_B(dtstexq)
+GEN_DFP_BF_A_B(dtstsf)
+GEN_DFP_BF_A_B(dtstsfq)
+GEN_DFP_T_B_U32_U32_Rc(dquai, SIMM5, RMC)
+GEN_DFP_T_B_U32_U32_Rc(dquaiq, SIMM5, RMC)
+GEN_DFP_T_A_B_I32_Rc(dqua, RMC)
+GEN_DFP_T_A_B_I32_Rc(dquaq, RMC)
+GEN_DFP_T_A_B_I32_Rc(drrnd, RMC)
+GEN_DFP_T_A_B_I32_Rc(drrndq, RMC)
+GEN_DFP_T_B_U32_U32_Rc(drintx, FPW, RMC)
+GEN_DFP_T_B_U32_U32_Rc(drintxq, FPW, RMC)
+GEN_DFP_T_B_U32_U32_Rc(drintn, FPW, RMC)
+GEN_DFP_T_B_U32_U32_Rc(drintnq, FPW, RMC)
+GEN_DFP_T_B_Rc(dctdp)
+GEN_DFP_T_B_Rc(dctqpq)
+GEN_DFP_T_B_Rc(drsp)
+GEN_DFP_T_B_Rc(drdpq)
+GEN_DFP_T_B_Rc(dcffix)
+GEN_DFP_T_B_Rc(dcffixq)
+GEN_DFP_T_B_Rc(dctfix)
+GEN_DFP_T_B_Rc(dctfixq)
+GEN_DFP_T_FPR_I32_Rc(ddedpd, rB, SP)
+GEN_DFP_T_FPR_I32_Rc(ddedpdq, rB, SP)
+GEN_DFP_T_FPR_I32_Rc(denbcd, rB, SP)
+GEN_DFP_T_FPR_I32_Rc(denbcdq, rB, SP)
+GEN_DFP_T_B_Rc(dxex)
+GEN_DFP_T_B_Rc(dxexq)
+GEN_DFP_T_A_B_Rc(diex)
+GEN_DFP_T_A_B_Rc(diexq)
+GEN_DFP_T_FPR_I32_Rc(dscli, rA, DCM)
+GEN_DFP_T_FPR_I32_Rc(dscliq, rA, DCM)
+GEN_DFP_T_FPR_I32_Rc(dscri, rA, DCM)
+GEN_DFP_T_FPR_I32_Rc(dscriq, rA, DCM)
+
+#undef GEN_DFP_T_A_B_Rc
+#undef GEN_DFP_BF_A_B
+#undef GEN_DFP_BF_A_DCM
+#undef GEN_DFP_T_B_U32_U32_Rc
+#undef GEN_DFP_T_A_B_I32_Rc
+#undef GEN_DFP_T_B_Rc
+#undef GEN_DFP_T_FPR_I32_Rc
diff --git a/target-ppc/translate/dfp-ops.c b/target-ppc/translate/dfp-ops.c
new file mode 100644
index 0000000..7f27d0f
--- /dev/null
+++ b/target-ppc/translate/dfp-ops.c
@@ -0,0 +1,151 @@
+#define _GEN_DFP_LONG(name, op1, op2, mask) \
+GEN_HANDLER_E(name, 0x3B, op1, op2, mask, PPC_NONE, PPC2_DFP)
+
+#define _GEN_DFP_LONGx2(name, op1, op2, mask) \
+GEN_HANDLER_E(name, 0x3B, op1, 0x00 | op2, mask, PPC_NONE, PPC2_DFP), \
+GEN_HANDLER_E(name, 0x3B, op1, 0x10 | op2, mask, PPC_NONE, PPC2_DFP)
+
+#define _GEN_DFP_LONGx4(name, op1, op2, mask) \
+GEN_HANDLER_E(name, 0x3B, op1, 0x00 | op2, mask, PPC_NONE, PPC2_DFP), \
+GEN_HANDLER_E(name, 0x3B, op1, 0x08 | op2, mask, PPC_NONE, PPC2_DFP), \
+GEN_HANDLER_E(name, 0x3B, op1, 0x10 | op2, mask, PPC_NONE, PPC2_DFP), \
+GEN_HANDLER_E(name, 0x3B, op1, 0x18 | op2, mask, PPC_NONE, PPC2_DFP)
+
+#define _GEN_DFP_QUAD(name, op1, op2, mask) \
+GEN_HANDLER_E(name, 0x3F, op1, op2, mask, PPC_NONE, PPC2_DFP)
+
+#define _GEN_DFP_QUADx2(name, op1, op2, mask) \
+GEN_HANDLER_E(name, 0x3F, op1, 0x00 | op2, mask, PPC_NONE, PPC2_DFP), \
+GEN_HANDLER_E(name, 0x3F, op1, 0x10 | op2, mask, PPC_NONE, PPC2_DFP)
+
+#define _GEN_DFP_QUADx4(name, op1, op2, mask)                         \
+GEN_HANDLER_E(name, 0x3F, op1, 0x00 | op2, mask, PPC_NONE, PPC2_DFP), \
+GEN_HANDLER_E(name, 0x3F, op1, 0x08 | op2, mask, PPC_NONE, PPC2_DFP), \
+GEN_HANDLER_E(name, 0x3F, op1, 0x10 | op2, mask, PPC_NONE, PPC2_DFP), \
+GEN_HANDLER_E(name, 0x3F, op1, 0x18 | op2, mask, PPC_NONE, PPC2_DFP)
+
+#define GEN_DFP_T_A_B_Rc(name, op1, op2) \
+_GEN_DFP_LONG(name, op1, op2, 0x00000000)
+
+#define GEN_DFP_Tp_Ap_Bp_Rc(name, op1, op2) \
+_GEN_DFP_QUAD(name, op1, op2, 0x00210800)
+
+#define GEN_DFP_Tp_A_Bp_Rc(name, op1, op2) \
+_GEN_DFP_QUAD(name, op1, op2, 0x00200800)
+
+#define GEN_DFP_T_B_Rc(name, op1, op2) \
+_GEN_DFP_LONG(name, op1, op2, 0x001F0000)
+
+#define GEN_DFP_Tp_Bp_Rc(name, op1, op2) \
+_GEN_DFP_QUAD(name, op1, op2, 0x003F0800)
+
+#define GEN_DFP_Tp_B_Rc(name, op1, op2) \
+_GEN_DFP_QUAD(name, op1, op2, 0x003F0000)
+
+#define GEN_DFP_T_Bp_Rc(name, op1, op2) \
+_GEN_DFP_QUAD(name, op1, op2, 0x001F0800)
+
+#define GEN_DFP_BF_A_B(name, op1, op2) \
+_GEN_DFP_LONG(name, op1, op2, 0x00000001)
+
+#define GEN_DFP_BF_Ap_Bp(name, op1, op2) \
+_GEN_DFP_QUAD(name, op1, op2, 0x00610801)
+
+#define GEN_DFP_BF_A_Bp(name, op1, op2) \
+_GEN_DFP_QUAD(name, op1, op2, 0x00600801)
+
+#define GEN_DFP_BF_A_DCM(name, op1, op2) \
+_GEN_DFP_LONGx2(name, op1, op2, 0x00600001)
+
+#define GEN_DFP_BF_Ap_DCM(name, op1, op2) \
+_GEN_DFP_QUADx2(name, op1, op2, 0x00610001)
+
+#define GEN_DFP_T_A_B_RMC_Rc(name, op1, op2) \
+_GEN_DFP_LONGx4(name, op1, op2, 0x00000000)
+
+#define GEN_DFP_Tp_Ap_Bp_RMC_Rc(name, op1, op2) \
+_GEN_DFP_QUADx4(name, op1, op2, 0x02010800)
+
+#define GEN_DFP_Tp_A_Bp_RMC_Rc(name, op1, op2) \
+_GEN_DFP_QUADx4(name, op1, op2, 0x02000800)
+
+#define GEN_DFP_TE_T_B_RMC_Rc(name, op1, op2) \
+_GEN_DFP_LONGx4(name, op1, op2, 0x00000000)
+
+#define GEN_DFP_TE_Tp_Bp_RMC_Rc(name, op1, op2) \
+_GEN_DFP_QUADx4(name, op1, op2, 0x00200800)
+
+#define GEN_DFP_R_T_B_RMC_Rc(name, op1, op2) \
+_GEN_DFP_LONGx4(name, op1, op2, 0x001E0000)
+
+#define GEN_DFP_R_Tp_Bp_RMC_Rc(name, op1, op2) \
+_GEN_DFP_QUADx4(name, op1, op2, 0x003E0800)
+
+#define GEN_DFP_SP_T_B_Rc(name, op1, op2) \
+_GEN_DFP_LONG(name, op1, op2, 0x00070000)
+
+#define GEN_DFP_SP_Tp_Bp_Rc(name, op1, op2) \
+_GEN_DFP_QUAD(name, op1, op2, 0x00270800)
+
+#define GEN_DFP_S_T_B_Rc(name, op1, op2) \
+_GEN_DFP_LONG(name, op1, op2, 0x000F0000)
+
+#define GEN_DFP_S_Tp_Bp_Rc(name, op1, op2) \
+_GEN_DFP_QUAD(name, op1, op2, 0x002F0800)
+
+#define GEN_DFP_T_A_SH_Rc(name, op1, op2) \
+_GEN_DFP_LONGx2(name, op1, op2, 0x00000000)
+
+#define GEN_DFP_Tp_Ap_SH_Rc(name, op1, op2) \
+_GEN_DFP_QUADx2(name, op1, op2, 0x00210000)
+
+GEN_DFP_T_A_B_Rc(dadd, 0x02, 0x00),
+GEN_DFP_Tp_Ap_Bp_Rc(daddq, 0x02, 0x00),
+GEN_DFP_T_A_B_Rc(dsub, 0x02, 0x10),
+GEN_DFP_Tp_Ap_Bp_Rc(dsubq, 0x02, 0x10),
+GEN_DFP_T_A_B_Rc(dmul, 0x02, 0x01),
+GEN_DFP_Tp_Ap_Bp_Rc(dmulq, 0x02, 0x01),
+GEN_DFP_T_A_B_Rc(ddiv, 0x02, 0x11),
+GEN_DFP_Tp_Ap_Bp_Rc(ddivq, 0x02, 0x11),
+GEN_DFP_BF_A_B(dcmpu, 0x02, 0x14),
+GEN_DFP_BF_Ap_Bp(dcmpuq, 0x02, 0x14),
+GEN_DFP_BF_A_B(dcmpo, 0x02, 0x04),
+GEN_DFP_BF_Ap_Bp(dcmpoq, 0x02, 0x04),
+GEN_DFP_BF_A_DCM(dtstdc, 0x02, 0x06),
+GEN_DFP_BF_Ap_DCM(dtstdcq, 0x02, 0x06),
+GEN_DFP_BF_A_DCM(dtstdg, 0x02, 0x07),
+GEN_DFP_BF_Ap_DCM(dtstdgq, 0x02, 0x07),
+GEN_DFP_BF_A_B(dtstex, 0x02, 0x05),
+GEN_DFP_BF_Ap_Bp(dtstexq, 0x02, 0x05),
+GEN_DFP_BF_A_B(dtstsf, 0x02, 0x15),
+GEN_DFP_BF_A_Bp(dtstsfq, 0x02, 0x15),
+GEN_DFP_TE_T_B_RMC_Rc(dquai, 0x03, 0x02),
+GEN_DFP_TE_Tp_Bp_RMC_Rc(dquaiq, 0x03, 0x02),
+GEN_DFP_T_A_B_RMC_Rc(dqua, 0x03, 0x00),
+GEN_DFP_Tp_Ap_Bp_RMC_Rc(dquaq, 0x03, 0x00),
+GEN_DFP_T_A_B_RMC_Rc(drrnd, 0x03, 0x01),
+GEN_DFP_Tp_A_Bp_RMC_Rc(drrndq, 0x03, 0x01),
+GEN_DFP_R_T_B_RMC_Rc(drintx, 0x03, 0x03),
+GEN_DFP_R_Tp_Bp_RMC_Rc(drintxq, 0x03, 0x03),
+GEN_DFP_R_T_B_RMC_Rc(drintn, 0x03, 0x07),
+GEN_DFP_R_Tp_Bp_RMC_Rc(drintnq, 0x03, 0x07),
+GEN_DFP_T_B_Rc(dctdp, 0x02, 0x08),
+GEN_DFP_Tp_B_Rc(dctqpq, 0x02, 0x08),
+GEN_DFP_T_B_Rc(drsp, 0x02, 0x18),
+GEN_DFP_Tp_Bp_Rc(drdpq, 0x02, 0x18),
+GEN_DFP_T_B_Rc(dcffix, 0x02, 0x19),
+GEN_DFP_Tp_B_Rc(dcffixq, 0x02, 0x19),
+GEN_DFP_T_B_Rc(dctfix, 0x02, 0x09),
+GEN_DFP_T_Bp_Rc(dctfixq, 0x02, 0x09),
+GEN_DFP_SP_T_B_Rc(ddedpd, 0x02, 0x0a),
+GEN_DFP_SP_Tp_Bp_Rc(ddedpdq, 0x02, 0x0a),
+GEN_DFP_S_T_B_Rc(denbcd, 0x02, 0x1a),
+GEN_DFP_S_Tp_Bp_Rc(denbcdq, 0x02, 0x1a),
+GEN_DFP_T_B_Rc(dxex, 0x02, 0x0b),
+GEN_DFP_T_Bp_Rc(dxexq, 0x02, 0x0b),
+GEN_DFP_T_A_B_Rc(diex, 0x02, 0x1b),
+GEN_DFP_Tp_A_Bp_Rc(diexq, 0x02, 0x1b),
+GEN_DFP_T_A_SH_Rc(dscli, 0x02, 0x02),
+GEN_DFP_Tp_Ap_SH_Rc(dscliq, 0x02, 0x02),
+GEN_DFP_T_A_SH_Rc(dscri, 0x02, 0x03),
+GEN_DFP_Tp_Ap_SH_Rc(dscriq, 0x02, 0x03),
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [Qemu-devel] [PATCH 06/32] ppc: Move VMX ops out of translate.c
  2016-07-26 22:20 [Qemu-devel] [PATCH 01/32] ppc: Fix fault PC reporting for lve*/stve* VMX instructions Benjamin Herrenschmidt
                   ` (3 preceding siblings ...)
  2016-07-26 22:20 ` [Qemu-devel] [PATCH 05/32] ppc: Move DFP " Benjamin Herrenschmidt
@ 2016-07-26 22:21 ` Benjamin Herrenschmidt
  2016-07-26 22:21 ` [Qemu-devel] [PATCH 07/32] ppc: Move VSX " Benjamin Herrenschmidt
                   ` (26 subsequent siblings)
  31 siblings, 0 replies; 69+ messages in thread
From: Benjamin Herrenschmidt @ 2016-07-26 22:21 UTC (permalink / raw)
  To: qemu-ppc; +Cc: qemu-devel, david, Benjamin Herrenschmidt

Makes things a bit more manageable

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
 target-ppc/translate.c          | 1069 +--------------------------------------
 target-ppc/translate/vmx-impl.c |  829 ++++++++++++++++++++++++++++++
 target-ppc/translate/vmx-ops.c  |  246 +++++++++
 3 files changed, 1078 insertions(+), 1066 deletions(-)
 create mode 100644 target-ppc/translate/vmx-impl.c
 create mode 100644 target-ppc/translate/vmx-ops.c

diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index ee45673..421fd98 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -5005,6 +5005,8 @@ static void gen_rfsvc(DisasContext *ctx)
 
 #include "translate/fp-impl.c"
 
+#include "translate/vmx-impl.c"
+
 /* svc is not implemented for now */
 
 /* BookE specific instructions */
@@ -5769,812 +5771,6 @@ static void gen_msgsnd(DisasContext *ctx)
 #endif /* defined(CONFIG_USER_ONLY) */
 }
 
-/***                      Altivec vector extension                         ***/
-/* Altivec registers moves */
-
-static inline TCGv_ptr gen_avr_ptr(int reg)
-{
-    TCGv_ptr r = tcg_temp_new_ptr();
-    tcg_gen_addi_ptr(r, cpu_env, offsetof(CPUPPCState, avr[reg]));
-    return r;
-}
-
-#define GEN_VR_LDX(name, opc2, opc3)                                          \
-static void glue(gen_, name)(DisasContext *ctx)                                       \
-{                                                                             \
-    TCGv EA;                                                                  \
-    if (unlikely(!ctx->altivec_enabled)) {                                    \
-        gen_exception(ctx, POWERPC_EXCP_VPU);                                 \
-        return;                                                               \
-    }                                                                         \
-    gen_set_access_type(ctx, ACCESS_INT);                                     \
-    EA = tcg_temp_new();                                                      \
-    gen_addr_reg_index(ctx, EA);                                              \
-    tcg_gen_andi_tl(EA, EA, ~0xf);                                            \
-    /* We only need to swap high and low halves. gen_qemu_ld64 does necessary \
-       64-bit byteswap already. */                                            \
-    if (ctx->le_mode) {                                                       \
-        gen_qemu_ld64(ctx, cpu_avrl[rD(ctx->opcode)], EA);                    \
-        tcg_gen_addi_tl(EA, EA, 8);                                           \
-        gen_qemu_ld64(ctx, cpu_avrh[rD(ctx->opcode)], EA);                    \
-    } else {                                                                  \
-        gen_qemu_ld64(ctx, cpu_avrh[rD(ctx->opcode)], EA);                    \
-        tcg_gen_addi_tl(EA, EA, 8);                                           \
-        gen_qemu_ld64(ctx, cpu_avrl[rD(ctx->opcode)], EA);                    \
-    }                                                                         \
-    tcg_temp_free(EA);                                                        \
-}
-
-#define GEN_VR_STX(name, opc2, opc3)                                          \
-static void gen_st##name(DisasContext *ctx)                                   \
-{                                                                             \
-    TCGv EA;                                                                  \
-    if (unlikely(!ctx->altivec_enabled)) {                                    \
-        gen_exception(ctx, POWERPC_EXCP_VPU);                                 \
-        return;                                                               \
-    }                                                                         \
-    gen_set_access_type(ctx, ACCESS_INT);                                     \
-    EA = tcg_temp_new();                                                      \
-    gen_addr_reg_index(ctx, EA);                                              \
-    tcg_gen_andi_tl(EA, EA, ~0xf);                                            \
-    /* We only need to swap high and low halves. gen_qemu_st64 does necessary \
-       64-bit byteswap already. */                                            \
-    if (ctx->le_mode) {                                                       \
-        gen_qemu_st64(ctx, cpu_avrl[rD(ctx->opcode)], EA);                    \
-        tcg_gen_addi_tl(EA, EA, 8);                                           \
-        gen_qemu_st64(ctx, cpu_avrh[rD(ctx->opcode)], EA);                    \
-    } else {                                                                  \
-        gen_qemu_st64(ctx, cpu_avrh[rD(ctx->opcode)], EA);                    \
-        tcg_gen_addi_tl(EA, EA, 8);                                           \
-        gen_qemu_st64(ctx, cpu_avrl[rD(ctx->opcode)], EA);                    \
-    }                                                                         \
-    tcg_temp_free(EA);                                                        \
-}
-
-#define GEN_VR_LVE(name, opc2, opc3, size)                              \
-static void gen_lve##name(DisasContext *ctx)                            \
-    {                                                                   \
-        TCGv EA;                                                        \
-        TCGv_ptr rs;                                                    \
-        if (unlikely(!ctx->altivec_enabled)) {                          \
-            gen_exception(ctx, POWERPC_EXCP_VPU);                       \
-            return;                                                     \
-        }                                                               \
-        gen_set_access_type(ctx, ACCESS_INT);                           \
-        EA = tcg_temp_new();                                            \
-        gen_addr_reg_index(ctx, EA);                                    \
-        if (size > 1) {                                                 \
-            tcg_gen_andi_tl(EA, EA, ~(size - 1));                       \
-        }                                                               \
-        rs = gen_avr_ptr(rS(ctx->opcode));                              \
-        gen_helper_lve##name(cpu_env, rs, EA);                          \
-        tcg_temp_free(EA);                                              \
-        tcg_temp_free_ptr(rs);                                          \
-    }
-
-#define GEN_VR_STVE(name, opc2, opc3, size)                             \
-static void gen_stve##name(DisasContext *ctx)                           \
-    {                                                                   \
-        TCGv EA;                                                        \
-        TCGv_ptr rs;                                                    \
-        if (unlikely(!ctx->altivec_enabled)) {                          \
-            gen_exception(ctx, POWERPC_EXCP_VPU);                       \
-            return;                                                     \
-        }                                                               \
-        gen_set_access_type(ctx, ACCESS_INT);                           \
-        EA = tcg_temp_new();                                            \
-        gen_addr_reg_index(ctx, EA);                                    \
-        if (size > 1) {                                                 \
-            tcg_gen_andi_tl(EA, EA, ~(size - 1));                       \
-        }                                                               \
-        rs = gen_avr_ptr(rS(ctx->opcode));                              \
-        gen_helper_stve##name(cpu_env, rs, EA);                         \
-        tcg_temp_free(EA);                                              \
-        tcg_temp_free_ptr(rs);                                          \
-    }
-
-GEN_VR_LDX(lvx, 0x07, 0x03);
-/* As we don't emulate the cache, lvxl is stricly equivalent to lvx */
-GEN_VR_LDX(lvxl, 0x07, 0x0B);
-
-GEN_VR_LVE(bx, 0x07, 0x00, 1);
-GEN_VR_LVE(hx, 0x07, 0x01, 2);
-GEN_VR_LVE(wx, 0x07, 0x02, 4);
-
-GEN_VR_STX(svx, 0x07, 0x07);
-/* As we don't emulate the cache, stvxl is stricly equivalent to stvx */
-GEN_VR_STX(svxl, 0x07, 0x0F);
-
-GEN_VR_STVE(bx, 0x07, 0x04, 1);
-GEN_VR_STVE(hx, 0x07, 0x05, 2);
-GEN_VR_STVE(wx, 0x07, 0x06, 4);
-
-static void gen_lvsl(DisasContext *ctx)
-{
-    TCGv_ptr rd;
-    TCGv EA;
-    if (unlikely(!ctx->altivec_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_VPU);
-        return;
-    }
-    EA = tcg_temp_new();
-    gen_addr_reg_index(ctx, EA);
-    rd = gen_avr_ptr(rD(ctx->opcode));
-    gen_helper_lvsl(rd, EA);
-    tcg_temp_free(EA);
-    tcg_temp_free_ptr(rd);
-}
-
-static void gen_lvsr(DisasContext *ctx)
-{
-    TCGv_ptr rd;
-    TCGv EA;
-    if (unlikely(!ctx->altivec_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_VPU);
-        return;
-    }
-    EA = tcg_temp_new();
-    gen_addr_reg_index(ctx, EA);
-    rd = gen_avr_ptr(rD(ctx->opcode));
-    gen_helper_lvsr(rd, EA);
-    tcg_temp_free(EA);
-    tcg_temp_free_ptr(rd);
-}
-
-static void gen_mfvscr(DisasContext *ctx)
-{
-    TCGv_i32 t;
-    if (unlikely(!ctx->altivec_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_VPU);
-        return;
-    }
-    tcg_gen_movi_i64(cpu_avrh[rD(ctx->opcode)], 0);
-    t = tcg_temp_new_i32();
-    tcg_gen_ld_i32(t, cpu_env, offsetof(CPUPPCState, vscr));
-    tcg_gen_extu_i32_i64(cpu_avrl[rD(ctx->opcode)], t);
-    tcg_temp_free_i32(t);
-}
-
-static void gen_mtvscr(DisasContext *ctx)
-{
-    TCGv_ptr p;
-    if (unlikely(!ctx->altivec_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_VPU);
-        return;
-    }
-    p = gen_avr_ptr(rB(ctx->opcode));
-    gen_helper_mtvscr(cpu_env, p);
-    tcg_temp_free_ptr(p);
-}
-
-/* Logical operations */
-#define GEN_VX_LOGICAL(name, tcg_op, opc2, opc3)                        \
-static void glue(gen_, name)(DisasContext *ctx)                                 \
-{                                                                       \
-    if (unlikely(!ctx->altivec_enabled)) {                              \
-        gen_exception(ctx, POWERPC_EXCP_VPU);                           \
-        return;                                                         \
-    }                                                                   \
-    tcg_op(cpu_avrh[rD(ctx->opcode)], cpu_avrh[rA(ctx->opcode)], cpu_avrh[rB(ctx->opcode)]); \
-    tcg_op(cpu_avrl[rD(ctx->opcode)], cpu_avrl[rA(ctx->opcode)], cpu_avrl[rB(ctx->opcode)]); \
-}
-
-GEN_VX_LOGICAL(vand, tcg_gen_and_i64, 2, 16);
-GEN_VX_LOGICAL(vandc, tcg_gen_andc_i64, 2, 17);
-GEN_VX_LOGICAL(vor, tcg_gen_or_i64, 2, 18);
-GEN_VX_LOGICAL(vxor, tcg_gen_xor_i64, 2, 19);
-GEN_VX_LOGICAL(vnor, tcg_gen_nor_i64, 2, 20);
-GEN_VX_LOGICAL(veqv, tcg_gen_eqv_i64, 2, 26);
-GEN_VX_LOGICAL(vnand, tcg_gen_nand_i64, 2, 22);
-GEN_VX_LOGICAL(vorc, tcg_gen_orc_i64, 2, 21);
-
-#define GEN_VXFORM(name, opc2, opc3)                                    \
-static void glue(gen_, name)(DisasContext *ctx)                                 \
-{                                                                       \
-    TCGv_ptr ra, rb, rd;                                                \
-    if (unlikely(!ctx->altivec_enabled)) {                              \
-        gen_exception(ctx, POWERPC_EXCP_VPU);                           \
-        return;                                                         \
-    }                                                                   \
-    ra = gen_avr_ptr(rA(ctx->opcode));                                  \
-    rb = gen_avr_ptr(rB(ctx->opcode));                                  \
-    rd = gen_avr_ptr(rD(ctx->opcode));                                  \
-    gen_helper_##name (rd, ra, rb);                                     \
-    tcg_temp_free_ptr(ra);                                              \
-    tcg_temp_free_ptr(rb);                                              \
-    tcg_temp_free_ptr(rd);                                              \
-}
-
-#define GEN_VXFORM_ENV(name, opc2, opc3)                                \
-static void glue(gen_, name)(DisasContext *ctx)                         \
-{                                                                       \
-    TCGv_ptr ra, rb, rd;                                                \
-    if (unlikely(!ctx->altivec_enabled)) {                              \
-        gen_exception(ctx, POWERPC_EXCP_VPU);                           \
-        return;                                                         \
-    }                                                                   \
-    ra = gen_avr_ptr(rA(ctx->opcode));                                  \
-    rb = gen_avr_ptr(rB(ctx->opcode));                                  \
-    rd = gen_avr_ptr(rD(ctx->opcode));                                  \
-    gen_helper_##name(cpu_env, rd, ra, rb);                             \
-    tcg_temp_free_ptr(ra);                                              \
-    tcg_temp_free_ptr(rb);                                              \
-    tcg_temp_free_ptr(rd);                                              \
-}
-
-#define GEN_VXFORM3(name, opc2, opc3)                                   \
-static void glue(gen_, name)(DisasContext *ctx)                         \
-{                                                                       \
-    TCGv_ptr ra, rb, rc, rd;                                            \
-    if (unlikely(!ctx->altivec_enabled)) {                              \
-        gen_exception(ctx, POWERPC_EXCP_VPU);                           \
-        return;                                                         \
-    }                                                                   \
-    ra = gen_avr_ptr(rA(ctx->opcode));                                  \
-    rb = gen_avr_ptr(rB(ctx->opcode));                                  \
-    rc = gen_avr_ptr(rC(ctx->opcode));                                  \
-    rd = gen_avr_ptr(rD(ctx->opcode));                                  \
-    gen_helper_##name(rd, ra, rb, rc);                                  \
-    tcg_temp_free_ptr(ra);                                              \
-    tcg_temp_free_ptr(rb);                                              \
-    tcg_temp_free_ptr(rc);                                              \
-    tcg_temp_free_ptr(rd);                                              \
-}
-
-/*
- * Support for Altivec instruction pairs that use bit 31 (Rc) as
- * an opcode bit.  In general, these pairs come from different
- * versions of the ISA, so we must also support a pair of flags for
- * each instruction.
- */
-#define GEN_VXFORM_DUAL(name0, flg0, flg2_0, name1, flg1, flg2_1)          \
-static void glue(gen_, name0##_##name1)(DisasContext *ctx)             \
-{                                                                      \
-    if ((Rc(ctx->opcode) == 0) &&                                      \
-        ((ctx->insns_flags & flg0) || (ctx->insns_flags2 & flg2_0))) { \
-        gen_##name0(ctx);                                              \
-    } else if ((Rc(ctx->opcode) == 1) &&                               \
-        ((ctx->insns_flags & flg1) || (ctx->insns_flags2 & flg2_1))) { \
-        gen_##name1(ctx);                                              \
-    } else {                                                           \
-        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);            \
-    }                                                                  \
-}
-
-GEN_VXFORM(vaddubm, 0, 0);
-GEN_VXFORM(vadduhm, 0, 1);
-GEN_VXFORM(vadduwm, 0, 2);
-GEN_VXFORM(vaddudm, 0, 3);
-GEN_VXFORM(vsububm, 0, 16);
-GEN_VXFORM(vsubuhm, 0, 17);
-GEN_VXFORM(vsubuwm, 0, 18);
-GEN_VXFORM(vsubudm, 0, 19);
-GEN_VXFORM(vmaxub, 1, 0);
-GEN_VXFORM(vmaxuh, 1, 1);
-GEN_VXFORM(vmaxuw, 1, 2);
-GEN_VXFORM(vmaxud, 1, 3);
-GEN_VXFORM(vmaxsb, 1, 4);
-GEN_VXFORM(vmaxsh, 1, 5);
-GEN_VXFORM(vmaxsw, 1, 6);
-GEN_VXFORM(vmaxsd, 1, 7);
-GEN_VXFORM(vminub, 1, 8);
-GEN_VXFORM(vminuh, 1, 9);
-GEN_VXFORM(vminuw, 1, 10);
-GEN_VXFORM(vminud, 1, 11);
-GEN_VXFORM(vminsb, 1, 12);
-GEN_VXFORM(vminsh, 1, 13);
-GEN_VXFORM(vminsw, 1, 14);
-GEN_VXFORM(vminsd, 1, 15);
-GEN_VXFORM(vavgub, 1, 16);
-GEN_VXFORM(vavguh, 1, 17);
-GEN_VXFORM(vavguw, 1, 18);
-GEN_VXFORM(vavgsb, 1, 20);
-GEN_VXFORM(vavgsh, 1, 21);
-GEN_VXFORM(vavgsw, 1, 22);
-GEN_VXFORM(vmrghb, 6, 0);
-GEN_VXFORM(vmrghh, 6, 1);
-GEN_VXFORM(vmrghw, 6, 2);
-GEN_VXFORM(vmrglb, 6, 4);
-GEN_VXFORM(vmrglh, 6, 5);
-GEN_VXFORM(vmrglw, 6, 6);
-
-static void gen_vmrgew(DisasContext *ctx)
-{
-    TCGv_i64 tmp;
-    int VT, VA, VB;
-    if (unlikely(!ctx->altivec_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_VPU);
-        return;
-    }
-    VT = rD(ctx->opcode);
-    VA = rA(ctx->opcode);
-    VB = rB(ctx->opcode);
-    tmp = tcg_temp_new_i64();
-    tcg_gen_shri_i64(tmp, cpu_avrh[VB], 32);
-    tcg_gen_deposit_i64(cpu_avrh[VT], cpu_avrh[VA], tmp, 0, 32);
-    tcg_gen_shri_i64(tmp, cpu_avrl[VB], 32);
-    tcg_gen_deposit_i64(cpu_avrl[VT], cpu_avrl[VA], tmp, 0, 32);
-    tcg_temp_free_i64(tmp);
-}
-
-static void gen_vmrgow(DisasContext *ctx)
-{
-    int VT, VA, VB;
-    if (unlikely(!ctx->altivec_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_VPU);
-        return;
-    }
-    VT = rD(ctx->opcode);
-    VA = rA(ctx->opcode);
-    VB = rB(ctx->opcode);
-
-    tcg_gen_deposit_i64(cpu_avrh[VT], cpu_avrh[VB], cpu_avrh[VA], 32, 32);
-    tcg_gen_deposit_i64(cpu_avrl[VT], cpu_avrl[VB], cpu_avrl[VA], 32, 32);
-}
-
-GEN_VXFORM(vmuloub, 4, 0);
-GEN_VXFORM(vmulouh, 4, 1);
-GEN_VXFORM(vmulouw, 4, 2);
-GEN_VXFORM(vmuluwm, 4, 2);
-GEN_VXFORM_DUAL(vmulouw, PPC_ALTIVEC, PPC_NONE,
-                vmuluwm, PPC_NONE, PPC2_ALTIVEC_207)
-GEN_VXFORM(vmulosb, 4, 4);
-GEN_VXFORM(vmulosh, 4, 5);
-GEN_VXFORM(vmulosw, 4, 6);
-GEN_VXFORM(vmuleub, 4, 8);
-GEN_VXFORM(vmuleuh, 4, 9);
-GEN_VXFORM(vmuleuw, 4, 10);
-GEN_VXFORM(vmulesb, 4, 12);
-GEN_VXFORM(vmulesh, 4, 13);
-GEN_VXFORM(vmulesw, 4, 14);
-GEN_VXFORM(vslb, 2, 4);
-GEN_VXFORM(vslh, 2, 5);
-GEN_VXFORM(vslw, 2, 6);
-GEN_VXFORM(vsld, 2, 23);
-GEN_VXFORM(vsrb, 2, 8);
-GEN_VXFORM(vsrh, 2, 9);
-GEN_VXFORM(vsrw, 2, 10);
-GEN_VXFORM(vsrd, 2, 27);
-GEN_VXFORM(vsrab, 2, 12);
-GEN_VXFORM(vsrah, 2, 13);
-GEN_VXFORM(vsraw, 2, 14);
-GEN_VXFORM(vsrad, 2, 15);
-GEN_VXFORM(vslo, 6, 16);
-GEN_VXFORM(vsro, 6, 17);
-GEN_VXFORM(vaddcuw, 0, 6);
-GEN_VXFORM(vsubcuw, 0, 22);
-GEN_VXFORM_ENV(vaddubs, 0, 8);
-GEN_VXFORM_ENV(vadduhs, 0, 9);
-GEN_VXFORM_ENV(vadduws, 0, 10);
-GEN_VXFORM_ENV(vaddsbs, 0, 12);
-GEN_VXFORM_ENV(vaddshs, 0, 13);
-GEN_VXFORM_ENV(vaddsws, 0, 14);
-GEN_VXFORM_ENV(vsububs, 0, 24);
-GEN_VXFORM_ENV(vsubuhs, 0, 25);
-GEN_VXFORM_ENV(vsubuws, 0, 26);
-GEN_VXFORM_ENV(vsubsbs, 0, 28);
-GEN_VXFORM_ENV(vsubshs, 0, 29);
-GEN_VXFORM_ENV(vsubsws, 0, 30);
-GEN_VXFORM(vadduqm, 0, 4);
-GEN_VXFORM(vaddcuq, 0, 5);
-GEN_VXFORM3(vaddeuqm, 30, 0);
-GEN_VXFORM3(vaddecuq, 30, 0);
-GEN_VXFORM_DUAL(vaddeuqm, PPC_NONE, PPC2_ALTIVEC_207, \
-            vaddecuq, PPC_NONE, PPC2_ALTIVEC_207)
-GEN_VXFORM(vsubuqm, 0, 20);
-GEN_VXFORM(vsubcuq, 0, 21);
-GEN_VXFORM3(vsubeuqm, 31, 0);
-GEN_VXFORM3(vsubecuq, 31, 0);
-GEN_VXFORM_DUAL(vsubeuqm, PPC_NONE, PPC2_ALTIVEC_207, \
-            vsubecuq, PPC_NONE, PPC2_ALTIVEC_207)
-GEN_VXFORM(vrlb, 2, 0);
-GEN_VXFORM(vrlh, 2, 1);
-GEN_VXFORM(vrlw, 2, 2);
-GEN_VXFORM(vrld, 2, 3);
-GEN_VXFORM(vsl, 2, 7);
-GEN_VXFORM(vsr, 2, 11);
-GEN_VXFORM_ENV(vpkuhum, 7, 0);
-GEN_VXFORM_ENV(vpkuwum, 7, 1);
-GEN_VXFORM_ENV(vpkudum, 7, 17);
-GEN_VXFORM_ENV(vpkuhus, 7, 2);
-GEN_VXFORM_ENV(vpkuwus, 7, 3);
-GEN_VXFORM_ENV(vpkudus, 7, 19);
-GEN_VXFORM_ENV(vpkshus, 7, 4);
-GEN_VXFORM_ENV(vpkswus, 7, 5);
-GEN_VXFORM_ENV(vpksdus, 7, 21);
-GEN_VXFORM_ENV(vpkshss, 7, 6);
-GEN_VXFORM_ENV(vpkswss, 7, 7);
-GEN_VXFORM_ENV(vpksdss, 7, 23);
-GEN_VXFORM(vpkpx, 7, 12);
-GEN_VXFORM_ENV(vsum4ubs, 4, 24);
-GEN_VXFORM_ENV(vsum4sbs, 4, 28);
-GEN_VXFORM_ENV(vsum4shs, 4, 25);
-GEN_VXFORM_ENV(vsum2sws, 4, 26);
-GEN_VXFORM_ENV(vsumsws, 4, 30);
-GEN_VXFORM_ENV(vaddfp, 5, 0);
-GEN_VXFORM_ENV(vsubfp, 5, 1);
-GEN_VXFORM_ENV(vmaxfp, 5, 16);
-GEN_VXFORM_ENV(vminfp, 5, 17);
-
-#define GEN_VXRFORM1(opname, name, str, opc2, opc3)                     \
-static void glue(gen_, name)(DisasContext *ctx)                         \
-    {                                                                   \
-        TCGv_ptr ra, rb, rd;                                            \
-        if (unlikely(!ctx->altivec_enabled)) {                          \
-            gen_exception(ctx, POWERPC_EXCP_VPU);                       \
-            return;                                                     \
-        }                                                               \
-        ra = gen_avr_ptr(rA(ctx->opcode));                              \
-        rb = gen_avr_ptr(rB(ctx->opcode));                              \
-        rd = gen_avr_ptr(rD(ctx->opcode));                              \
-        gen_helper_##opname(cpu_env, rd, ra, rb);                       \
-        tcg_temp_free_ptr(ra);                                          \
-        tcg_temp_free_ptr(rb);                                          \
-        tcg_temp_free_ptr(rd);                                          \
-    }
-
-#define GEN_VXRFORM(name, opc2, opc3)                                \
-    GEN_VXRFORM1(name, name, #name, opc2, opc3)                      \
-    GEN_VXRFORM1(name##_dot, name##_, #name ".", opc2, (opc3 | (0x1 << 4)))
-
-/*
- * Support for Altivec instructions that use bit 31 (Rc) as an opcode
- * bit but also use bit 21 as an actual Rc bit.  In general, thse pairs
- * come from different versions of the ISA, so we must also support a
- * pair of flags for each instruction.
- */
-#define GEN_VXRFORM_DUAL(name0, flg0, flg2_0, name1, flg1, flg2_1)     \
-static void glue(gen_, name0##_##name1)(DisasContext *ctx)             \
-{                                                                      \
-    if ((Rc(ctx->opcode) == 0) &&                                      \
-        ((ctx->insns_flags & flg0) || (ctx->insns_flags2 & flg2_0))) { \
-        if (Rc21(ctx->opcode) == 0) {                                  \
-            gen_##name0(ctx);                                          \
-        } else {                                                       \
-            gen_##name0##_(ctx);                                       \
-        }                                                              \
-    } else if ((Rc(ctx->opcode) == 1) &&                               \
-        ((ctx->insns_flags & flg1) || (ctx->insns_flags2 & flg2_1))) { \
-        if (Rc21(ctx->opcode) == 0) {                                  \
-            gen_##name1(ctx);                                          \
-        } else {                                                       \
-            gen_##name1##_(ctx);                                       \
-        }                                                              \
-    } else {                                                           \
-        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);            \
-    }                                                                  \
-}
-
-GEN_VXRFORM(vcmpequb, 3, 0)
-GEN_VXRFORM(vcmpequh, 3, 1)
-GEN_VXRFORM(vcmpequw, 3, 2)
-GEN_VXRFORM(vcmpequd, 3, 3)
-GEN_VXRFORM(vcmpgtsb, 3, 12)
-GEN_VXRFORM(vcmpgtsh, 3, 13)
-GEN_VXRFORM(vcmpgtsw, 3, 14)
-GEN_VXRFORM(vcmpgtsd, 3, 15)
-GEN_VXRFORM(vcmpgtub, 3, 8)
-GEN_VXRFORM(vcmpgtuh, 3, 9)
-GEN_VXRFORM(vcmpgtuw, 3, 10)
-GEN_VXRFORM(vcmpgtud, 3, 11)
-GEN_VXRFORM(vcmpeqfp, 3, 3)
-GEN_VXRFORM(vcmpgefp, 3, 7)
-GEN_VXRFORM(vcmpgtfp, 3, 11)
-GEN_VXRFORM(vcmpbfp, 3, 15)
-
-GEN_VXRFORM_DUAL(vcmpeqfp, PPC_ALTIVEC, PPC_NONE, \
-                 vcmpequd, PPC_NONE, PPC2_ALTIVEC_207)
-GEN_VXRFORM_DUAL(vcmpbfp, PPC_ALTIVEC, PPC_NONE, \
-                 vcmpgtsd, PPC_NONE, PPC2_ALTIVEC_207)
-GEN_VXRFORM_DUAL(vcmpgtfp, PPC_ALTIVEC, PPC_NONE, \
-                 vcmpgtud, PPC_NONE, PPC2_ALTIVEC_207)
-
-#define GEN_VXFORM_SIMM(name, opc2, opc3)                               \
-static void glue(gen_, name)(DisasContext *ctx)                         \
-    {                                                                   \
-        TCGv_ptr rd;                                                    \
-        TCGv_i32 simm;                                                  \
-        if (unlikely(!ctx->altivec_enabled)) {                          \
-            gen_exception(ctx, POWERPC_EXCP_VPU);                       \
-            return;                                                     \
-        }                                                               \
-        simm = tcg_const_i32(SIMM5(ctx->opcode));                       \
-        rd = gen_avr_ptr(rD(ctx->opcode));                              \
-        gen_helper_##name (rd, simm);                                   \
-        tcg_temp_free_i32(simm);                                        \
-        tcg_temp_free_ptr(rd);                                          \
-    }
-
-GEN_VXFORM_SIMM(vspltisb, 6, 12);
-GEN_VXFORM_SIMM(vspltish, 6, 13);
-GEN_VXFORM_SIMM(vspltisw, 6, 14);
-
-#define GEN_VXFORM_NOA(name, opc2, opc3)                                \
-static void glue(gen_, name)(DisasContext *ctx)                                 \
-    {                                                                   \
-        TCGv_ptr rb, rd;                                                \
-        if (unlikely(!ctx->altivec_enabled)) {                          \
-            gen_exception(ctx, POWERPC_EXCP_VPU);                       \
-            return;                                                     \
-        }                                                               \
-        rb = gen_avr_ptr(rB(ctx->opcode));                              \
-        rd = gen_avr_ptr(rD(ctx->opcode));                              \
-        gen_helper_##name (rd, rb);                                     \
-        tcg_temp_free_ptr(rb);                                          \
-        tcg_temp_free_ptr(rd);                                         \
-    }
-
-#define GEN_VXFORM_NOA_ENV(name, opc2, opc3)                            \
-static void glue(gen_, name)(DisasContext *ctx)                         \
-    {                                                                   \
-        TCGv_ptr rb, rd;                                                \
-                                                                        \
-        if (unlikely(!ctx->altivec_enabled)) {                          \
-            gen_exception(ctx, POWERPC_EXCP_VPU);                       \
-            return;                                                     \
-        }                                                               \
-        rb = gen_avr_ptr(rB(ctx->opcode));                              \
-        rd = gen_avr_ptr(rD(ctx->opcode));                              \
-        gen_helper_##name(cpu_env, rd, rb);                             \
-        tcg_temp_free_ptr(rb);                                          \
-        tcg_temp_free_ptr(rd);                                          \
-    }
-
-GEN_VXFORM_NOA(vupkhsb, 7, 8);
-GEN_VXFORM_NOA(vupkhsh, 7, 9);
-GEN_VXFORM_NOA(vupkhsw, 7, 25);
-GEN_VXFORM_NOA(vupklsb, 7, 10);
-GEN_VXFORM_NOA(vupklsh, 7, 11);
-GEN_VXFORM_NOA(vupklsw, 7, 27);
-GEN_VXFORM_NOA(vupkhpx, 7, 13);
-GEN_VXFORM_NOA(vupklpx, 7, 15);
-GEN_VXFORM_NOA_ENV(vrefp, 5, 4);
-GEN_VXFORM_NOA_ENV(vrsqrtefp, 5, 5);
-GEN_VXFORM_NOA_ENV(vexptefp, 5, 6);
-GEN_VXFORM_NOA_ENV(vlogefp, 5, 7);
-GEN_VXFORM_NOA_ENV(vrfim, 5, 11);
-GEN_VXFORM_NOA_ENV(vrfin, 5, 8);
-GEN_VXFORM_NOA_ENV(vrfip, 5, 10);
-GEN_VXFORM_NOA_ENV(vrfiz, 5, 9);
-
-#define GEN_VXFORM_SIMM(name, opc2, opc3)                               \
-static void glue(gen_, name)(DisasContext *ctx)                                 \
-    {                                                                   \
-        TCGv_ptr rd;                                                    \
-        TCGv_i32 simm;                                                  \
-        if (unlikely(!ctx->altivec_enabled)) {                          \
-            gen_exception(ctx, POWERPC_EXCP_VPU);                       \
-            return;                                                     \
-        }                                                               \
-        simm = tcg_const_i32(SIMM5(ctx->opcode));                       \
-        rd = gen_avr_ptr(rD(ctx->opcode));                              \
-        gen_helper_##name (rd, simm);                                   \
-        tcg_temp_free_i32(simm);                                        \
-        tcg_temp_free_ptr(rd);                                          \
-    }
-
-#define GEN_VXFORM_UIMM(name, opc2, opc3)                               \
-static void glue(gen_, name)(DisasContext *ctx)                                 \
-    {                                                                   \
-        TCGv_ptr rb, rd;                                                \
-        TCGv_i32 uimm;                                                  \
-        if (unlikely(!ctx->altivec_enabled)) {                          \
-            gen_exception(ctx, POWERPC_EXCP_VPU);                       \
-            return;                                                     \
-        }                                                               \
-        uimm = tcg_const_i32(UIMM5(ctx->opcode));                       \
-        rb = gen_avr_ptr(rB(ctx->opcode));                              \
-        rd = gen_avr_ptr(rD(ctx->opcode));                              \
-        gen_helper_##name (rd, rb, uimm);                               \
-        tcg_temp_free_i32(uimm);                                        \
-        tcg_temp_free_ptr(rb);                                          \
-        tcg_temp_free_ptr(rd);                                          \
-    }
-
-#define GEN_VXFORM_UIMM_ENV(name, opc2, opc3)                           \
-static void glue(gen_, name)(DisasContext *ctx)                         \
-    {                                                                   \
-        TCGv_ptr rb, rd;                                                \
-        TCGv_i32 uimm;                                                  \
-                                                                        \
-        if (unlikely(!ctx->altivec_enabled)) {                          \
-            gen_exception(ctx, POWERPC_EXCP_VPU);                       \
-            return;                                                     \
-        }                                                               \
-        uimm = tcg_const_i32(UIMM5(ctx->opcode));                       \
-        rb = gen_avr_ptr(rB(ctx->opcode));                              \
-        rd = gen_avr_ptr(rD(ctx->opcode));                              \
-        gen_helper_##name(cpu_env, rd, rb, uimm);                       \
-        tcg_temp_free_i32(uimm);                                        \
-        tcg_temp_free_ptr(rb);                                          \
-        tcg_temp_free_ptr(rd);                                          \
-    }
-
-GEN_VXFORM_UIMM(vspltb, 6, 8);
-GEN_VXFORM_UIMM(vsplth, 6, 9);
-GEN_VXFORM_UIMM(vspltw, 6, 10);
-GEN_VXFORM_UIMM_ENV(vcfux, 5, 12);
-GEN_VXFORM_UIMM_ENV(vcfsx, 5, 13);
-GEN_VXFORM_UIMM_ENV(vctuxs, 5, 14);
-GEN_VXFORM_UIMM_ENV(vctsxs, 5, 15);
-
-static void gen_vsldoi(DisasContext *ctx)
-{
-    TCGv_ptr ra, rb, rd;
-    TCGv_i32 sh;
-    if (unlikely(!ctx->altivec_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_VPU);
-        return;
-    }
-    ra = gen_avr_ptr(rA(ctx->opcode));
-    rb = gen_avr_ptr(rB(ctx->opcode));
-    rd = gen_avr_ptr(rD(ctx->opcode));
-    sh = tcg_const_i32(VSH(ctx->opcode));
-    gen_helper_vsldoi (rd, ra, rb, sh);
-    tcg_temp_free_ptr(ra);
-    tcg_temp_free_ptr(rb);
-    tcg_temp_free_ptr(rd);
-    tcg_temp_free_i32(sh);
-}
-
-#define GEN_VAFORM_PAIRED(name0, name1, opc2)                           \
-static void glue(gen_, name0##_##name1)(DisasContext *ctx)              \
-    {                                                                   \
-        TCGv_ptr ra, rb, rc, rd;                                        \
-        if (unlikely(!ctx->altivec_enabled)) {                          \
-            gen_exception(ctx, POWERPC_EXCP_VPU);                       \
-            return;                                                     \
-        }                                                               \
-        ra = gen_avr_ptr(rA(ctx->opcode));                              \
-        rb = gen_avr_ptr(rB(ctx->opcode));                              \
-        rc = gen_avr_ptr(rC(ctx->opcode));                              \
-        rd = gen_avr_ptr(rD(ctx->opcode));                              \
-        if (Rc(ctx->opcode)) {                                          \
-            gen_helper_##name1(cpu_env, rd, ra, rb, rc);                \
-        } else {                                                        \
-            gen_helper_##name0(cpu_env, rd, ra, rb, rc);                \
-        }                                                               \
-        tcg_temp_free_ptr(ra);                                          \
-        tcg_temp_free_ptr(rb);                                          \
-        tcg_temp_free_ptr(rc);                                          \
-        tcg_temp_free_ptr(rd);                                          \
-    }
-
-GEN_VAFORM_PAIRED(vmhaddshs, vmhraddshs, 16)
-
-static void gen_vmladduhm(DisasContext *ctx)
-{
-    TCGv_ptr ra, rb, rc, rd;
-    if (unlikely(!ctx->altivec_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_VPU);
-        return;
-    }
-    ra = gen_avr_ptr(rA(ctx->opcode));
-    rb = gen_avr_ptr(rB(ctx->opcode));
-    rc = gen_avr_ptr(rC(ctx->opcode));
-    rd = gen_avr_ptr(rD(ctx->opcode));
-    gen_helper_vmladduhm(rd, ra, rb, rc);
-    tcg_temp_free_ptr(ra);
-    tcg_temp_free_ptr(rb);
-    tcg_temp_free_ptr(rc);
-    tcg_temp_free_ptr(rd);
-}
-
-GEN_VAFORM_PAIRED(vmsumubm, vmsummbm, 18)
-GEN_VAFORM_PAIRED(vmsumuhm, vmsumuhs, 19)
-GEN_VAFORM_PAIRED(vmsumshm, vmsumshs, 20)
-GEN_VAFORM_PAIRED(vsel, vperm, 21)
-GEN_VAFORM_PAIRED(vmaddfp, vnmsubfp, 23)
-
-GEN_VXFORM_NOA(vclzb, 1, 28)
-GEN_VXFORM_NOA(vclzh, 1, 29)
-GEN_VXFORM_NOA(vclzw, 1, 30)
-GEN_VXFORM_NOA(vclzd, 1, 31)
-GEN_VXFORM_NOA(vpopcntb, 1, 28)
-GEN_VXFORM_NOA(vpopcnth, 1, 29)
-GEN_VXFORM_NOA(vpopcntw, 1, 30)
-GEN_VXFORM_NOA(vpopcntd, 1, 31)
-GEN_VXFORM_DUAL(vclzb, PPC_NONE, PPC2_ALTIVEC_207, \
-                vpopcntb, PPC_NONE, PPC2_ALTIVEC_207)
-GEN_VXFORM_DUAL(vclzh, PPC_NONE, PPC2_ALTIVEC_207, \
-                vpopcnth, PPC_NONE, PPC2_ALTIVEC_207)
-GEN_VXFORM_DUAL(vclzw, PPC_NONE, PPC2_ALTIVEC_207, \
-                vpopcntw, PPC_NONE, PPC2_ALTIVEC_207)
-GEN_VXFORM_DUAL(vclzd, PPC_NONE, PPC2_ALTIVEC_207, \
-                vpopcntd, PPC_NONE, PPC2_ALTIVEC_207)
-GEN_VXFORM(vbpermq, 6, 21);
-GEN_VXFORM_NOA(vgbbd, 6, 20);
-GEN_VXFORM(vpmsumb, 4, 16)
-GEN_VXFORM(vpmsumh, 4, 17)
-GEN_VXFORM(vpmsumw, 4, 18)
-GEN_VXFORM(vpmsumd, 4, 19)
-
-#define GEN_BCD(op)                                 \
-static void gen_##op(DisasContext *ctx)             \
-{                                                   \
-    TCGv_ptr ra, rb, rd;                            \
-    TCGv_i32 ps;                                    \
-                                                    \
-    if (unlikely(!ctx->altivec_enabled)) {          \
-        gen_exception(ctx, POWERPC_EXCP_VPU);       \
-        return;                                     \
-    }                                               \
-                                                    \
-    ra = gen_avr_ptr(rA(ctx->opcode));              \
-    rb = gen_avr_ptr(rB(ctx->opcode));              \
-    rd = gen_avr_ptr(rD(ctx->opcode));              \
-                                                    \
-    ps = tcg_const_i32((ctx->opcode & 0x200) != 0); \
-                                                    \
-    gen_helper_##op(cpu_crf[6], rd, ra, rb, ps);    \
-                                                    \
-    tcg_temp_free_ptr(ra);                          \
-    tcg_temp_free_ptr(rb);                          \
-    tcg_temp_free_ptr(rd);                          \
-    tcg_temp_free_i32(ps);                          \
-}
-
-GEN_BCD(bcdadd)
-GEN_BCD(bcdsub)
-
-GEN_VXFORM_DUAL(vsububm, PPC_ALTIVEC, PPC_NONE, \
-                bcdadd, PPC_NONE, PPC2_ALTIVEC_207)
-GEN_VXFORM_DUAL(vsububs, PPC_ALTIVEC, PPC_NONE, \
-                bcdadd, PPC_NONE, PPC2_ALTIVEC_207)
-GEN_VXFORM_DUAL(vsubuhm, PPC_ALTIVEC, PPC_NONE, \
-                bcdsub, PPC_NONE, PPC2_ALTIVEC_207)
-GEN_VXFORM_DUAL(vsubuhs, PPC_ALTIVEC, PPC_NONE, \
-                bcdsub, PPC_NONE, PPC2_ALTIVEC_207)
-
-static void gen_vsbox(DisasContext *ctx)
-{
-    TCGv_ptr ra, rd;
-    if (unlikely(!ctx->altivec_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_VPU);
-        return;
-    }
-    ra = gen_avr_ptr(rA(ctx->opcode));
-    rd = gen_avr_ptr(rD(ctx->opcode));
-    gen_helper_vsbox(rd, ra);
-    tcg_temp_free_ptr(ra);
-    tcg_temp_free_ptr(rd);
-}
-
-GEN_VXFORM(vcipher, 4, 20)
-GEN_VXFORM(vcipherlast, 4, 20)
-GEN_VXFORM(vncipher, 4, 21)
-GEN_VXFORM(vncipherlast, 4, 21)
-
-GEN_VXFORM_DUAL(vcipher, PPC_NONE, PPC2_ALTIVEC_207,
-                vcipherlast, PPC_NONE, PPC2_ALTIVEC_207)
-GEN_VXFORM_DUAL(vncipher, PPC_NONE, PPC2_ALTIVEC_207,
-                vncipherlast, PPC_NONE, PPC2_ALTIVEC_207)
-
-#define VSHASIGMA(op)                         \
-static void gen_##op(DisasContext *ctx)       \
-{                                             \
-    TCGv_ptr ra, rd;                          \
-    TCGv_i32 st_six;                          \
-    if (unlikely(!ctx->altivec_enabled)) {    \
-        gen_exception(ctx, POWERPC_EXCP_VPU); \
-        return;                               \
-    }                                         \
-    ra = gen_avr_ptr(rA(ctx->opcode));        \
-    rd = gen_avr_ptr(rD(ctx->opcode));        \
-    st_six = tcg_const_i32(rB(ctx->opcode));  \
-    gen_helper_##op(rd, ra, st_six);          \
-    tcg_temp_free_ptr(ra);                    \
-    tcg_temp_free_ptr(rd);                    \
-    tcg_temp_free_i32(st_six);                \
-}
-
-VSHASIGMA(vshasigmaw)
-VSHASIGMA(vshasigmad)
-
-GEN_VXFORM3(vpermxor, 22, 0xFF)
-GEN_VXFORM_DUAL(vsldoi, PPC_ALTIVEC, PPC_NONE,
-                vpermxor, PPC_NONE, PPC2_ALTIVEC_207)
-
 /***                           VSX extension                               ***/
 
 static inline TCGv_i64 cpu_vsrh(int n)
@@ -7878,266 +7074,7 @@ GEN_MAC_HANDLER(mullhwu, 0x08, 0x0C),
 
 #include "translate/fp-ops.c"
 
-#undef GEN_VR_LDX
-#undef GEN_VR_STX
-#undef GEN_VR_LVE
-#undef GEN_VR_STVE
-#define GEN_VR_LDX(name, opc2, opc3)                                          \
-GEN_HANDLER(name, 0x1F, opc2, opc3, 0x00000001, PPC_ALTIVEC)
-#define GEN_VR_STX(name, opc2, opc3)                                          \
-GEN_HANDLER(st##name, 0x1F, opc2, opc3, 0x00000001, PPC_ALTIVEC)
-#define GEN_VR_LVE(name, opc2, opc3)                                    \
-    GEN_HANDLER(lve##name, 0x1F, opc2, opc3, 0x00000001, PPC_ALTIVEC)
-#define GEN_VR_STVE(name, opc2, opc3)                                   \
-    GEN_HANDLER(stve##name, 0x1F, opc2, opc3, 0x00000001, PPC_ALTIVEC)
-GEN_VR_LDX(lvx, 0x07, 0x03),
-GEN_VR_LDX(lvxl, 0x07, 0x0B),
-GEN_VR_LVE(bx, 0x07, 0x00),
-GEN_VR_LVE(hx, 0x07, 0x01),
-GEN_VR_LVE(wx, 0x07, 0x02),
-GEN_VR_STX(svx, 0x07, 0x07),
-GEN_VR_STX(svxl, 0x07, 0x0F),
-GEN_VR_STVE(bx, 0x07, 0x04),
-GEN_VR_STVE(hx, 0x07, 0x05),
-GEN_VR_STVE(wx, 0x07, 0x06),
-
-#undef GEN_VX_LOGICAL
-#define GEN_VX_LOGICAL(name, tcg_op, opc2, opc3)                        \
-GEN_HANDLER(name, 0x04, opc2, opc3, 0x00000000, PPC_ALTIVEC)
-
-#undef GEN_VX_LOGICAL_207
-#define GEN_VX_LOGICAL_207(name, tcg_op, opc2, opc3) \
-GEN_HANDLER_E(name, 0x04, opc2, opc3, 0x00000000, PPC_NONE, PPC2_ALTIVEC_207)
-
-GEN_VX_LOGICAL(vand, tcg_gen_and_i64, 2, 16),
-GEN_VX_LOGICAL(vandc, tcg_gen_andc_i64, 2, 17),
-GEN_VX_LOGICAL(vor, tcg_gen_or_i64, 2, 18),
-GEN_VX_LOGICAL(vxor, tcg_gen_xor_i64, 2, 19),
-GEN_VX_LOGICAL(vnor, tcg_gen_nor_i64, 2, 20),
-GEN_VX_LOGICAL_207(veqv, tcg_gen_eqv_i64, 2, 26),
-GEN_VX_LOGICAL_207(vnand, tcg_gen_nand_i64, 2, 22),
-GEN_VX_LOGICAL_207(vorc, tcg_gen_orc_i64, 2, 21),
-
-#undef GEN_VXFORM
-#define GEN_VXFORM(name, opc2, opc3)                                    \
-GEN_HANDLER(name, 0x04, opc2, opc3, 0x00000000, PPC_ALTIVEC)
-
-#undef GEN_VXFORM_207
-#define GEN_VXFORM_207(name, opc2, opc3) \
-GEN_HANDLER_E(name, 0x04, opc2, opc3, 0x00000000, PPC_NONE, PPC2_ALTIVEC_207)
-
-#undef GEN_VXFORM_DUAL
-#define GEN_VXFORM_DUAL(name0, name1, opc2, opc3, type0, type1) \
-GEN_HANDLER_E(name0##_##name1, 0x4, opc2, opc3, 0x00000000, type0, type1)
-
-#undef GEN_VXRFORM_DUAL
-#define GEN_VXRFORM_DUAL(name0, name1, opc2, opc3, tp0, tp1) \
-GEN_HANDLER_E(name0##_##name1, 0x4, opc2, opc3, 0x00000000, tp0, tp1), \
-GEN_HANDLER_E(name0##_##name1, 0x4, opc2, (opc3 | 0x10), 0x00000000, tp0, tp1),
-
-GEN_VXFORM(vaddubm, 0, 0),
-GEN_VXFORM(vadduhm, 0, 1),
-GEN_VXFORM(vadduwm, 0, 2),
-GEN_VXFORM_207(vaddudm, 0, 3),
-GEN_VXFORM_DUAL(vsububm, bcdadd, 0, 16, PPC_ALTIVEC, PPC_NONE),
-GEN_VXFORM_DUAL(vsubuhm, bcdsub, 0, 17, PPC_ALTIVEC, PPC_NONE),
-GEN_VXFORM(vsubuwm, 0, 18),
-GEN_VXFORM_207(vsubudm, 0, 19),
-GEN_VXFORM(vmaxub, 1, 0),
-GEN_VXFORM(vmaxuh, 1, 1),
-GEN_VXFORM(vmaxuw, 1, 2),
-GEN_VXFORM_207(vmaxud, 1, 3),
-GEN_VXFORM(vmaxsb, 1, 4),
-GEN_VXFORM(vmaxsh, 1, 5),
-GEN_VXFORM(vmaxsw, 1, 6),
-GEN_VXFORM_207(vmaxsd, 1, 7),
-GEN_VXFORM(vminub, 1, 8),
-GEN_VXFORM(vminuh, 1, 9),
-GEN_VXFORM(vminuw, 1, 10),
-GEN_VXFORM_207(vminud, 1, 11),
-GEN_VXFORM(vminsb, 1, 12),
-GEN_VXFORM(vminsh, 1, 13),
-GEN_VXFORM(vminsw, 1, 14),
-GEN_VXFORM_207(vminsd, 1, 15),
-GEN_VXFORM(vavgub, 1, 16),
-GEN_VXFORM(vavguh, 1, 17),
-GEN_VXFORM(vavguw, 1, 18),
-GEN_VXFORM(vavgsb, 1, 20),
-GEN_VXFORM(vavgsh, 1, 21),
-GEN_VXFORM(vavgsw, 1, 22),
-GEN_VXFORM(vmrghb, 6, 0),
-GEN_VXFORM(vmrghh, 6, 1),
-GEN_VXFORM(vmrghw, 6, 2),
-GEN_VXFORM(vmrglb, 6, 4),
-GEN_VXFORM(vmrglh, 6, 5),
-GEN_VXFORM(vmrglw, 6, 6),
-GEN_VXFORM_207(vmrgew, 6, 30),
-GEN_VXFORM_207(vmrgow, 6, 26),
-GEN_VXFORM(vmuloub, 4, 0),
-GEN_VXFORM(vmulouh, 4, 1),
-GEN_VXFORM_DUAL(vmulouw, vmuluwm, 4, 2, PPC_ALTIVEC, PPC_NONE),
-GEN_VXFORM(vmulosb, 4, 4),
-GEN_VXFORM(vmulosh, 4, 5),
-GEN_VXFORM_207(vmulosw, 4, 6),
-GEN_VXFORM(vmuleub, 4, 8),
-GEN_VXFORM(vmuleuh, 4, 9),
-GEN_VXFORM_207(vmuleuw, 4, 10),
-GEN_VXFORM(vmulesb, 4, 12),
-GEN_VXFORM(vmulesh, 4, 13),
-GEN_VXFORM_207(vmulesw, 4, 14),
-GEN_VXFORM(vslb, 2, 4),
-GEN_VXFORM(vslh, 2, 5),
-GEN_VXFORM(vslw, 2, 6),
-GEN_VXFORM_207(vsld, 2, 23),
-GEN_VXFORM(vsrb, 2, 8),
-GEN_VXFORM(vsrh, 2, 9),
-GEN_VXFORM(vsrw, 2, 10),
-GEN_VXFORM_207(vsrd, 2, 27),
-GEN_VXFORM(vsrab, 2, 12),
-GEN_VXFORM(vsrah, 2, 13),
-GEN_VXFORM(vsraw, 2, 14),
-GEN_VXFORM_207(vsrad, 2, 15),
-GEN_VXFORM(vslo, 6, 16),
-GEN_VXFORM(vsro, 6, 17),
-GEN_VXFORM(vaddcuw, 0, 6),
-GEN_VXFORM(vsubcuw, 0, 22),
-GEN_VXFORM(vaddubs, 0, 8),
-GEN_VXFORM(vadduhs, 0, 9),
-GEN_VXFORM(vadduws, 0, 10),
-GEN_VXFORM(vaddsbs, 0, 12),
-GEN_VXFORM(vaddshs, 0, 13),
-GEN_VXFORM(vaddsws, 0, 14),
-GEN_VXFORM_DUAL(vsububs, bcdadd, 0, 24, PPC_ALTIVEC, PPC_NONE),
-GEN_VXFORM_DUAL(vsubuhs, bcdsub, 0, 25, PPC_ALTIVEC, PPC_NONE),
-GEN_VXFORM(vsubuws, 0, 26),
-GEN_VXFORM(vsubsbs, 0, 28),
-GEN_VXFORM(vsubshs, 0, 29),
-GEN_VXFORM(vsubsws, 0, 30),
-GEN_VXFORM_207(vadduqm, 0, 4),
-GEN_VXFORM_207(vaddcuq, 0, 5),
-GEN_VXFORM_DUAL(vaddeuqm, vaddecuq, 30, 0xFF, PPC_NONE, PPC2_ALTIVEC_207),
-GEN_VXFORM_207(vsubuqm, 0, 20),
-GEN_VXFORM_207(vsubcuq, 0, 21),
-GEN_VXFORM_DUAL(vsubeuqm, vsubecuq, 31, 0xFF, PPC_NONE, PPC2_ALTIVEC_207),
-GEN_VXFORM(vrlb, 2, 0),
-GEN_VXFORM(vrlh, 2, 1),
-GEN_VXFORM(vrlw, 2, 2),
-GEN_VXFORM_207(vrld, 2, 3),
-GEN_VXFORM(vsl, 2, 7),
-GEN_VXFORM(vsr, 2, 11),
-GEN_VXFORM(vpkuhum, 7, 0),
-GEN_VXFORM(vpkuwum, 7, 1),
-GEN_VXFORM_207(vpkudum, 7, 17),
-GEN_VXFORM(vpkuhus, 7, 2),
-GEN_VXFORM(vpkuwus, 7, 3),
-GEN_VXFORM_207(vpkudus, 7, 19),
-GEN_VXFORM(vpkshus, 7, 4),
-GEN_VXFORM(vpkswus, 7, 5),
-GEN_VXFORM_207(vpksdus, 7, 21),
-GEN_VXFORM(vpkshss, 7, 6),
-GEN_VXFORM(vpkswss, 7, 7),
-GEN_VXFORM_207(vpksdss, 7, 23),
-GEN_VXFORM(vpkpx, 7, 12),
-GEN_VXFORM(vsum4ubs, 4, 24),
-GEN_VXFORM(vsum4sbs, 4, 28),
-GEN_VXFORM(vsum4shs, 4, 25),
-GEN_VXFORM(vsum2sws, 4, 26),
-GEN_VXFORM(vsumsws, 4, 30),
-GEN_VXFORM(vaddfp, 5, 0),
-GEN_VXFORM(vsubfp, 5, 1),
-GEN_VXFORM(vmaxfp, 5, 16),
-GEN_VXFORM(vminfp, 5, 17),
-
-#undef GEN_VXRFORM1
-#undef GEN_VXRFORM
-#define GEN_VXRFORM1(opname, name, str, opc2, opc3)                     \
-    GEN_HANDLER2(name, str, 0x4, opc2, opc3, 0x00000000, PPC_ALTIVEC),
-#define GEN_VXRFORM(name, opc2, opc3)                                \
-    GEN_VXRFORM1(name, name, #name, opc2, opc3)                      \
-    GEN_VXRFORM1(name##_dot, name##_, #name ".", opc2, (opc3 | (0x1 << 4)))
-GEN_VXRFORM(vcmpequb, 3, 0)
-GEN_VXRFORM(vcmpequh, 3, 1)
-GEN_VXRFORM(vcmpequw, 3, 2)
-GEN_VXRFORM(vcmpgtsb, 3, 12)
-GEN_VXRFORM(vcmpgtsh, 3, 13)
-GEN_VXRFORM(vcmpgtsw, 3, 14)
-GEN_VXRFORM(vcmpgtub, 3, 8)
-GEN_VXRFORM(vcmpgtuh, 3, 9)
-GEN_VXRFORM(vcmpgtuw, 3, 10)
-GEN_VXRFORM_DUAL(vcmpeqfp, vcmpequd, 3, 3, PPC_ALTIVEC, PPC_NONE)
-GEN_VXRFORM(vcmpgefp, 3, 7)
-GEN_VXRFORM_DUAL(vcmpgtfp, vcmpgtud, 3, 11, PPC_ALTIVEC, PPC_NONE)
-GEN_VXRFORM_DUAL(vcmpbfp, vcmpgtsd, 3, 15, PPC_ALTIVEC, PPC_NONE)
-
-#undef GEN_VXFORM_SIMM
-#define GEN_VXFORM_SIMM(name, opc2, opc3)                               \
-    GEN_HANDLER(name, 0x04, opc2, opc3, 0x00000000, PPC_ALTIVEC)
-GEN_VXFORM_SIMM(vspltisb, 6, 12),
-GEN_VXFORM_SIMM(vspltish, 6, 13),
-GEN_VXFORM_SIMM(vspltisw, 6, 14),
-
-#undef GEN_VXFORM_NOA
-#define GEN_VXFORM_NOA(name, opc2, opc3)                                \
-    GEN_HANDLER(name, 0x04, opc2, opc3, 0x001f0000, PPC_ALTIVEC)
-GEN_VXFORM_NOA(vupkhsb, 7, 8),
-GEN_VXFORM_NOA(vupkhsh, 7, 9),
-GEN_VXFORM_207(vupkhsw, 7, 25),
-GEN_VXFORM_NOA(vupklsb, 7, 10),
-GEN_VXFORM_NOA(vupklsh, 7, 11),
-GEN_VXFORM_207(vupklsw, 7, 27),
-GEN_VXFORM_NOA(vupkhpx, 7, 13),
-GEN_VXFORM_NOA(vupklpx, 7, 15),
-GEN_VXFORM_NOA(vrefp, 5, 4),
-GEN_VXFORM_NOA(vrsqrtefp, 5, 5),
-GEN_VXFORM_NOA(vexptefp, 5, 6),
-GEN_VXFORM_NOA(vlogefp, 5, 7),
-GEN_VXFORM_NOA(vrfim, 5, 11),
-GEN_VXFORM_NOA(vrfin, 5, 8),
-GEN_VXFORM_NOA(vrfip, 5, 10),
-GEN_VXFORM_NOA(vrfiz, 5, 9),
-
-#undef GEN_VXFORM_UIMM
-#define GEN_VXFORM_UIMM(name, opc2, opc3)                               \
-    GEN_HANDLER(name, 0x04, opc2, opc3, 0x00000000, PPC_ALTIVEC)
-GEN_VXFORM_UIMM(vspltb, 6, 8),
-GEN_VXFORM_UIMM(vsplth, 6, 9),
-GEN_VXFORM_UIMM(vspltw, 6, 10),
-GEN_VXFORM_UIMM(vcfux, 5, 12),
-GEN_VXFORM_UIMM(vcfsx, 5, 13),
-GEN_VXFORM_UIMM(vctuxs, 5, 14),
-GEN_VXFORM_UIMM(vctsxs, 5, 15),
-
-#undef GEN_VAFORM_PAIRED
-#define GEN_VAFORM_PAIRED(name0, name1, opc2)                           \
-    GEN_HANDLER(name0##_##name1, 0x04, opc2, 0xFF, 0x00000000, PPC_ALTIVEC)
-GEN_VAFORM_PAIRED(vmhaddshs, vmhraddshs, 16),
-GEN_VAFORM_PAIRED(vmsumubm, vmsummbm, 18),
-GEN_VAFORM_PAIRED(vmsumuhm, vmsumuhs, 19),
-GEN_VAFORM_PAIRED(vmsumshm, vmsumshs, 20),
-GEN_VAFORM_PAIRED(vsel, vperm, 21),
-GEN_VAFORM_PAIRED(vmaddfp, vnmsubfp, 23),
-
-GEN_VXFORM_DUAL(vclzb, vpopcntb, 1, 28, PPC_NONE, PPC2_ALTIVEC_207),
-GEN_VXFORM_DUAL(vclzh, vpopcnth, 1, 29, PPC_NONE, PPC2_ALTIVEC_207),
-GEN_VXFORM_DUAL(vclzw, vpopcntw, 1, 30, PPC_NONE, PPC2_ALTIVEC_207),
-GEN_VXFORM_DUAL(vclzd, vpopcntd, 1, 31, PPC_NONE, PPC2_ALTIVEC_207),
-
-GEN_VXFORM_207(vbpermq, 6, 21),
-GEN_VXFORM_207(vgbbd, 6, 20),
-GEN_VXFORM_207(vpmsumb, 4, 16),
-GEN_VXFORM_207(vpmsumh, 4, 17),
-GEN_VXFORM_207(vpmsumw, 4, 18),
-GEN_VXFORM_207(vpmsumd, 4, 19),
-
-GEN_VXFORM_207(vsbox, 4, 23),
-
-GEN_VXFORM_DUAL(vcipher, vcipherlast, 4, 20, PPC_NONE, PPC2_ALTIVEC_207),
-GEN_VXFORM_DUAL(vncipher, vncipherlast, 4, 21, PPC_NONE, PPC2_ALTIVEC_207),
-
-GEN_VXFORM_207(vshasigmaw, 1, 26),
-GEN_VXFORM_207(vshasigmad, 1, 27),
-
-GEN_VXFORM_DUAL(vsldoi, vpermxor, 22, 0xFF, PPC_ALTIVEC, PPC_NONE),
+#include "translate/vmx-ops.c"
 
 GEN_HANDLER_E(lxsdx, 0x1F, 0x0C, 0x12, 0, PPC_NONE, PPC2_VSX),
 GEN_HANDLER_E(lxsiwax, 0x1F, 0x0C, 0x02, 0, PPC_NONE, PPC2_VSX207),
diff --git a/target-ppc/translate/vmx-impl.c b/target-ppc/translate/vmx-impl.c
new file mode 100644
index 0000000..110e19c
--- /dev/null
+++ b/target-ppc/translate/vmx-impl.c
@@ -0,0 +1,829 @@
+/*
+ * translate/vmx-impl.c
+ *
+ * Altivec/VMX translation
+ */
+
+/***                      Altivec vector extension                         ***/
+/* Altivec registers moves */
+
+static inline TCGv_ptr gen_avr_ptr(int reg)
+{
+    TCGv_ptr r = tcg_temp_new_ptr();
+    tcg_gen_addi_ptr(r, cpu_env, offsetof(CPUPPCState, avr[reg]));
+    return r;
+}
+
+#define GEN_VR_LDX(name, opc2, opc3)                                          \
+static void glue(gen_, name)(DisasContext *ctx)                                       \
+{                                                                             \
+    TCGv EA;                                                                  \
+    if (unlikely(!ctx->altivec_enabled)) {                                    \
+        gen_exception(ctx, POWERPC_EXCP_VPU);                                 \
+        return;                                                               \
+    }                                                                         \
+    gen_set_access_type(ctx, ACCESS_INT);                                     \
+    EA = tcg_temp_new();                                                      \
+    gen_addr_reg_index(ctx, EA);                                              \
+    tcg_gen_andi_tl(EA, EA, ~0xf);                                            \
+    /* We only need to swap high and low halves. gen_qemu_ld64 does necessary \
+       64-bit byteswap already. */                                            \
+    if (ctx->le_mode) {                                                       \
+        gen_qemu_ld64(ctx, cpu_avrl[rD(ctx->opcode)], EA);                    \
+        tcg_gen_addi_tl(EA, EA, 8);                                           \
+        gen_qemu_ld64(ctx, cpu_avrh[rD(ctx->opcode)], EA);                    \
+    } else {                                                                  \
+        gen_qemu_ld64(ctx, cpu_avrh[rD(ctx->opcode)], EA);                    \
+        tcg_gen_addi_tl(EA, EA, 8);                                           \
+        gen_qemu_ld64(ctx, cpu_avrl[rD(ctx->opcode)], EA);                    \
+    }                                                                         \
+    tcg_temp_free(EA);                                                        \
+}
+
+#define GEN_VR_STX(name, opc2, opc3)                                          \
+static void gen_st##name(DisasContext *ctx)                                   \
+{                                                                             \
+    TCGv EA;                                                                  \
+    if (unlikely(!ctx->altivec_enabled)) {                                    \
+        gen_exception(ctx, POWERPC_EXCP_VPU);                                 \
+        return;                                                               \
+    }                                                                         \
+    gen_set_access_type(ctx, ACCESS_INT);                                     \
+    EA = tcg_temp_new();                                                      \
+    gen_addr_reg_index(ctx, EA);                                              \
+    tcg_gen_andi_tl(EA, EA, ~0xf);                                            \
+    /* We only need to swap high and low halves. gen_qemu_st64 does necessary \
+       64-bit byteswap already. */                                            \
+    if (ctx->le_mode) {                                                       \
+        gen_qemu_st64(ctx, cpu_avrl[rD(ctx->opcode)], EA);                    \
+        tcg_gen_addi_tl(EA, EA, 8);                                           \
+        gen_qemu_st64(ctx, cpu_avrh[rD(ctx->opcode)], EA);                    \
+    } else {                                                                  \
+        gen_qemu_st64(ctx, cpu_avrh[rD(ctx->opcode)], EA);                    \
+        tcg_gen_addi_tl(EA, EA, 8);                                           \
+        gen_qemu_st64(ctx, cpu_avrl[rD(ctx->opcode)], EA);                    \
+    }                                                                         \
+    tcg_temp_free(EA);                                                        \
+}
+
+#define GEN_VR_LVE(name, opc2, opc3, size)                              \
+static void gen_lve##name(DisasContext *ctx)                            \
+    {                                                                   \
+        TCGv EA;                                                        \
+        TCGv_ptr rs;                                                    \
+        if (unlikely(!ctx->altivec_enabled)) {                          \
+            gen_exception(ctx, POWERPC_EXCP_VPU);                       \
+            return;                                                     \
+        }                                                               \
+        gen_set_access_type(ctx, ACCESS_INT);                           \
+        EA = tcg_temp_new();                                            \
+        gen_addr_reg_index(ctx, EA);                                    \
+        if (size > 1) {                                                 \
+            tcg_gen_andi_tl(EA, EA, ~(size - 1));                       \
+        }                                                               \
+        rs = gen_avr_ptr(rS(ctx->opcode));                              \
+        gen_helper_lve##name(cpu_env, rs, EA);                          \
+        tcg_temp_free(EA);                                              \
+        tcg_temp_free_ptr(rs);                                          \
+    }
+
+#define GEN_VR_STVE(name, opc2, opc3, size)                             \
+static void gen_stve##name(DisasContext *ctx)                           \
+    {                                                                   \
+        TCGv EA;                                                        \
+        TCGv_ptr rs;                                                    \
+        if (unlikely(!ctx->altivec_enabled)) {                          \
+            gen_exception(ctx, POWERPC_EXCP_VPU);                       \
+            return;                                                     \
+        }                                                               \
+        gen_set_access_type(ctx, ACCESS_INT);                           \
+        EA = tcg_temp_new();                                            \
+        gen_addr_reg_index(ctx, EA);                                    \
+        if (size > 1) {                                                 \
+            tcg_gen_andi_tl(EA, EA, ~(size - 1));                       \
+        }                                                               \
+        rs = gen_avr_ptr(rS(ctx->opcode));                              \
+        gen_helper_stve##name(cpu_env, rs, EA);                         \
+        tcg_temp_free(EA);                                              \
+        tcg_temp_free_ptr(rs);                                          \
+    }
+
+GEN_VR_LDX(lvx, 0x07, 0x03);
+/* As we don't emulate the cache, lvxl is stricly equivalent to lvx */
+GEN_VR_LDX(lvxl, 0x07, 0x0B);
+
+GEN_VR_LVE(bx, 0x07, 0x00, 1);
+GEN_VR_LVE(hx, 0x07, 0x01, 2);
+GEN_VR_LVE(wx, 0x07, 0x02, 4);
+
+GEN_VR_STX(svx, 0x07, 0x07);
+/* As we don't emulate the cache, stvxl is stricly equivalent to stvx */
+GEN_VR_STX(svxl, 0x07, 0x0F);
+
+GEN_VR_STVE(bx, 0x07, 0x04, 1);
+GEN_VR_STVE(hx, 0x07, 0x05, 2);
+GEN_VR_STVE(wx, 0x07, 0x06, 4);
+
+static void gen_lvsl(DisasContext *ctx)
+{
+    TCGv_ptr rd;
+    TCGv EA;
+    if (unlikely(!ctx->altivec_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_VPU);
+        return;
+    }
+    EA = tcg_temp_new();
+    gen_addr_reg_index(ctx, EA);
+    rd = gen_avr_ptr(rD(ctx->opcode));
+    gen_helper_lvsl(rd, EA);
+    tcg_temp_free(EA);
+    tcg_temp_free_ptr(rd);
+}
+
+static void gen_lvsr(DisasContext *ctx)
+{
+    TCGv_ptr rd;
+    TCGv EA;
+    if (unlikely(!ctx->altivec_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_VPU);
+        return;
+    }
+    EA = tcg_temp_new();
+    gen_addr_reg_index(ctx, EA);
+    rd = gen_avr_ptr(rD(ctx->opcode));
+    gen_helper_lvsr(rd, EA);
+    tcg_temp_free(EA);
+    tcg_temp_free_ptr(rd);
+}
+
+static void gen_mfvscr(DisasContext *ctx)
+{
+    TCGv_i32 t;
+    if (unlikely(!ctx->altivec_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_VPU);
+        return;
+    }
+    tcg_gen_movi_i64(cpu_avrh[rD(ctx->opcode)], 0);
+    t = tcg_temp_new_i32();
+    tcg_gen_ld_i32(t, cpu_env, offsetof(CPUPPCState, vscr));
+    tcg_gen_extu_i32_i64(cpu_avrl[rD(ctx->opcode)], t);
+    tcg_temp_free_i32(t);
+}
+
+static void gen_mtvscr(DisasContext *ctx)
+{
+    TCGv_ptr p;
+    if (unlikely(!ctx->altivec_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_VPU);
+        return;
+    }
+    p = gen_avr_ptr(rB(ctx->opcode));
+    gen_helper_mtvscr(cpu_env, p);
+    tcg_temp_free_ptr(p);
+}
+
+/* Logical operations */
+#define GEN_VX_LOGICAL(name, tcg_op, opc2, opc3)                        \
+static void glue(gen_, name)(DisasContext *ctx)                                 \
+{                                                                       \
+    if (unlikely(!ctx->altivec_enabled)) {                              \
+        gen_exception(ctx, POWERPC_EXCP_VPU);                           \
+        return;                                                         \
+    }                                                                   \
+    tcg_op(cpu_avrh[rD(ctx->opcode)], cpu_avrh[rA(ctx->opcode)], cpu_avrh[rB(ctx->opcode)]); \
+    tcg_op(cpu_avrl[rD(ctx->opcode)], cpu_avrl[rA(ctx->opcode)], cpu_avrl[rB(ctx->opcode)]); \
+}
+
+GEN_VX_LOGICAL(vand, tcg_gen_and_i64, 2, 16);
+GEN_VX_LOGICAL(vandc, tcg_gen_andc_i64, 2, 17);
+GEN_VX_LOGICAL(vor, tcg_gen_or_i64, 2, 18);
+GEN_VX_LOGICAL(vxor, tcg_gen_xor_i64, 2, 19);
+GEN_VX_LOGICAL(vnor, tcg_gen_nor_i64, 2, 20);
+GEN_VX_LOGICAL(veqv, tcg_gen_eqv_i64, 2, 26);
+GEN_VX_LOGICAL(vnand, tcg_gen_nand_i64, 2, 22);
+GEN_VX_LOGICAL(vorc, tcg_gen_orc_i64, 2, 21);
+
+#define GEN_VXFORM(name, opc2, opc3)                                    \
+static void glue(gen_, name)(DisasContext *ctx)                                 \
+{                                                                       \
+    TCGv_ptr ra, rb, rd;                                                \
+    if (unlikely(!ctx->altivec_enabled)) {                              \
+        gen_exception(ctx, POWERPC_EXCP_VPU);                           \
+        return;                                                         \
+    }                                                                   \
+    ra = gen_avr_ptr(rA(ctx->opcode));                                  \
+    rb = gen_avr_ptr(rB(ctx->opcode));                                  \
+    rd = gen_avr_ptr(rD(ctx->opcode));                                  \
+    gen_helper_##name (rd, ra, rb);                                     \
+    tcg_temp_free_ptr(ra);                                              \
+    tcg_temp_free_ptr(rb);                                              \
+    tcg_temp_free_ptr(rd);                                              \
+}
+
+#define GEN_VXFORM_ENV(name, opc2, opc3)                                \
+static void glue(gen_, name)(DisasContext *ctx)                         \
+{                                                                       \
+    TCGv_ptr ra, rb, rd;                                                \
+    if (unlikely(!ctx->altivec_enabled)) {                              \
+        gen_exception(ctx, POWERPC_EXCP_VPU);                           \
+        return;                                                         \
+    }                                                                   \
+    ra = gen_avr_ptr(rA(ctx->opcode));                                  \
+    rb = gen_avr_ptr(rB(ctx->opcode));                                  \
+    rd = gen_avr_ptr(rD(ctx->opcode));                                  \
+    gen_helper_##name(cpu_env, rd, ra, rb);                             \
+    tcg_temp_free_ptr(ra);                                              \
+    tcg_temp_free_ptr(rb);                                              \
+    tcg_temp_free_ptr(rd);                                              \
+}
+
+#define GEN_VXFORM3(name, opc2, opc3)                                   \
+static void glue(gen_, name)(DisasContext *ctx)                         \
+{                                                                       \
+    TCGv_ptr ra, rb, rc, rd;                                            \
+    if (unlikely(!ctx->altivec_enabled)) {                              \
+        gen_exception(ctx, POWERPC_EXCP_VPU);                           \
+        return;                                                         \
+    }                                                                   \
+    ra = gen_avr_ptr(rA(ctx->opcode));                                  \
+    rb = gen_avr_ptr(rB(ctx->opcode));                                  \
+    rc = gen_avr_ptr(rC(ctx->opcode));                                  \
+    rd = gen_avr_ptr(rD(ctx->opcode));                                  \
+    gen_helper_##name(rd, ra, rb, rc);                                  \
+    tcg_temp_free_ptr(ra);                                              \
+    tcg_temp_free_ptr(rb);                                              \
+    tcg_temp_free_ptr(rc);                                              \
+    tcg_temp_free_ptr(rd);                                              \
+}
+
+/*
+ * Support for Altivec instruction pairs that use bit 31 (Rc) as
+ * an opcode bit.  In general, these pairs come from different
+ * versions of the ISA, so we must also support a pair of flags for
+ * each instruction.
+ */
+#define GEN_VXFORM_DUAL(name0, flg0, flg2_0, name1, flg1, flg2_1)          \
+static void glue(gen_, name0##_##name1)(DisasContext *ctx)             \
+{                                                                      \
+    if ((Rc(ctx->opcode) == 0) &&                                      \
+        ((ctx->insns_flags & flg0) || (ctx->insns_flags2 & flg2_0))) { \
+        gen_##name0(ctx);                                              \
+    } else if ((Rc(ctx->opcode) == 1) &&                               \
+        ((ctx->insns_flags & flg1) || (ctx->insns_flags2 & flg2_1))) { \
+        gen_##name1(ctx);                                              \
+    } else {                                                           \
+        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);            \
+    }                                                                  \
+}
+
+GEN_VXFORM(vaddubm, 0, 0);
+GEN_VXFORM(vadduhm, 0, 1);
+GEN_VXFORM(vadduwm, 0, 2);
+GEN_VXFORM(vaddudm, 0, 3);
+GEN_VXFORM(vsububm, 0, 16);
+GEN_VXFORM(vsubuhm, 0, 17);
+GEN_VXFORM(vsubuwm, 0, 18);
+GEN_VXFORM(vsubudm, 0, 19);
+GEN_VXFORM(vmaxub, 1, 0);
+GEN_VXFORM(vmaxuh, 1, 1);
+GEN_VXFORM(vmaxuw, 1, 2);
+GEN_VXFORM(vmaxud, 1, 3);
+GEN_VXFORM(vmaxsb, 1, 4);
+GEN_VXFORM(vmaxsh, 1, 5);
+GEN_VXFORM(vmaxsw, 1, 6);
+GEN_VXFORM(vmaxsd, 1, 7);
+GEN_VXFORM(vminub, 1, 8);
+GEN_VXFORM(vminuh, 1, 9);
+GEN_VXFORM(vminuw, 1, 10);
+GEN_VXFORM(vminud, 1, 11);
+GEN_VXFORM(vminsb, 1, 12);
+GEN_VXFORM(vminsh, 1, 13);
+GEN_VXFORM(vminsw, 1, 14);
+GEN_VXFORM(vminsd, 1, 15);
+GEN_VXFORM(vavgub, 1, 16);
+GEN_VXFORM(vavguh, 1, 17);
+GEN_VXFORM(vavguw, 1, 18);
+GEN_VXFORM(vavgsb, 1, 20);
+GEN_VXFORM(vavgsh, 1, 21);
+GEN_VXFORM(vavgsw, 1, 22);
+GEN_VXFORM(vmrghb, 6, 0);
+GEN_VXFORM(vmrghh, 6, 1);
+GEN_VXFORM(vmrghw, 6, 2);
+GEN_VXFORM(vmrglb, 6, 4);
+GEN_VXFORM(vmrglh, 6, 5);
+GEN_VXFORM(vmrglw, 6, 6);
+
+static void gen_vmrgew(DisasContext *ctx)
+{
+    TCGv_i64 tmp;
+    int VT, VA, VB;
+    if (unlikely(!ctx->altivec_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_VPU);
+        return;
+    }
+    VT = rD(ctx->opcode);
+    VA = rA(ctx->opcode);
+    VB = rB(ctx->opcode);
+    tmp = tcg_temp_new_i64();
+    tcg_gen_shri_i64(tmp, cpu_avrh[VB], 32);
+    tcg_gen_deposit_i64(cpu_avrh[VT], cpu_avrh[VA], tmp, 0, 32);
+    tcg_gen_shri_i64(tmp, cpu_avrl[VB], 32);
+    tcg_gen_deposit_i64(cpu_avrl[VT], cpu_avrl[VA], tmp, 0, 32);
+    tcg_temp_free_i64(tmp);
+}
+
+static void gen_vmrgow(DisasContext *ctx)
+{
+    int VT, VA, VB;
+    if (unlikely(!ctx->altivec_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_VPU);
+        return;
+    }
+    VT = rD(ctx->opcode);
+    VA = rA(ctx->opcode);
+    VB = rB(ctx->opcode);
+
+    tcg_gen_deposit_i64(cpu_avrh[VT], cpu_avrh[VB], cpu_avrh[VA], 32, 32);
+    tcg_gen_deposit_i64(cpu_avrl[VT], cpu_avrl[VB], cpu_avrl[VA], 32, 32);
+}
+
+GEN_VXFORM(vmuloub, 4, 0);
+GEN_VXFORM(vmulouh, 4, 1);
+GEN_VXFORM(vmulouw, 4, 2);
+GEN_VXFORM(vmuluwm, 4, 2);
+GEN_VXFORM_DUAL(vmulouw, PPC_ALTIVEC, PPC_NONE,
+                vmuluwm, PPC_NONE, PPC2_ALTIVEC_207)
+GEN_VXFORM(vmulosb, 4, 4);
+GEN_VXFORM(vmulosh, 4, 5);
+GEN_VXFORM(vmulosw, 4, 6);
+GEN_VXFORM(vmuleub, 4, 8);
+GEN_VXFORM(vmuleuh, 4, 9);
+GEN_VXFORM(vmuleuw, 4, 10);
+GEN_VXFORM(vmulesb, 4, 12);
+GEN_VXFORM(vmulesh, 4, 13);
+GEN_VXFORM(vmulesw, 4, 14);
+GEN_VXFORM(vslb, 2, 4);
+GEN_VXFORM(vslh, 2, 5);
+GEN_VXFORM(vslw, 2, 6);
+GEN_VXFORM(vsld, 2, 23);
+GEN_VXFORM(vsrb, 2, 8);
+GEN_VXFORM(vsrh, 2, 9);
+GEN_VXFORM(vsrw, 2, 10);
+GEN_VXFORM(vsrd, 2, 27);
+GEN_VXFORM(vsrab, 2, 12);
+GEN_VXFORM(vsrah, 2, 13);
+GEN_VXFORM(vsraw, 2, 14);
+GEN_VXFORM(vsrad, 2, 15);
+GEN_VXFORM(vslo, 6, 16);
+GEN_VXFORM(vsro, 6, 17);
+GEN_VXFORM(vaddcuw, 0, 6);
+GEN_VXFORM(vsubcuw, 0, 22);
+GEN_VXFORM_ENV(vaddubs, 0, 8);
+GEN_VXFORM_ENV(vadduhs, 0, 9);
+GEN_VXFORM_ENV(vadduws, 0, 10);
+GEN_VXFORM_ENV(vaddsbs, 0, 12);
+GEN_VXFORM_ENV(vaddshs, 0, 13);
+GEN_VXFORM_ENV(vaddsws, 0, 14);
+GEN_VXFORM_ENV(vsububs, 0, 24);
+GEN_VXFORM_ENV(vsubuhs, 0, 25);
+GEN_VXFORM_ENV(vsubuws, 0, 26);
+GEN_VXFORM_ENV(vsubsbs, 0, 28);
+GEN_VXFORM_ENV(vsubshs, 0, 29);
+GEN_VXFORM_ENV(vsubsws, 0, 30);
+GEN_VXFORM(vadduqm, 0, 4);
+GEN_VXFORM(vaddcuq, 0, 5);
+GEN_VXFORM3(vaddeuqm, 30, 0);
+GEN_VXFORM3(vaddecuq, 30, 0);
+GEN_VXFORM_DUAL(vaddeuqm, PPC_NONE, PPC2_ALTIVEC_207, \
+            vaddecuq, PPC_NONE, PPC2_ALTIVEC_207)
+GEN_VXFORM(vsubuqm, 0, 20);
+GEN_VXFORM(vsubcuq, 0, 21);
+GEN_VXFORM3(vsubeuqm, 31, 0);
+GEN_VXFORM3(vsubecuq, 31, 0);
+GEN_VXFORM_DUAL(vsubeuqm, PPC_NONE, PPC2_ALTIVEC_207, \
+            vsubecuq, PPC_NONE, PPC2_ALTIVEC_207)
+GEN_VXFORM(vrlb, 2, 0);
+GEN_VXFORM(vrlh, 2, 1);
+GEN_VXFORM(vrlw, 2, 2);
+GEN_VXFORM(vrld, 2, 3);
+GEN_VXFORM(vsl, 2, 7);
+GEN_VXFORM(vsr, 2, 11);
+GEN_VXFORM_ENV(vpkuhum, 7, 0);
+GEN_VXFORM_ENV(vpkuwum, 7, 1);
+GEN_VXFORM_ENV(vpkudum, 7, 17);
+GEN_VXFORM_ENV(vpkuhus, 7, 2);
+GEN_VXFORM_ENV(vpkuwus, 7, 3);
+GEN_VXFORM_ENV(vpkudus, 7, 19);
+GEN_VXFORM_ENV(vpkshus, 7, 4);
+GEN_VXFORM_ENV(vpkswus, 7, 5);
+GEN_VXFORM_ENV(vpksdus, 7, 21);
+GEN_VXFORM_ENV(vpkshss, 7, 6);
+GEN_VXFORM_ENV(vpkswss, 7, 7);
+GEN_VXFORM_ENV(vpksdss, 7, 23);
+GEN_VXFORM(vpkpx, 7, 12);
+GEN_VXFORM_ENV(vsum4ubs, 4, 24);
+GEN_VXFORM_ENV(vsum4sbs, 4, 28);
+GEN_VXFORM_ENV(vsum4shs, 4, 25);
+GEN_VXFORM_ENV(vsum2sws, 4, 26);
+GEN_VXFORM_ENV(vsumsws, 4, 30);
+GEN_VXFORM_ENV(vaddfp, 5, 0);
+GEN_VXFORM_ENV(vsubfp, 5, 1);
+GEN_VXFORM_ENV(vmaxfp, 5, 16);
+GEN_VXFORM_ENV(vminfp, 5, 17);
+
+#define GEN_VXRFORM1(opname, name, str, opc2, opc3)                     \
+static void glue(gen_, name)(DisasContext *ctx)                         \
+    {                                                                   \
+        TCGv_ptr ra, rb, rd;                                            \
+        if (unlikely(!ctx->altivec_enabled)) {                          \
+            gen_exception(ctx, POWERPC_EXCP_VPU);                       \
+            return;                                                     \
+        }                                                               \
+        ra = gen_avr_ptr(rA(ctx->opcode));                              \
+        rb = gen_avr_ptr(rB(ctx->opcode));                              \
+        rd = gen_avr_ptr(rD(ctx->opcode));                              \
+        gen_helper_##opname(cpu_env, rd, ra, rb);                       \
+        tcg_temp_free_ptr(ra);                                          \
+        tcg_temp_free_ptr(rb);                                          \
+        tcg_temp_free_ptr(rd);                                          \
+    }
+
+#define GEN_VXRFORM(name, opc2, opc3)                                \
+    GEN_VXRFORM1(name, name, #name, opc2, opc3)                      \
+    GEN_VXRFORM1(name##_dot, name##_, #name ".", opc2, (opc3 | (0x1 << 4)))
+
+/*
+ * Support for Altivec instructions that use bit 31 (Rc) as an opcode
+ * bit but also use bit 21 as an actual Rc bit.  In general, thse pairs
+ * come from different versions of the ISA, so we must also support a
+ * pair of flags for each instruction.
+ */
+#define GEN_VXRFORM_DUAL(name0, flg0, flg2_0, name1, flg1, flg2_1)     \
+static void glue(gen_, name0##_##name1)(DisasContext *ctx)             \
+{                                                                      \
+    if ((Rc(ctx->opcode) == 0) &&                                      \
+        ((ctx->insns_flags & flg0) || (ctx->insns_flags2 & flg2_0))) { \
+        if (Rc21(ctx->opcode) == 0) {                                  \
+            gen_##name0(ctx);                                          \
+        } else {                                                       \
+            gen_##name0##_(ctx);                                       \
+        }                                                              \
+    } else if ((Rc(ctx->opcode) == 1) &&                               \
+        ((ctx->insns_flags & flg1) || (ctx->insns_flags2 & flg2_1))) { \
+        if (Rc21(ctx->opcode) == 0) {                                  \
+            gen_##name1(ctx);                                          \
+        } else {                                                       \
+            gen_##name1##_(ctx);                                       \
+        }                                                              \
+    } else {                                                           \
+        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);            \
+    }                                                                  \
+}
+
+GEN_VXRFORM(vcmpequb, 3, 0)
+GEN_VXRFORM(vcmpequh, 3, 1)
+GEN_VXRFORM(vcmpequw, 3, 2)
+GEN_VXRFORM(vcmpequd, 3, 3)
+GEN_VXRFORM(vcmpgtsb, 3, 12)
+GEN_VXRFORM(vcmpgtsh, 3, 13)
+GEN_VXRFORM(vcmpgtsw, 3, 14)
+GEN_VXRFORM(vcmpgtsd, 3, 15)
+GEN_VXRFORM(vcmpgtub, 3, 8)
+GEN_VXRFORM(vcmpgtuh, 3, 9)
+GEN_VXRFORM(vcmpgtuw, 3, 10)
+GEN_VXRFORM(vcmpgtud, 3, 11)
+GEN_VXRFORM(vcmpeqfp, 3, 3)
+GEN_VXRFORM(vcmpgefp, 3, 7)
+GEN_VXRFORM(vcmpgtfp, 3, 11)
+GEN_VXRFORM(vcmpbfp, 3, 15)
+
+GEN_VXRFORM_DUAL(vcmpeqfp, PPC_ALTIVEC, PPC_NONE, \
+                 vcmpequd, PPC_NONE, PPC2_ALTIVEC_207)
+GEN_VXRFORM_DUAL(vcmpbfp, PPC_ALTIVEC, PPC_NONE, \
+                 vcmpgtsd, PPC_NONE, PPC2_ALTIVEC_207)
+GEN_VXRFORM_DUAL(vcmpgtfp, PPC_ALTIVEC, PPC_NONE, \
+                 vcmpgtud, PPC_NONE, PPC2_ALTIVEC_207)
+
+#define GEN_VXFORM_SIMM(name, opc2, opc3)                               \
+static void glue(gen_, name)(DisasContext *ctx)                         \
+    {                                                                   \
+        TCGv_ptr rd;                                                    \
+        TCGv_i32 simm;                                                  \
+        if (unlikely(!ctx->altivec_enabled)) {                          \
+            gen_exception(ctx, POWERPC_EXCP_VPU);                       \
+            return;                                                     \
+        }                                                               \
+        simm = tcg_const_i32(SIMM5(ctx->opcode));                       \
+        rd = gen_avr_ptr(rD(ctx->opcode));                              \
+        gen_helper_##name (rd, simm);                                   \
+        tcg_temp_free_i32(simm);                                        \
+        tcg_temp_free_ptr(rd);                                          \
+    }
+
+GEN_VXFORM_SIMM(vspltisb, 6, 12);
+GEN_VXFORM_SIMM(vspltish, 6, 13);
+GEN_VXFORM_SIMM(vspltisw, 6, 14);
+
+#define GEN_VXFORM_NOA(name, opc2, opc3)                                \
+static void glue(gen_, name)(DisasContext *ctx)                                 \
+    {                                                                   \
+        TCGv_ptr rb, rd;                                                \
+        if (unlikely(!ctx->altivec_enabled)) {                          \
+            gen_exception(ctx, POWERPC_EXCP_VPU);                       \
+            return;                                                     \
+        }                                                               \
+        rb = gen_avr_ptr(rB(ctx->opcode));                              \
+        rd = gen_avr_ptr(rD(ctx->opcode));                              \
+        gen_helper_##name (rd, rb);                                     \
+        tcg_temp_free_ptr(rb);                                          \
+        tcg_temp_free_ptr(rd);                                         \
+    }
+
+#define GEN_VXFORM_NOA_ENV(name, opc2, opc3)                            \
+static void glue(gen_, name)(DisasContext *ctx)                         \
+    {                                                                   \
+        TCGv_ptr rb, rd;                                                \
+                                                                        \
+        if (unlikely(!ctx->altivec_enabled)) {                          \
+            gen_exception(ctx, POWERPC_EXCP_VPU);                       \
+            return;                                                     \
+        }                                                               \
+        rb = gen_avr_ptr(rB(ctx->opcode));                              \
+        rd = gen_avr_ptr(rD(ctx->opcode));                              \
+        gen_helper_##name(cpu_env, rd, rb);                             \
+        tcg_temp_free_ptr(rb);                                          \
+        tcg_temp_free_ptr(rd);                                          \
+    }
+
+GEN_VXFORM_NOA(vupkhsb, 7, 8);
+GEN_VXFORM_NOA(vupkhsh, 7, 9);
+GEN_VXFORM_NOA(vupkhsw, 7, 25);
+GEN_VXFORM_NOA(vupklsb, 7, 10);
+GEN_VXFORM_NOA(vupklsh, 7, 11);
+GEN_VXFORM_NOA(vupklsw, 7, 27);
+GEN_VXFORM_NOA(vupkhpx, 7, 13);
+GEN_VXFORM_NOA(vupklpx, 7, 15);
+GEN_VXFORM_NOA_ENV(vrefp, 5, 4);
+GEN_VXFORM_NOA_ENV(vrsqrtefp, 5, 5);
+GEN_VXFORM_NOA_ENV(vexptefp, 5, 6);
+GEN_VXFORM_NOA_ENV(vlogefp, 5, 7);
+GEN_VXFORM_NOA_ENV(vrfim, 5, 11);
+GEN_VXFORM_NOA_ENV(vrfin, 5, 8);
+GEN_VXFORM_NOA_ENV(vrfip, 5, 10);
+GEN_VXFORM_NOA_ENV(vrfiz, 5, 9);
+
+#define GEN_VXFORM_SIMM(name, opc2, opc3)                               \
+static void glue(gen_, name)(DisasContext *ctx)                                 \
+    {                                                                   \
+        TCGv_ptr rd;                                                    \
+        TCGv_i32 simm;                                                  \
+        if (unlikely(!ctx->altivec_enabled)) {                          \
+            gen_exception(ctx, POWERPC_EXCP_VPU);                       \
+            return;                                                     \
+        }                                                               \
+        simm = tcg_const_i32(SIMM5(ctx->opcode));                       \
+        rd = gen_avr_ptr(rD(ctx->opcode));                              \
+        gen_helper_##name (rd, simm);                                   \
+        tcg_temp_free_i32(simm);                                        \
+        tcg_temp_free_ptr(rd);                                          \
+    }
+
+#define GEN_VXFORM_UIMM(name, opc2, opc3)                               \
+static void glue(gen_, name)(DisasContext *ctx)                                 \
+    {                                                                   \
+        TCGv_ptr rb, rd;                                                \
+        TCGv_i32 uimm;                                                  \
+        if (unlikely(!ctx->altivec_enabled)) {                          \
+            gen_exception(ctx, POWERPC_EXCP_VPU);                       \
+            return;                                                     \
+        }                                                               \
+        uimm = tcg_const_i32(UIMM5(ctx->opcode));                       \
+        rb = gen_avr_ptr(rB(ctx->opcode));                              \
+        rd = gen_avr_ptr(rD(ctx->opcode));                              \
+        gen_helper_##name (rd, rb, uimm);                               \
+        tcg_temp_free_i32(uimm);                                        \
+        tcg_temp_free_ptr(rb);                                          \
+        tcg_temp_free_ptr(rd);                                          \
+    }
+
+#define GEN_VXFORM_UIMM_ENV(name, opc2, opc3)                           \
+static void glue(gen_, name)(DisasContext *ctx)                         \
+    {                                                                   \
+        TCGv_ptr rb, rd;                                                \
+        TCGv_i32 uimm;                                                  \
+                                                                        \
+        if (unlikely(!ctx->altivec_enabled)) {                          \
+            gen_exception(ctx, POWERPC_EXCP_VPU);                       \
+            return;                                                     \
+        }                                                               \
+        uimm = tcg_const_i32(UIMM5(ctx->opcode));                       \
+        rb = gen_avr_ptr(rB(ctx->opcode));                              \
+        rd = gen_avr_ptr(rD(ctx->opcode));                              \
+        gen_helper_##name(cpu_env, rd, rb, uimm);                       \
+        tcg_temp_free_i32(uimm);                                        \
+        tcg_temp_free_ptr(rb);                                          \
+        tcg_temp_free_ptr(rd);                                          \
+    }
+
+GEN_VXFORM_UIMM(vspltb, 6, 8);
+GEN_VXFORM_UIMM(vsplth, 6, 9);
+GEN_VXFORM_UIMM(vspltw, 6, 10);
+GEN_VXFORM_UIMM_ENV(vcfux, 5, 12);
+GEN_VXFORM_UIMM_ENV(vcfsx, 5, 13);
+GEN_VXFORM_UIMM_ENV(vctuxs, 5, 14);
+GEN_VXFORM_UIMM_ENV(vctsxs, 5, 15);
+
+static void gen_vsldoi(DisasContext *ctx)
+{
+    TCGv_ptr ra, rb, rd;
+    TCGv_i32 sh;
+    if (unlikely(!ctx->altivec_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_VPU);
+        return;
+    }
+    ra = gen_avr_ptr(rA(ctx->opcode));
+    rb = gen_avr_ptr(rB(ctx->opcode));
+    rd = gen_avr_ptr(rD(ctx->opcode));
+    sh = tcg_const_i32(VSH(ctx->opcode));
+    gen_helper_vsldoi (rd, ra, rb, sh);
+    tcg_temp_free_ptr(ra);
+    tcg_temp_free_ptr(rb);
+    tcg_temp_free_ptr(rd);
+    tcg_temp_free_i32(sh);
+}
+
+#define GEN_VAFORM_PAIRED(name0, name1, opc2)                           \
+static void glue(gen_, name0##_##name1)(DisasContext *ctx)              \
+    {                                                                   \
+        TCGv_ptr ra, rb, rc, rd;                                        \
+        if (unlikely(!ctx->altivec_enabled)) {                          \
+            gen_exception(ctx, POWERPC_EXCP_VPU);                       \
+            return;                                                     \
+        }                                                               \
+        ra = gen_avr_ptr(rA(ctx->opcode));                              \
+        rb = gen_avr_ptr(rB(ctx->opcode));                              \
+        rc = gen_avr_ptr(rC(ctx->opcode));                              \
+        rd = gen_avr_ptr(rD(ctx->opcode));                              \
+        if (Rc(ctx->opcode)) {                                          \
+            gen_helper_##name1(cpu_env, rd, ra, rb, rc);                \
+        } else {                                                        \
+            gen_helper_##name0(cpu_env, rd, ra, rb, rc);                \
+        }                                                               \
+        tcg_temp_free_ptr(ra);                                          \
+        tcg_temp_free_ptr(rb);                                          \
+        tcg_temp_free_ptr(rc);                                          \
+        tcg_temp_free_ptr(rd);                                          \
+    }
+
+GEN_VAFORM_PAIRED(vmhaddshs, vmhraddshs, 16)
+
+static void gen_vmladduhm(DisasContext *ctx)
+{
+    TCGv_ptr ra, rb, rc, rd;
+    if (unlikely(!ctx->altivec_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_VPU);
+        return;
+    }
+    ra = gen_avr_ptr(rA(ctx->opcode));
+    rb = gen_avr_ptr(rB(ctx->opcode));
+    rc = gen_avr_ptr(rC(ctx->opcode));
+    rd = gen_avr_ptr(rD(ctx->opcode));
+    gen_helper_vmladduhm(rd, ra, rb, rc);
+    tcg_temp_free_ptr(ra);
+    tcg_temp_free_ptr(rb);
+    tcg_temp_free_ptr(rc);
+    tcg_temp_free_ptr(rd);
+}
+
+GEN_VAFORM_PAIRED(vmsumubm, vmsummbm, 18)
+GEN_VAFORM_PAIRED(vmsumuhm, vmsumuhs, 19)
+GEN_VAFORM_PAIRED(vmsumshm, vmsumshs, 20)
+GEN_VAFORM_PAIRED(vsel, vperm, 21)
+GEN_VAFORM_PAIRED(vmaddfp, vnmsubfp, 23)
+
+GEN_VXFORM_NOA(vclzb, 1, 28)
+GEN_VXFORM_NOA(vclzh, 1, 29)
+GEN_VXFORM_NOA(vclzw, 1, 30)
+GEN_VXFORM_NOA(vclzd, 1, 31)
+GEN_VXFORM_NOA(vpopcntb, 1, 28)
+GEN_VXFORM_NOA(vpopcnth, 1, 29)
+GEN_VXFORM_NOA(vpopcntw, 1, 30)
+GEN_VXFORM_NOA(vpopcntd, 1, 31)
+GEN_VXFORM_DUAL(vclzb, PPC_NONE, PPC2_ALTIVEC_207, \
+                vpopcntb, PPC_NONE, PPC2_ALTIVEC_207)
+GEN_VXFORM_DUAL(vclzh, PPC_NONE, PPC2_ALTIVEC_207, \
+                vpopcnth, PPC_NONE, PPC2_ALTIVEC_207)
+GEN_VXFORM_DUAL(vclzw, PPC_NONE, PPC2_ALTIVEC_207, \
+                vpopcntw, PPC_NONE, PPC2_ALTIVEC_207)
+GEN_VXFORM_DUAL(vclzd, PPC_NONE, PPC2_ALTIVEC_207, \
+                vpopcntd, PPC_NONE, PPC2_ALTIVEC_207)
+GEN_VXFORM(vbpermq, 6, 21);
+GEN_VXFORM_NOA(vgbbd, 6, 20);
+GEN_VXFORM(vpmsumb, 4, 16)
+GEN_VXFORM(vpmsumh, 4, 17)
+GEN_VXFORM(vpmsumw, 4, 18)
+GEN_VXFORM(vpmsumd, 4, 19)
+
+#define GEN_BCD(op)                                 \
+static void gen_##op(DisasContext *ctx)             \
+{                                                   \
+    TCGv_ptr ra, rb, rd;                            \
+    TCGv_i32 ps;                                    \
+                                                    \
+    if (unlikely(!ctx->altivec_enabled)) {          \
+        gen_exception(ctx, POWERPC_EXCP_VPU);       \
+        return;                                     \
+    }                                               \
+                                                    \
+    ra = gen_avr_ptr(rA(ctx->opcode));              \
+    rb = gen_avr_ptr(rB(ctx->opcode));              \
+    rd = gen_avr_ptr(rD(ctx->opcode));              \
+                                                    \
+    ps = tcg_const_i32((ctx->opcode & 0x200) != 0); \
+                                                    \
+    gen_helper_##op(cpu_crf[6], rd, ra, rb, ps);    \
+                                                    \
+    tcg_temp_free_ptr(ra);                          \
+    tcg_temp_free_ptr(rb);                          \
+    tcg_temp_free_ptr(rd);                          \
+    tcg_temp_free_i32(ps);                          \
+}
+
+GEN_BCD(bcdadd)
+GEN_BCD(bcdsub)
+
+GEN_VXFORM_DUAL(vsububm, PPC_ALTIVEC, PPC_NONE, \
+                bcdadd, PPC_NONE, PPC2_ALTIVEC_207)
+GEN_VXFORM_DUAL(vsububs, PPC_ALTIVEC, PPC_NONE, \
+                bcdadd, PPC_NONE, PPC2_ALTIVEC_207)
+GEN_VXFORM_DUAL(vsubuhm, PPC_ALTIVEC, PPC_NONE, \
+                bcdsub, PPC_NONE, PPC2_ALTIVEC_207)
+GEN_VXFORM_DUAL(vsubuhs, PPC_ALTIVEC, PPC_NONE, \
+                bcdsub, PPC_NONE, PPC2_ALTIVEC_207)
+
+static void gen_vsbox(DisasContext *ctx)
+{
+    TCGv_ptr ra, rd;
+    if (unlikely(!ctx->altivec_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_VPU);
+        return;
+    }
+    ra = gen_avr_ptr(rA(ctx->opcode));
+    rd = gen_avr_ptr(rD(ctx->opcode));
+    gen_helper_vsbox(rd, ra);
+    tcg_temp_free_ptr(ra);
+    tcg_temp_free_ptr(rd);
+}
+
+GEN_VXFORM(vcipher, 4, 20)
+GEN_VXFORM(vcipherlast, 4, 20)
+GEN_VXFORM(vncipher, 4, 21)
+GEN_VXFORM(vncipherlast, 4, 21)
+
+GEN_VXFORM_DUAL(vcipher, PPC_NONE, PPC2_ALTIVEC_207,
+                vcipherlast, PPC_NONE, PPC2_ALTIVEC_207)
+GEN_VXFORM_DUAL(vncipher, PPC_NONE, PPC2_ALTIVEC_207,
+                vncipherlast, PPC_NONE, PPC2_ALTIVEC_207)
+
+#define VSHASIGMA(op)                         \
+static void gen_##op(DisasContext *ctx)       \
+{                                             \
+    TCGv_ptr ra, rd;                          \
+    TCGv_i32 st_six;                          \
+    if (unlikely(!ctx->altivec_enabled)) {    \
+        gen_exception(ctx, POWERPC_EXCP_VPU); \
+        return;                               \
+    }                                         \
+    ra = gen_avr_ptr(rA(ctx->opcode));        \
+    rd = gen_avr_ptr(rD(ctx->opcode));        \
+    st_six = tcg_const_i32(rB(ctx->opcode));  \
+    gen_helper_##op(rd, ra, st_six);          \
+    tcg_temp_free_ptr(ra);                    \
+    tcg_temp_free_ptr(rd);                    \
+    tcg_temp_free_i32(st_six);                \
+}
+
+VSHASIGMA(vshasigmaw)
+VSHASIGMA(vshasigmad)
+
+GEN_VXFORM3(vpermxor, 22, 0xFF)
+GEN_VXFORM_DUAL(vsldoi, PPC_ALTIVEC, PPC_NONE,
+                vpermxor, PPC_NONE, PPC2_ALTIVEC_207)
+
+#undef GEN_VR_LDX
+#undef GEN_VR_STX
+#undef GEN_VR_LVE
+#undef GEN_VR_STVE
+
+#undef GEN_VX_LOGICAL
+#undef GEN_VX_LOGICAL_207
+#undef GEN_VXFORM
+#undef GEN_VXFORM_207
+#undef GEN_VXFORM_DUAL
+#undef GEN_VXRFORM_DUAL
+#undef GEN_VXRFORM1
+#undef GEN_VXRFORM
+#undef GEN_VXFORM_SIMM
+#undef GEN_VXFORM_NOA
+#undef GEN_VXFORM_UIMM
+#undef GEN_VAFORM_PAIRED
diff --git a/target-ppc/translate/vmx-ops.c b/target-ppc/translate/vmx-ops.c
new file mode 100644
index 0000000..b9c982a
--- /dev/null
+++ b/target-ppc/translate/vmx-ops.c
@@ -0,0 +1,246 @@
+#define GEN_VR_LDX(name, opc2, opc3)                                          \
+GEN_HANDLER(name, 0x1F, opc2, opc3, 0x00000001, PPC_ALTIVEC)
+#define GEN_VR_STX(name, opc2, opc3)                                          \
+GEN_HANDLER(st##name, 0x1F, opc2, opc3, 0x00000001, PPC_ALTIVEC)
+#define GEN_VR_LVE(name, opc2, opc3)                                    \
+    GEN_HANDLER(lve##name, 0x1F, opc2, opc3, 0x00000001, PPC_ALTIVEC)
+#define GEN_VR_STVE(name, opc2, opc3)                                   \
+    GEN_HANDLER(stve##name, 0x1F, opc2, opc3, 0x00000001, PPC_ALTIVEC)
+GEN_VR_LDX(lvx, 0x07, 0x03),
+GEN_VR_LDX(lvxl, 0x07, 0x0B),
+GEN_VR_LVE(bx, 0x07, 0x00),
+GEN_VR_LVE(hx, 0x07, 0x01),
+GEN_VR_LVE(wx, 0x07, 0x02),
+GEN_VR_STX(svx, 0x07, 0x07),
+GEN_VR_STX(svxl, 0x07, 0x0F),
+GEN_VR_STVE(bx, 0x07, 0x04),
+GEN_VR_STVE(hx, 0x07, 0x05),
+GEN_VR_STVE(wx, 0x07, 0x06),
+
+#define GEN_VX_LOGICAL(name, tcg_op, opc2, opc3)                        \
+GEN_HANDLER(name, 0x04, opc2, opc3, 0x00000000, PPC_ALTIVEC)
+
+#define GEN_VX_LOGICAL_207(name, tcg_op, opc2, opc3) \
+GEN_HANDLER_E(name, 0x04, opc2, opc3, 0x00000000, PPC_NONE, PPC2_ALTIVEC_207)
+
+GEN_VX_LOGICAL(vand, tcg_gen_and_i64, 2, 16),
+GEN_VX_LOGICAL(vandc, tcg_gen_andc_i64, 2, 17),
+GEN_VX_LOGICAL(vor, tcg_gen_or_i64, 2, 18),
+GEN_VX_LOGICAL(vxor, tcg_gen_xor_i64, 2, 19),
+GEN_VX_LOGICAL(vnor, tcg_gen_nor_i64, 2, 20),
+GEN_VX_LOGICAL_207(veqv, tcg_gen_eqv_i64, 2, 26),
+GEN_VX_LOGICAL_207(vnand, tcg_gen_nand_i64, 2, 22),
+GEN_VX_LOGICAL_207(vorc, tcg_gen_orc_i64, 2, 21),
+
+#define GEN_VXFORM(name, opc2, opc3)                                    \
+GEN_HANDLER(name, 0x04, opc2, opc3, 0x00000000, PPC_ALTIVEC)
+
+#define GEN_VXFORM_207(name, opc2, opc3) \
+GEN_HANDLER_E(name, 0x04, opc2, opc3, 0x00000000, PPC_NONE, PPC2_ALTIVEC_207)
+
+#define GEN_VXFORM_DUAL(name0, name1, opc2, opc3, type0, type1) \
+GEN_HANDLER_E(name0##_##name1, 0x4, opc2, opc3, 0x00000000, type0, type1)
+
+#define GEN_VXRFORM_DUAL(name0, name1, opc2, opc3, tp0, tp1) \
+GEN_HANDLER_E(name0##_##name1, 0x4, opc2, opc3, 0x00000000, tp0, tp1), \
+GEN_HANDLER_E(name0##_##name1, 0x4, opc2, (opc3 | 0x10), 0x00000000, tp0, tp1),
+
+GEN_VXFORM(vaddubm, 0, 0),
+GEN_VXFORM(vadduhm, 0, 1),
+GEN_VXFORM(vadduwm, 0, 2),
+GEN_VXFORM_207(vaddudm, 0, 3),
+GEN_VXFORM_DUAL(vsububm, bcdadd, 0, 16, PPC_ALTIVEC, PPC_NONE),
+GEN_VXFORM_DUAL(vsubuhm, bcdsub, 0, 17, PPC_ALTIVEC, PPC_NONE),
+GEN_VXFORM(vsubuwm, 0, 18),
+GEN_VXFORM_207(vsubudm, 0, 19),
+GEN_VXFORM(vmaxub, 1, 0),
+GEN_VXFORM(vmaxuh, 1, 1),
+GEN_VXFORM(vmaxuw, 1, 2),
+GEN_VXFORM_207(vmaxud, 1, 3),
+GEN_VXFORM(vmaxsb, 1, 4),
+GEN_VXFORM(vmaxsh, 1, 5),
+GEN_VXFORM(vmaxsw, 1, 6),
+GEN_VXFORM_207(vmaxsd, 1, 7),
+GEN_VXFORM(vminub, 1, 8),
+GEN_VXFORM(vminuh, 1, 9),
+GEN_VXFORM(vminuw, 1, 10),
+GEN_VXFORM_207(vminud, 1, 11),
+GEN_VXFORM(vminsb, 1, 12),
+GEN_VXFORM(vminsh, 1, 13),
+GEN_VXFORM(vminsw, 1, 14),
+GEN_VXFORM_207(vminsd, 1, 15),
+GEN_VXFORM(vavgub, 1, 16),
+GEN_VXFORM(vavguh, 1, 17),
+GEN_VXFORM(vavguw, 1, 18),
+GEN_VXFORM(vavgsb, 1, 20),
+GEN_VXFORM(vavgsh, 1, 21),
+GEN_VXFORM(vavgsw, 1, 22),
+GEN_VXFORM(vmrghb, 6, 0),
+GEN_VXFORM(vmrghh, 6, 1),
+GEN_VXFORM(vmrghw, 6, 2),
+GEN_VXFORM(vmrglb, 6, 4),
+GEN_VXFORM(vmrglh, 6, 5),
+GEN_VXFORM(vmrglw, 6, 6),
+GEN_VXFORM_207(vmrgew, 6, 30),
+GEN_VXFORM_207(vmrgow, 6, 26),
+GEN_VXFORM(vmuloub, 4, 0),
+GEN_VXFORM(vmulouh, 4, 1),
+GEN_VXFORM_DUAL(vmulouw, vmuluwm, 4, 2, PPC_ALTIVEC, PPC_NONE),
+GEN_VXFORM(vmulosb, 4, 4),
+GEN_VXFORM(vmulosh, 4, 5),
+GEN_VXFORM_207(vmulosw, 4, 6),
+GEN_VXFORM(vmuleub, 4, 8),
+GEN_VXFORM(vmuleuh, 4, 9),
+GEN_VXFORM_207(vmuleuw, 4, 10),
+GEN_VXFORM(vmulesb, 4, 12),
+GEN_VXFORM(vmulesh, 4, 13),
+GEN_VXFORM_207(vmulesw, 4, 14),
+GEN_VXFORM(vslb, 2, 4),
+GEN_VXFORM(vslh, 2, 5),
+GEN_VXFORM(vslw, 2, 6),
+GEN_VXFORM_207(vsld, 2, 23),
+GEN_VXFORM(vsrb, 2, 8),
+GEN_VXFORM(vsrh, 2, 9),
+GEN_VXFORM(vsrw, 2, 10),
+GEN_VXFORM_207(vsrd, 2, 27),
+GEN_VXFORM(vsrab, 2, 12),
+GEN_VXFORM(vsrah, 2, 13),
+GEN_VXFORM(vsraw, 2, 14),
+GEN_VXFORM_207(vsrad, 2, 15),
+GEN_VXFORM(vslo, 6, 16),
+GEN_VXFORM(vsro, 6, 17),
+GEN_VXFORM(vaddcuw, 0, 6),
+GEN_VXFORM(vsubcuw, 0, 22),
+GEN_VXFORM(vaddubs, 0, 8),
+GEN_VXFORM(vadduhs, 0, 9),
+GEN_VXFORM(vadduws, 0, 10),
+GEN_VXFORM(vaddsbs, 0, 12),
+GEN_VXFORM(vaddshs, 0, 13),
+GEN_VXFORM(vaddsws, 0, 14),
+GEN_VXFORM_DUAL(vsububs, bcdadd, 0, 24, PPC_ALTIVEC, PPC_NONE),
+GEN_VXFORM_DUAL(vsubuhs, bcdsub, 0, 25, PPC_ALTIVEC, PPC_NONE),
+GEN_VXFORM(vsubuws, 0, 26),
+GEN_VXFORM(vsubsbs, 0, 28),
+GEN_VXFORM(vsubshs, 0, 29),
+GEN_VXFORM(vsubsws, 0, 30),
+GEN_VXFORM_207(vadduqm, 0, 4),
+GEN_VXFORM_207(vaddcuq, 0, 5),
+GEN_VXFORM_DUAL(vaddeuqm, vaddecuq, 30, 0xFF, PPC_NONE, PPC2_ALTIVEC_207),
+GEN_VXFORM_207(vsubuqm, 0, 20),
+GEN_VXFORM_207(vsubcuq, 0, 21),
+GEN_VXFORM_DUAL(vsubeuqm, vsubecuq, 31, 0xFF, PPC_NONE, PPC2_ALTIVEC_207),
+GEN_VXFORM(vrlb, 2, 0),
+GEN_VXFORM(vrlh, 2, 1),
+GEN_VXFORM(vrlw, 2, 2),
+GEN_VXFORM_207(vrld, 2, 3),
+GEN_VXFORM(vsl, 2, 7),
+GEN_VXFORM(vsr, 2, 11),
+GEN_VXFORM(vpkuhum, 7, 0),
+GEN_VXFORM(vpkuwum, 7, 1),
+GEN_VXFORM_207(vpkudum, 7, 17),
+GEN_VXFORM(vpkuhus, 7, 2),
+GEN_VXFORM(vpkuwus, 7, 3),
+GEN_VXFORM_207(vpkudus, 7, 19),
+GEN_VXFORM(vpkshus, 7, 4),
+GEN_VXFORM(vpkswus, 7, 5),
+GEN_VXFORM_207(vpksdus, 7, 21),
+GEN_VXFORM(vpkshss, 7, 6),
+GEN_VXFORM(vpkswss, 7, 7),
+GEN_VXFORM_207(vpksdss, 7, 23),
+GEN_VXFORM(vpkpx, 7, 12),
+GEN_VXFORM(vsum4ubs, 4, 24),
+GEN_VXFORM(vsum4sbs, 4, 28),
+GEN_VXFORM(vsum4shs, 4, 25),
+GEN_VXFORM(vsum2sws, 4, 26),
+GEN_VXFORM(vsumsws, 4, 30),
+GEN_VXFORM(vaddfp, 5, 0),
+GEN_VXFORM(vsubfp, 5, 1),
+GEN_VXFORM(vmaxfp, 5, 16),
+GEN_VXFORM(vminfp, 5, 17),
+
+#define GEN_VXRFORM1(opname, name, str, opc2, opc3)                     \
+    GEN_HANDLER2(name, str, 0x4, opc2, opc3, 0x00000000, PPC_ALTIVEC),
+#define GEN_VXRFORM(name, opc2, opc3)                                \
+    GEN_VXRFORM1(name, name, #name, opc2, opc3)                      \
+    GEN_VXRFORM1(name##_dot, name##_, #name ".", opc2, (opc3 | (0x1 << 4)))
+GEN_VXRFORM(vcmpequb, 3, 0)
+GEN_VXRFORM(vcmpequh, 3, 1)
+GEN_VXRFORM(vcmpequw, 3, 2)
+GEN_VXRFORM(vcmpgtsb, 3, 12)
+GEN_VXRFORM(vcmpgtsh, 3, 13)
+GEN_VXRFORM(vcmpgtsw, 3, 14)
+GEN_VXRFORM(vcmpgtub, 3, 8)
+GEN_VXRFORM(vcmpgtuh, 3, 9)
+GEN_VXRFORM(vcmpgtuw, 3, 10)
+GEN_VXRFORM_DUAL(vcmpeqfp, vcmpequd, 3, 3, PPC_ALTIVEC, PPC_NONE)
+GEN_VXRFORM(vcmpgefp, 3, 7)
+GEN_VXRFORM_DUAL(vcmpgtfp, vcmpgtud, 3, 11, PPC_ALTIVEC, PPC_NONE)
+GEN_VXRFORM_DUAL(vcmpbfp, vcmpgtsd, 3, 15, PPC_ALTIVEC, PPC_NONE)
+
+#define GEN_VXFORM_SIMM(name, opc2, opc3)                               \
+    GEN_HANDLER(name, 0x04, opc2, opc3, 0x00000000, PPC_ALTIVEC)
+GEN_VXFORM_SIMM(vspltisb, 6, 12),
+GEN_VXFORM_SIMM(vspltish, 6, 13),
+GEN_VXFORM_SIMM(vspltisw, 6, 14),
+
+#define GEN_VXFORM_NOA(name, opc2, opc3)                                \
+    GEN_HANDLER(name, 0x04, opc2, opc3, 0x001f0000, PPC_ALTIVEC)
+GEN_VXFORM_NOA(vupkhsb, 7, 8),
+GEN_VXFORM_NOA(vupkhsh, 7, 9),
+GEN_VXFORM_207(vupkhsw, 7, 25),
+GEN_VXFORM_NOA(vupklsb, 7, 10),
+GEN_VXFORM_NOA(vupklsh, 7, 11),
+GEN_VXFORM_207(vupklsw, 7, 27),
+GEN_VXFORM_NOA(vupkhpx, 7, 13),
+GEN_VXFORM_NOA(vupklpx, 7, 15),
+GEN_VXFORM_NOA(vrefp, 5, 4),
+GEN_VXFORM_NOA(vrsqrtefp, 5, 5),
+GEN_VXFORM_NOA(vexptefp, 5, 6),
+GEN_VXFORM_NOA(vlogefp, 5, 7),
+GEN_VXFORM_NOA(vrfim, 5, 11),
+GEN_VXFORM_NOA(vrfin, 5, 8),
+GEN_VXFORM_NOA(vrfip, 5, 10),
+GEN_VXFORM_NOA(vrfiz, 5, 9),
+
+#define GEN_VXFORM_UIMM(name, opc2, opc3)                               \
+    GEN_HANDLER(name, 0x04, opc2, opc3, 0x00000000, PPC_ALTIVEC)
+GEN_VXFORM_UIMM(vspltb, 6, 8),
+GEN_VXFORM_UIMM(vsplth, 6, 9),
+GEN_VXFORM_UIMM(vspltw, 6, 10),
+GEN_VXFORM_UIMM(vcfux, 5, 12),
+GEN_VXFORM_UIMM(vcfsx, 5, 13),
+GEN_VXFORM_UIMM(vctuxs, 5, 14),
+GEN_VXFORM_UIMM(vctsxs, 5, 15),
+
+
+#define GEN_VAFORM_PAIRED(name0, name1, opc2)                           \
+    GEN_HANDLER(name0##_##name1, 0x04, opc2, 0xFF, 0x00000000, PPC_ALTIVEC)
+GEN_VAFORM_PAIRED(vmhaddshs, vmhraddshs, 16),
+GEN_VAFORM_PAIRED(vmsumubm, vmsummbm, 18),
+GEN_VAFORM_PAIRED(vmsumuhm, vmsumuhs, 19),
+GEN_VAFORM_PAIRED(vmsumshm, vmsumshs, 20),
+GEN_VAFORM_PAIRED(vsel, vperm, 21),
+GEN_VAFORM_PAIRED(vmaddfp, vnmsubfp, 23),
+
+GEN_VXFORM_DUAL(vclzb, vpopcntb, 1, 28, PPC_NONE, PPC2_ALTIVEC_207),
+GEN_VXFORM_DUAL(vclzh, vpopcnth, 1, 29, PPC_NONE, PPC2_ALTIVEC_207),
+GEN_VXFORM_DUAL(vclzw, vpopcntw, 1, 30, PPC_NONE, PPC2_ALTIVEC_207),
+GEN_VXFORM_DUAL(vclzd, vpopcntd, 1, 31, PPC_NONE, PPC2_ALTIVEC_207),
+
+GEN_VXFORM_207(vbpermq, 6, 21),
+GEN_VXFORM_207(vgbbd, 6, 20),
+GEN_VXFORM_207(vpmsumb, 4, 16),
+GEN_VXFORM_207(vpmsumh, 4, 17),
+GEN_VXFORM_207(vpmsumw, 4, 18),
+GEN_VXFORM_207(vpmsumd, 4, 19),
+
+GEN_VXFORM_207(vsbox, 4, 23),
+
+GEN_VXFORM_DUAL(vcipher, vcipherlast, 4, 20, PPC_NONE, PPC2_ALTIVEC_207),
+GEN_VXFORM_DUAL(vncipher, vncipherlast, 4, 21, PPC_NONE, PPC2_ALTIVEC_207),
+
+GEN_VXFORM_207(vshasigmaw, 1, 26),
+GEN_VXFORM_207(vshasigmad, 1, 27),
+
+GEN_VXFORM_DUAL(vsldoi, vpermxor, 22, 0xFF, PPC_ALTIVEC, PPC_NONE),
+
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [Qemu-devel] [PATCH 07/32] ppc: Move VSX ops out of translate.c
  2016-07-26 22:20 [Qemu-devel] [PATCH 01/32] ppc: Fix fault PC reporting for lve*/stve* VMX instructions Benjamin Herrenschmidt
                   ` (4 preceding siblings ...)
  2016-07-26 22:21 ` [Qemu-devel] [PATCH 06/32] ppc: Move VMX " Benjamin Herrenschmidt
@ 2016-07-26 22:21 ` Benjamin Herrenschmidt
  2016-07-26 22:21 ` [Qemu-devel] [PATCH 08/32] ppc: Rename fload_invalid_op_excp to float_invalid_op_excp Benjamin Herrenschmidt
                   ` (25 subsequent siblings)
  31 siblings, 0 replies; 69+ messages in thread
From: Benjamin Herrenschmidt @ 2016-07-26 22:21 UTC (permalink / raw)
  To: qemu-ppc; +Cc: qemu-devel, david, Benjamin Herrenschmidt

Makes things a bit more manageable

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
 target-ppc/translate.c          | 994 +---------------------------------------
 target-ppc/translate/vsx-impl.c | 721 +++++++++++++++++++++++++++++
 target-ppc/translate/vsx-ops.c  | 271 +++++++++++
 3 files changed, 995 insertions(+), 991 deletions(-)
 create mode 100644 target-ppc/translate/vsx-impl.c
 create mode 100644 target-ppc/translate/vsx-ops.c

diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index 421fd98..cb4e313 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -5007,6 +5007,8 @@ static void gen_rfsvc(DisasContext *ctx)
 
 #include "translate/vmx-impl.c"
 
+#include "translate/vsx-impl.c"
+
 /* svc is not implemented for now */
 
 /* BookE specific instructions */
@@ -5771,721 +5773,6 @@ static void gen_msgsnd(DisasContext *ctx)
 #endif /* defined(CONFIG_USER_ONLY) */
 }
 
-/***                           VSX extension                               ***/
-
-static inline TCGv_i64 cpu_vsrh(int n)
-{
-    if (n < 32) {
-        return cpu_fpr[n];
-    } else {
-        return cpu_avrh[n-32];
-    }
-}
-
-static inline TCGv_i64 cpu_vsrl(int n)
-{
-    if (n < 32) {
-        return cpu_vsr[n];
-    } else {
-        return cpu_avrl[n-32];
-    }
-}
-
-#define VSX_LOAD_SCALAR(name, operation)                      \
-static void gen_##name(DisasContext *ctx)                     \
-{                                                             \
-    TCGv EA;                                                  \
-    if (unlikely(!ctx->vsx_enabled)) {                        \
-        gen_exception(ctx, POWERPC_EXCP_VSXU);                \
-        return;                                               \
-    }                                                         \
-    gen_set_access_type(ctx, ACCESS_INT);                     \
-    EA = tcg_temp_new();                                      \
-    gen_addr_reg_index(ctx, EA);                              \
-    gen_qemu_##operation(ctx, cpu_vsrh(xT(ctx->opcode)), EA); \
-    /* NOTE: cpu_vsrl is undefined */                         \
-    tcg_temp_free(EA);                                        \
-}
-
-VSX_LOAD_SCALAR(lxsdx, ld64)
-VSX_LOAD_SCALAR(lxsiwax, ld32s_i64)
-VSX_LOAD_SCALAR(lxsiwzx, ld32u_i64)
-VSX_LOAD_SCALAR(lxsspx, ld32fs)
-
-static void gen_lxvd2x(DisasContext *ctx)
-{
-    TCGv EA;
-    if (unlikely(!ctx->vsx_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_VSXU);
-        return;
-    }
-    gen_set_access_type(ctx, ACCESS_INT);
-    EA = tcg_temp_new();
-    gen_addr_reg_index(ctx, EA);
-    gen_qemu_ld64(ctx, cpu_vsrh(xT(ctx->opcode)), EA);
-    tcg_gen_addi_tl(EA, EA, 8);
-    gen_qemu_ld64(ctx, cpu_vsrl(xT(ctx->opcode)), EA);
-    tcg_temp_free(EA);
-}
-
-static void gen_lxvdsx(DisasContext *ctx)
-{
-    TCGv EA;
-    if (unlikely(!ctx->vsx_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_VSXU);
-        return;
-    }
-    gen_set_access_type(ctx, ACCESS_INT);
-    EA = tcg_temp_new();
-    gen_addr_reg_index(ctx, EA);
-    gen_qemu_ld64(ctx, cpu_vsrh(xT(ctx->opcode)), EA);
-    tcg_gen_mov_i64(cpu_vsrl(xT(ctx->opcode)), cpu_vsrh(xT(ctx->opcode)));
-    tcg_temp_free(EA);
-}
-
-static void gen_lxvw4x(DisasContext *ctx)
-{
-    TCGv EA;
-    TCGv_i64 tmp;
-    TCGv_i64 xth = cpu_vsrh(xT(ctx->opcode));
-    TCGv_i64 xtl = cpu_vsrl(xT(ctx->opcode));
-    if (unlikely(!ctx->vsx_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_VSXU);
-        return;
-    }
-    gen_set_access_type(ctx, ACCESS_INT);
-    EA = tcg_temp_new();
-    tmp = tcg_temp_new_i64();
-
-    gen_addr_reg_index(ctx, EA);
-    gen_qemu_ld32u_i64(ctx, tmp, EA);
-    tcg_gen_addi_tl(EA, EA, 4);
-    gen_qemu_ld32u_i64(ctx, xth, EA);
-    tcg_gen_deposit_i64(xth, xth, tmp, 32, 32);
-
-    tcg_gen_addi_tl(EA, EA, 4);
-    gen_qemu_ld32u_i64(ctx, tmp, EA);
-    tcg_gen_addi_tl(EA, EA, 4);
-    gen_qemu_ld32u_i64(ctx, xtl, EA);
-    tcg_gen_deposit_i64(xtl, xtl, tmp, 32, 32);
-
-    tcg_temp_free(EA);
-    tcg_temp_free_i64(tmp);
-}
-
-#define VSX_STORE_SCALAR(name, operation)                     \
-static void gen_##name(DisasContext *ctx)                     \
-{                                                             \
-    TCGv EA;                                                  \
-    if (unlikely(!ctx->vsx_enabled)) {                        \
-        gen_exception(ctx, POWERPC_EXCP_VSXU);                \
-        return;                                               \
-    }                                                         \
-    gen_set_access_type(ctx, ACCESS_INT);                     \
-    EA = tcg_temp_new();                                      \
-    gen_addr_reg_index(ctx, EA);                              \
-    gen_qemu_##operation(ctx, cpu_vsrh(xS(ctx->opcode)), EA); \
-    tcg_temp_free(EA);                                        \
-}
-
-VSX_STORE_SCALAR(stxsdx, st64)
-VSX_STORE_SCALAR(stxsiwx, st32_i64)
-VSX_STORE_SCALAR(stxsspx, st32fs)
-
-static void gen_stxvd2x(DisasContext *ctx)
-{
-    TCGv EA;
-    if (unlikely(!ctx->vsx_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_VSXU);
-        return;
-    }
-    gen_set_access_type(ctx, ACCESS_INT);
-    EA = tcg_temp_new();
-    gen_addr_reg_index(ctx, EA);
-    gen_qemu_st64(ctx, cpu_vsrh(xS(ctx->opcode)), EA);
-    tcg_gen_addi_tl(EA, EA, 8);
-    gen_qemu_st64(ctx, cpu_vsrl(xS(ctx->opcode)), EA);
-    tcg_temp_free(EA);
-}
-
-static void gen_stxvw4x(DisasContext *ctx)
-{
-    TCGv_i64 tmp;
-    TCGv EA;
-    if (unlikely(!ctx->vsx_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_VSXU);
-        return;
-    }
-    gen_set_access_type(ctx, ACCESS_INT);
-    EA = tcg_temp_new();
-    gen_addr_reg_index(ctx, EA);
-    tmp = tcg_temp_new_i64();
-
-    tcg_gen_shri_i64(tmp, cpu_vsrh(xS(ctx->opcode)), 32);
-    gen_qemu_st32_i64(ctx, tmp, EA);
-    tcg_gen_addi_tl(EA, EA, 4);
-    gen_qemu_st32_i64(ctx, cpu_vsrh(xS(ctx->opcode)), EA);
-
-    tcg_gen_shri_i64(tmp, cpu_vsrl(xS(ctx->opcode)), 32);
-    tcg_gen_addi_tl(EA, EA, 4);
-    gen_qemu_st32_i64(ctx, tmp, EA);
-    tcg_gen_addi_tl(EA, EA, 4);
-    gen_qemu_st32_i64(ctx, cpu_vsrl(xS(ctx->opcode)), EA);
-
-    tcg_temp_free(EA);
-    tcg_temp_free_i64(tmp);
-}
-
-#define MV_VSRW(name, tcgop1, tcgop2, target, source)           \
-static void gen_##name(DisasContext *ctx)                       \
-{                                                               \
-    if (xS(ctx->opcode) < 32) {                                 \
-        if (unlikely(!ctx->fpu_enabled)) {                      \
-            gen_exception(ctx, POWERPC_EXCP_FPU);               \
-            return;                                             \
-        }                                                       \
-    } else {                                                    \
-        if (unlikely(!ctx->altivec_enabled)) {                  \
-            gen_exception(ctx, POWERPC_EXCP_VPU);               \
-            return;                                             \
-        }                                                       \
-    }                                                           \
-    TCGv_i64 tmp = tcg_temp_new_i64();                          \
-    tcg_gen_##tcgop1(tmp, source);                              \
-    tcg_gen_##tcgop2(target, tmp);                              \
-    tcg_temp_free_i64(tmp);                                     \
-}
-
-
-MV_VSRW(mfvsrwz, ext32u_i64, trunc_i64_tl, cpu_gpr[rA(ctx->opcode)], \
-        cpu_vsrh(xS(ctx->opcode)))
-MV_VSRW(mtvsrwa, extu_tl_i64, ext32s_i64, cpu_vsrh(xT(ctx->opcode)), \
-        cpu_gpr[rA(ctx->opcode)])
-MV_VSRW(mtvsrwz, extu_tl_i64, ext32u_i64, cpu_vsrh(xT(ctx->opcode)), \
-        cpu_gpr[rA(ctx->opcode)])
-
-#if defined(TARGET_PPC64)
-#define MV_VSRD(name, target, source)                           \
-static void gen_##name(DisasContext *ctx)                       \
-{                                                               \
-    if (xS(ctx->opcode) < 32) {                                 \
-        if (unlikely(!ctx->fpu_enabled)) {                      \
-            gen_exception(ctx, POWERPC_EXCP_FPU);               \
-            return;                                             \
-        }                                                       \
-    } else {                                                    \
-        if (unlikely(!ctx->altivec_enabled)) {                  \
-            gen_exception(ctx, POWERPC_EXCP_VPU);               \
-            return;                                             \
-        }                                                       \
-    }                                                           \
-    tcg_gen_mov_i64(target, source);                            \
-}
-
-MV_VSRD(mfvsrd, cpu_gpr[rA(ctx->opcode)], cpu_vsrh(xS(ctx->opcode)))
-MV_VSRD(mtvsrd, cpu_vsrh(xT(ctx->opcode)), cpu_gpr[rA(ctx->opcode)])
-
-#endif
-
-static void gen_xxpermdi(DisasContext *ctx)
-{
-    if (unlikely(!ctx->vsx_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_VSXU);
-        return;
-    }
-
-    if (unlikely((xT(ctx->opcode) == xA(ctx->opcode)) ||
-                 (xT(ctx->opcode) == xB(ctx->opcode)))) {
-        TCGv_i64 xh, xl;
-
-        xh = tcg_temp_new_i64();
-        xl = tcg_temp_new_i64();
-
-        if ((DM(ctx->opcode) & 2) == 0) {
-            tcg_gen_mov_i64(xh, cpu_vsrh(xA(ctx->opcode)));
-        } else {
-            tcg_gen_mov_i64(xh, cpu_vsrl(xA(ctx->opcode)));
-        }
-        if ((DM(ctx->opcode) & 1) == 0) {
-            tcg_gen_mov_i64(xl, cpu_vsrh(xB(ctx->opcode)));
-        } else {
-            tcg_gen_mov_i64(xl, cpu_vsrl(xB(ctx->opcode)));
-        }
-
-        tcg_gen_mov_i64(cpu_vsrh(xT(ctx->opcode)), xh);
-        tcg_gen_mov_i64(cpu_vsrl(xT(ctx->opcode)), xl);
-
-        tcg_temp_free_i64(xh);
-        tcg_temp_free_i64(xl);
-    } else {
-        if ((DM(ctx->opcode) & 2) == 0) {
-            tcg_gen_mov_i64(cpu_vsrh(xT(ctx->opcode)), cpu_vsrh(xA(ctx->opcode)));
-        } else {
-            tcg_gen_mov_i64(cpu_vsrh(xT(ctx->opcode)), cpu_vsrl(xA(ctx->opcode)));
-        }
-        if ((DM(ctx->opcode) & 1) == 0) {
-            tcg_gen_mov_i64(cpu_vsrl(xT(ctx->opcode)), cpu_vsrh(xB(ctx->opcode)));
-        } else {
-            tcg_gen_mov_i64(cpu_vsrl(xT(ctx->opcode)), cpu_vsrl(xB(ctx->opcode)));
-        }
-    }
-}
-
-#define OP_ABS 1
-#define OP_NABS 2
-#define OP_NEG 3
-#define OP_CPSGN 4
-#define SGN_MASK_DP  0x8000000000000000ull
-#define SGN_MASK_SP 0x8000000080000000ull
-
-#define VSX_SCALAR_MOVE(name, op, sgn_mask)                       \
-static void glue(gen_, name)(DisasContext * ctx)                  \
-    {                                                             \
-        TCGv_i64 xb, sgm;                                         \
-        if (unlikely(!ctx->vsx_enabled)) {                        \
-            gen_exception(ctx, POWERPC_EXCP_VSXU);                \
-            return;                                               \
-        }                                                         \
-        xb = tcg_temp_new_i64();                                  \
-        sgm = tcg_temp_new_i64();                                 \
-        tcg_gen_mov_i64(xb, cpu_vsrh(xB(ctx->opcode)));           \
-        tcg_gen_movi_i64(sgm, sgn_mask);                          \
-        switch (op) {                                             \
-            case OP_ABS: {                                        \
-                tcg_gen_andc_i64(xb, xb, sgm);                    \
-                break;                                            \
-            }                                                     \
-            case OP_NABS: {                                       \
-                tcg_gen_or_i64(xb, xb, sgm);                      \
-                break;                                            \
-            }                                                     \
-            case OP_NEG: {                                        \
-                tcg_gen_xor_i64(xb, xb, sgm);                     \
-                break;                                            \
-            }                                                     \
-            case OP_CPSGN: {                                      \
-                TCGv_i64 xa = tcg_temp_new_i64();                 \
-                tcg_gen_mov_i64(xa, cpu_vsrh(xA(ctx->opcode)));   \
-                tcg_gen_and_i64(xa, xa, sgm);                     \
-                tcg_gen_andc_i64(xb, xb, sgm);                    \
-                tcg_gen_or_i64(xb, xb, xa);                       \
-                tcg_temp_free_i64(xa);                            \
-                break;                                            \
-            }                                                     \
-        }                                                         \
-        tcg_gen_mov_i64(cpu_vsrh(xT(ctx->opcode)), xb);           \
-        tcg_temp_free_i64(xb);                                    \
-        tcg_temp_free_i64(sgm);                                   \
-    }
-
-VSX_SCALAR_MOVE(xsabsdp, OP_ABS, SGN_MASK_DP)
-VSX_SCALAR_MOVE(xsnabsdp, OP_NABS, SGN_MASK_DP)
-VSX_SCALAR_MOVE(xsnegdp, OP_NEG, SGN_MASK_DP)
-VSX_SCALAR_MOVE(xscpsgndp, OP_CPSGN, SGN_MASK_DP)
-
-#define VSX_VECTOR_MOVE(name, op, sgn_mask)                      \
-static void glue(gen_, name)(DisasContext * ctx)                 \
-    {                                                            \
-        TCGv_i64 xbh, xbl, sgm;                                  \
-        if (unlikely(!ctx->vsx_enabled)) {                       \
-            gen_exception(ctx, POWERPC_EXCP_VSXU);               \
-            return;                                              \
-        }                                                        \
-        xbh = tcg_temp_new_i64();                                \
-        xbl = tcg_temp_new_i64();                                \
-        sgm = tcg_temp_new_i64();                                \
-        tcg_gen_mov_i64(xbh, cpu_vsrh(xB(ctx->opcode)));         \
-        tcg_gen_mov_i64(xbl, cpu_vsrl(xB(ctx->opcode)));         \
-        tcg_gen_movi_i64(sgm, sgn_mask);                         \
-        switch (op) {                                            \
-            case OP_ABS: {                                       \
-                tcg_gen_andc_i64(xbh, xbh, sgm);                 \
-                tcg_gen_andc_i64(xbl, xbl, sgm);                 \
-                break;                                           \
-            }                                                    \
-            case OP_NABS: {                                      \
-                tcg_gen_or_i64(xbh, xbh, sgm);                   \
-                tcg_gen_or_i64(xbl, xbl, sgm);                   \
-                break;                                           \
-            }                                                    \
-            case OP_NEG: {                                       \
-                tcg_gen_xor_i64(xbh, xbh, sgm);                  \
-                tcg_gen_xor_i64(xbl, xbl, sgm);                  \
-                break;                                           \
-            }                                                    \
-            case OP_CPSGN: {                                     \
-                TCGv_i64 xah = tcg_temp_new_i64();               \
-                TCGv_i64 xal = tcg_temp_new_i64();               \
-                tcg_gen_mov_i64(xah, cpu_vsrh(xA(ctx->opcode))); \
-                tcg_gen_mov_i64(xal, cpu_vsrl(xA(ctx->opcode))); \
-                tcg_gen_and_i64(xah, xah, sgm);                  \
-                tcg_gen_and_i64(xal, xal, sgm);                  \
-                tcg_gen_andc_i64(xbh, xbh, sgm);                 \
-                tcg_gen_andc_i64(xbl, xbl, sgm);                 \
-                tcg_gen_or_i64(xbh, xbh, xah);                   \
-                tcg_gen_or_i64(xbl, xbl, xal);                   \
-                tcg_temp_free_i64(xah);                          \
-                tcg_temp_free_i64(xal);                          \
-                break;                                           \
-            }                                                    \
-        }                                                        \
-        tcg_gen_mov_i64(cpu_vsrh(xT(ctx->opcode)), xbh);         \
-        tcg_gen_mov_i64(cpu_vsrl(xT(ctx->opcode)), xbl);         \
-        tcg_temp_free_i64(xbh);                                  \
-        tcg_temp_free_i64(xbl);                                  \
-        tcg_temp_free_i64(sgm);                                  \
-    }
-
-VSX_VECTOR_MOVE(xvabsdp, OP_ABS, SGN_MASK_DP)
-VSX_VECTOR_MOVE(xvnabsdp, OP_NABS, SGN_MASK_DP)
-VSX_VECTOR_MOVE(xvnegdp, OP_NEG, SGN_MASK_DP)
-VSX_VECTOR_MOVE(xvcpsgndp, OP_CPSGN, SGN_MASK_DP)
-VSX_VECTOR_MOVE(xvabssp, OP_ABS, SGN_MASK_SP)
-VSX_VECTOR_MOVE(xvnabssp, OP_NABS, SGN_MASK_SP)
-VSX_VECTOR_MOVE(xvnegsp, OP_NEG, SGN_MASK_SP)
-VSX_VECTOR_MOVE(xvcpsgnsp, OP_CPSGN, SGN_MASK_SP)
-
-#define GEN_VSX_HELPER_2(name, op1, op2, inval, type)                         \
-static void gen_##name(DisasContext * ctx)                                    \
-{                                                                             \
-    TCGv_i32 opc;                                                             \
-    if (unlikely(!ctx->vsx_enabled)) {                                        \
-        gen_exception(ctx, POWERPC_EXCP_VSXU);                                \
-        return;                                                               \
-    }                                                                         \
-    /* NIP cannot be restored if the memory exception comes from an helper */ \
-    gen_update_nip(ctx, ctx->nip - 4);                                        \
-    opc = tcg_const_i32(ctx->opcode);                                         \
-    gen_helper_##name(cpu_env, opc);                                          \
-    tcg_temp_free_i32(opc);                                                   \
-}
-
-#define GEN_VSX_HELPER_XT_XB_ENV(name, op1, op2, inval, type) \
-static void gen_##name(DisasContext * ctx)                    \
-{                                                             \
-    if (unlikely(!ctx->vsx_enabled)) {                        \
-        gen_exception(ctx, POWERPC_EXCP_VSXU);                \
-        return;                                               \
-    }                                                         \
-    /* NIP cannot be restored if the exception comes */       \
-    /* from a helper. */                                      \
-    gen_update_nip(ctx, ctx->nip - 4);                        \
-                                                              \
-    gen_helper_##name(cpu_vsrh(xT(ctx->opcode)), cpu_env,     \
-                      cpu_vsrh(xB(ctx->opcode)));             \
-}
-
-GEN_VSX_HELPER_2(xsadddp, 0x00, 0x04, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xssubdp, 0x00, 0x05, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xsmuldp, 0x00, 0x06, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xsdivdp, 0x00, 0x07, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xsredp, 0x14, 0x05, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xssqrtdp, 0x16, 0x04, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xsrsqrtedp, 0x14, 0x04, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xstdivdp, 0x14, 0x07, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xstsqrtdp, 0x14, 0x06, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xsmaddadp, 0x04, 0x04, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xsmaddmdp, 0x04, 0x05, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xsmsubadp, 0x04, 0x06, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xsmsubmdp, 0x04, 0x07, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xsnmaddadp, 0x04, 0x14, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xsnmaddmdp, 0x04, 0x15, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xsnmsubadp, 0x04, 0x16, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xsnmsubmdp, 0x04, 0x17, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xscmpodp, 0x0C, 0x05, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xscmpudp, 0x0C, 0x04, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xsmaxdp, 0x00, 0x14, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xsmindp, 0x00, 0x15, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xscvdpsp, 0x12, 0x10, 0, PPC2_VSX)
-GEN_VSX_HELPER_XT_XB_ENV(xscvdpspn, 0x16, 0x10, 0, PPC2_VSX207)
-GEN_VSX_HELPER_2(xscvspdp, 0x12, 0x14, 0, PPC2_VSX)
-GEN_VSX_HELPER_XT_XB_ENV(xscvspdpn, 0x16, 0x14, 0, PPC2_VSX207)
-GEN_VSX_HELPER_2(xscvdpsxds, 0x10, 0x15, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xscvdpsxws, 0x10, 0x05, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xscvdpuxds, 0x10, 0x14, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xscvdpuxws, 0x10, 0x04, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xscvsxddp, 0x10, 0x17, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xscvuxddp, 0x10, 0x16, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xsrdpi, 0x12, 0x04, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xsrdpic, 0x16, 0x06, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xsrdpim, 0x12, 0x07, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xsrdpip, 0x12, 0x06, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xsrdpiz, 0x12, 0x05, 0, PPC2_VSX)
-GEN_VSX_HELPER_XT_XB_ENV(xsrsp, 0x12, 0x11, 0, PPC2_VSX207)
-
-GEN_VSX_HELPER_2(xsaddsp, 0x00, 0x00, 0, PPC2_VSX207)
-GEN_VSX_HELPER_2(xssubsp, 0x00, 0x01, 0, PPC2_VSX207)
-GEN_VSX_HELPER_2(xsmulsp, 0x00, 0x02, 0, PPC2_VSX207)
-GEN_VSX_HELPER_2(xsdivsp, 0x00, 0x03, 0, PPC2_VSX207)
-GEN_VSX_HELPER_2(xsresp, 0x14, 0x01, 0, PPC2_VSX207)
-GEN_VSX_HELPER_2(xssqrtsp, 0x16, 0x00, 0, PPC2_VSX207)
-GEN_VSX_HELPER_2(xsrsqrtesp, 0x14, 0x00, 0, PPC2_VSX207)
-GEN_VSX_HELPER_2(xsmaddasp, 0x04, 0x00, 0, PPC2_VSX207)
-GEN_VSX_HELPER_2(xsmaddmsp, 0x04, 0x01, 0, PPC2_VSX207)
-GEN_VSX_HELPER_2(xsmsubasp, 0x04, 0x02, 0, PPC2_VSX207)
-GEN_VSX_HELPER_2(xsmsubmsp, 0x04, 0x03, 0, PPC2_VSX207)
-GEN_VSX_HELPER_2(xsnmaddasp, 0x04, 0x10, 0, PPC2_VSX207)
-GEN_VSX_HELPER_2(xsnmaddmsp, 0x04, 0x11, 0, PPC2_VSX207)
-GEN_VSX_HELPER_2(xsnmsubasp, 0x04, 0x12, 0, PPC2_VSX207)
-GEN_VSX_HELPER_2(xsnmsubmsp, 0x04, 0x13, 0, PPC2_VSX207)
-GEN_VSX_HELPER_2(xscvsxdsp, 0x10, 0x13, 0, PPC2_VSX207)
-GEN_VSX_HELPER_2(xscvuxdsp, 0x10, 0x12, 0, PPC2_VSX207)
-
-GEN_VSX_HELPER_2(xvadddp, 0x00, 0x0C, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvsubdp, 0x00, 0x0D, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvmuldp, 0x00, 0x0E, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvdivdp, 0x00, 0x0F, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvredp, 0x14, 0x0D, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvsqrtdp, 0x16, 0x0C, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvrsqrtedp, 0x14, 0x0C, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvtdivdp, 0x14, 0x0F, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvtsqrtdp, 0x14, 0x0E, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvmaddadp, 0x04, 0x0C, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvmaddmdp, 0x04, 0x0D, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvmsubadp, 0x04, 0x0E, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvmsubmdp, 0x04, 0x0F, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvnmaddadp, 0x04, 0x1C, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvnmaddmdp, 0x04, 0x1D, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvnmsubadp, 0x04, 0x1E, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvnmsubmdp, 0x04, 0x1F, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvmaxdp, 0x00, 0x1C, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvmindp, 0x00, 0x1D, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvcmpeqdp, 0x0C, 0x0C, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvcmpgtdp, 0x0C, 0x0D, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvcmpgedp, 0x0C, 0x0E, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvcvdpsp, 0x12, 0x18, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvcvdpsxds, 0x10, 0x1D, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvcvdpsxws, 0x10, 0x0D, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvcvdpuxds, 0x10, 0x1C, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvcvdpuxws, 0x10, 0x0C, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvcvsxddp, 0x10, 0x1F, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvcvuxddp, 0x10, 0x1E, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvcvsxwdp, 0x10, 0x0F, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvcvuxwdp, 0x10, 0x0E, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvrdpi, 0x12, 0x0C, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvrdpic, 0x16, 0x0E, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvrdpim, 0x12, 0x0F, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvrdpip, 0x12, 0x0E, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvrdpiz, 0x12, 0x0D, 0, PPC2_VSX)
-
-GEN_VSX_HELPER_2(xvaddsp, 0x00, 0x08, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvsubsp, 0x00, 0x09, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvmulsp, 0x00, 0x0A, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvdivsp, 0x00, 0x0B, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvresp, 0x14, 0x09, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvsqrtsp, 0x16, 0x08, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvrsqrtesp, 0x14, 0x08, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvtdivsp, 0x14, 0x0B, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvtsqrtsp, 0x14, 0x0A, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvmaddasp, 0x04, 0x08, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvmaddmsp, 0x04, 0x09, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvmsubasp, 0x04, 0x0A, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvmsubmsp, 0x04, 0x0B, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvnmaddasp, 0x04, 0x18, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvnmaddmsp, 0x04, 0x19, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvnmsubasp, 0x04, 0x1A, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvnmsubmsp, 0x04, 0x1B, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvmaxsp, 0x00, 0x18, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvminsp, 0x00, 0x19, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvcmpeqsp, 0x0C, 0x08, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvcmpgtsp, 0x0C, 0x09, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvcmpgesp, 0x0C, 0x0A, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvcvspdp, 0x12, 0x1C, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvcvspsxds, 0x10, 0x19, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvcvspsxws, 0x10, 0x09, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvcvspuxds, 0x10, 0x18, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvcvspuxws, 0x10, 0x08, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvcvsxdsp, 0x10, 0x1B, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvcvuxdsp, 0x10, 0x1A, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvcvsxwsp, 0x10, 0x0B, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvcvuxwsp, 0x10, 0x0A, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvrspi, 0x12, 0x08, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvrspic, 0x16, 0x0A, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvrspim, 0x12, 0x0B, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvrspip, 0x12, 0x0A, 0, PPC2_VSX)
-GEN_VSX_HELPER_2(xvrspiz, 0x12, 0x09, 0, PPC2_VSX)
-
-#define VSX_LOGICAL(name, tcg_op)                                    \
-static void glue(gen_, name)(DisasContext * ctx)                     \
-    {                                                                \
-        if (unlikely(!ctx->vsx_enabled)) {                           \
-            gen_exception(ctx, POWERPC_EXCP_VSXU);                   \
-            return;                                                  \
-        }                                                            \
-        tcg_op(cpu_vsrh(xT(ctx->opcode)), cpu_vsrh(xA(ctx->opcode)), \
-            cpu_vsrh(xB(ctx->opcode)));                              \
-        tcg_op(cpu_vsrl(xT(ctx->opcode)), cpu_vsrl(xA(ctx->opcode)), \
-            cpu_vsrl(xB(ctx->opcode)));                              \
-    }
-
-VSX_LOGICAL(xxland, tcg_gen_and_i64)
-VSX_LOGICAL(xxlandc, tcg_gen_andc_i64)
-VSX_LOGICAL(xxlor, tcg_gen_or_i64)
-VSX_LOGICAL(xxlxor, tcg_gen_xor_i64)
-VSX_LOGICAL(xxlnor, tcg_gen_nor_i64)
-VSX_LOGICAL(xxleqv, tcg_gen_eqv_i64)
-VSX_LOGICAL(xxlnand, tcg_gen_nand_i64)
-VSX_LOGICAL(xxlorc, tcg_gen_orc_i64)
-
-#define VSX_XXMRG(name, high)                               \
-static void glue(gen_, name)(DisasContext * ctx)            \
-    {                                                       \
-        TCGv_i64 a0, a1, b0, b1;                            \
-        if (unlikely(!ctx->vsx_enabled)) {                  \
-            gen_exception(ctx, POWERPC_EXCP_VSXU);          \
-            return;                                         \
-        }                                                   \
-        a0 = tcg_temp_new_i64();                            \
-        a1 = tcg_temp_new_i64();                            \
-        b0 = tcg_temp_new_i64();                            \
-        b1 = tcg_temp_new_i64();                            \
-        if (high) {                                         \
-            tcg_gen_mov_i64(a0, cpu_vsrh(xA(ctx->opcode))); \
-            tcg_gen_mov_i64(a1, cpu_vsrh(xA(ctx->opcode))); \
-            tcg_gen_mov_i64(b0, cpu_vsrh(xB(ctx->opcode))); \
-            tcg_gen_mov_i64(b1, cpu_vsrh(xB(ctx->opcode))); \
-        } else {                                            \
-            tcg_gen_mov_i64(a0, cpu_vsrl(xA(ctx->opcode))); \
-            tcg_gen_mov_i64(a1, cpu_vsrl(xA(ctx->opcode))); \
-            tcg_gen_mov_i64(b0, cpu_vsrl(xB(ctx->opcode))); \
-            tcg_gen_mov_i64(b1, cpu_vsrl(xB(ctx->opcode))); \
-        }                                                   \
-        tcg_gen_shri_i64(a0, a0, 32);                       \
-        tcg_gen_shri_i64(b0, b0, 32);                       \
-        tcg_gen_deposit_i64(cpu_vsrh(xT(ctx->opcode)),      \
-                            b0, a0, 32, 32);                \
-        tcg_gen_deposit_i64(cpu_vsrl(xT(ctx->opcode)),      \
-                            b1, a1, 32, 32);                \
-        tcg_temp_free_i64(a0);                              \
-        tcg_temp_free_i64(a1);                              \
-        tcg_temp_free_i64(b0);                              \
-        tcg_temp_free_i64(b1);                              \
-    }
-
-VSX_XXMRG(xxmrghw, 1)
-VSX_XXMRG(xxmrglw, 0)
-
-static void gen_xxsel(DisasContext * ctx)
-{
-    TCGv_i64 a, b, c;
-    if (unlikely(!ctx->vsx_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_VSXU);
-        return;
-    }
-    a = tcg_temp_new_i64();
-    b = tcg_temp_new_i64();
-    c = tcg_temp_new_i64();
-
-    tcg_gen_mov_i64(a, cpu_vsrh(xA(ctx->opcode)));
-    tcg_gen_mov_i64(b, cpu_vsrh(xB(ctx->opcode)));
-    tcg_gen_mov_i64(c, cpu_vsrh(xC(ctx->opcode)));
-
-    tcg_gen_and_i64(b, b, c);
-    tcg_gen_andc_i64(a, a, c);
-    tcg_gen_or_i64(cpu_vsrh(xT(ctx->opcode)), a, b);
-
-    tcg_gen_mov_i64(a, cpu_vsrl(xA(ctx->opcode)));
-    tcg_gen_mov_i64(b, cpu_vsrl(xB(ctx->opcode)));
-    tcg_gen_mov_i64(c, cpu_vsrl(xC(ctx->opcode)));
-
-    tcg_gen_and_i64(b, b, c);
-    tcg_gen_andc_i64(a, a, c);
-    tcg_gen_or_i64(cpu_vsrl(xT(ctx->opcode)), a, b);
-
-    tcg_temp_free_i64(a);
-    tcg_temp_free_i64(b);
-    tcg_temp_free_i64(c);
-}
-
-static void gen_xxspltw(DisasContext *ctx)
-{
-    TCGv_i64 b, b2;
-    TCGv_i64 vsr = (UIM(ctx->opcode) & 2) ?
-                   cpu_vsrl(xB(ctx->opcode)) :
-                   cpu_vsrh(xB(ctx->opcode));
-
-    if (unlikely(!ctx->vsx_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_VSXU);
-        return;
-    }
-
-    b = tcg_temp_new_i64();
-    b2 = tcg_temp_new_i64();
-
-    if (UIM(ctx->opcode) & 1) {
-        tcg_gen_ext32u_i64(b, vsr);
-    } else {
-        tcg_gen_shri_i64(b, vsr, 32);
-    }
-
-    tcg_gen_shli_i64(b2, b, 32);
-    tcg_gen_or_i64(cpu_vsrh(xT(ctx->opcode)), b, b2);
-    tcg_gen_mov_i64(cpu_vsrl(xT(ctx->opcode)), cpu_vsrh(xT(ctx->opcode)));
-
-    tcg_temp_free_i64(b);
-    tcg_temp_free_i64(b2);
-}
-
-static void gen_xxsldwi(DisasContext *ctx)
-{
-    TCGv_i64 xth, xtl;
-    if (unlikely(!ctx->vsx_enabled)) {
-        gen_exception(ctx, POWERPC_EXCP_VSXU);
-        return;
-    }
-    xth = tcg_temp_new_i64();
-    xtl = tcg_temp_new_i64();
-
-    switch (SHW(ctx->opcode)) {
-        case 0: {
-            tcg_gen_mov_i64(xth, cpu_vsrh(xA(ctx->opcode)));
-            tcg_gen_mov_i64(xtl, cpu_vsrl(xA(ctx->opcode)));
-            break;
-        }
-        case 1: {
-            TCGv_i64 t0 = tcg_temp_new_i64();
-            tcg_gen_mov_i64(xth, cpu_vsrh(xA(ctx->opcode)));
-            tcg_gen_shli_i64(xth, xth, 32);
-            tcg_gen_mov_i64(t0, cpu_vsrl(xA(ctx->opcode)));
-            tcg_gen_shri_i64(t0, t0, 32);
-            tcg_gen_or_i64(xth, xth, t0);
-            tcg_gen_mov_i64(xtl, cpu_vsrl(xA(ctx->opcode)));
-            tcg_gen_shli_i64(xtl, xtl, 32);
-            tcg_gen_mov_i64(t0, cpu_vsrh(xB(ctx->opcode)));
-            tcg_gen_shri_i64(t0, t0, 32);
-            tcg_gen_or_i64(xtl, xtl, t0);
-            tcg_temp_free_i64(t0);
-            break;
-        }
-        case 2: {
-            tcg_gen_mov_i64(xth, cpu_vsrl(xA(ctx->opcode)));
-            tcg_gen_mov_i64(xtl, cpu_vsrh(xB(ctx->opcode)));
-            break;
-        }
-        case 3: {
-            TCGv_i64 t0 = tcg_temp_new_i64();
-            tcg_gen_mov_i64(xth, cpu_vsrl(xA(ctx->opcode)));
-            tcg_gen_shli_i64(xth, xth, 32);
-            tcg_gen_mov_i64(t0, cpu_vsrh(xB(ctx->opcode)));
-            tcg_gen_shri_i64(t0, t0, 32);
-            tcg_gen_or_i64(xth, xth, t0);
-            tcg_gen_mov_i64(xtl, cpu_vsrh(xB(ctx->opcode)));
-            tcg_gen_shli_i64(xtl, xtl, 32);
-            tcg_gen_mov_i64(t0, cpu_vsrl(xB(ctx->opcode)));
-            tcg_gen_shri_i64(t0, t0, 32);
-            tcg_gen_or_i64(xtl, xtl, t0);
-            tcg_temp_free_i64(t0);
-            break;
-        }
-    }
-
-    tcg_gen_mov_i64(cpu_vsrh(xT(ctx->opcode)), xth);
-    tcg_gen_mov_i64(cpu_vsrl(xT(ctx->opcode)), xtl);
-
-    tcg_temp_free_i64(xth);
-    tcg_temp_free_i64(xtl);
-}
-
 #include "translate/dfp-impl.c"
 
 #include "translate/spe-impl.c"
@@ -7076,282 +6363,7 @@ GEN_MAC_HANDLER(mullhwu, 0x08, 0x0C),
 
 #include "translate/vmx-ops.c"
 
-GEN_HANDLER_E(lxsdx, 0x1F, 0x0C, 0x12, 0, PPC_NONE, PPC2_VSX),
-GEN_HANDLER_E(lxsiwax, 0x1F, 0x0C, 0x02, 0, PPC_NONE, PPC2_VSX207),
-GEN_HANDLER_E(lxsiwzx, 0x1F, 0x0C, 0x00, 0, PPC_NONE, PPC2_VSX207),
-GEN_HANDLER_E(lxsspx, 0x1F, 0x0C, 0x10, 0, PPC_NONE, PPC2_VSX207),
-GEN_HANDLER_E(lxvd2x, 0x1F, 0x0C, 0x1A, 0, PPC_NONE, PPC2_VSX),
-GEN_HANDLER_E(lxvdsx, 0x1F, 0x0C, 0x0A, 0, PPC_NONE, PPC2_VSX),
-GEN_HANDLER_E(lxvw4x, 0x1F, 0x0C, 0x18, 0, PPC_NONE, PPC2_VSX),
-
-GEN_HANDLER_E(stxsdx, 0x1F, 0xC, 0x16, 0, PPC_NONE, PPC2_VSX),
-GEN_HANDLER_E(stxsiwx, 0x1F, 0xC, 0x04, 0, PPC_NONE, PPC2_VSX207),
-GEN_HANDLER_E(stxsspx, 0x1F, 0xC, 0x14, 0, PPC_NONE, PPC2_VSX207),
-GEN_HANDLER_E(stxvd2x, 0x1F, 0xC, 0x1E, 0, PPC_NONE, PPC2_VSX),
-GEN_HANDLER_E(stxvw4x, 0x1F, 0xC, 0x1C, 0, PPC_NONE, PPC2_VSX),
-
-GEN_HANDLER_E(mfvsrwz, 0x1F, 0x13, 0x03, 0x0000F800, PPC_NONE, PPC2_VSX207),
-GEN_HANDLER_E(mtvsrwa, 0x1F, 0x13, 0x06, 0x0000F800, PPC_NONE, PPC2_VSX207),
-GEN_HANDLER_E(mtvsrwz, 0x1F, 0x13, 0x07, 0x0000F800, PPC_NONE, PPC2_VSX207),
-#if defined(TARGET_PPC64)
-GEN_HANDLER_E(mfvsrd, 0x1F, 0x13, 0x01, 0x0000F800, PPC_NONE, PPC2_VSX207),
-GEN_HANDLER_E(mtvsrd, 0x1F, 0x13, 0x05, 0x0000F800, PPC_NONE, PPC2_VSX207),
-#endif
-
-#undef GEN_XX2FORM
-#define GEN_XX2FORM(name, opc2, opc3, fl2)                           \
-GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 0, opc3, 0, PPC_NONE, fl2), \
-GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 1, opc3, 0, PPC_NONE, fl2)
-
-#undef GEN_XX3FORM
-#define GEN_XX3FORM(name, opc2, opc3, fl2)                           \
-GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 0, opc3, 0, PPC_NONE, fl2), \
-GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 1, opc3, 0, PPC_NONE, fl2), \
-GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 2, opc3, 0, PPC_NONE, fl2), \
-GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 3, opc3, 0, PPC_NONE, fl2)
-
-#undef GEN_XX2IFORM
-#define GEN_XX2IFORM(name, opc2, opc3, fl2)                           \
-GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 0, opc3, 1, PPC_NONE, fl2), \
-GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 1, opc3, 1, PPC_NONE, fl2), \
-GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 2, opc3, 1, PPC_NONE, fl2), \
-GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 3, opc3, 1, PPC_NONE, fl2)
-
-#undef GEN_XX3_RC_FORM
-#define GEN_XX3_RC_FORM(name, opc2, opc3, fl2)                          \
-GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 0x00, opc3 | 0x00, 0, PPC_NONE, fl2), \
-GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 0x01, opc3 | 0x00, 0, PPC_NONE, fl2), \
-GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 0x02, opc3 | 0x00, 0, PPC_NONE, fl2), \
-GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 0x03, opc3 | 0x00, 0, PPC_NONE, fl2), \
-GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 0x00, opc3 | 0x10, 0, PPC_NONE, fl2), \
-GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 0x01, opc3 | 0x10, 0, PPC_NONE, fl2), \
-GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 0x02, opc3 | 0x10, 0, PPC_NONE, fl2), \
-GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 0x03, opc3 | 0x10, 0, PPC_NONE, fl2)
-
-#undef GEN_XX3FORM_DM
-#define GEN_XX3FORM_DM(name, opc2, opc3) \
-GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x00, opc3|0x00, 0, PPC_NONE, PPC2_VSX),\
-GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x01, opc3|0x00, 0, PPC_NONE, PPC2_VSX),\
-GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x02, opc3|0x00, 0, PPC_NONE, PPC2_VSX),\
-GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x03, opc3|0x00, 0, PPC_NONE, PPC2_VSX),\
-GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x00, opc3|0x04, 0, PPC_NONE, PPC2_VSX),\
-GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x01, opc3|0x04, 0, PPC_NONE, PPC2_VSX),\
-GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x02, opc3|0x04, 0, PPC_NONE, PPC2_VSX),\
-GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x03, opc3|0x04, 0, PPC_NONE, PPC2_VSX),\
-GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x00, opc3|0x08, 0, PPC_NONE, PPC2_VSX),\
-GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x01, opc3|0x08, 0, PPC_NONE, PPC2_VSX),\
-GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x02, opc3|0x08, 0, PPC_NONE, PPC2_VSX),\
-GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x03, opc3|0x08, 0, PPC_NONE, PPC2_VSX),\
-GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x00, opc3|0x0C, 0, PPC_NONE, PPC2_VSX),\
-GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x01, opc3|0x0C, 0, PPC_NONE, PPC2_VSX),\
-GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x02, opc3|0x0C, 0, PPC_NONE, PPC2_VSX),\
-GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x03, opc3|0x0C, 0, PPC_NONE, PPC2_VSX)
-
-GEN_XX2FORM(xsabsdp, 0x12, 0x15, PPC2_VSX),
-GEN_XX2FORM(xsnabsdp, 0x12, 0x16, PPC2_VSX),
-GEN_XX2FORM(xsnegdp, 0x12, 0x17, PPC2_VSX),
-GEN_XX3FORM(xscpsgndp, 0x00, 0x16, PPC2_VSX),
-
-GEN_XX2FORM(xvabsdp, 0x12, 0x1D, PPC2_VSX),
-GEN_XX2FORM(xvnabsdp, 0x12, 0x1E, PPC2_VSX),
-GEN_XX2FORM(xvnegdp, 0x12, 0x1F, PPC2_VSX),
-GEN_XX3FORM(xvcpsgndp, 0x00, 0x1E, PPC2_VSX),
-GEN_XX2FORM(xvabssp, 0x12, 0x19, PPC2_VSX),
-GEN_XX2FORM(xvnabssp, 0x12, 0x1A, PPC2_VSX),
-GEN_XX2FORM(xvnegsp, 0x12, 0x1B, PPC2_VSX),
-GEN_XX3FORM(xvcpsgnsp, 0x00, 0x1A, PPC2_VSX),
-
-GEN_XX3FORM(xsadddp, 0x00, 0x04, PPC2_VSX),
-GEN_XX3FORM(xssubdp, 0x00, 0x05, PPC2_VSX),
-GEN_XX3FORM(xsmuldp, 0x00, 0x06, PPC2_VSX),
-GEN_XX3FORM(xsdivdp, 0x00, 0x07, PPC2_VSX),
-GEN_XX2FORM(xsredp,  0x14, 0x05, PPC2_VSX),
-GEN_XX2FORM(xssqrtdp,  0x16, 0x04, PPC2_VSX),
-GEN_XX2FORM(xsrsqrtedp,  0x14, 0x04, PPC2_VSX),
-GEN_XX3FORM(xstdivdp,  0x14, 0x07, PPC2_VSX),
-GEN_XX2FORM(xstsqrtdp,  0x14, 0x06, PPC2_VSX),
-GEN_XX3FORM(xsmaddadp, 0x04, 0x04, PPC2_VSX),
-GEN_XX3FORM(xsmaddmdp, 0x04, 0x05, PPC2_VSX),
-GEN_XX3FORM(xsmsubadp, 0x04, 0x06, PPC2_VSX),
-GEN_XX3FORM(xsmsubmdp, 0x04, 0x07, PPC2_VSX),
-GEN_XX3FORM(xsnmaddadp, 0x04, 0x14, PPC2_VSX),
-GEN_XX3FORM(xsnmaddmdp, 0x04, 0x15, PPC2_VSX),
-GEN_XX3FORM(xsnmsubadp, 0x04, 0x16, PPC2_VSX),
-GEN_XX3FORM(xsnmsubmdp, 0x04, 0x17, PPC2_VSX),
-GEN_XX2IFORM(xscmpodp,  0x0C, 0x05, PPC2_VSX),
-GEN_XX2IFORM(xscmpudp,  0x0C, 0x04, PPC2_VSX),
-GEN_XX3FORM(xsmaxdp, 0x00, 0x14, PPC2_VSX),
-GEN_XX3FORM(xsmindp, 0x00, 0x15, PPC2_VSX),
-GEN_XX2FORM(xscvdpsp, 0x12, 0x10, PPC2_VSX),
-GEN_XX2FORM(xscvdpspn, 0x16, 0x10, PPC2_VSX207),
-GEN_XX2FORM(xscvspdp, 0x12, 0x14, PPC2_VSX),
-GEN_XX2FORM(xscvspdpn, 0x16, 0x14, PPC2_VSX207),
-GEN_XX2FORM(xscvdpsxds, 0x10, 0x15, PPC2_VSX),
-GEN_XX2FORM(xscvdpsxws, 0x10, 0x05, PPC2_VSX),
-GEN_XX2FORM(xscvdpuxds, 0x10, 0x14, PPC2_VSX),
-GEN_XX2FORM(xscvdpuxws, 0x10, 0x04, PPC2_VSX),
-GEN_XX2FORM(xscvsxddp, 0x10, 0x17, PPC2_VSX),
-GEN_XX2FORM(xscvuxddp, 0x10, 0x16, PPC2_VSX),
-GEN_XX2FORM(xsrdpi, 0x12, 0x04, PPC2_VSX),
-GEN_XX2FORM(xsrdpic, 0x16, 0x06, PPC2_VSX),
-GEN_XX2FORM(xsrdpim, 0x12, 0x07, PPC2_VSX),
-GEN_XX2FORM(xsrdpip, 0x12, 0x06, PPC2_VSX),
-GEN_XX2FORM(xsrdpiz, 0x12, 0x05, PPC2_VSX),
-
-GEN_XX3FORM(xsaddsp, 0x00, 0x00, PPC2_VSX207),
-GEN_XX3FORM(xssubsp, 0x00, 0x01, PPC2_VSX207),
-GEN_XX3FORM(xsmulsp, 0x00, 0x02, PPC2_VSX207),
-GEN_XX3FORM(xsdivsp, 0x00, 0x03, PPC2_VSX207),
-GEN_XX2FORM(xsresp,  0x14, 0x01, PPC2_VSX207),
-GEN_XX2FORM(xsrsp, 0x12, 0x11, PPC2_VSX207),
-GEN_XX2FORM(xssqrtsp,  0x16, 0x00, PPC2_VSX207),
-GEN_XX2FORM(xsrsqrtesp,  0x14, 0x00, PPC2_VSX207),
-GEN_XX3FORM(xsmaddasp, 0x04, 0x00, PPC2_VSX207),
-GEN_XX3FORM(xsmaddmsp, 0x04, 0x01, PPC2_VSX207),
-GEN_XX3FORM(xsmsubasp, 0x04, 0x02, PPC2_VSX207),
-GEN_XX3FORM(xsmsubmsp, 0x04, 0x03, PPC2_VSX207),
-GEN_XX3FORM(xsnmaddasp, 0x04, 0x10, PPC2_VSX207),
-GEN_XX3FORM(xsnmaddmsp, 0x04, 0x11, PPC2_VSX207),
-GEN_XX3FORM(xsnmsubasp, 0x04, 0x12, PPC2_VSX207),
-GEN_XX3FORM(xsnmsubmsp, 0x04, 0x13, PPC2_VSX207),
-GEN_XX2FORM(xscvsxdsp, 0x10, 0x13, PPC2_VSX207),
-GEN_XX2FORM(xscvuxdsp, 0x10, 0x12, PPC2_VSX207),
-
-GEN_XX3FORM(xvadddp, 0x00, 0x0C, PPC2_VSX),
-GEN_XX3FORM(xvsubdp, 0x00, 0x0D, PPC2_VSX),
-GEN_XX3FORM(xvmuldp, 0x00, 0x0E, PPC2_VSX),
-GEN_XX3FORM(xvdivdp, 0x00, 0x0F, PPC2_VSX),
-GEN_XX2FORM(xvredp,  0x14, 0x0D, PPC2_VSX),
-GEN_XX2FORM(xvsqrtdp,  0x16, 0x0C, PPC2_VSX),
-GEN_XX2FORM(xvrsqrtedp,  0x14, 0x0C, PPC2_VSX),
-GEN_XX3FORM(xvtdivdp, 0x14, 0x0F, PPC2_VSX),
-GEN_XX2FORM(xvtsqrtdp, 0x14, 0x0E, PPC2_VSX),
-GEN_XX3FORM(xvmaddadp, 0x04, 0x0C, PPC2_VSX),
-GEN_XX3FORM(xvmaddmdp, 0x04, 0x0D, PPC2_VSX),
-GEN_XX3FORM(xvmsubadp, 0x04, 0x0E, PPC2_VSX),
-GEN_XX3FORM(xvmsubmdp, 0x04, 0x0F, PPC2_VSX),
-GEN_XX3FORM(xvnmaddadp, 0x04, 0x1C, PPC2_VSX),
-GEN_XX3FORM(xvnmaddmdp, 0x04, 0x1D, PPC2_VSX),
-GEN_XX3FORM(xvnmsubadp, 0x04, 0x1E, PPC2_VSX),
-GEN_XX3FORM(xvnmsubmdp, 0x04, 0x1F, PPC2_VSX),
-GEN_XX3FORM(xvmaxdp, 0x00, 0x1C, PPC2_VSX),
-GEN_XX3FORM(xvmindp, 0x00, 0x1D, PPC2_VSX),
-GEN_XX3_RC_FORM(xvcmpeqdp, 0x0C, 0x0C, PPC2_VSX),
-GEN_XX3_RC_FORM(xvcmpgtdp, 0x0C, 0x0D, PPC2_VSX),
-GEN_XX3_RC_FORM(xvcmpgedp, 0x0C, 0x0E, PPC2_VSX),
-GEN_XX2FORM(xvcvdpsp, 0x12, 0x18, PPC2_VSX),
-GEN_XX2FORM(xvcvdpsxds, 0x10, 0x1D, PPC2_VSX),
-GEN_XX2FORM(xvcvdpsxws, 0x10, 0x0D, PPC2_VSX),
-GEN_XX2FORM(xvcvdpuxds, 0x10, 0x1C, PPC2_VSX),
-GEN_XX2FORM(xvcvdpuxws, 0x10, 0x0C, PPC2_VSX),
-GEN_XX2FORM(xvcvsxddp, 0x10, 0x1F, PPC2_VSX),
-GEN_XX2FORM(xvcvuxddp, 0x10, 0x1E, PPC2_VSX),
-GEN_XX2FORM(xvcvsxwdp, 0x10, 0x0F, PPC2_VSX),
-GEN_XX2FORM(xvcvuxwdp, 0x10, 0x0E, PPC2_VSX),
-GEN_XX2FORM(xvrdpi, 0x12, 0x0C, PPC2_VSX),
-GEN_XX2FORM(xvrdpic, 0x16, 0x0E, PPC2_VSX),
-GEN_XX2FORM(xvrdpim, 0x12, 0x0F, PPC2_VSX),
-GEN_XX2FORM(xvrdpip, 0x12, 0x0E, PPC2_VSX),
-GEN_XX2FORM(xvrdpiz, 0x12, 0x0D, PPC2_VSX),
-
-GEN_XX3FORM(xvaddsp, 0x00, 0x08, PPC2_VSX),
-GEN_XX3FORM(xvsubsp, 0x00, 0x09, PPC2_VSX),
-GEN_XX3FORM(xvmulsp, 0x00, 0x0A, PPC2_VSX),
-GEN_XX3FORM(xvdivsp, 0x00, 0x0B, PPC2_VSX),
-GEN_XX2FORM(xvresp, 0x14, 0x09, PPC2_VSX),
-GEN_XX2FORM(xvsqrtsp, 0x16, 0x08, PPC2_VSX),
-GEN_XX2FORM(xvrsqrtesp, 0x14, 0x08, PPC2_VSX),
-GEN_XX3FORM(xvtdivsp, 0x14, 0x0B, PPC2_VSX),
-GEN_XX2FORM(xvtsqrtsp, 0x14, 0x0A, PPC2_VSX),
-GEN_XX3FORM(xvmaddasp, 0x04, 0x08, PPC2_VSX),
-GEN_XX3FORM(xvmaddmsp, 0x04, 0x09, PPC2_VSX),
-GEN_XX3FORM(xvmsubasp, 0x04, 0x0A, PPC2_VSX),
-GEN_XX3FORM(xvmsubmsp, 0x04, 0x0B, PPC2_VSX),
-GEN_XX3FORM(xvnmaddasp, 0x04, 0x18, PPC2_VSX),
-GEN_XX3FORM(xvnmaddmsp, 0x04, 0x19, PPC2_VSX),
-GEN_XX3FORM(xvnmsubasp, 0x04, 0x1A, PPC2_VSX),
-GEN_XX3FORM(xvnmsubmsp, 0x04, 0x1B, PPC2_VSX),
-GEN_XX3FORM(xvmaxsp, 0x00, 0x18, PPC2_VSX),
-GEN_XX3FORM(xvminsp, 0x00, 0x19, PPC2_VSX),
-GEN_XX3_RC_FORM(xvcmpeqsp, 0x0C, 0x08, PPC2_VSX),
-GEN_XX3_RC_FORM(xvcmpgtsp, 0x0C, 0x09, PPC2_VSX),
-GEN_XX3_RC_FORM(xvcmpgesp, 0x0C, 0x0A, PPC2_VSX),
-GEN_XX2FORM(xvcvspdp, 0x12, 0x1C, PPC2_VSX),
-GEN_XX2FORM(xvcvspsxds, 0x10, 0x19, PPC2_VSX),
-GEN_XX2FORM(xvcvspsxws, 0x10, 0x09, PPC2_VSX),
-GEN_XX2FORM(xvcvspuxds, 0x10, 0x18, PPC2_VSX),
-GEN_XX2FORM(xvcvspuxws, 0x10, 0x08, PPC2_VSX),
-GEN_XX2FORM(xvcvsxdsp, 0x10, 0x1B, PPC2_VSX),
-GEN_XX2FORM(xvcvuxdsp, 0x10, 0x1A, PPC2_VSX),
-GEN_XX2FORM(xvcvsxwsp, 0x10, 0x0B, PPC2_VSX),
-GEN_XX2FORM(xvcvuxwsp, 0x10, 0x0A, PPC2_VSX),
-GEN_XX2FORM(xvrspi, 0x12, 0x08, PPC2_VSX),
-GEN_XX2FORM(xvrspic, 0x16, 0x0A, PPC2_VSX),
-GEN_XX2FORM(xvrspim, 0x12, 0x0B, PPC2_VSX),
-GEN_XX2FORM(xvrspip, 0x12, 0x0A, PPC2_VSX),
-GEN_XX2FORM(xvrspiz, 0x12, 0x09, PPC2_VSX),
-
-#undef VSX_LOGICAL
-#define VSX_LOGICAL(name, opc2, opc3, fl2) \
-GEN_XX3FORM(name, opc2, opc3, fl2)
-
-VSX_LOGICAL(xxland, 0x8, 0x10, PPC2_VSX),
-VSX_LOGICAL(xxlandc, 0x8, 0x11, PPC2_VSX),
-VSX_LOGICAL(xxlor, 0x8, 0x12, PPC2_VSX),
-VSX_LOGICAL(xxlxor, 0x8, 0x13, PPC2_VSX),
-VSX_LOGICAL(xxlnor, 0x8, 0x14, PPC2_VSX),
-VSX_LOGICAL(xxleqv, 0x8, 0x17, PPC2_VSX207),
-VSX_LOGICAL(xxlnand, 0x8, 0x16, PPC2_VSX207),
-VSX_LOGICAL(xxlorc, 0x8, 0x15, PPC2_VSX207),
-GEN_XX3FORM(xxmrghw, 0x08, 0x02, PPC2_VSX),
-GEN_XX3FORM(xxmrglw, 0x08, 0x06, PPC2_VSX),
-GEN_XX2FORM(xxspltw, 0x08, 0x0A, PPC2_VSX),
-GEN_XX3FORM_DM(xxsldwi, 0x08, 0x00),
-
-#define GEN_XXSEL_ROW(opc3) \
-GEN_HANDLER2_E(xxsel, "xxsel", 0x3C, 0x18, opc3, 0, PPC_NONE, PPC2_VSX), \
-GEN_HANDLER2_E(xxsel, "xxsel", 0x3C, 0x19, opc3, 0, PPC_NONE, PPC2_VSX), \
-GEN_HANDLER2_E(xxsel, "xxsel", 0x3C, 0x1A, opc3, 0, PPC_NONE, PPC2_VSX), \
-GEN_HANDLER2_E(xxsel, "xxsel", 0x3C, 0x1B, opc3, 0, PPC_NONE, PPC2_VSX), \
-GEN_HANDLER2_E(xxsel, "xxsel", 0x3C, 0x1C, opc3, 0, PPC_NONE, PPC2_VSX), \
-GEN_HANDLER2_E(xxsel, "xxsel", 0x3C, 0x1D, opc3, 0, PPC_NONE, PPC2_VSX), \
-GEN_HANDLER2_E(xxsel, "xxsel", 0x3C, 0x1E, opc3, 0, PPC_NONE, PPC2_VSX), \
-GEN_HANDLER2_E(xxsel, "xxsel", 0x3C, 0x1F, opc3, 0, PPC_NONE, PPC2_VSX), \
-
-GEN_XXSEL_ROW(0x00)
-GEN_XXSEL_ROW(0x01)
-GEN_XXSEL_ROW(0x02)
-GEN_XXSEL_ROW(0x03)
-GEN_XXSEL_ROW(0x04)
-GEN_XXSEL_ROW(0x05)
-GEN_XXSEL_ROW(0x06)
-GEN_XXSEL_ROW(0x07)
-GEN_XXSEL_ROW(0x08)
-GEN_XXSEL_ROW(0x09)
-GEN_XXSEL_ROW(0x0A)
-GEN_XXSEL_ROW(0x0B)
-GEN_XXSEL_ROW(0x0C)
-GEN_XXSEL_ROW(0x0D)
-GEN_XXSEL_ROW(0x0E)
-GEN_XXSEL_ROW(0x0F)
-GEN_XXSEL_ROW(0x10)
-GEN_XXSEL_ROW(0x11)
-GEN_XXSEL_ROW(0x12)
-GEN_XXSEL_ROW(0x13)
-GEN_XXSEL_ROW(0x14)
-GEN_XXSEL_ROW(0x15)
-GEN_XXSEL_ROW(0x16)
-GEN_XXSEL_ROW(0x17)
-GEN_XXSEL_ROW(0x18)
-GEN_XXSEL_ROW(0x19)
-GEN_XXSEL_ROW(0x1A)
-GEN_XXSEL_ROW(0x1B)
-GEN_XXSEL_ROW(0x1C)
-GEN_XXSEL_ROW(0x1D)
-GEN_XXSEL_ROW(0x1E)
-GEN_XXSEL_ROW(0x1F)
-
-GEN_XX3FORM_DM(xxpermdi, 0x08, 0x01),
+#include "translate/vsx-ops.c"
 
 #include "translate/dfp-ops.c"
 
diff --git a/target-ppc/translate/vsx-impl.c b/target-ppc/translate/vsx-impl.c
new file mode 100644
index 0000000..7361c47
--- /dev/null
+++ b/target-ppc/translate/vsx-impl.c
@@ -0,0 +1,721 @@
+/***                           VSX extension                               ***/
+
+static inline TCGv_i64 cpu_vsrh(int n)
+{
+    if (n < 32) {
+        return cpu_fpr[n];
+    } else {
+        return cpu_avrh[n-32];
+    }
+}
+
+static inline TCGv_i64 cpu_vsrl(int n)
+{
+    if (n < 32) {
+        return cpu_vsr[n];
+    } else {
+        return cpu_avrl[n-32];
+    }
+}
+
+#define VSX_LOAD_SCALAR(name, operation)                      \
+static void gen_##name(DisasContext *ctx)                     \
+{                                                             \
+    TCGv EA;                                                  \
+    if (unlikely(!ctx->vsx_enabled)) {                        \
+        gen_exception(ctx, POWERPC_EXCP_VSXU);                \
+        return;                                               \
+    }                                                         \
+    gen_set_access_type(ctx, ACCESS_INT);                     \
+    EA = tcg_temp_new();                                      \
+    gen_addr_reg_index(ctx, EA);                              \
+    gen_qemu_##operation(ctx, cpu_vsrh(xT(ctx->opcode)), EA); \
+    /* NOTE: cpu_vsrl is undefined */                         \
+    tcg_temp_free(EA);                                        \
+}
+
+VSX_LOAD_SCALAR(lxsdx, ld64)
+VSX_LOAD_SCALAR(lxsiwax, ld32s_i64)
+VSX_LOAD_SCALAR(lxsiwzx, ld32u_i64)
+VSX_LOAD_SCALAR(lxsspx, ld32fs)
+
+static void gen_lxvd2x(DisasContext *ctx)
+{
+    TCGv EA;
+    if (unlikely(!ctx->vsx_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_VSXU);
+        return;
+    }
+    gen_set_access_type(ctx, ACCESS_INT);
+    EA = tcg_temp_new();
+    gen_addr_reg_index(ctx, EA);
+    gen_qemu_ld64(ctx, cpu_vsrh(xT(ctx->opcode)), EA);
+    tcg_gen_addi_tl(EA, EA, 8);
+    gen_qemu_ld64(ctx, cpu_vsrl(xT(ctx->opcode)), EA);
+    tcg_temp_free(EA);
+}
+
+static void gen_lxvdsx(DisasContext *ctx)
+{
+    TCGv EA;
+    if (unlikely(!ctx->vsx_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_VSXU);
+        return;
+    }
+    gen_set_access_type(ctx, ACCESS_INT);
+    EA = tcg_temp_new();
+    gen_addr_reg_index(ctx, EA);
+    gen_qemu_ld64(ctx, cpu_vsrh(xT(ctx->opcode)), EA);
+    tcg_gen_mov_i64(cpu_vsrl(xT(ctx->opcode)), cpu_vsrh(xT(ctx->opcode)));
+    tcg_temp_free(EA);
+}
+
+static void gen_lxvw4x(DisasContext *ctx)
+{
+    TCGv EA;
+    TCGv_i64 tmp;
+    TCGv_i64 xth = cpu_vsrh(xT(ctx->opcode));
+    TCGv_i64 xtl = cpu_vsrl(xT(ctx->opcode));
+    if (unlikely(!ctx->vsx_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_VSXU);
+        return;
+    }
+    gen_set_access_type(ctx, ACCESS_INT);
+    EA = tcg_temp_new();
+    tmp = tcg_temp_new_i64();
+
+    gen_addr_reg_index(ctx, EA);
+    gen_qemu_ld32u_i64(ctx, tmp, EA);
+    tcg_gen_addi_tl(EA, EA, 4);
+    gen_qemu_ld32u_i64(ctx, xth, EA);
+    tcg_gen_deposit_i64(xth, xth, tmp, 32, 32);
+
+    tcg_gen_addi_tl(EA, EA, 4);
+    gen_qemu_ld32u_i64(ctx, tmp, EA);
+    tcg_gen_addi_tl(EA, EA, 4);
+    gen_qemu_ld32u_i64(ctx, xtl, EA);
+    tcg_gen_deposit_i64(xtl, xtl, tmp, 32, 32);
+
+    tcg_temp_free(EA);
+    tcg_temp_free_i64(tmp);
+}
+
+#define VSX_STORE_SCALAR(name, operation)                     \
+static void gen_##name(DisasContext *ctx)                     \
+{                                                             \
+    TCGv EA;                                                  \
+    if (unlikely(!ctx->vsx_enabled)) {                        \
+        gen_exception(ctx, POWERPC_EXCP_VSXU);                \
+        return;                                               \
+    }                                                         \
+    gen_set_access_type(ctx, ACCESS_INT);                     \
+    EA = tcg_temp_new();                                      \
+    gen_addr_reg_index(ctx, EA);                              \
+    gen_qemu_##operation(ctx, cpu_vsrh(xS(ctx->opcode)), EA); \
+    tcg_temp_free(EA);                                        \
+}
+
+VSX_STORE_SCALAR(stxsdx, st64)
+VSX_STORE_SCALAR(stxsiwx, st32_i64)
+VSX_STORE_SCALAR(stxsspx, st32fs)
+
+static void gen_stxvd2x(DisasContext *ctx)
+{
+    TCGv EA;
+    if (unlikely(!ctx->vsx_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_VSXU);
+        return;
+    }
+    gen_set_access_type(ctx, ACCESS_INT);
+    EA = tcg_temp_new();
+    gen_addr_reg_index(ctx, EA);
+    gen_qemu_st64(ctx, cpu_vsrh(xS(ctx->opcode)), EA);
+    tcg_gen_addi_tl(EA, EA, 8);
+    gen_qemu_st64(ctx, cpu_vsrl(xS(ctx->opcode)), EA);
+    tcg_temp_free(EA);
+}
+
+static void gen_stxvw4x(DisasContext *ctx)
+{
+    TCGv_i64 tmp;
+    TCGv EA;
+    if (unlikely(!ctx->vsx_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_VSXU);
+        return;
+    }
+    gen_set_access_type(ctx, ACCESS_INT);
+    EA = tcg_temp_new();
+    gen_addr_reg_index(ctx, EA);
+    tmp = tcg_temp_new_i64();
+
+    tcg_gen_shri_i64(tmp, cpu_vsrh(xS(ctx->opcode)), 32);
+    gen_qemu_st32_i64(ctx, tmp, EA);
+    tcg_gen_addi_tl(EA, EA, 4);
+    gen_qemu_st32_i64(ctx, cpu_vsrh(xS(ctx->opcode)), EA);
+
+    tcg_gen_shri_i64(tmp, cpu_vsrl(xS(ctx->opcode)), 32);
+    tcg_gen_addi_tl(EA, EA, 4);
+    gen_qemu_st32_i64(ctx, tmp, EA);
+    tcg_gen_addi_tl(EA, EA, 4);
+    gen_qemu_st32_i64(ctx, cpu_vsrl(xS(ctx->opcode)), EA);
+
+    tcg_temp_free(EA);
+    tcg_temp_free_i64(tmp);
+}
+
+#define MV_VSRW(name, tcgop1, tcgop2, target, source)           \
+static void gen_##name(DisasContext *ctx)                       \
+{                                                               \
+    if (xS(ctx->opcode) < 32) {                                 \
+        if (unlikely(!ctx->fpu_enabled)) {                      \
+            gen_exception(ctx, POWERPC_EXCP_FPU);               \
+            return;                                             \
+        }                                                       \
+    } else {                                                    \
+        if (unlikely(!ctx->altivec_enabled)) {                  \
+            gen_exception(ctx, POWERPC_EXCP_VPU);               \
+            return;                                             \
+        }                                                       \
+    }                                                           \
+    TCGv_i64 tmp = tcg_temp_new_i64();                          \
+    tcg_gen_##tcgop1(tmp, source);                              \
+    tcg_gen_##tcgop2(target, tmp);                              \
+    tcg_temp_free_i64(tmp);                                     \
+}
+
+
+MV_VSRW(mfvsrwz, ext32u_i64, trunc_i64_tl, cpu_gpr[rA(ctx->opcode)], \
+        cpu_vsrh(xS(ctx->opcode)))
+MV_VSRW(mtvsrwa, extu_tl_i64, ext32s_i64, cpu_vsrh(xT(ctx->opcode)), \
+        cpu_gpr[rA(ctx->opcode)])
+MV_VSRW(mtvsrwz, extu_tl_i64, ext32u_i64, cpu_vsrh(xT(ctx->opcode)), \
+        cpu_gpr[rA(ctx->opcode)])
+
+#if defined(TARGET_PPC64)
+#define MV_VSRD(name, target, source)                           \
+static void gen_##name(DisasContext *ctx)                       \
+{                                                               \
+    if (xS(ctx->opcode) < 32) {                                 \
+        if (unlikely(!ctx->fpu_enabled)) {                      \
+            gen_exception(ctx, POWERPC_EXCP_FPU);               \
+            return;                                             \
+        }                                                       \
+    } else {                                                    \
+        if (unlikely(!ctx->altivec_enabled)) {                  \
+            gen_exception(ctx, POWERPC_EXCP_VPU);               \
+            return;                                             \
+        }                                                       \
+    }                                                           \
+    tcg_gen_mov_i64(target, source);                            \
+}
+
+MV_VSRD(mfvsrd, cpu_gpr[rA(ctx->opcode)], cpu_vsrh(xS(ctx->opcode)))
+MV_VSRD(mtvsrd, cpu_vsrh(xT(ctx->opcode)), cpu_gpr[rA(ctx->opcode)])
+
+#endif
+
+static void gen_xxpermdi(DisasContext *ctx)
+{
+    if (unlikely(!ctx->vsx_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_VSXU);
+        return;
+    }
+
+    if (unlikely((xT(ctx->opcode) == xA(ctx->opcode)) ||
+                 (xT(ctx->opcode) == xB(ctx->opcode)))) {
+        TCGv_i64 xh, xl;
+
+        xh = tcg_temp_new_i64();
+        xl = tcg_temp_new_i64();
+
+        if ((DM(ctx->opcode) & 2) == 0) {
+            tcg_gen_mov_i64(xh, cpu_vsrh(xA(ctx->opcode)));
+        } else {
+            tcg_gen_mov_i64(xh, cpu_vsrl(xA(ctx->opcode)));
+        }
+        if ((DM(ctx->opcode) & 1) == 0) {
+            tcg_gen_mov_i64(xl, cpu_vsrh(xB(ctx->opcode)));
+        } else {
+            tcg_gen_mov_i64(xl, cpu_vsrl(xB(ctx->opcode)));
+        }
+
+        tcg_gen_mov_i64(cpu_vsrh(xT(ctx->opcode)), xh);
+        tcg_gen_mov_i64(cpu_vsrl(xT(ctx->opcode)), xl);
+
+        tcg_temp_free_i64(xh);
+        tcg_temp_free_i64(xl);
+    } else {
+        if ((DM(ctx->opcode) & 2) == 0) {
+            tcg_gen_mov_i64(cpu_vsrh(xT(ctx->opcode)), cpu_vsrh(xA(ctx->opcode)));
+        } else {
+            tcg_gen_mov_i64(cpu_vsrh(xT(ctx->opcode)), cpu_vsrl(xA(ctx->opcode)));
+        }
+        if ((DM(ctx->opcode) & 1) == 0) {
+            tcg_gen_mov_i64(cpu_vsrl(xT(ctx->opcode)), cpu_vsrh(xB(ctx->opcode)));
+        } else {
+            tcg_gen_mov_i64(cpu_vsrl(xT(ctx->opcode)), cpu_vsrl(xB(ctx->opcode)));
+        }
+    }
+}
+
+#define OP_ABS 1
+#define OP_NABS 2
+#define OP_NEG 3
+#define OP_CPSGN 4
+#define SGN_MASK_DP  0x8000000000000000ull
+#define SGN_MASK_SP 0x8000000080000000ull
+
+#define VSX_SCALAR_MOVE(name, op, sgn_mask)                       \
+static void glue(gen_, name)(DisasContext * ctx)                  \
+    {                                                             \
+        TCGv_i64 xb, sgm;                                         \
+        if (unlikely(!ctx->vsx_enabled)) {                        \
+            gen_exception(ctx, POWERPC_EXCP_VSXU);                \
+            return;                                               \
+        }                                                         \
+        xb = tcg_temp_new_i64();                                  \
+        sgm = tcg_temp_new_i64();                                 \
+        tcg_gen_mov_i64(xb, cpu_vsrh(xB(ctx->opcode)));           \
+        tcg_gen_movi_i64(sgm, sgn_mask);                          \
+        switch (op) {                                             \
+            case OP_ABS: {                                        \
+                tcg_gen_andc_i64(xb, xb, sgm);                    \
+                break;                                            \
+            }                                                     \
+            case OP_NABS: {                                       \
+                tcg_gen_or_i64(xb, xb, sgm);                      \
+                break;                                            \
+            }                                                     \
+            case OP_NEG: {                                        \
+                tcg_gen_xor_i64(xb, xb, sgm);                     \
+                break;                                            \
+            }                                                     \
+            case OP_CPSGN: {                                      \
+                TCGv_i64 xa = tcg_temp_new_i64();                 \
+                tcg_gen_mov_i64(xa, cpu_vsrh(xA(ctx->opcode)));   \
+                tcg_gen_and_i64(xa, xa, sgm);                     \
+                tcg_gen_andc_i64(xb, xb, sgm);                    \
+                tcg_gen_or_i64(xb, xb, xa);                       \
+                tcg_temp_free_i64(xa);                            \
+                break;                                            \
+            }                                                     \
+        }                                                         \
+        tcg_gen_mov_i64(cpu_vsrh(xT(ctx->opcode)), xb);           \
+        tcg_temp_free_i64(xb);                                    \
+        tcg_temp_free_i64(sgm);                                   \
+    }
+
+VSX_SCALAR_MOVE(xsabsdp, OP_ABS, SGN_MASK_DP)
+VSX_SCALAR_MOVE(xsnabsdp, OP_NABS, SGN_MASK_DP)
+VSX_SCALAR_MOVE(xsnegdp, OP_NEG, SGN_MASK_DP)
+VSX_SCALAR_MOVE(xscpsgndp, OP_CPSGN, SGN_MASK_DP)
+
+#define VSX_VECTOR_MOVE(name, op, sgn_mask)                      \
+static void glue(gen_, name)(DisasContext * ctx)                 \
+    {                                                            \
+        TCGv_i64 xbh, xbl, sgm;                                  \
+        if (unlikely(!ctx->vsx_enabled)) {                       \
+            gen_exception(ctx, POWERPC_EXCP_VSXU);               \
+            return;                                              \
+        }                                                        \
+        xbh = tcg_temp_new_i64();                                \
+        xbl = tcg_temp_new_i64();                                \
+        sgm = tcg_temp_new_i64();                                \
+        tcg_gen_mov_i64(xbh, cpu_vsrh(xB(ctx->opcode)));         \
+        tcg_gen_mov_i64(xbl, cpu_vsrl(xB(ctx->opcode)));         \
+        tcg_gen_movi_i64(sgm, sgn_mask);                         \
+        switch (op) {                                            \
+            case OP_ABS: {                                       \
+                tcg_gen_andc_i64(xbh, xbh, sgm);                 \
+                tcg_gen_andc_i64(xbl, xbl, sgm);                 \
+                break;                                           \
+            }                                                    \
+            case OP_NABS: {                                      \
+                tcg_gen_or_i64(xbh, xbh, sgm);                   \
+                tcg_gen_or_i64(xbl, xbl, sgm);                   \
+                break;                                           \
+            }                                                    \
+            case OP_NEG: {                                       \
+                tcg_gen_xor_i64(xbh, xbh, sgm);                  \
+                tcg_gen_xor_i64(xbl, xbl, sgm);                  \
+                break;                                           \
+            }                                                    \
+            case OP_CPSGN: {                                     \
+                TCGv_i64 xah = tcg_temp_new_i64();               \
+                TCGv_i64 xal = tcg_temp_new_i64();               \
+                tcg_gen_mov_i64(xah, cpu_vsrh(xA(ctx->opcode))); \
+                tcg_gen_mov_i64(xal, cpu_vsrl(xA(ctx->opcode))); \
+                tcg_gen_and_i64(xah, xah, sgm);                  \
+                tcg_gen_and_i64(xal, xal, sgm);                  \
+                tcg_gen_andc_i64(xbh, xbh, sgm);                 \
+                tcg_gen_andc_i64(xbl, xbl, sgm);                 \
+                tcg_gen_or_i64(xbh, xbh, xah);                   \
+                tcg_gen_or_i64(xbl, xbl, xal);                   \
+                tcg_temp_free_i64(xah);                          \
+                tcg_temp_free_i64(xal);                          \
+                break;                                           \
+            }                                                    \
+        }                                                        \
+        tcg_gen_mov_i64(cpu_vsrh(xT(ctx->opcode)), xbh);         \
+        tcg_gen_mov_i64(cpu_vsrl(xT(ctx->opcode)), xbl);         \
+        tcg_temp_free_i64(xbh);                                  \
+        tcg_temp_free_i64(xbl);                                  \
+        tcg_temp_free_i64(sgm);                                  \
+    }
+
+VSX_VECTOR_MOVE(xvabsdp, OP_ABS, SGN_MASK_DP)
+VSX_VECTOR_MOVE(xvnabsdp, OP_NABS, SGN_MASK_DP)
+VSX_VECTOR_MOVE(xvnegdp, OP_NEG, SGN_MASK_DP)
+VSX_VECTOR_MOVE(xvcpsgndp, OP_CPSGN, SGN_MASK_DP)
+VSX_VECTOR_MOVE(xvabssp, OP_ABS, SGN_MASK_SP)
+VSX_VECTOR_MOVE(xvnabssp, OP_NABS, SGN_MASK_SP)
+VSX_VECTOR_MOVE(xvnegsp, OP_NEG, SGN_MASK_SP)
+VSX_VECTOR_MOVE(xvcpsgnsp, OP_CPSGN, SGN_MASK_SP)
+
+#define GEN_VSX_HELPER_2(name, op1, op2, inval, type)                         \
+static void gen_##name(DisasContext * ctx)                                    \
+{                                                                             \
+    TCGv_i32 opc;                                                             \
+    if (unlikely(!ctx->vsx_enabled)) {                                        \
+        gen_exception(ctx, POWERPC_EXCP_VSXU);                                \
+        return;                                                               \
+    }                                                                         \
+    /* NIP cannot be restored if the memory exception comes from an helper */ \
+    gen_update_nip(ctx, ctx->nip - 4);                                        \
+    opc = tcg_const_i32(ctx->opcode);                                         \
+    gen_helper_##name(cpu_env, opc);                                          \
+    tcg_temp_free_i32(opc);                                                   \
+}
+
+#define GEN_VSX_HELPER_XT_XB_ENV(name, op1, op2, inval, type) \
+static void gen_##name(DisasContext * ctx)                    \
+{                                                             \
+    if (unlikely(!ctx->vsx_enabled)) {                        \
+        gen_exception(ctx, POWERPC_EXCP_VSXU);                \
+        return;                                               \
+    }                                                         \
+    /* NIP cannot be restored if the exception comes */       \
+    /* from a helper. */                                      \
+    gen_update_nip(ctx, ctx->nip - 4);                        \
+                                                              \
+    gen_helper_##name(cpu_vsrh(xT(ctx->opcode)), cpu_env,     \
+                      cpu_vsrh(xB(ctx->opcode)));             \
+}
+
+GEN_VSX_HELPER_2(xsadddp, 0x00, 0x04, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xssubdp, 0x00, 0x05, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xsmuldp, 0x00, 0x06, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xsdivdp, 0x00, 0x07, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xsredp, 0x14, 0x05, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xssqrtdp, 0x16, 0x04, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xsrsqrtedp, 0x14, 0x04, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xstdivdp, 0x14, 0x07, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xstsqrtdp, 0x14, 0x06, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xsmaddadp, 0x04, 0x04, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xsmaddmdp, 0x04, 0x05, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xsmsubadp, 0x04, 0x06, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xsmsubmdp, 0x04, 0x07, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xsnmaddadp, 0x04, 0x14, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xsnmaddmdp, 0x04, 0x15, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xsnmsubadp, 0x04, 0x16, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xsnmsubmdp, 0x04, 0x17, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xscmpodp, 0x0C, 0x05, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xscmpudp, 0x0C, 0x04, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xsmaxdp, 0x00, 0x14, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xsmindp, 0x00, 0x15, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xscvdpsp, 0x12, 0x10, 0, PPC2_VSX)
+GEN_VSX_HELPER_XT_XB_ENV(xscvdpspn, 0x16, 0x10, 0, PPC2_VSX207)
+GEN_VSX_HELPER_2(xscvspdp, 0x12, 0x14, 0, PPC2_VSX)
+GEN_VSX_HELPER_XT_XB_ENV(xscvspdpn, 0x16, 0x14, 0, PPC2_VSX207)
+GEN_VSX_HELPER_2(xscvdpsxds, 0x10, 0x15, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xscvdpsxws, 0x10, 0x05, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xscvdpuxds, 0x10, 0x14, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xscvdpuxws, 0x10, 0x04, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xscvsxddp, 0x10, 0x17, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xscvuxddp, 0x10, 0x16, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xsrdpi, 0x12, 0x04, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xsrdpic, 0x16, 0x06, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xsrdpim, 0x12, 0x07, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xsrdpip, 0x12, 0x06, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xsrdpiz, 0x12, 0x05, 0, PPC2_VSX)
+GEN_VSX_HELPER_XT_XB_ENV(xsrsp, 0x12, 0x11, 0, PPC2_VSX207)
+
+GEN_VSX_HELPER_2(xsaddsp, 0x00, 0x00, 0, PPC2_VSX207)
+GEN_VSX_HELPER_2(xssubsp, 0x00, 0x01, 0, PPC2_VSX207)
+GEN_VSX_HELPER_2(xsmulsp, 0x00, 0x02, 0, PPC2_VSX207)
+GEN_VSX_HELPER_2(xsdivsp, 0x00, 0x03, 0, PPC2_VSX207)
+GEN_VSX_HELPER_2(xsresp, 0x14, 0x01, 0, PPC2_VSX207)
+GEN_VSX_HELPER_2(xssqrtsp, 0x16, 0x00, 0, PPC2_VSX207)
+GEN_VSX_HELPER_2(xsrsqrtesp, 0x14, 0x00, 0, PPC2_VSX207)
+GEN_VSX_HELPER_2(xsmaddasp, 0x04, 0x00, 0, PPC2_VSX207)
+GEN_VSX_HELPER_2(xsmaddmsp, 0x04, 0x01, 0, PPC2_VSX207)
+GEN_VSX_HELPER_2(xsmsubasp, 0x04, 0x02, 0, PPC2_VSX207)
+GEN_VSX_HELPER_2(xsmsubmsp, 0x04, 0x03, 0, PPC2_VSX207)
+GEN_VSX_HELPER_2(xsnmaddasp, 0x04, 0x10, 0, PPC2_VSX207)
+GEN_VSX_HELPER_2(xsnmaddmsp, 0x04, 0x11, 0, PPC2_VSX207)
+GEN_VSX_HELPER_2(xsnmsubasp, 0x04, 0x12, 0, PPC2_VSX207)
+GEN_VSX_HELPER_2(xsnmsubmsp, 0x04, 0x13, 0, PPC2_VSX207)
+GEN_VSX_HELPER_2(xscvsxdsp, 0x10, 0x13, 0, PPC2_VSX207)
+GEN_VSX_HELPER_2(xscvuxdsp, 0x10, 0x12, 0, PPC2_VSX207)
+
+GEN_VSX_HELPER_2(xvadddp, 0x00, 0x0C, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvsubdp, 0x00, 0x0D, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvmuldp, 0x00, 0x0E, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvdivdp, 0x00, 0x0F, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvredp, 0x14, 0x0D, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvsqrtdp, 0x16, 0x0C, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvrsqrtedp, 0x14, 0x0C, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvtdivdp, 0x14, 0x0F, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvtsqrtdp, 0x14, 0x0E, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvmaddadp, 0x04, 0x0C, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvmaddmdp, 0x04, 0x0D, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvmsubadp, 0x04, 0x0E, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvmsubmdp, 0x04, 0x0F, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvnmaddadp, 0x04, 0x1C, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvnmaddmdp, 0x04, 0x1D, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvnmsubadp, 0x04, 0x1E, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvnmsubmdp, 0x04, 0x1F, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvmaxdp, 0x00, 0x1C, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvmindp, 0x00, 0x1D, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvcmpeqdp, 0x0C, 0x0C, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvcmpgtdp, 0x0C, 0x0D, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvcmpgedp, 0x0C, 0x0E, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvcvdpsp, 0x12, 0x18, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvcvdpsxds, 0x10, 0x1D, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvcvdpsxws, 0x10, 0x0D, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvcvdpuxds, 0x10, 0x1C, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvcvdpuxws, 0x10, 0x0C, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvcvsxddp, 0x10, 0x1F, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvcvuxddp, 0x10, 0x1E, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvcvsxwdp, 0x10, 0x0F, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvcvuxwdp, 0x10, 0x0E, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvrdpi, 0x12, 0x0C, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvrdpic, 0x16, 0x0E, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvrdpim, 0x12, 0x0F, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvrdpip, 0x12, 0x0E, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvrdpiz, 0x12, 0x0D, 0, PPC2_VSX)
+
+GEN_VSX_HELPER_2(xvaddsp, 0x00, 0x08, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvsubsp, 0x00, 0x09, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvmulsp, 0x00, 0x0A, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvdivsp, 0x00, 0x0B, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvresp, 0x14, 0x09, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvsqrtsp, 0x16, 0x08, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvrsqrtesp, 0x14, 0x08, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvtdivsp, 0x14, 0x0B, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvtsqrtsp, 0x14, 0x0A, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvmaddasp, 0x04, 0x08, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvmaddmsp, 0x04, 0x09, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvmsubasp, 0x04, 0x0A, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvmsubmsp, 0x04, 0x0B, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvnmaddasp, 0x04, 0x18, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvnmaddmsp, 0x04, 0x19, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvnmsubasp, 0x04, 0x1A, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvnmsubmsp, 0x04, 0x1B, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvmaxsp, 0x00, 0x18, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvminsp, 0x00, 0x19, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvcmpeqsp, 0x0C, 0x08, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvcmpgtsp, 0x0C, 0x09, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvcmpgesp, 0x0C, 0x0A, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvcvspdp, 0x12, 0x1C, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvcvspsxds, 0x10, 0x19, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvcvspsxws, 0x10, 0x09, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvcvspuxds, 0x10, 0x18, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvcvspuxws, 0x10, 0x08, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvcvsxdsp, 0x10, 0x1B, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvcvuxdsp, 0x10, 0x1A, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvcvsxwsp, 0x10, 0x0B, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvcvuxwsp, 0x10, 0x0A, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvrspi, 0x12, 0x08, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvrspic, 0x16, 0x0A, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvrspim, 0x12, 0x0B, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvrspip, 0x12, 0x0A, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvrspiz, 0x12, 0x09, 0, PPC2_VSX)
+
+#define VSX_LOGICAL(name, tcg_op)                                    \
+static void glue(gen_, name)(DisasContext * ctx)                     \
+    {                                                                \
+        if (unlikely(!ctx->vsx_enabled)) {                           \
+            gen_exception(ctx, POWERPC_EXCP_VSXU);                   \
+            return;                                                  \
+        }                                                            \
+        tcg_op(cpu_vsrh(xT(ctx->opcode)), cpu_vsrh(xA(ctx->opcode)), \
+            cpu_vsrh(xB(ctx->opcode)));                              \
+        tcg_op(cpu_vsrl(xT(ctx->opcode)), cpu_vsrl(xA(ctx->opcode)), \
+            cpu_vsrl(xB(ctx->opcode)));                              \
+    }
+
+VSX_LOGICAL(xxland, tcg_gen_and_i64)
+VSX_LOGICAL(xxlandc, tcg_gen_andc_i64)
+VSX_LOGICAL(xxlor, tcg_gen_or_i64)
+VSX_LOGICAL(xxlxor, tcg_gen_xor_i64)
+VSX_LOGICAL(xxlnor, tcg_gen_nor_i64)
+VSX_LOGICAL(xxleqv, tcg_gen_eqv_i64)
+VSX_LOGICAL(xxlnand, tcg_gen_nand_i64)
+VSX_LOGICAL(xxlorc, tcg_gen_orc_i64)
+
+#define VSX_XXMRG(name, high)                               \
+static void glue(gen_, name)(DisasContext * ctx)            \
+    {                                                       \
+        TCGv_i64 a0, a1, b0, b1;                            \
+        if (unlikely(!ctx->vsx_enabled)) {                  \
+            gen_exception(ctx, POWERPC_EXCP_VSXU);          \
+            return;                                         \
+        }                                                   \
+        a0 = tcg_temp_new_i64();                            \
+        a1 = tcg_temp_new_i64();                            \
+        b0 = tcg_temp_new_i64();                            \
+        b1 = tcg_temp_new_i64();                            \
+        if (high) {                                         \
+            tcg_gen_mov_i64(a0, cpu_vsrh(xA(ctx->opcode))); \
+            tcg_gen_mov_i64(a1, cpu_vsrh(xA(ctx->opcode))); \
+            tcg_gen_mov_i64(b0, cpu_vsrh(xB(ctx->opcode))); \
+            tcg_gen_mov_i64(b1, cpu_vsrh(xB(ctx->opcode))); \
+        } else {                                            \
+            tcg_gen_mov_i64(a0, cpu_vsrl(xA(ctx->opcode))); \
+            tcg_gen_mov_i64(a1, cpu_vsrl(xA(ctx->opcode))); \
+            tcg_gen_mov_i64(b0, cpu_vsrl(xB(ctx->opcode))); \
+            tcg_gen_mov_i64(b1, cpu_vsrl(xB(ctx->opcode))); \
+        }                                                   \
+        tcg_gen_shri_i64(a0, a0, 32);                       \
+        tcg_gen_shri_i64(b0, b0, 32);                       \
+        tcg_gen_deposit_i64(cpu_vsrh(xT(ctx->opcode)),      \
+                            b0, a0, 32, 32);                \
+        tcg_gen_deposit_i64(cpu_vsrl(xT(ctx->opcode)),      \
+                            b1, a1, 32, 32);                \
+        tcg_temp_free_i64(a0);                              \
+        tcg_temp_free_i64(a1);                              \
+        tcg_temp_free_i64(b0);                              \
+        tcg_temp_free_i64(b1);                              \
+    }
+
+VSX_XXMRG(xxmrghw, 1)
+VSX_XXMRG(xxmrglw, 0)
+
+static void gen_xxsel(DisasContext * ctx)
+{
+    TCGv_i64 a, b, c;
+    if (unlikely(!ctx->vsx_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_VSXU);
+        return;
+    }
+    a = tcg_temp_new_i64();
+    b = tcg_temp_new_i64();
+    c = tcg_temp_new_i64();
+
+    tcg_gen_mov_i64(a, cpu_vsrh(xA(ctx->opcode)));
+    tcg_gen_mov_i64(b, cpu_vsrh(xB(ctx->opcode)));
+    tcg_gen_mov_i64(c, cpu_vsrh(xC(ctx->opcode)));
+
+    tcg_gen_and_i64(b, b, c);
+    tcg_gen_andc_i64(a, a, c);
+    tcg_gen_or_i64(cpu_vsrh(xT(ctx->opcode)), a, b);
+
+    tcg_gen_mov_i64(a, cpu_vsrl(xA(ctx->opcode)));
+    tcg_gen_mov_i64(b, cpu_vsrl(xB(ctx->opcode)));
+    tcg_gen_mov_i64(c, cpu_vsrl(xC(ctx->opcode)));
+
+    tcg_gen_and_i64(b, b, c);
+    tcg_gen_andc_i64(a, a, c);
+    tcg_gen_or_i64(cpu_vsrl(xT(ctx->opcode)), a, b);
+
+    tcg_temp_free_i64(a);
+    tcg_temp_free_i64(b);
+    tcg_temp_free_i64(c);
+}
+
+static void gen_xxspltw(DisasContext *ctx)
+{
+    TCGv_i64 b, b2;
+    TCGv_i64 vsr = (UIM(ctx->opcode) & 2) ?
+                   cpu_vsrl(xB(ctx->opcode)) :
+                   cpu_vsrh(xB(ctx->opcode));
+
+    if (unlikely(!ctx->vsx_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_VSXU);
+        return;
+    }
+
+    b = tcg_temp_new_i64();
+    b2 = tcg_temp_new_i64();
+
+    if (UIM(ctx->opcode) & 1) {
+        tcg_gen_ext32u_i64(b, vsr);
+    } else {
+        tcg_gen_shri_i64(b, vsr, 32);
+    }
+
+    tcg_gen_shli_i64(b2, b, 32);
+    tcg_gen_or_i64(cpu_vsrh(xT(ctx->opcode)), b, b2);
+    tcg_gen_mov_i64(cpu_vsrl(xT(ctx->opcode)), cpu_vsrh(xT(ctx->opcode)));
+
+    tcg_temp_free_i64(b);
+    tcg_temp_free_i64(b2);
+}
+
+static void gen_xxsldwi(DisasContext *ctx)
+{
+    TCGv_i64 xth, xtl;
+    if (unlikely(!ctx->vsx_enabled)) {
+        gen_exception(ctx, POWERPC_EXCP_VSXU);
+        return;
+    }
+    xth = tcg_temp_new_i64();
+    xtl = tcg_temp_new_i64();
+
+    switch (SHW(ctx->opcode)) {
+        case 0: {
+            tcg_gen_mov_i64(xth, cpu_vsrh(xA(ctx->opcode)));
+            tcg_gen_mov_i64(xtl, cpu_vsrl(xA(ctx->opcode)));
+            break;
+        }
+        case 1: {
+            TCGv_i64 t0 = tcg_temp_new_i64();
+            tcg_gen_mov_i64(xth, cpu_vsrh(xA(ctx->opcode)));
+            tcg_gen_shli_i64(xth, xth, 32);
+            tcg_gen_mov_i64(t0, cpu_vsrl(xA(ctx->opcode)));
+            tcg_gen_shri_i64(t0, t0, 32);
+            tcg_gen_or_i64(xth, xth, t0);
+            tcg_gen_mov_i64(xtl, cpu_vsrl(xA(ctx->opcode)));
+            tcg_gen_shli_i64(xtl, xtl, 32);
+            tcg_gen_mov_i64(t0, cpu_vsrh(xB(ctx->opcode)));
+            tcg_gen_shri_i64(t0, t0, 32);
+            tcg_gen_or_i64(xtl, xtl, t0);
+            tcg_temp_free_i64(t0);
+            break;
+        }
+        case 2: {
+            tcg_gen_mov_i64(xth, cpu_vsrl(xA(ctx->opcode)));
+            tcg_gen_mov_i64(xtl, cpu_vsrh(xB(ctx->opcode)));
+            break;
+        }
+        case 3: {
+            TCGv_i64 t0 = tcg_temp_new_i64();
+            tcg_gen_mov_i64(xth, cpu_vsrl(xA(ctx->opcode)));
+            tcg_gen_shli_i64(xth, xth, 32);
+            tcg_gen_mov_i64(t0, cpu_vsrh(xB(ctx->opcode)));
+            tcg_gen_shri_i64(t0, t0, 32);
+            tcg_gen_or_i64(xth, xth, t0);
+            tcg_gen_mov_i64(xtl, cpu_vsrh(xB(ctx->opcode)));
+            tcg_gen_shli_i64(xtl, xtl, 32);
+            tcg_gen_mov_i64(t0, cpu_vsrl(xB(ctx->opcode)));
+            tcg_gen_shri_i64(t0, t0, 32);
+            tcg_gen_or_i64(xtl, xtl, t0);
+            tcg_temp_free_i64(t0);
+            break;
+        }
+    }
+
+    tcg_gen_mov_i64(cpu_vsrh(xT(ctx->opcode)), xth);
+    tcg_gen_mov_i64(cpu_vsrl(xT(ctx->opcode)), xtl);
+
+    tcg_temp_free_i64(xth);
+    tcg_temp_free_i64(xtl);
+}
+
+#undef GEN_XX2FORM
+#undef GEN_XX3FORM
+#undef GEN_XX2IFORM
+#undef GEN_XX3_RC_FORM
+#undef GEN_XX3FORM_DM
+#undef VSX_LOGICAL
diff --git a/target-ppc/translate/vsx-ops.c b/target-ppc/translate/vsx-ops.c
new file mode 100644
index 0000000..874039e
--- /dev/null
+++ b/target-ppc/translate/vsx-ops.c
@@ -0,0 +1,271 @@
+GEN_HANDLER_E(lxsdx, 0x1F, 0x0C, 0x12, 0, PPC_NONE, PPC2_VSX),
+GEN_HANDLER_E(lxsiwax, 0x1F, 0x0C, 0x02, 0, PPC_NONE, PPC2_VSX207),
+GEN_HANDLER_E(lxsiwzx, 0x1F, 0x0C, 0x00, 0, PPC_NONE, PPC2_VSX207),
+GEN_HANDLER_E(lxsspx, 0x1F, 0x0C, 0x10, 0, PPC_NONE, PPC2_VSX207),
+GEN_HANDLER_E(lxvd2x, 0x1F, 0x0C, 0x1A, 0, PPC_NONE, PPC2_VSX),
+GEN_HANDLER_E(lxvdsx, 0x1F, 0x0C, 0x0A, 0, PPC_NONE, PPC2_VSX),
+GEN_HANDLER_E(lxvw4x, 0x1F, 0x0C, 0x18, 0, PPC_NONE, PPC2_VSX),
+
+GEN_HANDLER_E(stxsdx, 0x1F, 0xC, 0x16, 0, PPC_NONE, PPC2_VSX),
+GEN_HANDLER_E(stxsiwx, 0x1F, 0xC, 0x04, 0, PPC_NONE, PPC2_VSX207),
+GEN_HANDLER_E(stxsspx, 0x1F, 0xC, 0x14, 0, PPC_NONE, PPC2_VSX207),
+GEN_HANDLER_E(stxvd2x, 0x1F, 0xC, 0x1E, 0, PPC_NONE, PPC2_VSX),
+GEN_HANDLER_E(stxvw4x, 0x1F, 0xC, 0x1C, 0, PPC_NONE, PPC2_VSX),
+
+GEN_HANDLER_E(mfvsrwz, 0x1F, 0x13, 0x03, 0x0000F800, PPC_NONE, PPC2_VSX207),
+GEN_HANDLER_E(mtvsrwa, 0x1F, 0x13, 0x06, 0x0000F800, PPC_NONE, PPC2_VSX207),
+GEN_HANDLER_E(mtvsrwz, 0x1F, 0x13, 0x07, 0x0000F800, PPC_NONE, PPC2_VSX207),
+#if defined(TARGET_PPC64)
+GEN_HANDLER_E(mfvsrd, 0x1F, 0x13, 0x01, 0x0000F800, PPC_NONE, PPC2_VSX207),
+GEN_HANDLER_E(mtvsrd, 0x1F, 0x13, 0x05, 0x0000F800, PPC_NONE, PPC2_VSX207),
+#endif
+
+#define GEN_XX2FORM(name, opc2, opc3, fl2)                           \
+GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 0, opc3, 0, PPC_NONE, fl2), \
+GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 1, opc3, 0, PPC_NONE, fl2)
+
+#define GEN_XX3FORM(name, opc2, opc3, fl2)                           \
+GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 0, opc3, 0, PPC_NONE, fl2), \
+GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 1, opc3, 0, PPC_NONE, fl2), \
+GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 2, opc3, 0, PPC_NONE, fl2), \
+GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 3, opc3, 0, PPC_NONE, fl2)
+
+#define GEN_XX2IFORM(name, opc2, opc3, fl2)                           \
+GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 0, opc3, 1, PPC_NONE, fl2), \
+GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 1, opc3, 1, PPC_NONE, fl2), \
+GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 2, opc3, 1, PPC_NONE, fl2), \
+GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 3, opc3, 1, PPC_NONE, fl2)
+
+#define GEN_XX3_RC_FORM(name, opc2, opc3, fl2)                          \
+GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 0x00, opc3 | 0x00, 0, PPC_NONE, fl2), \
+GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 0x01, opc3 | 0x00, 0, PPC_NONE, fl2), \
+GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 0x02, opc3 | 0x00, 0, PPC_NONE, fl2), \
+GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 0x03, opc3 | 0x00, 0, PPC_NONE, fl2), \
+GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 0x00, opc3 | 0x10, 0, PPC_NONE, fl2), \
+GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 0x01, opc3 | 0x10, 0, PPC_NONE, fl2), \
+GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 0x02, opc3 | 0x10, 0, PPC_NONE, fl2), \
+GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 0x03, opc3 | 0x10, 0, PPC_NONE, fl2)
+
+#define GEN_XX3FORM_DM(name, opc2, opc3) \
+GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x00, opc3|0x00, 0, PPC_NONE, PPC2_VSX),\
+GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x01, opc3|0x00, 0, PPC_NONE, PPC2_VSX),\
+GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x02, opc3|0x00, 0, PPC_NONE, PPC2_VSX),\
+GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x03, opc3|0x00, 0, PPC_NONE, PPC2_VSX),\
+GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x00, opc3|0x04, 0, PPC_NONE, PPC2_VSX),\
+GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x01, opc3|0x04, 0, PPC_NONE, PPC2_VSX),\
+GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x02, opc3|0x04, 0, PPC_NONE, PPC2_VSX),\
+GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x03, opc3|0x04, 0, PPC_NONE, PPC2_VSX),\
+GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x00, opc3|0x08, 0, PPC_NONE, PPC2_VSX),\
+GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x01, opc3|0x08, 0, PPC_NONE, PPC2_VSX),\
+GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x02, opc3|0x08, 0, PPC_NONE, PPC2_VSX),\
+GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x03, opc3|0x08, 0, PPC_NONE, PPC2_VSX),\
+GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x00, opc3|0x0C, 0, PPC_NONE, PPC2_VSX),\
+GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x01, opc3|0x0C, 0, PPC_NONE, PPC2_VSX),\
+GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x02, opc3|0x0C, 0, PPC_NONE, PPC2_VSX),\
+GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x03, opc3|0x0C, 0, PPC_NONE, PPC2_VSX)
+
+GEN_XX2FORM(xsabsdp, 0x12, 0x15, PPC2_VSX),
+GEN_XX2FORM(xsnabsdp, 0x12, 0x16, PPC2_VSX),
+GEN_XX2FORM(xsnegdp, 0x12, 0x17, PPC2_VSX),
+GEN_XX3FORM(xscpsgndp, 0x00, 0x16, PPC2_VSX),
+
+GEN_XX2FORM(xvabsdp, 0x12, 0x1D, PPC2_VSX),
+GEN_XX2FORM(xvnabsdp, 0x12, 0x1E, PPC2_VSX),
+GEN_XX2FORM(xvnegdp, 0x12, 0x1F, PPC2_VSX),
+GEN_XX3FORM(xvcpsgndp, 0x00, 0x1E, PPC2_VSX),
+GEN_XX2FORM(xvabssp, 0x12, 0x19, PPC2_VSX),
+GEN_XX2FORM(xvnabssp, 0x12, 0x1A, PPC2_VSX),
+GEN_XX2FORM(xvnegsp, 0x12, 0x1B, PPC2_VSX),
+GEN_XX3FORM(xvcpsgnsp, 0x00, 0x1A, PPC2_VSX),
+
+GEN_XX3FORM(xsadddp, 0x00, 0x04, PPC2_VSX),
+GEN_XX3FORM(xssubdp, 0x00, 0x05, PPC2_VSX),
+GEN_XX3FORM(xsmuldp, 0x00, 0x06, PPC2_VSX),
+GEN_XX3FORM(xsdivdp, 0x00, 0x07, PPC2_VSX),
+GEN_XX2FORM(xsredp,  0x14, 0x05, PPC2_VSX),
+GEN_XX2FORM(xssqrtdp,  0x16, 0x04, PPC2_VSX),
+GEN_XX2FORM(xsrsqrtedp,  0x14, 0x04, PPC2_VSX),
+GEN_XX3FORM(xstdivdp,  0x14, 0x07, PPC2_VSX),
+GEN_XX2FORM(xstsqrtdp,  0x14, 0x06, PPC2_VSX),
+GEN_XX3FORM(xsmaddadp, 0x04, 0x04, PPC2_VSX),
+GEN_XX3FORM(xsmaddmdp, 0x04, 0x05, PPC2_VSX),
+GEN_XX3FORM(xsmsubadp, 0x04, 0x06, PPC2_VSX),
+GEN_XX3FORM(xsmsubmdp, 0x04, 0x07, PPC2_VSX),
+GEN_XX3FORM(xsnmaddadp, 0x04, 0x14, PPC2_VSX),
+GEN_XX3FORM(xsnmaddmdp, 0x04, 0x15, PPC2_VSX),
+GEN_XX3FORM(xsnmsubadp, 0x04, 0x16, PPC2_VSX),
+GEN_XX3FORM(xsnmsubmdp, 0x04, 0x17, PPC2_VSX),
+GEN_XX2IFORM(xscmpodp,  0x0C, 0x05, PPC2_VSX),
+GEN_XX2IFORM(xscmpudp,  0x0C, 0x04, PPC2_VSX),
+GEN_XX3FORM(xsmaxdp, 0x00, 0x14, PPC2_VSX),
+GEN_XX3FORM(xsmindp, 0x00, 0x15, PPC2_VSX),
+GEN_XX2FORM(xscvdpsp, 0x12, 0x10, PPC2_VSX),
+GEN_XX2FORM(xscvdpspn, 0x16, 0x10, PPC2_VSX207),
+GEN_XX2FORM(xscvspdp, 0x12, 0x14, PPC2_VSX),
+GEN_XX2FORM(xscvspdpn, 0x16, 0x14, PPC2_VSX207),
+GEN_XX2FORM(xscvdpsxds, 0x10, 0x15, PPC2_VSX),
+GEN_XX2FORM(xscvdpsxws, 0x10, 0x05, PPC2_VSX),
+GEN_XX2FORM(xscvdpuxds, 0x10, 0x14, PPC2_VSX),
+GEN_XX2FORM(xscvdpuxws, 0x10, 0x04, PPC2_VSX),
+GEN_XX2FORM(xscvsxddp, 0x10, 0x17, PPC2_VSX),
+GEN_XX2FORM(xscvuxddp, 0x10, 0x16, PPC2_VSX),
+GEN_XX2FORM(xsrdpi, 0x12, 0x04, PPC2_VSX),
+GEN_XX2FORM(xsrdpic, 0x16, 0x06, PPC2_VSX),
+GEN_XX2FORM(xsrdpim, 0x12, 0x07, PPC2_VSX),
+GEN_XX2FORM(xsrdpip, 0x12, 0x06, PPC2_VSX),
+GEN_XX2FORM(xsrdpiz, 0x12, 0x05, PPC2_VSX),
+
+GEN_XX3FORM(xsaddsp, 0x00, 0x00, PPC2_VSX207),
+GEN_XX3FORM(xssubsp, 0x00, 0x01, PPC2_VSX207),
+GEN_XX3FORM(xsmulsp, 0x00, 0x02, PPC2_VSX207),
+GEN_XX3FORM(xsdivsp, 0x00, 0x03, PPC2_VSX207),
+GEN_XX2FORM(xsresp,  0x14, 0x01, PPC2_VSX207),
+GEN_XX2FORM(xsrsp, 0x12, 0x11, PPC2_VSX207),
+GEN_XX2FORM(xssqrtsp,  0x16, 0x00, PPC2_VSX207),
+GEN_XX2FORM(xsrsqrtesp,  0x14, 0x00, PPC2_VSX207),
+GEN_XX3FORM(xsmaddasp, 0x04, 0x00, PPC2_VSX207),
+GEN_XX3FORM(xsmaddmsp, 0x04, 0x01, PPC2_VSX207),
+GEN_XX3FORM(xsmsubasp, 0x04, 0x02, PPC2_VSX207),
+GEN_XX3FORM(xsmsubmsp, 0x04, 0x03, PPC2_VSX207),
+GEN_XX3FORM(xsnmaddasp, 0x04, 0x10, PPC2_VSX207),
+GEN_XX3FORM(xsnmaddmsp, 0x04, 0x11, PPC2_VSX207),
+GEN_XX3FORM(xsnmsubasp, 0x04, 0x12, PPC2_VSX207),
+GEN_XX3FORM(xsnmsubmsp, 0x04, 0x13, PPC2_VSX207),
+GEN_XX2FORM(xscvsxdsp, 0x10, 0x13, PPC2_VSX207),
+GEN_XX2FORM(xscvuxdsp, 0x10, 0x12, PPC2_VSX207),
+
+GEN_XX3FORM(xvadddp, 0x00, 0x0C, PPC2_VSX),
+GEN_XX3FORM(xvsubdp, 0x00, 0x0D, PPC2_VSX),
+GEN_XX3FORM(xvmuldp, 0x00, 0x0E, PPC2_VSX),
+GEN_XX3FORM(xvdivdp, 0x00, 0x0F, PPC2_VSX),
+GEN_XX2FORM(xvredp,  0x14, 0x0D, PPC2_VSX),
+GEN_XX2FORM(xvsqrtdp,  0x16, 0x0C, PPC2_VSX),
+GEN_XX2FORM(xvrsqrtedp,  0x14, 0x0C, PPC2_VSX),
+GEN_XX3FORM(xvtdivdp, 0x14, 0x0F, PPC2_VSX),
+GEN_XX2FORM(xvtsqrtdp, 0x14, 0x0E, PPC2_VSX),
+GEN_XX3FORM(xvmaddadp, 0x04, 0x0C, PPC2_VSX),
+GEN_XX3FORM(xvmaddmdp, 0x04, 0x0D, PPC2_VSX),
+GEN_XX3FORM(xvmsubadp, 0x04, 0x0E, PPC2_VSX),
+GEN_XX3FORM(xvmsubmdp, 0x04, 0x0F, PPC2_VSX),
+GEN_XX3FORM(xvnmaddadp, 0x04, 0x1C, PPC2_VSX),
+GEN_XX3FORM(xvnmaddmdp, 0x04, 0x1D, PPC2_VSX),
+GEN_XX3FORM(xvnmsubadp, 0x04, 0x1E, PPC2_VSX),
+GEN_XX3FORM(xvnmsubmdp, 0x04, 0x1F, PPC2_VSX),
+GEN_XX3FORM(xvmaxdp, 0x00, 0x1C, PPC2_VSX),
+GEN_XX3FORM(xvmindp, 0x00, 0x1D, PPC2_VSX),
+GEN_XX3_RC_FORM(xvcmpeqdp, 0x0C, 0x0C, PPC2_VSX),
+GEN_XX3_RC_FORM(xvcmpgtdp, 0x0C, 0x0D, PPC2_VSX),
+GEN_XX3_RC_FORM(xvcmpgedp, 0x0C, 0x0E, PPC2_VSX),
+GEN_XX2FORM(xvcvdpsp, 0x12, 0x18, PPC2_VSX),
+GEN_XX2FORM(xvcvdpsxds, 0x10, 0x1D, PPC2_VSX),
+GEN_XX2FORM(xvcvdpsxws, 0x10, 0x0D, PPC2_VSX),
+GEN_XX2FORM(xvcvdpuxds, 0x10, 0x1C, PPC2_VSX),
+GEN_XX2FORM(xvcvdpuxws, 0x10, 0x0C, PPC2_VSX),
+GEN_XX2FORM(xvcvsxddp, 0x10, 0x1F, PPC2_VSX),
+GEN_XX2FORM(xvcvuxddp, 0x10, 0x1E, PPC2_VSX),
+GEN_XX2FORM(xvcvsxwdp, 0x10, 0x0F, PPC2_VSX),
+GEN_XX2FORM(xvcvuxwdp, 0x10, 0x0E, PPC2_VSX),
+GEN_XX2FORM(xvrdpi, 0x12, 0x0C, PPC2_VSX),
+GEN_XX2FORM(xvrdpic, 0x16, 0x0E, PPC2_VSX),
+GEN_XX2FORM(xvrdpim, 0x12, 0x0F, PPC2_VSX),
+GEN_XX2FORM(xvrdpip, 0x12, 0x0E, PPC2_VSX),
+GEN_XX2FORM(xvrdpiz, 0x12, 0x0D, PPC2_VSX),
+
+GEN_XX3FORM(xvaddsp, 0x00, 0x08, PPC2_VSX),
+GEN_XX3FORM(xvsubsp, 0x00, 0x09, PPC2_VSX),
+GEN_XX3FORM(xvmulsp, 0x00, 0x0A, PPC2_VSX),
+GEN_XX3FORM(xvdivsp, 0x00, 0x0B, PPC2_VSX),
+GEN_XX2FORM(xvresp, 0x14, 0x09, PPC2_VSX),
+GEN_XX2FORM(xvsqrtsp, 0x16, 0x08, PPC2_VSX),
+GEN_XX2FORM(xvrsqrtesp, 0x14, 0x08, PPC2_VSX),
+GEN_XX3FORM(xvtdivsp, 0x14, 0x0B, PPC2_VSX),
+GEN_XX2FORM(xvtsqrtsp, 0x14, 0x0A, PPC2_VSX),
+GEN_XX3FORM(xvmaddasp, 0x04, 0x08, PPC2_VSX),
+GEN_XX3FORM(xvmaddmsp, 0x04, 0x09, PPC2_VSX),
+GEN_XX3FORM(xvmsubasp, 0x04, 0x0A, PPC2_VSX),
+GEN_XX3FORM(xvmsubmsp, 0x04, 0x0B, PPC2_VSX),
+GEN_XX3FORM(xvnmaddasp, 0x04, 0x18, PPC2_VSX),
+GEN_XX3FORM(xvnmaddmsp, 0x04, 0x19, PPC2_VSX),
+GEN_XX3FORM(xvnmsubasp, 0x04, 0x1A, PPC2_VSX),
+GEN_XX3FORM(xvnmsubmsp, 0x04, 0x1B, PPC2_VSX),
+GEN_XX3FORM(xvmaxsp, 0x00, 0x18, PPC2_VSX),
+GEN_XX3FORM(xvminsp, 0x00, 0x19, PPC2_VSX),
+GEN_XX3_RC_FORM(xvcmpeqsp, 0x0C, 0x08, PPC2_VSX),
+GEN_XX3_RC_FORM(xvcmpgtsp, 0x0C, 0x09, PPC2_VSX),
+GEN_XX3_RC_FORM(xvcmpgesp, 0x0C, 0x0A, PPC2_VSX),
+GEN_XX2FORM(xvcvspdp, 0x12, 0x1C, PPC2_VSX),
+GEN_XX2FORM(xvcvspsxds, 0x10, 0x19, PPC2_VSX),
+GEN_XX2FORM(xvcvspsxws, 0x10, 0x09, PPC2_VSX),
+GEN_XX2FORM(xvcvspuxds, 0x10, 0x18, PPC2_VSX),
+GEN_XX2FORM(xvcvspuxws, 0x10, 0x08, PPC2_VSX),
+GEN_XX2FORM(xvcvsxdsp, 0x10, 0x1B, PPC2_VSX),
+GEN_XX2FORM(xvcvuxdsp, 0x10, 0x1A, PPC2_VSX),
+GEN_XX2FORM(xvcvsxwsp, 0x10, 0x0B, PPC2_VSX),
+GEN_XX2FORM(xvcvuxwsp, 0x10, 0x0A, PPC2_VSX),
+GEN_XX2FORM(xvrspi, 0x12, 0x08, PPC2_VSX),
+GEN_XX2FORM(xvrspic, 0x16, 0x0A, PPC2_VSX),
+GEN_XX2FORM(xvrspim, 0x12, 0x0B, PPC2_VSX),
+GEN_XX2FORM(xvrspip, 0x12, 0x0A, PPC2_VSX),
+GEN_XX2FORM(xvrspiz, 0x12, 0x09, PPC2_VSX),
+
+#define VSX_LOGICAL(name, opc2, opc3, fl2) \
+GEN_XX3FORM(name, opc2, opc3, fl2)
+
+VSX_LOGICAL(xxland, 0x8, 0x10, PPC2_VSX),
+VSX_LOGICAL(xxlandc, 0x8, 0x11, PPC2_VSX),
+VSX_LOGICAL(xxlor, 0x8, 0x12, PPC2_VSX),
+VSX_LOGICAL(xxlxor, 0x8, 0x13, PPC2_VSX),
+VSX_LOGICAL(xxlnor, 0x8, 0x14, PPC2_VSX),
+VSX_LOGICAL(xxleqv, 0x8, 0x17, PPC2_VSX207),
+VSX_LOGICAL(xxlnand, 0x8, 0x16, PPC2_VSX207),
+VSX_LOGICAL(xxlorc, 0x8, 0x15, PPC2_VSX207),
+GEN_XX3FORM(xxmrghw, 0x08, 0x02, PPC2_VSX),
+GEN_XX3FORM(xxmrglw, 0x08, 0x06, PPC2_VSX),
+GEN_XX2FORM(xxspltw, 0x08, 0x0A, PPC2_VSX),
+GEN_XX3FORM_DM(xxsldwi, 0x08, 0x00),
+
+#define GEN_XXSEL_ROW(opc3) \
+GEN_HANDLER2_E(xxsel, "xxsel", 0x3C, 0x18, opc3, 0, PPC_NONE, PPC2_VSX), \
+GEN_HANDLER2_E(xxsel, "xxsel", 0x3C, 0x19, opc3, 0, PPC_NONE, PPC2_VSX), \
+GEN_HANDLER2_E(xxsel, "xxsel", 0x3C, 0x1A, opc3, 0, PPC_NONE, PPC2_VSX), \
+GEN_HANDLER2_E(xxsel, "xxsel", 0x3C, 0x1B, opc3, 0, PPC_NONE, PPC2_VSX), \
+GEN_HANDLER2_E(xxsel, "xxsel", 0x3C, 0x1C, opc3, 0, PPC_NONE, PPC2_VSX), \
+GEN_HANDLER2_E(xxsel, "xxsel", 0x3C, 0x1D, opc3, 0, PPC_NONE, PPC2_VSX), \
+GEN_HANDLER2_E(xxsel, "xxsel", 0x3C, 0x1E, opc3, 0, PPC_NONE, PPC2_VSX), \
+GEN_HANDLER2_E(xxsel, "xxsel", 0x3C, 0x1F, opc3, 0, PPC_NONE, PPC2_VSX), \
+
+GEN_XXSEL_ROW(0x00)
+GEN_XXSEL_ROW(0x01)
+GEN_XXSEL_ROW(0x02)
+GEN_XXSEL_ROW(0x03)
+GEN_XXSEL_ROW(0x04)
+GEN_XXSEL_ROW(0x05)
+GEN_XXSEL_ROW(0x06)
+GEN_XXSEL_ROW(0x07)
+GEN_XXSEL_ROW(0x08)
+GEN_XXSEL_ROW(0x09)
+GEN_XXSEL_ROW(0x0A)
+GEN_XXSEL_ROW(0x0B)
+GEN_XXSEL_ROW(0x0C)
+GEN_XXSEL_ROW(0x0D)
+GEN_XXSEL_ROW(0x0E)
+GEN_XXSEL_ROW(0x0F)
+GEN_XXSEL_ROW(0x10)
+GEN_XXSEL_ROW(0x11)
+GEN_XXSEL_ROW(0x12)
+GEN_XXSEL_ROW(0x13)
+GEN_XXSEL_ROW(0x14)
+GEN_XXSEL_ROW(0x15)
+GEN_XXSEL_ROW(0x16)
+GEN_XXSEL_ROW(0x17)
+GEN_XXSEL_ROW(0x18)
+GEN_XXSEL_ROW(0x19)
+GEN_XXSEL_ROW(0x1A)
+GEN_XXSEL_ROW(0x1B)
+GEN_XXSEL_ROW(0x1C)
+GEN_XXSEL_ROW(0x1D)
+GEN_XXSEL_ROW(0x1E)
+GEN_XXSEL_ROW(0x1F)
+
+GEN_XX3FORM_DM(xxpermdi, 0x08, 0x01),
+
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [Qemu-devel] [PATCH 08/32] ppc: Rename fload_invalid_op_excp to float_invalid_op_excp
  2016-07-26 22:20 [Qemu-devel] [PATCH 01/32] ppc: Fix fault PC reporting for lve*/stve* VMX instructions Benjamin Herrenschmidt
                   ` (5 preceding siblings ...)
  2016-07-26 22:21 ` [Qemu-devel] [PATCH 07/32] ppc: Move VSX " Benjamin Herrenschmidt
@ 2016-07-26 22:21 ` Benjamin Herrenschmidt
  2016-07-26 22:21 ` [Qemu-devel] [PATCH 09/32] ppc: Make float_invalid_op_excp() pass the return address Benjamin Herrenschmidt
                   ` (24 subsequent siblings)
  31 siblings, 0 replies; 69+ messages in thread
From: Benjamin Herrenschmidt @ 2016-07-26 22:21 UTC (permalink / raw)
  To: qemu-ppc; +Cc: qemu-devel, david, Benjamin Herrenschmidt

No other change

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
 target-ppc/fpu_helper.c | 122 ++++++++++++++++++++++++------------------------
 1 file changed, 61 insertions(+), 61 deletions(-)

diff --git a/target-ppc/fpu_helper.c b/target-ppc/fpu_helper.c
index d9795d0..e1f600a 100644
--- a/target-ppc/fpu_helper.c
+++ b/target-ppc/fpu_helper.c
@@ -116,7 +116,7 @@ void helper_compute_fprf(CPUPPCState *env, uint64_t arg)
 }
 
 /* Floating-point invalid operations exception */
-static inline uint64_t fload_invalid_op_excp(CPUPPCState *env, int op,
+static inline uint64_t float_invalid_op_excp(CPUPPCState *env, int op,
                                              int set_fpcc)
 {
     CPUState *cs = CPU(ppc_env_get_cpu(env));
@@ -532,12 +532,12 @@ uint64_t helper_fadd(CPUPPCState *env, uint64_t arg1, uint64_t arg2)
     if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d) &&
                  float64_is_neg(farg1.d) != float64_is_neg(farg2.d))) {
         /* Magnitude subtraction of infinities */
-        farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1);
+        farg1.ll = float_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1);
     } else {
         if (unlikely(float64_is_signaling_nan(farg1.d, &env->fp_status) ||
                      float64_is_signaling_nan(farg2.d, &env->fp_status))) {
             /* sNaN addition */
-            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
+            float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
         }
         farg1.d = float64_add(farg1.d, farg2.d, &env->fp_status);
     }
@@ -556,12 +556,12 @@ uint64_t helper_fsub(CPUPPCState *env, uint64_t arg1, uint64_t arg2)
     if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d) &&
                  float64_is_neg(farg1.d) == float64_is_neg(farg2.d))) {
         /* Magnitude subtraction of infinities */
-        farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1);
+        farg1.ll = float_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1);
     } else {
         if (unlikely(float64_is_signaling_nan(farg1.d, &env->fp_status) ||
                      float64_is_signaling_nan(farg2.d, &env->fp_status))) {
             /* sNaN subtraction */
-            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
+            float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
         }
         farg1.d = float64_sub(farg1.d, farg2.d, &env->fp_status);
     }
@@ -580,12 +580,12 @@ uint64_t helper_fmul(CPUPPCState *env, uint64_t arg1, uint64_t arg2)
     if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
                  (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
         /* Multiplication of zero by infinity */
-        farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1);
+        farg1.ll = float_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1);
     } else {
         if (unlikely(float64_is_signaling_nan(farg1.d, &env->fp_status) ||
                      float64_is_signaling_nan(farg2.d, &env->fp_status))) {
             /* sNaN multiplication */
-            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
+            float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
         }
         farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
     }
@@ -604,15 +604,15 @@ uint64_t helper_fdiv(CPUPPCState *env, uint64_t arg1, uint64_t arg2)
     if (unlikely(float64_is_infinity(farg1.d) &&
                  float64_is_infinity(farg2.d))) {
         /* Division of infinity by infinity */
-        farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIDI, 1);
+        farg1.ll = float_invalid_op_excp(env, POWERPC_EXCP_FP_VXIDI, 1);
     } else if (unlikely(float64_is_zero(farg1.d) && float64_is_zero(farg2.d))) {
         /* Division of zero by zero */
-        farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXZDZ, 1);
+        farg1.ll = float_invalid_op_excp(env, POWERPC_EXCP_FP_VXZDZ, 1);
     } else {
         if (unlikely(float64_is_signaling_nan(farg1.d, &env->fp_status) ||
                      float64_is_signaling_nan(farg2.d, &env->fp_status))) {
             /* sNaN division */
-            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
+            float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
         }
         farg1.d = float64_div(farg1.d, farg2.d, &env->fp_status);
     }
@@ -631,14 +631,14 @@ uint64_t helper_##op(CPUPPCState *env, uint64_t arg)                   \
                                                                        \
     if (unlikely(env->fp_status.float_exception_flags)) {              \
         if (float64_is_any_nan(arg)) {                                 \
-            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 1);      \
+            float_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 1);      \
             if (float64_is_signaling_nan(arg, &env->fp_status)) {      \
-                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); \
+                float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); \
             }                                                          \
             farg.ll = nanval;                                          \
         } else if (env->fp_status.float_exception_flags &              \
                    float_flag_invalid) {                               \
-            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 1);      \
+            float_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 1);      \
         }                                                              \
         helper_float_check_status(env);                                \
     }                                                                  \
@@ -683,7 +683,7 @@ static inline uint64_t do_fri(CPUPPCState *env, uint64_t arg,
 
     if (unlikely(float64_is_signaling_nan(farg.d, &env->fp_status))) {
         /* sNaN round */
-        fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
+        float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
         farg.ll = arg | 0x0008000000000000ULL;
     } else {
         int inexact = get_float_exception_flags(&env->fp_status) &
@@ -735,13 +735,13 @@ uint64_t helper_fmadd(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
     if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
                  (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
         /* Multiplication of zero by infinity */
-        farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1);
+        farg1.ll = float_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1);
     } else {
         if (unlikely(float64_is_signaling_nan(farg1.d, &env->fp_status) ||
                      float64_is_signaling_nan(farg2.d, &env->fp_status) ||
                      float64_is_signaling_nan(farg3.d, &env->fp_status))) {
             /* sNaN operation */
-            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
+            float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
         }
         /* This is the way the PowerPC specification defines it */
         float128 ft0_128, ft1_128;
@@ -753,7 +753,7 @@ uint64_t helper_fmadd(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
                      float64_is_infinity(farg3.d) &&
                      float128_is_neg(ft0_128) != float64_is_neg(farg3.d))) {
             /* Magnitude subtraction of infinities */
-            farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1);
+            farg1.ll = float_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1);
         } else {
             ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
             ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
@@ -778,13 +778,13 @@ uint64_t helper_fmsub(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
                  (float64_is_zero(farg1.d) &&
                   float64_is_infinity(farg2.d)))) {
         /* Multiplication of zero by infinity */
-        farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1);
+        farg1.ll = float_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1);
     } else {
         if (unlikely(float64_is_signaling_nan(farg1.d, &env->fp_status) ||
                      float64_is_signaling_nan(farg2.d, &env->fp_status) ||
                      float64_is_signaling_nan(farg3.d, &env->fp_status))) {
             /* sNaN operation */
-            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
+            float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
         }
         /* This is the way the PowerPC specification defines it */
         float128 ft0_128, ft1_128;
@@ -796,7 +796,7 @@ uint64_t helper_fmsub(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
                      float64_is_infinity(farg3.d) &&
                      float128_is_neg(ft0_128) == float64_is_neg(farg3.d))) {
             /* Magnitude subtraction of infinities */
-            farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1);
+            farg1.ll = float_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1);
         } else {
             ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
             ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
@@ -819,13 +819,13 @@ uint64_t helper_fnmadd(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
     if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
                  (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
         /* Multiplication of zero by infinity */
-        farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1);
+        farg1.ll = float_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1);
     } else {
         if (unlikely(float64_is_signaling_nan(farg1.d, &env->fp_status) ||
                      float64_is_signaling_nan(farg2.d, &env->fp_status) ||
                      float64_is_signaling_nan(farg3.d, &env->fp_status))) {
             /* sNaN operation */
-            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
+            float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
         }
         /* This is the way the PowerPC specification defines it */
         float128 ft0_128, ft1_128;
@@ -837,7 +837,7 @@ uint64_t helper_fnmadd(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
                      float64_is_infinity(farg3.d) &&
                      float128_is_neg(ft0_128) != float64_is_neg(farg3.d))) {
             /* Magnitude subtraction of infinities */
-            farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1);
+            farg1.ll = float_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1);
         } else {
             ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
             ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
@@ -864,13 +864,13 @@ uint64_t helper_fnmsub(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
                  (float64_is_zero(farg1.d) &&
                   float64_is_infinity(farg2.d)))) {
         /* Multiplication of zero by infinity */
-        farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1);
+        farg1.ll = float_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1);
     } else {
         if (unlikely(float64_is_signaling_nan(farg1.d, &env->fp_status) ||
                      float64_is_signaling_nan(farg2.d, &env->fp_status) ||
                      float64_is_signaling_nan(farg3.d, &env->fp_status))) {
             /* sNaN operation */
-            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
+            float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
         }
         /* This is the way the PowerPC specification defines it */
         float128 ft0_128, ft1_128;
@@ -882,7 +882,7 @@ uint64_t helper_fnmsub(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
                      float64_is_infinity(farg3.d) &&
                      float128_is_neg(ft0_128) == float64_is_neg(farg3.d))) {
             /* Magnitude subtraction of infinities */
-            farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1);
+            farg1.ll = float_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1);
         } else {
             ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
             ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
@@ -905,7 +905,7 @@ uint64_t helper_frsp(CPUPPCState *env, uint64_t arg)
 
     if (unlikely(float64_is_signaling_nan(farg.d, &env->fp_status))) {
         /* sNaN square root */
-        fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
+        float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
     }
     f32 = float64_to_float32(farg.d, &env->fp_status);
     farg.d = float32_to_float64(f32, &env->fp_status);
@@ -923,12 +923,12 @@ uint64_t helper_fsqrt(CPUPPCState *env, uint64_t arg)
     if (unlikely(float64_is_any_nan(farg.d))) {
         if (unlikely(float64_is_signaling_nan(farg.d, &env->fp_status))) {
             /* sNaN reciprocal square root */
-            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
+            float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
             farg.ll = float64_snan_to_qnan(farg.ll);
         }
     } else if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) {
         /* Square root of a negative nonzero number */
-        farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, 1);
+        farg.ll = float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, 1);
     } else {
         farg.d = float64_sqrt(farg.d, &env->fp_status);
     }
@@ -944,7 +944,7 @@ uint64_t helper_fre(CPUPPCState *env, uint64_t arg)
 
     if (unlikely(float64_is_signaling_nan(farg.d, &env->fp_status))) {
         /* sNaN reciprocal */
-        fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
+        float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
     }
     farg.d = float64_div(float64_one, farg.d, &env->fp_status);
     return farg.d;
@@ -960,7 +960,7 @@ uint64_t helper_fres(CPUPPCState *env, uint64_t arg)
 
     if (unlikely(float64_is_signaling_nan(farg.d, &env->fp_status))) {
         /* sNaN reciprocal */
-        fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
+        float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
     }
     farg.d = float64_div(float64_one, farg.d, &env->fp_status);
     f32 = float64_to_float32(farg.d, &env->fp_status);
@@ -979,12 +979,12 @@ uint64_t helper_frsqrte(CPUPPCState *env, uint64_t arg)
     if (unlikely(float64_is_any_nan(farg.d))) {
         if (unlikely(float64_is_signaling_nan(farg.d, &env->fp_status))) {
             /* sNaN reciprocal square root */
-            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
+            float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
             farg.ll = float64_snan_to_qnan(farg.ll);
         }
     } else if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) {
         /* Reciprocal square root of a negative nonzero number */
-        farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, 1);
+        farg.ll = float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, 1);
     } else {
         farg.d = float64_sqrt(farg.d, &env->fp_status);
         farg.d = float64_div(float64_one, farg.d, &env->fp_status);
@@ -1103,7 +1103,7 @@ void helper_fcmpu(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
                  && (float64_is_signaling_nan(farg1.d, &env->fp_status) ||
                      float64_is_signaling_nan(farg2.d, &env->fp_status)))) {
         /* sNaN comparison */
-        fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
+        float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
     }
 }
 
@@ -1134,11 +1134,11 @@ void helper_fcmpo(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
         if (float64_is_signaling_nan(farg1.d, &env->fp_status) ||
             float64_is_signaling_nan(farg2.d, &env->fp_status)) {
             /* sNaN comparison */
-            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN |
+            float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN |
                                   POWERPC_EXCP_FP_VXVC, 1);
         } else {
             /* qNaN comparison */
-            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXVC, 1);
+            float_invalid_op_excp(env, POWERPC_EXCP_FP_VXVC, 1);
         }
     }
 }
@@ -1838,10 +1838,10 @@ void helper_##name(CPUPPCState *env, uint32_t opcode)                        \
                                                                              \
         if (unlikely(tstat.float_exception_flags & float_flag_invalid)) {    \
             if (tp##_is_infinity(xa.fld) && tp##_is_infinity(xb.fld)) {      \
-                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, sfprf);    \
+                float_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, sfprf);    \
             } else if (tp##_is_signaling_nan(xa.fld, &tstat) ||              \
                        tp##_is_signaling_nan(xb.fld, &tstat)) {              \
-                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf);   \
+                float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf);   \
             }                                                                \
         }                                                                    \
                                                                              \
@@ -1893,10 +1893,10 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)                          \
         if (unlikely(tstat.float_exception_flags & float_flag_invalid)) {    \
             if ((tp##_is_infinity(xa.fld) && tp##_is_zero(xb.fld)) ||        \
                 (tp##_is_infinity(xb.fld) && tp##_is_zero(xa.fld))) {        \
-                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, sfprf);    \
+                float_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, sfprf);    \
             } else if (tp##_is_signaling_nan(xa.fld, &tstat) ||              \
                        tp##_is_signaling_nan(xb.fld, &tstat)) {              \
-                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf);   \
+                float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf);   \
             }                                                                \
         }                                                                    \
                                                                              \
@@ -1944,13 +1944,13 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)                           \
                                                                               \
         if (unlikely(tstat.float_exception_flags & float_flag_invalid)) {     \
             if (tp##_is_infinity(xa.fld) && tp##_is_infinity(xb.fld)) {       \
-                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIDI, sfprf);     \
+                float_invalid_op_excp(env, POWERPC_EXCP_FP_VXIDI, sfprf);     \
             } else if (tp##_is_zero(xa.fld) &&                                \
                 tp##_is_zero(xb.fld)) {                                       \
-                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXZDZ, sfprf);     \
+                float_invalid_op_excp(env, POWERPC_EXCP_FP_VXZDZ, sfprf);     \
             } else if (tp##_is_signaling_nan(xa.fld, &tstat) ||               \
                 tp##_is_signaling_nan(xb.fld, &tstat)) {                      \
-                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf);    \
+                float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf);    \
             }                                                                 \
         }                                                                     \
                                                                               \
@@ -1991,7 +1991,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)                           \
                                                                               \
     for (i = 0; i < nels; i++) {                                              \
         if (unlikely(tp##_is_signaling_nan(xb.fld, &env->fp_status))) {       \
-                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf);    \
+                float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf);    \
         }                                                                     \
         xt.fld = tp##_div(tp##_one, xb.fld, &env->fp_status);                 \
                                                                               \
@@ -2038,9 +2038,9 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)                          \
                                                                              \
         if (unlikely(tstat.float_exception_flags & float_flag_invalid)) {    \
             if (tp##_is_neg(xb.fld) && !tp##_is_zero(xb.fld)) {              \
-                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, sfprf);   \
+                float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, sfprf);   \
             } else if (tp##_is_signaling_nan(xb.fld, &tstat)) {              \
-                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf);   \
+                float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf);   \
             }                                                                \
         }                                                                    \
                                                                              \
@@ -2088,9 +2088,9 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)                          \
                                                                              \
         if (unlikely(tstat.float_exception_flags & float_flag_invalid)) {    \
             if (tp##_is_neg(xb.fld) && !tp##_is_zero(xb.fld)) {              \
-                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, sfprf);   \
+                float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, sfprf);   \
             } else if (tp##_is_signaling_nan(xb.fld, &tstat)) {              \
-                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf);   \
+                float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf);   \
             }                                                                \
         }                                                                    \
                                                                              \
@@ -2277,12 +2277,12 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)                           \
             if (tp##_is_signaling_nan(xa.fld, &tstat) ||                      \
                 tp##_is_signaling_nan(b->fld, &tstat) ||                      \
                 tp##_is_signaling_nan(c->fld, &tstat)) {                      \
-                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf);    \
+                float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf);    \
                 tstat.float_exception_flags &= ~float_flag_invalid;           \
             }                                                                 \
             if ((tp##_is_infinity(xa.fld) && tp##_is_zero(b->fld)) ||         \
                 (tp##_is_zero(xa.fld) && tp##_is_infinity(b->fld))) {         \
-                xt_out.fld = float64_to_##tp(fload_invalid_op_excp(env,       \
+                xt_out.fld = float64_to_##tp(float_invalid_op_excp(env,       \
                     POWERPC_EXCP_FP_VXIMZ, sfprf), &env->fp_status);          \
                 tstat.float_exception_flags &= ~float_flag_invalid;           \
             }                                                                 \
@@ -2290,7 +2290,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)                           \
                 ((tp##_is_infinity(xa.fld) ||                                 \
                   tp##_is_infinity(b->fld)) &&                                \
                   tp##_is_infinity(c->fld))) {                                \
-                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, sfprf);     \
+                float_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, sfprf);     \
             }                                                                 \
         }                                                                     \
                                                                               \
@@ -2360,10 +2360,10 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)                      \
                  float64_is_any_nan(xb.VsrD(0)))) {                      \
         if (float64_is_signaling_nan(xa.VsrD(0), &env->fp_status) ||     \
             float64_is_signaling_nan(xb.VsrD(0), &env->fp_status)) {     \
-            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0);       \
+            float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0);       \
         }                                                                \
         if (ordered) {                                                   \
-            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXVC, 0);         \
+            float_invalid_op_excp(env, POWERPC_EXCP_FP_VXVC, 0);         \
         }                                                                \
         cc = 1;                                                          \
     } else {                                                             \
@@ -2408,7 +2408,7 @@ void helper_##name(CPUPPCState *env, uint32_t opcode)                         \
         xt.fld = tp##_##op(xa.fld, xb.fld, &env->fp_status);                  \
         if (unlikely(tp##_is_signaling_nan(xa.fld, &env->fp_status) ||        \
                      tp##_is_signaling_nan(xb.fld, &env->fp_status))) {       \
-            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0);            \
+            float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0);            \
         }                                                                     \
     }                                                                         \
                                                                               \
@@ -2448,10 +2448,10 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)                       \
                      tp##_is_any_nan(xb.fld))) {                          \
             if (tp##_is_signaling_nan(xa.fld, &env->fp_status) ||         \
                 tp##_is_signaling_nan(xb.fld, &env->fp_status)) {         \
-                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0);    \
+                float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0);    \
             }                                                             \
             if (svxvc) {                                                  \
-                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXVC, 0);      \
+                float_invalid_op_excp(env, POWERPC_EXCP_FP_VXVC, 0);      \
             }                                                             \
             xt.fld = 0;                                                   \
             all_true = 0;                                                 \
@@ -2502,7 +2502,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)                \
         xt.tfld = stp##_to_##ttp(xb.sfld, &env->fp_status);        \
         if (unlikely(stp##_is_signaling_nan(xb.sfld,               \
                                             &env->fp_status))) {   \
-            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0); \
+            float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0); \
             xt.tfld = ttp##_snan_to_qnan(xt.tfld);                 \
         }                                                          \
         if (sfprf) {                                               \
@@ -2557,15 +2557,15 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)                          \
     for (i = 0; i < nels; i++) {                                             \
         if (unlikely(stp##_is_any_nan(xb.sfld))) {                           \
             if (stp##_is_signaling_nan(xb.sfld, &env->fp_status)) {          \
-                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0);       \
+                float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0);       \
             }                                                                \
-            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 0);            \
+            float_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 0);            \
             xt.tfld = rnan;                                                  \
         } else {                                                             \
             xt.tfld = stp##_to_##ttp##_round_to_zero(xb.sfld,                \
                           &env->fp_status);                                  \
             if (env->fp_status.float_exception_flags & float_flag_invalid) { \
-                fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 0);        \
+                float_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 0);        \
             }                                                                \
         }                                                                    \
     }                                                                        \
@@ -2667,7 +2667,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)                    \
     for (i = 0; i < nels; i++) {                                       \
         if (unlikely(tp##_is_signaling_nan(xb.fld,                     \
                                            &env->fp_status))) {        \
-            fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0);     \
+            float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0);     \
             xt.fld = tp##_snan_to_qnan(xb.fld);                        \
         } else {                                                       \
             xt.fld = tp##_round_to_int(xb.fld, &env->fp_status);       \
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [Qemu-devel] [PATCH 09/32] ppc: Make float_invalid_op_excp() pass the return address
  2016-07-26 22:20 [Qemu-devel] [PATCH 01/32] ppc: Fix fault PC reporting for lve*/stve* VMX instructions Benjamin Herrenschmidt
                   ` (6 preceding siblings ...)
  2016-07-26 22:21 ` [Qemu-devel] [PATCH 08/32] ppc: Rename fload_invalid_op_excp to float_invalid_op_excp Benjamin Herrenschmidt
@ 2016-07-26 22:21 ` Benjamin Herrenschmidt
  2016-07-28 16:06   ` Richard Henderson
  2016-07-26 22:21 ` [Qemu-devel] [PATCH 10/32] ppc: Make float_check_status() " Benjamin Herrenschmidt
                   ` (23 subsequent siblings)
  31 siblings, 1 reply; 69+ messages in thread
From: Benjamin Herrenschmidt @ 2016-07-26 22:21 UTC (permalink / raw)
  To: qemu-ppc; +Cc: qemu-devel, david, Benjamin Herrenschmidt

Instead of relying on NIP having been updated already

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
 target-ppc/fpu_helper.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/target-ppc/fpu_helper.c b/target-ppc/fpu_helper.c
index e1f600a..8d881fc 100644
--- a/target-ppc/fpu_helper.c
+++ b/target-ppc/fpu_helper.c
@@ -19,6 +19,7 @@
 #include "qemu/osdep.h"
 #include "cpu.h"
 #include "exec/helper-proto.h"
+#include "exec/exec-all.h"
 
 #define float64_snan_to_qnan(x) ((x) | 0x0008000000000000ULL)
 #define float32_snan_to_qnan(x) ((x) | 0x00400000)
@@ -200,8 +201,9 @@ static inline uint64_t float_invalid_op_excp(CPUPPCState *env, int op,
         /* Update the floating-point enabled exception summary */
         env->fpscr |= 1 << FPSCR_FEX;
         if (msr_fe0 != 0 || msr_fe1 != 0) {
-            helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
-                                       POWERPC_EXCP_FP | op);
+            /* GETPC() works here because this is inline */
+            raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM,
+                                   POWERPC_EXCP_FP | op, GETPC());
         }
     }
     return ret;
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [Qemu-devel] [PATCH 10/32] ppc: Make float_check_status() pass the return address
  2016-07-26 22:20 [Qemu-devel] [PATCH 01/32] ppc: Fix fault PC reporting for lve*/stve* VMX instructions Benjamin Herrenschmidt
                   ` (7 preceding siblings ...)
  2016-07-26 22:21 ` [Qemu-devel] [PATCH 09/32] ppc: Make float_invalid_op_excp() pass the return address Benjamin Herrenschmidt
@ 2016-07-26 22:21 ` Benjamin Herrenschmidt
  2016-07-27  1:57   ` David Gibson
  2016-07-26 22:21 ` [Qemu-devel] [PATCH 11/32] ppc: Don't update the NIP in floating point generated code Benjamin Herrenschmidt
                   ` (22 subsequent siblings)
  31 siblings, 1 reply; 69+ messages in thread
From: Benjamin Herrenschmidt @ 2016-07-26 22:21 UTC (permalink / raw)
  To: qemu-ppc; +Cc: qemu-devel, david, Benjamin Herrenschmidt

Instead of relying on NIP having been updated already.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
 target-ppc/fpu_helper.c | 63 +++++++++++++++++++++++++++++--------------------
 1 file changed, 38 insertions(+), 25 deletions(-)

diff --git a/target-ppc/fpu_helper.c b/target-ppc/fpu_helper.c
index 8d881fc..7bab3ff 100644
--- a/target-ppc/fpu_helper.c
+++ b/target-ppc/fpu_helper.c
@@ -209,7 +209,7 @@ static inline uint64_t float_invalid_op_excp(CPUPPCState *env, int op,
     return ret;
 }
 
-static inline void float_zero_divide_excp(CPUPPCState *env)
+static inline void float_zero_divide_excp(CPUPPCState *env, uintptr_t raddr)
 {
     env->fpscr |= 1 << FPSCR_ZX;
     env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
@@ -219,8 +219,9 @@ static inline void float_zero_divide_excp(CPUPPCState *env)
         /* Update the floating-point enabled exception summary */
         env->fpscr |= 1 << FPSCR_FEX;
         if (msr_fe0 != 0 || msr_fe1 != 0) {
-            helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
-                                       POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX);
+            raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM,
+                                   POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX,
+                                   raddr);
         }
     }
 }
@@ -493,13 +494,14 @@ void store_fpscr(CPUPPCState *env, uint64_t arg, uint32_t mask)
     helper_store_fpscr(env, arg, mask);
 }
 
-void helper_float_check_status(CPUPPCState *env)
+static __attribute__((noinline)) void do_float_check_status(CPUPPCState *env,
+                                                            uintptr_t raddr)
 {
     CPUState *cs = CPU(ppc_env_get_cpu(env));
     int status = get_float_exception_flags(&env->fp_status);
 
     if (status & float_flag_divbyzero) {
-        float_zero_divide_excp(env);
+        float_zero_divide_excp(env, raddr);
     } else if (status & float_flag_overflow) {
         float_overflow_excp(env);
     } else if (status & float_flag_underflow) {
@@ -512,12 +514,23 @@ void helper_float_check_status(CPUPPCState *env)
         (env->error_code & POWERPC_EXCP_FP)) {
         /* Differred floating-point exception after target FPR update */
         if (msr_fe0 != 0 || msr_fe1 != 0) {
-            helper_raise_exception_err(env, cs->exception_index,
-                                       env->error_code);
+            raise_exception_err_ra(env, cs->exception_index,
+                                   env->error_code, raddr);
         }
     }
 }
 
+static inline void float_check_status(CPUPPCState *env)
+{
+    /* GETPC() works here because this is inline */
+    do_float_check_status(env, GETPC());
+}
+
+void helper_float_check_status(CPUPPCState *env)
+{
+    do_float_check_status(env, GETPC());
+}
+
 void helper_reset_fpstatus(CPUPPCState *env)
 {
     set_float_exception_flags(0, &env->fp_status);
@@ -642,7 +655,7 @@ uint64_t helper_##op(CPUPPCState *env, uint64_t arg)                   \
                    float_flag_invalid) {                               \
             float_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 1);      \
         }                                                              \
-        helper_float_check_status(env);                                \
+        float_check_status(env);                                       \
     }                                                                  \
     return farg.ll;                                                    \
  }
@@ -667,7 +680,7 @@ uint64_t helper_##op(CPUPPCState *env, uint64_t arg)       \
     } else {                                               \
         farg.d = cvtr(arg, &env->fp_status);               \
     }                                                      \
-    helper_float_check_status(env);                        \
+    float_check_status(env);                               \
     return farg.ll;                                        \
 }
 
@@ -700,7 +713,7 @@ static inline uint64_t do_fri(CPUPPCState *env, uint64_t arg,
             env->fp_status.float_exception_flags &= ~float_flag_inexact;
         }
     }
-    helper_float_check_status(env);
+    float_check_status(env);
     return farg.ll;
 }
 
@@ -1856,7 +1869,7 @@ void helper_##name(CPUPPCState *env, uint32_t opcode)                        \
         }                                                                    \
     }                                                                        \
     putVSR(xT(opcode), &xt, env);                                            \
-    helper_float_check_status(env);                                          \
+    float_check_status(env);                                                 \
 }
 
 VSX_ADD_SUB(xsadddp, add, 1, float64, VsrD(0), 1, 0)
@@ -1912,7 +1925,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)                          \
     }                                                                        \
                                                                              \
     putVSR(xT(opcode), &xt, env);                                            \
-    helper_float_check_status(env);                                          \
+    float_check_status(env);                                                 \
 }
 
 VSX_MUL(xsmuldp, 1, float64, VsrD(0), 1, 0)
@@ -1966,7 +1979,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)                           \
     }                                                                         \
                                                                               \
     putVSR(xT(opcode), &xt, env);                                             \
-    helper_float_check_status(env);                                           \
+    float_check_status(env);                                                  \
 }
 
 VSX_DIV(xsdivdp, 1, float64, VsrD(0), 1, 0)
@@ -2007,7 +2020,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)                           \
     }                                                                         \
                                                                               \
     putVSR(xT(opcode), &xt, env);                                             \
-    helper_float_check_status(env);                                           \
+    float_check_status(env);                                                  \
 }
 
 VSX_RE(xsredp, 1, float64, VsrD(0), 1, 0)
@@ -2056,7 +2069,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)                          \
     }                                                                        \
                                                                              \
     putVSR(xT(opcode), &xt, env);                                            \
-    helper_float_check_status(env);                                          \
+    float_check_status(env);                                                 \
 }
 
 VSX_SQRT(xssqrtdp, 1, float64, VsrD(0), 1, 0)
@@ -2106,7 +2119,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)                          \
     }                                                                        \
                                                                              \
     putVSR(xT(opcode), &xt, env);                                            \
-    helper_float_check_status(env);                                          \
+    float_check_status(env);                                                 \
 }
 
 VSX_RSQRTE(xsrsqrtedp, 1, float64, VsrD(0), 1, 0)
@@ -2305,7 +2318,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)                           \
         }                                                                     \
     }                                                                         \
     putVSR(xT(opcode), &xt_out, env);                                         \
-    helper_float_check_status(env);                                           \
+    float_check_status(env);                                                  \
 }
 
 #define MADD_FLGS 0
@@ -2383,7 +2396,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)                      \
     env->fpscr |= cc << FPSCR_FPRF;                                      \
     env->crf[BF(opcode)] = cc;                                           \
                                                                          \
-    helper_float_check_status(env);                                      \
+    float_check_status(env);                                             \
 }
 
 VSX_SCALAR_CMP(xscmpodp, 1)
@@ -2415,7 +2428,7 @@ void helper_##name(CPUPPCState *env, uint32_t opcode)                         \
     }                                                                         \
                                                                               \
     putVSR(xT(opcode), &xt, env);                                             \
-    helper_float_check_status(env);                                           \
+    float_check_status(env);                                                  \
 }
 
 VSX_MAX_MIN(xsmaxdp, maxnum, 1, float64, VsrD(0))
@@ -2472,7 +2485,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)                       \
     if ((opcode >> (31-21)) & 1) {                                        \
         env->crf[6] = (all_true ? 0x8 : 0) | (all_false ? 0x2 : 0);       \
     }                                                                     \
-    helper_float_check_status(env);                                       \
+    float_check_status(env);                                              \
  }
 
 VSX_CMP(xvcmpeqdp, 2, float64, VsrD(i), eq, 0)
@@ -2514,7 +2527,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)                \
     }                                                              \
                                                                    \
     putVSR(xT(opcode), &xt, env);                                  \
-    helper_float_check_status(env);                                \
+    float_check_status(env);                                       \
 }
 
 VSX_CVT_FP_TO_FP(xscvdpsp, 1, float64, float32, VsrD(0), VsrW(0), 1)
@@ -2573,7 +2586,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)                          \
     }                                                                        \
                                                                              \
     putVSR(xT(opcode), &xt, env);                                            \
-    helper_float_check_status(env);                                          \
+    float_check_status(env);                                                 \
 }
 
 VSX_CVT_FP_TO_INT(xscvdpsxds, 1, float64, int64, VsrD(0), VsrD(0), \
@@ -2624,7 +2637,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)                     \
     }                                                                   \
                                                                         \
     putVSR(xT(opcode), &xt, env);                                       \
-    helper_float_check_status(env);                                     \
+    float_check_status(env);                                            \
 }
 
 VSX_CVT_INT_TO_FP(xscvsxddp, 1, int64, float64, VsrD(0), VsrD(0), 1, 0)
@@ -2688,7 +2701,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)                    \
     }                                                                  \
                                                                        \
     putVSR(xT(opcode), &xt, env);                                      \
-    helper_float_check_status(env);                                    \
+    float_check_status(env);                                           \
 }
 
 VSX_ROUND(xsrdpi, 1, float64, VsrD(0), float_round_ties_away, 1)
@@ -2716,6 +2729,6 @@ uint64_t helper_xsrsp(CPUPPCState *env, uint64_t xb)
     uint64_t xt = helper_frsp(env, xb);
 
     helper_compute_fprf(env, xt);
-    helper_float_check_status(env);
+    float_check_status(env);
     return xt;
 }
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [Qemu-devel] [PATCH 11/32] ppc: Don't update the NIP in floating point generated code
  2016-07-26 22:20 [Qemu-devel] [PATCH 01/32] ppc: Fix fault PC reporting for lve*/stve* VMX instructions Benjamin Herrenschmidt
                   ` (8 preceding siblings ...)
  2016-07-26 22:21 ` [Qemu-devel] [PATCH 10/32] ppc: Make float_check_status() " Benjamin Herrenschmidt
@ 2016-07-26 22:21 ` Benjamin Herrenschmidt
  2016-07-26 22:21 ` [Qemu-devel] [PATCH 12/32] ppc: FP exceptions are always precise Benjamin Herrenschmidt
                   ` (21 subsequent siblings)
  31 siblings, 0 replies; 69+ messages in thread
From: Benjamin Herrenschmidt @ 2016-07-26 22:21 UTC (permalink / raw)
  To: qemu-ppc; +Cc: qemu-devel, david, Benjamin Herrenschmidt

This is no longer necessary as the helpers will properly retrieve
the return address.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
 target-ppc/translate/fp-impl.c  | 28 ----------------------------
 target-ppc/translate/vsx-impl.c |  6 ------
 2 files changed, 34 deletions(-)

diff --git a/target-ppc/translate/fp-impl.c b/target-ppc/translate/fp-impl.c
index 2abc386..9ba9289 100644
--- a/target-ppc/translate/fp-impl.c
+++ b/target-ppc/translate/fp-impl.c
@@ -38,8 +38,6 @@ static void gen_f##name(DisasContext *ctx)                                    \
         gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
         return;                                                               \
     }                                                                         \
-    /* NIP cannot be restored if the memory exception comes from an helper */ \
-    gen_update_nip(ctx, ctx->nip - 4);                                        \
     gen_reset_fpstatus();                                                     \
     gen_helper_f##op(cpu_fpr[rD(ctx->opcode)], cpu_env,                       \
                      cpu_fpr[rA(ctx->opcode)],                                \
@@ -67,8 +65,6 @@ static void gen_f##name(DisasContext *ctx)                                    \
         gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
         return;                                                               \
     }                                                                         \
-    /* NIP cannot be restored if the memory exception comes from an helper */ \
-    gen_update_nip(ctx, ctx->nip - 4);                                        \
     gen_reset_fpstatus();                                                     \
     gen_helper_f##op(cpu_fpr[rD(ctx->opcode)], cpu_env,                       \
                      cpu_fpr[rA(ctx->opcode)],                                \
@@ -95,8 +91,6 @@ static void gen_f##name(DisasContext *ctx)                                    \
         gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
         return;                                                               \
     }                                                                         \
-    /* NIP cannot be restored if the memory exception comes from an helper */ \
-    gen_update_nip(ctx, ctx->nip - 4);                                        \
     gen_reset_fpstatus();                                                     \
     gen_helper_f##op(cpu_fpr[rD(ctx->opcode)], cpu_env,                       \
                      cpu_fpr[rA(ctx->opcode)],                                \
@@ -123,8 +117,6 @@ static void gen_f##name(DisasContext *ctx)                                    \
         gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
         return;                                                               \
     }                                                                         \
-    /* NIP cannot be restored if the memory exception comes from an helper */ \
-    gen_update_nip(ctx, ctx->nip - 4);                                        \
     gen_reset_fpstatus();                                                     \
     gen_helper_f##name(cpu_fpr[rD(ctx->opcode)], cpu_env,                     \
                        cpu_fpr[rB(ctx->opcode)]);                             \
@@ -143,8 +135,6 @@ static void gen_f##name(DisasContext *ctx)                                    \
         gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
         return;                                                               \
     }                                                                         \
-    /* NIP cannot be restored if the memory exception comes from an helper */ \
-    gen_update_nip(ctx, ctx->nip - 4);                                        \
     gen_reset_fpstatus();                                                     \
     gen_helper_f##name(cpu_fpr[rD(ctx->opcode)], cpu_env,                     \
                        cpu_fpr[rB(ctx->opcode)]);                             \
@@ -179,8 +169,6 @@ static void gen_frsqrtes(DisasContext *ctx)
         gen_exception(ctx, POWERPC_EXCP_FPU);
         return;
     }
-    /* NIP cannot be restored if the memory exception comes from an helper */
-    gen_update_nip(ctx, ctx->nip - 4);
     gen_reset_fpstatus();
     gen_helper_frsqrte(cpu_fpr[rD(ctx->opcode)], cpu_env,
                        cpu_fpr[rB(ctx->opcode)]);
@@ -205,8 +193,6 @@ static void gen_fsqrt(DisasContext *ctx)
         gen_exception(ctx, POWERPC_EXCP_FPU);
         return;
     }
-    /* NIP cannot be restored if the memory exception comes from an helper */
-    gen_update_nip(ctx, ctx->nip - 4);
     gen_reset_fpstatus();
     gen_helper_fsqrt(cpu_fpr[rD(ctx->opcode)], cpu_env,
                      cpu_fpr[rB(ctx->opcode)]);
@@ -222,8 +208,6 @@ static void gen_fsqrts(DisasContext *ctx)
         gen_exception(ctx, POWERPC_EXCP_FPU);
         return;
     }
-    /* NIP cannot be restored if the memory exception comes from an helper */
-    gen_update_nip(ctx, ctx->nip - 4);
     gen_reset_fpstatus();
     gen_helper_fsqrt(cpu_fpr[rD(ctx->opcode)], cpu_env,
                      cpu_fpr[rB(ctx->opcode)]);
@@ -313,8 +297,6 @@ static void gen_fcmpo(DisasContext *ctx)
         gen_exception(ctx, POWERPC_EXCP_FPU);
         return;
     }
-    /* NIP cannot be restored if the memory exception comes from an helper */
-    gen_update_nip(ctx, ctx->nip - 4);
     gen_reset_fpstatus();
     crf = tcg_const_i32(crfD(ctx->opcode));
     gen_helper_fcmpo(cpu_env, cpu_fpr[rA(ctx->opcode)],
@@ -331,8 +313,6 @@ static void gen_fcmpu(DisasContext *ctx)
         gen_exception(ctx, POWERPC_EXCP_FPU);
         return;
     }
-    /* NIP cannot be restored if the memory exception comes from an helper */
-    gen_update_nip(ctx, ctx->nip - 4);
     gen_reset_fpstatus();
     crf = tcg_const_i32(crfD(ctx->opcode));
     gen_helper_fcmpu(cpu_env, cpu_fpr[rA(ctx->opcode)],
@@ -502,8 +482,6 @@ static void gen_mtfsb0(DisasContext *ctx)
     gen_reset_fpstatus();
     if (likely(crb != FPSCR_FEX && crb != FPSCR_VX)) {
         TCGv_i32 t0;
-        /* NIP cannot be restored if the memory exception comes from an helper */
-        gen_update_nip(ctx, ctx->nip - 4);
         t0 = tcg_const_i32(crb);
         gen_helper_fpscr_clrbit(cpu_env, t0);
         tcg_temp_free_i32(t0);
@@ -528,8 +506,6 @@ static void gen_mtfsb1(DisasContext *ctx)
     /* XXX: we pretend we can only do IEEE floating-point computations */
     if (likely(crb != FPSCR_FEX && crb != FPSCR_VX && crb != FPSCR_NI)) {
         TCGv_i32 t0;
-        /* NIP cannot be restored if the memory exception comes from an helper */
-        gen_update_nip(ctx, ctx->nip - 4);
         t0 = tcg_const_i32(crb);
         gen_helper_fpscr_setbit(cpu_env, t0);
         tcg_temp_free_i32(t0);
@@ -559,8 +535,6 @@ static void gen_mtfsf(DisasContext *ctx)
         gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
         return;
     }
-    /* NIP cannot be restored if the memory exception comes from an helper */
-    gen_update_nip(ctx, ctx->nip - 4);
     gen_reset_fpstatus();
     if (l) {
         t0 = tcg_const_i32((ctx->insns_flags2 & PPC2_ISA205) ? 0xffff : 0xff);
@@ -595,8 +569,6 @@ static void gen_mtfsfi(DisasContext *ctx)
         return;
     }
     sh = (8 * w) + 7 - bf;
-    /* NIP cannot be restored if the memory exception comes from an helper */
-    gen_update_nip(ctx, ctx->nip - 4);
     gen_reset_fpstatus();
     t0 = tcg_const_i64(((uint64_t)FPIMM(ctx->opcode)) << (4 * sh));
     t1 = tcg_const_i32(1 << sh);
diff --git a/target-ppc/translate/vsx-impl.c b/target-ppc/translate/vsx-impl.c
index 7361c47..9f77b06 100644
--- a/target-ppc/translate/vsx-impl.c
+++ b/target-ppc/translate/vsx-impl.c
@@ -380,8 +380,6 @@ static void gen_##name(DisasContext * ctx)                                    \
         gen_exception(ctx, POWERPC_EXCP_VSXU);                                \
         return;                                                               \
     }                                                                         \
-    /* NIP cannot be restored if the memory exception comes from an helper */ \
-    gen_update_nip(ctx, ctx->nip - 4);                                        \
     opc = tcg_const_i32(ctx->opcode);                                         \
     gen_helper_##name(cpu_env, opc);                                          \
     tcg_temp_free_i32(opc);                                                   \
@@ -394,10 +392,6 @@ static void gen_##name(DisasContext * ctx)                    \
         gen_exception(ctx, POWERPC_EXCP_VSXU);                \
         return;                                               \
     }                                                         \
-    /* NIP cannot be restored if the exception comes */       \
-    /* from a helper. */                                      \
-    gen_update_nip(ctx, ctx->nip - 4);                        \
-                                                              \
     gen_helper_##name(cpu_vsrh(xT(ctx->opcode)), cpu_env,     \
                       cpu_vsrh(xB(ctx->opcode)));             \
 }
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [Qemu-devel] [PATCH 12/32] ppc: FP exceptions are always precise
  2016-07-26 22:20 [Qemu-devel] [PATCH 01/32] ppc: Fix fault PC reporting for lve*/stve* VMX instructions Benjamin Herrenschmidt
                   ` (9 preceding siblings ...)
  2016-07-26 22:21 ` [Qemu-devel] [PATCH 11/32] ppc: Don't update the NIP in floating point generated code Benjamin Herrenschmidt
@ 2016-07-26 22:21 ` Benjamin Herrenschmidt
  2016-07-27  2:00   ` David Gibson
  2016-07-26 22:21 ` [Qemu-devel] [PATCH 13/32] ppc: Don't update NIP in lswi/lswx/stswi/stswx Benjamin Herrenschmidt
                   ` (20 subsequent siblings)
  31 siblings, 1 reply; 69+ messages in thread
From: Benjamin Herrenschmidt @ 2016-07-26 22:21 UTC (permalink / raw)
  To: qemu-ppc; +Cc: qemu-devel, david, Benjamin Herrenschmidt

We don't implement imprecise FP exceptions and using store_current
which sets SRR1 to the *previous* instruction never makes sense
for these. So let's be truthful and make them precise, which is
allowed by the architecture.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
 target-ppc/excp_helper.c | 11 ++++++-----
 target-ppc/translate.c   |  1 -
 2 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/target-ppc/excp_helper.c b/target-ppc/excp_helper.c
index f4b115e..91fdf4b 100644
--- a/target-ppc/excp_helper.c
+++ b/target-ppc/excp_helper.c
@@ -274,12 +274,13 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
                 env->error_code = 0;
                 return;
             }
+
+            /* FP exceptions always have NIP pointing to the faulting
+             * instruction, so always use store_next and claim we are
+             * precise in the MSR.
+             */
             msr |= 0x00100000;
-            if (msr_fe0 == msr_fe1) {
-                goto store_next;
-            }
-            msr |= 0x00010000;
-            break;
+            goto store_next;
         case POWERPC_EXCP_INVAL:
             LOG_EXCP("Invalid instruction at " TARGET_FMT_lx "\n", env->nip);
             msr |= 0x00080000;
diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index cb4e313..a05fed7 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -2846,7 +2846,6 @@ static void gen_conditional_store(DisasContext *ctx, TCGv EA,
                                   int reg, int size)
 {
     TCGv t0 = tcg_temp_new();
-    uint32_t save_exception = ctx->exception;
 
     tcg_gen_st_tl(EA, cpu_env, offsetof(CPUPPCState, reserve_ea));
     tcg_gen_movi_tl(t0, (size << 5) | reg);
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [Qemu-devel] [PATCH 13/32] ppc: Don't update NIP in lswi/lswx/stswi/stswx
  2016-07-26 22:20 [Qemu-devel] [PATCH 01/32] ppc: Fix fault PC reporting for lve*/stve* VMX instructions Benjamin Herrenschmidt
                   ` (10 preceding siblings ...)
  2016-07-26 22:21 ` [Qemu-devel] [PATCH 12/32] ppc: FP exceptions are always precise Benjamin Herrenschmidt
@ 2016-07-26 22:21 ` Benjamin Herrenschmidt
  2016-07-27  2:04   ` David Gibson
  2016-07-26 22:21 ` [Qemu-devel] [PATCH 14/32] ppc: Don't update NIP in lmw/stmw/icbi Benjamin Herrenschmidt
                   ` (19 subsequent siblings)
  31 siblings, 1 reply; 69+ messages in thread
From: Benjamin Herrenschmidt @ 2016-07-26 22:21 UTC (permalink / raw)
  To: qemu-ppc; +Cc: qemu-devel, david, Benjamin Herrenschmidt

Instead, pass GETPC() result to the corresponding helpers. This
requires a bit of fiddling to get the PC (hopefully) right in
the case where we generate a program check, though the hacks there
are temporary, a subsequent patch will clean this all up by always
having the nip already set to the right instruction when taking
the fault.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
 target-ppc/excp_helper.c |  8 ++++++++
 target-ppc/mem_helper.c  | 26 ++++++++++++++++----------
 target-ppc/translate.c   | 18 ++++++++----------
 3 files changed, 32 insertions(+), 20 deletions(-)

diff --git a/target-ppc/excp_helper.c b/target-ppc/excp_helper.c
index 91fdf4b..563c7bc 100644
--- a/target-ppc/excp_helper.c
+++ b/target-ppc/excp_helper.c
@@ -285,6 +285,10 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
             LOG_EXCP("Invalid instruction at " TARGET_FMT_lx "\n", env->nip);
             msr |= 0x00080000;
             env->spr[SPR_BOOKE_ESR] = ESR_PIL;
+            /* Some invalids will have the PC in the right place already */
+            if (env->error_code & POWERPC_EXCP_INVAL_LSWX) {
+                goto store_next;
+            }
             break;
         case POWERPC_EXCP_PRIV:
             msr |= 0x00040000;
@@ -306,6 +310,10 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
         srr1 = SPR_HSRR1;
         new_msr |= (target_ulong)MSR_HVB;
         new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
+        /* Some invalids will have the PC in the right place already */
+        if (env->error_code == (POWERPC_EXCP_INVAL|POWERPC_EXCP_INVAL_LSWX)) {
+                goto store_next;
+        }
         goto store_current;
     case POWERPC_EXCP_FPU:       /* Floating-point unavailable exception     */
         goto store_current;
diff --git a/target-ppc/mem_helper.c b/target-ppc/mem_helper.c
index e4ed377..de96c91 100644
--- a/target-ppc/mem_helper.c
+++ b/target-ppc/mem_helper.c
@@ -77,23 +77,30 @@ void helper_stmw(CPUPPCState *env, target_ulong addr, uint32_t reg)
     }
 }
 
-void helper_lsw(CPUPPCState *env, target_ulong addr, uint32_t nb, uint32_t reg)
+static void do_lsw(CPUPPCState *env, target_ulong addr, uint32_t nb,
+                   uint32_t reg, uintptr_t raddr)
 {
     int sh;
 
     for (; nb > 3; nb -= 4) {
-        env->gpr[reg] = cpu_ldl_data(env, addr);
+        env->gpr[reg] = cpu_ldl_data_ra(env, addr, raddr);
         reg = (reg + 1) % 32;
         addr = addr_add(env, addr, 4);
     }
     if (unlikely(nb > 0)) {
         env->gpr[reg] = 0;
         for (sh = 24; nb > 0; nb--, sh -= 8) {
-            env->gpr[reg] |= cpu_ldub_data(env, addr) << sh;
+            env->gpr[reg] |= cpu_ldub_data_ra(env, addr, raddr) << sh;
             addr = addr_add(env, addr, 1);
         }
     }
 }
+
+void helper_lsw(CPUPPCState *env, target_ulong addr, uint32_t nb, uint32_t reg)
+{
+    do_lsw(env, addr, nb, reg, GETPC());
+}
+
 /* PPC32 specification says we must generate an exception if
  * rA is in the range of registers to be loaded.
  * In an other hand, IBM says this is valid, but rA won't be loaded.
@@ -106,12 +113,11 @@ void helper_lswx(CPUPPCState *env, target_ulong addr, uint32_t reg,
         int num_used_regs = (xer_bc + 3) / 4;
         if (unlikely((ra != 0 && lsw_reg_in_range(reg, num_used_regs, ra)) ||
                      lsw_reg_in_range(reg, num_used_regs, rb))) {
-            env->nip += 4;     /* Compensate the "nip - 4" from gen_lswx() */
-            helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
-                                       POWERPC_EXCP_INVAL |
-                                       POWERPC_EXCP_INVAL_LSWX);
+            raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM,
+                                   POWERPC_EXCP_INVAL |
+                                   POWERPC_EXCP_INVAL_LSWX, GETPC());
         } else {
-            helper_lsw(env, addr, xer_bc, reg);
+            do_lsw(env, addr, xer_bc, reg, GETPC());
         }
     }
 }
@@ -122,13 +128,13 @@ void helper_stsw(CPUPPCState *env, target_ulong addr, uint32_t nb,
     int sh;
 
     for (; nb > 3; nb -= 4) {
-        cpu_stl_data(env, addr, env->gpr[reg]);
+        cpu_stl_data_ra(env, addr, env->gpr[reg], GETPC());
         reg = (reg + 1) % 32;
         addr = addr_add(env, addr, 4);
     }
     if (unlikely(nb > 0)) {
         for (sh = 24; nb > 0; nb--, sh -= 8) {
-            cpu_stb_data(env, addr, (env->gpr[reg] >> sh) & 0xFF);
+            cpu_stb_data_ra(env, addr, (env->gpr[reg] >> sh) & 0xFF, GETPC());
             addr = addr_add(env, addr, 1);
         }
     }
diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index a05fed7..9d2e923 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -2701,12 +2701,16 @@ static void gen_lswi(DisasContext *ctx)
         nb = 32;
     nr = (nb + 3) / 4;
     if (unlikely(lsw_reg_in_range(start, nr, ra))) {
+        /* The handler expects the PC to point to *this* instruction,
+         * so setting ctx->exception here prevents it from being
+         * improperly updated again by gen_inval_exception
+         */
+        gen_update_nip(ctx, ctx->nip - 4);
+        ctx->exception = POWERPC_EXCP_HV_EMU;
         gen_inval_exception(ctx, POWERPC_EXCP_INVAL_LSWX);
         return;
     }
     gen_set_access_type(ctx, ACCESS_INT);
-    /* NIP cannot be restored if the memory exception comes from an helper */
-    gen_update_nip(ctx, ctx->nip - 4);
     t0 = tcg_temp_new();
     gen_addr_register(ctx, t0);
     t1 = tcg_const_i32(nb);
@@ -2723,8 +2727,6 @@ static void gen_lswx(DisasContext *ctx)
     TCGv t0;
     TCGv_i32 t1, t2, t3;
     gen_set_access_type(ctx, ACCESS_INT);
-    /* NIP cannot be restored if the memory exception comes from an helper */
-    gen_update_nip(ctx, ctx->nip - 4);
     t0 = tcg_temp_new();
     gen_addr_reg_index(ctx, t0);
     t1 = tcg_const_i32(rD(ctx->opcode));
@@ -2744,8 +2746,6 @@ static void gen_stswi(DisasContext *ctx)
     TCGv_i32 t1, t2;
     int nb = NB(ctx->opcode);
     gen_set_access_type(ctx, ACCESS_INT);
-    /* NIP cannot be restored if the memory exception comes from an helper */
-    gen_update_nip(ctx, ctx->nip - 4);
     t0 = tcg_temp_new();
     gen_addr_register(ctx, t0);
     if (nb == 0)
@@ -2764,8 +2764,6 @@ static void gen_stswx(DisasContext *ctx)
     TCGv t0;
     TCGv_i32 t1, t2;
     gen_set_access_type(ctx, ACCESS_INT);
-    /* NIP cannot be restored if the memory exception comes from an helper */
-    gen_update_nip(ctx, ctx->nip - 4);
     t0 = tcg_temp_new();
     gen_addr_reg_index(ctx, t0);
     t1 = tcg_temp_new_i32();
@@ -3846,7 +3844,7 @@ static void gen_dcbz(DisasContext *ctx)
 static void gen_dst(DisasContext *ctx)
 {
     if (rA(ctx->opcode) == 0) {
-        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_LSWX);
+        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
     } else {
         /* interpreted as no-op */
     }
@@ -3856,7 +3854,7 @@ static void gen_dst(DisasContext *ctx)
 static void gen_dstst(DisasContext *ctx)
 {
     if (rA(ctx->opcode) == 0) {
-        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_LSWX);
+        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
     } else {
         /* interpreted as no-op */
     }
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [Qemu-devel] [PATCH 14/32] ppc: Don't update NIP in lmw/stmw/icbi
  2016-07-26 22:20 [Qemu-devel] [PATCH 01/32] ppc: Fix fault PC reporting for lve*/stve* VMX instructions Benjamin Herrenschmidt
                   ` (11 preceding siblings ...)
  2016-07-26 22:21 ` [Qemu-devel] [PATCH 13/32] ppc: Don't update NIP in lswi/lswx/stswi/stswx Benjamin Herrenschmidt
@ 2016-07-26 22:21 ` Benjamin Herrenschmidt
  2016-07-26 22:21 ` [Qemu-devel] [PATCH 15/32] ppc: Make tlb_fill() use new exception helper Benjamin Herrenschmidt
                   ` (18 subsequent siblings)
  31 siblings, 0 replies; 69+ messages in thread
From: Benjamin Herrenschmidt @ 2016-07-26 22:21 UTC (permalink / raw)
  To: qemu-ppc; +Cc: qemu-devel, david, Benjamin Herrenschmidt

Instead, pass GETPC() result to the corresponding helpers.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
 target-ppc/mem_helper.c | 11 ++++++-----
 target-ppc/translate.c  |  6 ------
 2 files changed, 6 insertions(+), 11 deletions(-)

diff --git a/target-ppc/mem_helper.c b/target-ppc/mem_helper.c
index de96c91..e20a53e 100644
--- a/target-ppc/mem_helper.c
+++ b/target-ppc/mem_helper.c
@@ -57,9 +57,9 @@ void helper_lmw(CPUPPCState *env, target_ulong addr, uint32_t reg)
 {
     for (; reg < 32; reg++) {
         if (needs_byteswap(env)) {
-            env->gpr[reg] = bswap32(cpu_ldl_data(env, addr));
+            env->gpr[reg] = bswap32(cpu_ldl_data_ra(env, addr, GETPC()));
         } else {
-            env->gpr[reg] = cpu_ldl_data(env, addr);
+            env->gpr[reg] = cpu_ldl_data_ra(env, addr, GETPC());
         }
         addr = addr_add(env, addr, 4);
     }
@@ -69,9 +69,10 @@ void helper_stmw(CPUPPCState *env, target_ulong addr, uint32_t reg)
 {
     for (; reg < 32; reg++) {
         if (needs_byteswap(env)) {
-            cpu_stl_data(env, addr, bswap32((uint32_t)env->gpr[reg]));
+            cpu_stl_data_ra(env, addr, bswap32((uint32_t)env->gpr[reg]),
+                                                   GETPC());
         } else {
-            cpu_stl_data(env, addr, (uint32_t)env->gpr[reg]);
+            cpu_stl_data_ra(env, addr, (uint32_t)env->gpr[reg], GETPC());
         }
         addr = addr_add(env, addr, 4);
     }
@@ -178,7 +179,7 @@ void helper_icbi(CPUPPCState *env, target_ulong addr)
      * (not a fetch) by the MMU. To be sure it will be so,
      * do the load "by hand".
      */
-    cpu_ldl_data(env, addr);
+    cpu_ldl_data_ra(env, addr, GETPC());
 }
 
 /* XXX: to be tested */
diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index 9d2e923..c4f8916 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -2654,8 +2654,6 @@ static void gen_lmw(DisasContext *ctx)
     TCGv t0;
     TCGv_i32 t1;
     gen_set_access_type(ctx, ACCESS_INT);
-    /* NIP cannot be restored if the memory exception comes from an helper */
-    gen_update_nip(ctx, ctx->nip - 4);
     t0 = tcg_temp_new();
     t1 = tcg_const_i32(rD(ctx->opcode));
     gen_addr_imm_index(ctx, t0, 0);
@@ -2670,8 +2668,6 @@ static void gen_stmw(DisasContext *ctx)
     TCGv t0;
     TCGv_i32 t1;
     gen_set_access_type(ctx, ACCESS_INT);
-    /* NIP cannot be restored if the memory exception comes from an helper */
-    gen_update_nip(ctx, ctx->nip - 4);
     t0 = tcg_temp_new();
     t1 = tcg_const_i32(rS(ctx->opcode));
     gen_addr_imm_index(ctx, t0, 0);
@@ -3872,8 +3868,6 @@ static void gen_icbi(DisasContext *ctx)
 {
     TCGv t0;
     gen_set_access_type(ctx, ACCESS_CACHE);
-    /* NIP cannot be restored if the memory exception comes from an helper */
-    gen_update_nip(ctx, ctx->nip - 4);
     t0 = tcg_temp_new();
     gen_addr_reg_index(ctx, t0);
     gen_helper_icbi(cpu_env, t0);
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [Qemu-devel] [PATCH 15/32] ppc: Make tlb_fill() use new exception helper
  2016-07-26 22:20 [Qemu-devel] [PATCH 01/32] ppc: Fix fault PC reporting for lve*/stve* VMX instructions Benjamin Herrenschmidt
                   ` (12 preceding siblings ...)
  2016-07-26 22:21 ` [Qemu-devel] [PATCH 14/32] ppc: Don't update NIP in lmw/stmw/icbi Benjamin Herrenschmidt
@ 2016-07-26 22:21 ` Benjamin Herrenschmidt
  2016-07-26 22:21 ` [Qemu-devel] [PATCH 16/32] ppc: Rework NIP updates vs. exception generation Benjamin Herrenschmidt
                   ` (17 subsequent siblings)
  31 siblings, 0 replies; 69+ messages in thread
From: Benjamin Herrenschmidt @ 2016-07-26 22:21 UTC (permalink / raw)
  To: qemu-ppc; +Cc: qemu-devel, david, Benjamin Herrenschmidt

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
 target-ppc/mmu_helper.c | 7 ++-----
 1 file changed, 2 insertions(+), 5 deletions(-)

diff --git a/target-ppc/mmu_helper.c b/target-ppc/mmu_helper.c
index 3eb3cd7..80cc262 100644
--- a/target-ppc/mmu_helper.c
+++ b/target-ppc/mmu_helper.c
@@ -2892,10 +2892,7 @@ void tlb_fill(CPUState *cs, target_ulong addr, MMUAccessType access_type,
         ret = cpu_ppc_handle_mmu_fault(env, addr, access_type, mmu_idx);
     }
     if (unlikely(ret != 0)) {
-        if (likely(retaddr)) {
-            /* now we have a real cpu fault */
-            cpu_restore_state(cs, retaddr);
-        }
-        helper_raise_exception_err(env, cs->exception_index, env->error_code);
+        raise_exception_err_ra(env, cs->exception_index, env->error_code,
+                               retaddr);
     }
 }
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [Qemu-devel] [PATCH 16/32] ppc: Rework NIP updates vs. exception generation
  2016-07-26 22:20 [Qemu-devel] [PATCH 01/32] ppc: Fix fault PC reporting for lve*/stve* VMX instructions Benjamin Herrenschmidt
                   ` (13 preceding siblings ...)
  2016-07-26 22:21 ` [Qemu-devel] [PATCH 15/32] ppc: Make tlb_fill() use new exception helper Benjamin Herrenschmidt
@ 2016-07-26 22:21 ` Benjamin Herrenschmidt
  2016-07-27  2:19   ` David Gibson
  2016-07-26 22:21 ` [Qemu-devel] [PATCH 17/32] ppc: Fix source NIP on SLB related interrupts Benjamin Herrenschmidt
                   ` (16 subsequent siblings)
  31 siblings, 1 reply; 69+ messages in thread
From: Benjamin Herrenschmidt @ 2016-07-26 22:21 UTC (permalink / raw)
  To: qemu-ppc; +Cc: qemu-devel, david, Benjamin Herrenschmidt

We make env->nip almost always point to the faulting instruction,
thus avoiding a mess of "store_current" vs "store_next" in the
exception handling. The syscall exception knows to move the PC by
4 and that's really about it.

This actually fixes a number of cases where the translator was
setting env->nip to ctx->nip - 4 (ie. the *current* instruction)
but the program check exception handler would branch to
"store_current" which applies another -4 offset.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
 linux-user/main.c        |  12 ++--
 target-ppc/excp_helper.c | 148 ++++++++++++++++++-----------------------------
 target-ppc/translate.c   |  59 +++++++++++--------
 3 files changed, 96 insertions(+), 123 deletions(-)

diff --git a/linux-user/main.c b/linux-user/main.c
index 462e820..1d149dc 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -1814,7 +1814,7 @@ void cpu_loop(CPUPPCState *env)
                           env->error_code);
                 break;
             }
-            info._sifields._sigfault._addr = env->nip - 4;
+            info._sifields._sigfault._addr = env->nip;
             queue_signal(env, info.si_signo, &info);
             break;
         case POWERPC_EXCP_FPU:      /* Floating-point unavailable exception  */
@@ -1822,7 +1822,7 @@ void cpu_loop(CPUPPCState *env)
             info.si_signo = TARGET_SIGILL;
             info.si_errno = 0;
             info.si_code = TARGET_ILL_COPROC;
-            info._sifields._sigfault._addr = env->nip - 4;
+            info._sifields._sigfault._addr = env->nip;
             queue_signal(env, info.si_signo, &info);
             break;
         case POWERPC_EXCP_SYSCALL:  /* System call exception                 */
@@ -1834,7 +1834,7 @@ void cpu_loop(CPUPPCState *env)
             info.si_signo = TARGET_SIGILL;
             info.si_errno = 0;
             info.si_code = TARGET_ILL_COPROC;
-            info._sifields._sigfault._addr = env->nip - 4;
+            info._sifields._sigfault._addr = env->nip;
             queue_signal(env, info.si_signo, &info);
             break;
         case POWERPC_EXCP_DECR:     /* Decrementer exception                 */
@@ -1862,7 +1862,7 @@ void cpu_loop(CPUPPCState *env)
             info.si_signo = TARGET_SIGILL;
             info.si_errno = 0;
             info.si_code = TARGET_ILL_COPROC;
-            info._sifields._sigfault._addr = env->nip - 4;
+            info._sifields._sigfault._addr = env->nip;
             queue_signal(env, info.si_signo, &info);
             break;
         case POWERPC_EXCP_EFPDI:    /* Embedded floating-point data IRQ      */
@@ -1926,7 +1926,7 @@ void cpu_loop(CPUPPCState *env)
             info.si_signo = TARGET_SIGILL;
             info.si_errno = 0;
             info.si_code = TARGET_ILL_COPROC;
-            info._sifields._sigfault._addr = env->nip - 4;
+            info._sifields._sigfault._addr = env->nip;
             queue_signal(env, info.si_signo, &info);
             break;
         case POWERPC_EXCP_PIT:      /* Programmable interval timer IRQ       */
@@ -2001,9 +2001,9 @@ void cpu_loop(CPUPPCState *env)
                              env->gpr[5], env->gpr[6], env->gpr[7],
                              env->gpr[8], 0, 0);
             if (ret == -TARGET_ERESTARTSYS) {
-                env->nip -= 4;
                 break;
             }
+            env->nip += 4;
             if (ret == (target_ulong)(-TARGET_QEMU_ESIGRETURN)) {
                 /* Returning from a successful sigreturn syscall.
                    Avoid corrupting register state.  */
diff --git a/target-ppc/excp_helper.c b/target-ppc/excp_helper.c
index 563c7bc..570d188 100644
--- a/target-ppc/excp_helper.c
+++ b/target-ppc/excp_helper.c
@@ -198,7 +198,7 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
         default:
             goto excp_invalid;
         }
-        goto store_next;
+        break;
     case POWERPC_EXCP_MCHECK:    /* Machine check exception                  */
         if (msr_me == 0) {
             /* Machine check exception is not enabled.
@@ -209,7 +209,7 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
             if (qemu_log_separate()) {
                 qemu_log("Machine check while not allowed. "
                         "Entering checkstop state\n");
-            }
+             }
             cs->halted = 1;
             cs->interrupt_request |= CPU_INTERRUPT_EXITTB;
         }
@@ -235,16 +235,16 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
         default:
             break;
         }
-        goto store_next;
+        break;
     case POWERPC_EXCP_DSI:       /* Data storage exception                   */
         LOG_EXCP("DSI exception: DSISR=" TARGET_FMT_lx" DAR=" TARGET_FMT_lx
                  "\n", env->spr[SPR_DSISR], env->spr[SPR_DAR]);
-        goto store_next;
+        break;
     case POWERPC_EXCP_ISI:       /* Instruction storage exception            */
         LOG_EXCP("ISI exception: msr=" TARGET_FMT_lx ", nip=" TARGET_FMT_lx
                  "\n", msr, env->nip);
         msr |= env->error_code;
-        goto store_next;
+        break;
     case POWERPC_EXCP_EXTERNAL:  /* External input                           */
         cs = CPU(cpu);
 
@@ -258,13 +258,14 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
             /* IACK the IRQ on delivery */
             env->spr[SPR_BOOKE_EPR] = ldl_phys(cs->as, env->mpic_iack);
         }
-        goto store_next;
+        break;
     case POWERPC_EXCP_ALIGN:     /* Alignment exception                      */
         /* XXX: this is false */
         /* Get rS/rD and rA from faulting opcode */
-        env->spr[SPR_DSISR] |= (cpu_ldl_code(env, (env->nip - 4))
+        /* Broken for LE mode */
+        env->spr[SPR_DSISR] |= (cpu_ldl_code(env, env->nip)
                                 & 0x03FF0000) >> 16;
-        goto store_next;
+        break;
     case POWERPC_EXCP_PROGRAM:   /* Program exception                        */
         switch (env->error_code & ~0xF) {
         case POWERPC_EXCP_FP:
@@ -280,15 +281,11 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
              * precise in the MSR.
              */
             msr |= 0x00100000;
-            goto store_next;
+            break;
         case POWERPC_EXCP_INVAL:
             LOG_EXCP("Invalid instruction at " TARGET_FMT_lx "\n", env->nip);
             msr |= 0x00080000;
             env->spr[SPR_BOOKE_ESR] = ESR_PIL;
-            /* Some invalids will have the PC in the right place already */
-            if (env->error_code & POWERPC_EXCP_INVAL_LSWX) {
-                goto store_next;
-            }
             break;
         case POWERPC_EXCP_PRIV:
             msr |= 0x00040000;
@@ -304,23 +301,16 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
                       env->error_code);
             break;
         }
-        goto store_current;
-    case POWERPC_EXCP_HV_EMU:
-        srr0 = SPR_HSRR0;
-        srr1 = SPR_HSRR1;
-        new_msr |= (target_ulong)MSR_HVB;
-        new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
-        /* Some invalids will have the PC in the right place already */
-        if (env->error_code == (POWERPC_EXCP_INVAL|POWERPC_EXCP_INVAL_LSWX)) {
-                goto store_next;
-        }
-        goto store_current;
-    case POWERPC_EXCP_FPU:       /* Floating-point unavailable exception     */
-        goto store_current;
+        break;
     case POWERPC_EXCP_SYSCALL:   /* System call exception                    */
         dump_syscall(env);
         lev = env->error_code;
 
+        /* We need to correct the NIP which in this case is supposed
+         * to point to the next instruction
+         */
+        env->nip += 4;
+
         /* "PAPR mode" built-in hypercall emulation */
         if ((lev == 1) && cpu_ppc_hypercall) {
             cpu_ppc_hypercall(cpu);
@@ -329,15 +319,15 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
         if (lev == 1) {
             new_msr |= (target_ulong)MSR_HVB;
         }
-        goto store_next;
+        break;
+    case POWERPC_EXCP_FPU:       /* Floating-point unavailable exception     */
     case POWERPC_EXCP_APU:       /* Auxiliary processor unavailable          */
-        goto store_current;
     case POWERPC_EXCP_DECR:      /* Decrementer exception                    */
-        goto store_next;
+        break;
     case POWERPC_EXCP_FIT:       /* Fixed-interval timer interrupt           */
         /* FIT on 4xx */
         LOG_EXCP("FIT exception\n");
-        goto store_next;
+        break;
     case POWERPC_EXCP_WDT:       /* Watchdog timer interrupt                 */
         LOG_EXCP("WDT exception\n");
         switch (excp_model) {
@@ -348,11 +338,10 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
         default:
             break;
         }
-        goto store_next;
+        break;
     case POWERPC_EXCP_DTLB:      /* Data TLB error                           */
-        goto store_next;
     case POWERPC_EXCP_ITLB:      /* Instruction TLB error                    */
-        goto store_next;
+        break;
     case POWERPC_EXCP_DEBUG:     /* Debug interrupt                          */
         switch (excp_model) {
         case POWERPC_EXCP_BOOKE:
@@ -367,33 +356,33 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
         }
         /* XXX: TODO */
         cpu_abort(cs, "Debug exception is not implemented yet !\n");
-        goto store_next;
+        break;
     case POWERPC_EXCP_SPEU:      /* SPE/embedded floating-point unavailable  */
         env->spr[SPR_BOOKE_ESR] = ESR_SPV;
-        goto store_current;
+        break;
     case POWERPC_EXCP_EFPDI:     /* Embedded floating-point data interrupt   */
         /* XXX: TODO */
         cpu_abort(cs, "Embedded floating point data exception "
                   "is not implemented yet !\n");
         env->spr[SPR_BOOKE_ESR] = ESR_SPV;
-        goto store_next;
+        break;
     case POWERPC_EXCP_EFPRI:     /* Embedded floating-point round interrupt  */
         /* XXX: TODO */
         cpu_abort(cs, "Embedded floating point round exception "
                   "is not implemented yet !\n");
         env->spr[SPR_BOOKE_ESR] = ESR_SPV;
-        goto store_next;
+        break;
     case POWERPC_EXCP_EPERFM:    /* Embedded performance monitor interrupt   */
         /* XXX: TODO */
         cpu_abort(cs,
                   "Performance counter exception is not implemented yet !\n");
-        goto store_next;
+        break;
     case POWERPC_EXCP_DOORI:     /* Embedded doorbell interrupt              */
-        goto store_next;
+        break;
     case POWERPC_EXCP_DOORCI:    /* Embedded doorbell critical interrupt     */
         srr0 = SPR_BOOKE_CSRR0;
         srr1 = SPR_BOOKE_CSRR1;
-        goto store_next;
+        break;
     case POWERPC_EXCP_RESET:     /* System reset exception                   */
         if (msr_pow) {
             /* indicate that we resumed from power save mode */
@@ -404,65 +393,42 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
 
         new_msr |= (target_ulong)MSR_HVB;
         ail = 0;
-        goto store_next;
+        break;
     case POWERPC_EXCP_DSEG:      /* Data segment exception                   */
-        goto store_next;
     case POWERPC_EXCP_ISEG:      /* Instruction segment exception            */
-        goto store_next;
-    case POWERPC_EXCP_HDECR:     /* Hypervisor decrementer exception         */
-        srr0 = SPR_HSRR0;
-        srr1 = SPR_HSRR1;
-        new_msr |= (target_ulong)MSR_HVB;
-        new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
-        goto store_next;
     case POWERPC_EXCP_TRACE:     /* Trace exception                          */
-        goto store_next;
+        break;
+    case POWERPC_EXCP_HDECR:     /* Hypervisor decrementer exception         */
     case POWERPC_EXCP_HDSI:      /* Hypervisor data storage exception        */
-        srr0 = SPR_HSRR0;
-        srr1 = SPR_HSRR1;
-        new_msr |= (target_ulong)MSR_HVB;
-        new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
-        goto store_next;
     case POWERPC_EXCP_HISI:      /* Hypervisor instruction storage exception */
-        srr0 = SPR_HSRR0;
-        srr1 = SPR_HSRR1;
-        new_msr |= (target_ulong)MSR_HVB;
-        new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
-        goto store_next;
     case POWERPC_EXCP_HDSEG:     /* Hypervisor data segment exception        */
-        srr0 = SPR_HSRR0;
-        srr1 = SPR_HSRR1;
-        new_msr |= (target_ulong)MSR_HVB;
-        new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
-        goto store_next;
     case POWERPC_EXCP_HISEG:     /* Hypervisor instruction segment exception */
+    case POWERPC_EXCP_HV_EMU:
         srr0 = SPR_HSRR0;
         srr1 = SPR_HSRR1;
         new_msr |= (target_ulong)MSR_HVB;
         new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
-        goto store_next;
+        break;
     case POWERPC_EXCP_VPU:       /* Vector unavailable exception             */
-        goto store_current;
     case POWERPC_EXCP_VSXU:       /* VSX unavailable exception               */
-        goto store_current;
     case POWERPC_EXCP_FU:         /* Facility unavailable exception          */
-        goto store_current;
+        break;
     case POWERPC_EXCP_PIT:       /* Programmable interval timer interrupt    */
         LOG_EXCP("PIT exception\n");
-        goto store_next;
+        break;
     case POWERPC_EXCP_IO:        /* IO error exception                       */
         /* XXX: TODO */
         cpu_abort(cs, "601 IO error exception is not implemented yet !\n");
-        goto store_next;
+        break;
     case POWERPC_EXCP_RUNM:      /* Run mode exception                       */
         /* XXX: TODO */
         cpu_abort(cs, "601 run mode exception is not implemented yet !\n");
-        goto store_next;
+        break;
     case POWERPC_EXCP_EMUL:      /* Emulation trap exception                 */
         /* XXX: TODO */
         cpu_abort(cs, "602 emulation trap exception "
                   "is not implemented yet !\n");
-        goto store_next;
+        break;
     case POWERPC_EXCP_IFTLB:     /* Instruction fetch TLB error              */
         switch (excp_model) {
         case POWERPC_EXCP_602:
@@ -577,71 +543,67 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
             cpu_abort(cs, "Invalid data store TLB miss exception\n");
             break;
         }
-        goto store_next;
+        break;
     case POWERPC_EXCP_FPA:       /* Floating-point assist exception          */
         /* XXX: TODO */
         cpu_abort(cs, "Floating point assist exception "
                   "is not implemented yet !\n");
-        goto store_next;
+        break;
     case POWERPC_EXCP_DABR:      /* Data address breakpoint                  */
         /* XXX: TODO */
         cpu_abort(cs, "DABR exception is not implemented yet !\n");
-        goto store_next;
+        break;
     case POWERPC_EXCP_IABR:      /* Instruction address breakpoint           */
         /* XXX: TODO */
         cpu_abort(cs, "IABR exception is not implemented yet !\n");
-        goto store_next;
+        break;
     case POWERPC_EXCP_SMI:       /* System management interrupt              */
         /* XXX: TODO */
         cpu_abort(cs, "SMI exception is not implemented yet !\n");
-        goto store_next;
+        break;
     case POWERPC_EXCP_THERM:     /* Thermal interrupt                        */
         /* XXX: TODO */
         cpu_abort(cs, "Thermal management exception "
                   "is not implemented yet !\n");
-        goto store_next;
+        break;
     case POWERPC_EXCP_PERFM:     /* Embedded performance monitor interrupt   */
         /* XXX: TODO */
         cpu_abort(cs,
                   "Performance counter exception is not implemented yet !\n");
-        goto store_next;
+        break;
     case POWERPC_EXCP_VPUA:      /* Vector assist exception                  */
         /* XXX: TODO */
         cpu_abort(cs, "VPU assist exception is not implemented yet !\n");
-        goto store_next;
+        break;
     case POWERPC_EXCP_SOFTP:     /* Soft patch exception                     */
         /* XXX: TODO */
         cpu_abort(cs,
                   "970 soft-patch exception is not implemented yet !\n");
-        goto store_next;
+        break;
     case POWERPC_EXCP_MAINT:     /* Maintenance exception                    */
         /* XXX: TODO */
         cpu_abort(cs,
                   "970 maintenance exception is not implemented yet !\n");
-        goto store_next;
+        break;
     case POWERPC_EXCP_MEXTBR:    /* Maskable external breakpoint             */
         /* XXX: TODO */
         cpu_abort(cs, "Maskable external exception "
                   "is not implemented yet !\n");
-        goto store_next;
+        break;
     case POWERPC_EXCP_NMEXTBR:   /* Non maskable external breakpoint         */
         /* XXX: TODO */
         cpu_abort(cs, "Non maskable external exception "
                   "is not implemented yet !\n");
-        goto store_next;
+        break;
     default:
     excp_invalid:
         cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp);
         break;
-    store_current:
-        /* save current instruction location */
-        env->spr[srr0] = env->nip - 4;
-        break;
-    store_next:
-        /* save next instruction location */
-        env->spr[srr0] = env->nip;
-        break;
     }
+
+    /* Save PC */
+    env->spr[srr0] = env->nip;
+
     /* Save MSR */
     env->spr[srr1] = msr;
 
diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index c4f8916..84bcb09 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -276,8 +276,12 @@ void gen_update_current_nip(void *opaque)
 static void gen_exception_err(DisasContext *ctx, uint32_t excp, uint32_t error)
 {
     TCGv_i32 t0, t1;
+
+    /* These are all synchronous exceptions, we set the PC back to
+     * the faulting instruction
+     */
     if (ctx->exception == POWERPC_EXCP_NONE) {
-        gen_update_nip(ctx, ctx->nip);
+        gen_update_nip(ctx, ctx->nip - 4);
     }
     t0 = tcg_const_i32(excp);
     t1 = tcg_const_i32(error);
@@ -290,8 +294,12 @@ static void gen_exception_err(DisasContext *ctx, uint32_t excp, uint32_t error)
 static void gen_exception(DisasContext *ctx, uint32_t excp)
 {
     TCGv_i32 t0;
+
+    /* These are all synchronous exceptions, we set the PC back to
+     * the faulting instruction
+     */
     if (ctx->exception == POWERPC_EXCP_NONE) {
-        gen_update_nip(ctx, ctx->nip);
+        gen_update_nip(ctx, ctx->nip - 4);
     }
     t0 = tcg_const_i32(excp);
     gen_helper_raise_exception(cpu_env, t0);
@@ -299,13 +307,28 @@ static void gen_exception(DisasContext *ctx, uint32_t excp)
     ctx->exception = (excp);
 }
 
+static void gen_exception_nip(DisasContext *ctx, uint32_t excp,
+                              target_ulong nip)
+{
+    TCGv_i32 t0;
+
+    gen_update_nip(ctx, nip);
+    t0 = tcg_const_i32(excp);
+    gen_helper_raise_exception(cpu_env, t0);
+    tcg_temp_free_i32(t0);
+    ctx->exception = (excp);
+}
+
 static void gen_debug_exception(DisasContext *ctx)
 {
     TCGv_i32 t0;
 
+    /* These are all synchronous exceptions, we set the PC back to
+     * the faulting instruction
+     */
     if ((ctx->exception != POWERPC_EXCP_BRANCH) &&
         (ctx->exception != POWERPC_EXCP_SYNC)) {
-        gen_update_nip(ctx, ctx->nip);
+        gen_update_nip(ctx, ctx->nip - 4);
     }
     t0 = tcg_const_i32(EXCP_DEBUG);
     gen_helper_raise_exception(cpu_env, t0);
@@ -1437,7 +1460,7 @@ static void gen_pause(DisasContext *ctx)
     tcg_temp_free_i32(t0);
 
     /* Stop translation, this gives other CPUs a chance to run */
-    gen_exception_err(ctx, EXCP_HLT, 1);
+    gen_exception_nip(ctx, EXCP_HLT, ctx->nip);
 }
 #endif /* defined(TARGET_PPC64) */
 
@@ -2697,12 +2720,6 @@ static void gen_lswi(DisasContext *ctx)
         nb = 32;
     nr = (nb + 3) / 4;
     if (unlikely(lsw_reg_in_range(start, nr, ra))) {
-        /* The handler expects the PC to point to *this* instruction,
-         * so setting ctx->exception here prevents it from being
-         * improperly updated again by gen_inval_exception
-         */
-        gen_update_nip(ctx, ctx->nip - 4);
-        ctx->exception = POWERPC_EXCP_HV_EMU;
         gen_inval_exception(ctx, POWERPC_EXCP_INVAL_LSWX);
         return;
     }
@@ -2845,10 +2862,7 @@ static void gen_conditional_store(DisasContext *ctx, TCGv EA,
     tcg_gen_movi_tl(t0, (size << 5) | reg);
     tcg_gen_st_tl(t0, cpu_env, offsetof(CPUPPCState, reserve_info));
     tcg_temp_free(t0);
-    gen_update_nip(ctx, ctx->nip-4);
-    ctx->exception = POWERPC_EXCP_BRANCH;
-    gen_exception(ctx, POWERPC_EXCP_STCX);
-    ctx->exception = save_exception;
+    gen_exception_err(ctx, POWERPC_EXCP_STCX, 0);
 }
 #else
 static void gen_conditional_store(DisasContext *ctx, TCGv EA,
@@ -2987,7 +3001,7 @@ static void gen_wait(DisasContext *ctx)
                    -offsetof(PowerPCCPU, env) + offsetof(CPUState, halted));
     tcg_temp_free_i32(t0);
     /* Stop translation, as the CPU is supposed to sleep from now */
-    gen_exception_err(ctx, EXCP_HLT, 1);
+    gen_exception_nip(ctx, EXCP_HLT, ctx->nip);
 }
 
 #if defined(TARGET_PPC64)
@@ -3090,10 +3104,7 @@ static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
                 (CPU_BRANCH_STEP | CPU_SINGLE_STEP)) &&
                 (ctx->exception == POWERPC_EXCP_BRANCH ||
                  ctx->exception == POWERPC_EXCP_TRACE)) {
-                target_ulong tmp = ctx->nip;
-                ctx->nip = dest;
-                gen_exception(ctx, POWERPC_EXCP_TRACE);
-                ctx->nip = tmp;
+                gen_exception_nip(ctx, POWERPC_EXCP_TRACE, dest);
             }
             if (ctx->singlestep_enabled & GDBSTUB_SINGLE_STEP) {
                 gen_debug_exception(ctx);
@@ -3362,7 +3373,7 @@ static void gen_tw(DisasContext *ctx)
 {
     TCGv_i32 t0 = tcg_const_i32(TO(ctx->opcode));
     /* Update the nip since this might generate a trap exception */
-    gen_update_nip(ctx, ctx->nip);
+    gen_update_nip(ctx, ctx->nip - 4);
     gen_helper_tw(cpu_env, cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)],
                   t0);
     tcg_temp_free_i32(t0);
@@ -3374,7 +3385,7 @@ static void gen_twi(DisasContext *ctx)
     TCGv t0 = tcg_const_tl(SIMM(ctx->opcode));
     TCGv_i32 t1 = tcg_const_i32(TO(ctx->opcode));
     /* Update the nip since this might generate a trap exception */
-    gen_update_nip(ctx, ctx->nip);
+    gen_update_nip(ctx, ctx->nip - 4);
     gen_helper_tw(cpu_env, cpu_gpr[rA(ctx->opcode)], t0, t1);
     tcg_temp_free(t0);
     tcg_temp_free_i32(t1);
@@ -3386,7 +3397,7 @@ static void gen_td(DisasContext *ctx)
 {
     TCGv_i32 t0 = tcg_const_i32(TO(ctx->opcode));
     /* Update the nip since this might generate a trap exception */
-    gen_update_nip(ctx, ctx->nip);
+    gen_update_nip(ctx, ctx->nip - 4);
     gen_helper_td(cpu_env, cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)],
                   t0);
     tcg_temp_free_i32(t0);
@@ -3398,7 +3409,7 @@ static void gen_tdi(DisasContext *ctx)
     TCGv t0 = tcg_const_tl(SIMM(ctx->opcode));
     TCGv_i32 t1 = tcg_const_i32(TO(ctx->opcode));
     /* Update the nip since this might generate a trap exception */
-    gen_update_nip(ctx, ctx->nip);
+    gen_update_nip(ctx, ctx->nip - 4);
     gen_helper_td(cpu_env, cpu_gpr[rA(ctx->opcode)], t0, t1);
     tcg_temp_free(t0);
     tcg_temp_free_i32(t1);
@@ -6757,7 +6768,7 @@ void gen_intermediate_code(CPUPPCState *env, struct TranslationBlock *tb)
                      ctx.exception != POWERPC_SYSCALL &&
                      ctx.exception != POWERPC_EXCP_TRAP &&
                      ctx.exception != POWERPC_EXCP_BRANCH)) {
-            gen_exception(ctxp, POWERPC_EXCP_TRACE);
+            gen_exception_nip(ctxp, POWERPC_EXCP_TRACE, ctx.nip);
         } else if (unlikely(((ctx.nip & (TARGET_PAGE_SIZE - 1)) == 0) ||
                             (cs->singlestep_enabled) ||
                             singlestep ||
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [Qemu-devel] [PATCH 17/32] ppc: Fix source NIP on SLB related interrupts
  2016-07-26 22:20 [Qemu-devel] [PATCH 01/32] ppc: Fix fault PC reporting for lve*/stve* VMX instructions Benjamin Herrenschmidt
                   ` (14 preceding siblings ...)
  2016-07-26 22:21 ` [Qemu-devel] [PATCH 16/32] ppc: Rework NIP updates vs. exception generation Benjamin Herrenschmidt
@ 2016-07-26 22:21 ` Benjamin Herrenschmidt
  2016-07-26 22:21 ` [Qemu-devel] [PATCH 18/32] ppc: Don't update NIP in DCR access routines Benjamin Herrenschmidt
                   ` (15 subsequent siblings)
  31 siblings, 0 replies; 69+ messages in thread
From: Benjamin Herrenschmidt @ 2016-07-26 22:21 UTC (permalink / raw)
  To: qemu-ppc; +Cc: qemu-devel, david, Benjamin Herrenschmidt

We need to pass it to the raise helper since we don't update it
before the calls.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
 target-ppc/mmu-hash64.c | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/target-ppc/mmu-hash64.c b/target-ppc/mmu-hash64.c
index 5de1358..8118143 100644
--- a/target-ppc/mmu-hash64.c
+++ b/target-ppc/mmu-hash64.c
@@ -241,8 +241,8 @@ void helper_store_slb(CPUPPCState *env, target_ulong rb, target_ulong rs)
     PowerPCCPU *cpu = ppc_env_get_cpu(env);
 
     if (ppc_store_slb(cpu, rb & 0xfff, rb & ~0xfffULL, rs) < 0) {
-        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
-                                   POWERPC_EXCP_INVAL);
+        raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM,
+                               POWERPC_EXCP_INVAL, GETPC());
     }
 }
 
@@ -252,8 +252,8 @@ target_ulong helper_load_slb_esid(CPUPPCState *env, target_ulong rb)
     target_ulong rt = 0;
 
     if (ppc_load_slb_esid(cpu, rb, &rt) < 0) {
-        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
-                                   POWERPC_EXCP_INVAL);
+        raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM,
+                               POWERPC_EXCP_INVAL, GETPC());
     }
     return rt;
 }
@@ -264,8 +264,8 @@ target_ulong helper_find_slb_vsid(CPUPPCState *env, target_ulong rb)
     target_ulong rt = 0;
 
     if (ppc_find_slb_vsid(cpu, rb, &rt) < 0) {
-        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
-                                   POWERPC_EXCP_INVAL);
+        raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM,
+                               POWERPC_EXCP_INVAL, GETPC());
     }
     return rt;
 }
@@ -276,8 +276,8 @@ target_ulong helper_load_slb_vsid(CPUPPCState *env, target_ulong rb)
     target_ulong rt = 0;
 
     if (ppc_load_slb_vsid(cpu, rb, &rt) < 0) {
-        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
-                                   POWERPC_EXCP_INVAL);
+        raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM,
+                               POWERPC_EXCP_INVAL, GETPC());
     }
     return rt;
 }
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [Qemu-devel] [PATCH 18/32] ppc: Don't update NIP in DCR access routines
  2016-07-26 22:20 [Qemu-devel] [PATCH 01/32] ppc: Fix fault PC reporting for lve*/stve* VMX instructions Benjamin Herrenschmidt
                   ` (15 preceding siblings ...)
  2016-07-26 22:21 ` [Qemu-devel] [PATCH 17/32] ppc: Fix source NIP on SLB related interrupts Benjamin Herrenschmidt
@ 2016-07-26 22:21 ` Benjamin Herrenschmidt
  2016-07-27  2:21   ` David Gibson
  2016-07-26 22:21 ` [Qemu-devel] [PATCH 19/32] ppc: Don't update NIP in facility unavailable interrupts Benjamin Herrenschmidt
                   ` (14 subsequent siblings)
  31 siblings, 1 reply; 69+ messages in thread
From: Benjamin Herrenschmidt @ 2016-07-26 22:21 UTC (permalink / raw)
  To: qemu-ppc; +Cc: qemu-devel, david, Benjamin Herrenschmidt

This is no longer necessary as the helpers will properly retrieve
the return address when needed

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
 target-ppc/timebase_helper.c | 23 +++++++++++++----------
 target-ppc/translate.c       | 12 ------------
 2 files changed, 13 insertions(+), 22 deletions(-)

diff --git a/target-ppc/timebase_helper.c b/target-ppc/timebase_helper.c
index a07faa4..73363e0 100644
--- a/target-ppc/timebase_helper.c
+++ b/target-ppc/timebase_helper.c
@@ -19,6 +19,7 @@
 #include "qemu/osdep.h"
 #include "cpu.h"
 #include "exec/helper-proto.h"
+#include "exec/exec-all.h"
 #include "qemu/log.h"
 
 /*****************************************************************************/
@@ -143,15 +144,16 @@ target_ulong helper_load_dcr(CPUPPCState *env, target_ulong dcrn)
 
     if (unlikely(env->dcr_env == NULL)) {
         qemu_log_mask(LOG_GUEST_ERROR, "No DCR environment\n");
-        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
-                                   POWERPC_EXCP_INVAL |
-                                   POWERPC_EXCP_INVAL_INVAL);
+        raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM,
+                               POWERPC_EXCP_INVAL |
+                               POWERPC_EXCP_INVAL_INVAL, GETPC());
     } else if (unlikely(ppc_dcr_read(env->dcr_env,
                                      (uint32_t)dcrn, &val) != 0)) {
         qemu_log_mask(LOG_GUEST_ERROR, "DCR read error %d %03x\n",
                       (uint32_t)dcrn, (uint32_t)dcrn);
-        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
-                                   POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG);
+        raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM,
+                               POWERPC_EXCP_INVAL |
+                               POWERPC_EXCP_PRIV_REG, GETPC());
     }
     return val;
 }
@@ -160,14 +162,15 @@ void helper_store_dcr(CPUPPCState *env, target_ulong dcrn, target_ulong val)
 {
     if (unlikely(env->dcr_env == NULL)) {
         qemu_log_mask(LOG_GUEST_ERROR, "No DCR environment\n");
-        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
-                                   POWERPC_EXCP_INVAL |
-                                   POWERPC_EXCP_INVAL_INVAL);
+        raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM,
+                               POWERPC_EXCP_INVAL |
+                               POWERPC_EXCP_INVAL_INVAL, GETPC());
     } else if (unlikely(ppc_dcr_write(env->dcr_env, (uint32_t)dcrn,
                                       (uint32_t)val) != 0)) {
         qemu_log_mask(LOG_GUEST_ERROR, "DCR write error %d %03x\n",
                       (uint32_t)dcrn, (uint32_t)dcrn);
-        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
-                                   POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG);
+        raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM,
+                               POWERPC_EXCP_INVAL |
+                               POWERPC_EXCP_PRIV_REG, GETPC());
     }
 }
diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index 84bcb09..f0e0ec6 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -5262,8 +5262,6 @@ static void gen_mfdcr(DisasContext *ctx)
     TCGv dcrn;
 
     CHK_SV;
-    /* NIP cannot be restored if the memory exception comes from an helper */
-    gen_update_nip(ctx, ctx->nip - 4);
     dcrn = tcg_const_tl(SPR(ctx->opcode));
     gen_helper_load_dcr(cpu_gpr[rD(ctx->opcode)], cpu_env, dcrn);
     tcg_temp_free(dcrn);
@@ -5279,8 +5277,6 @@ static void gen_mtdcr(DisasContext *ctx)
     TCGv dcrn;
 
     CHK_SV;
-    /* NIP cannot be restored if the memory exception comes from an helper */
-    gen_update_nip(ctx, ctx->nip - 4);
     dcrn = tcg_const_tl(SPR(ctx->opcode));
     gen_helper_store_dcr(cpu_env, dcrn, cpu_gpr[rS(ctx->opcode)]);
     tcg_temp_free(dcrn);
@@ -5295,8 +5291,6 @@ static void gen_mfdcrx(DisasContext *ctx)
     GEN_PRIV;
 #else
     CHK_SV;
-    /* NIP cannot be restored if the memory exception comes from an helper */
-    gen_update_nip(ctx, ctx->nip - 4);
     gen_helper_load_dcr(cpu_gpr[rD(ctx->opcode)], cpu_env,
                         cpu_gpr[rA(ctx->opcode)]);
     /* Note: Rc update flag set leads to undefined state of Rc0 */
@@ -5311,8 +5305,6 @@ static void gen_mtdcrx(DisasContext *ctx)
     GEN_PRIV;
 #else
     CHK_SV;
-    /* NIP cannot be restored if the memory exception comes from an helper */
-    gen_update_nip(ctx, ctx->nip - 4);
     gen_helper_store_dcr(cpu_env, cpu_gpr[rA(ctx->opcode)],
                          cpu_gpr[rS(ctx->opcode)]);
     /* Note: Rc update flag set leads to undefined state of Rc0 */
@@ -5322,8 +5314,6 @@ static void gen_mtdcrx(DisasContext *ctx)
 /* mfdcrux (PPC 460) : user-mode access to DCR */
 static void gen_mfdcrux(DisasContext *ctx)
 {
-    /* NIP cannot be restored if the memory exception comes from an helper */
-    gen_update_nip(ctx, ctx->nip - 4);
     gen_helper_load_dcr(cpu_gpr[rD(ctx->opcode)], cpu_env,
                         cpu_gpr[rA(ctx->opcode)]);
     /* Note: Rc update flag set leads to undefined state of Rc0 */
@@ -5332,8 +5322,6 @@ static void gen_mfdcrux(DisasContext *ctx)
 /* mtdcrux (PPC 460) : user-mode access to DCR */
 static void gen_mtdcrux(DisasContext *ctx)
 {
-    /* NIP cannot be restored if the memory exception comes from an helper */
-    gen_update_nip(ctx, ctx->nip - 4);
     gen_helper_store_dcr(cpu_env, cpu_gpr[rA(ctx->opcode)],
                          cpu_gpr[rS(ctx->opcode)]);
     /* Note: Rc update flag set leads to undefined state of Rc0 */
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [Qemu-devel] [PATCH 19/32] ppc: Don't update NIP in facility unavailable interrupts
  2016-07-26 22:20 [Qemu-devel] [PATCH 01/32] ppc: Fix fault PC reporting for lve*/stve* VMX instructions Benjamin Herrenschmidt
                   ` (16 preceding siblings ...)
  2016-07-26 22:21 ` [Qemu-devel] [PATCH 18/32] ppc: Don't update NIP in DCR access routines Benjamin Herrenschmidt
@ 2016-07-26 22:21 ` Benjamin Herrenschmidt
  2016-07-26 22:21 ` [Qemu-devel] [PATCH 20/32] ppc: Don't update NIP BookE 2.06 tlbwe Benjamin Herrenschmidt
                   ` (13 subsequent siblings)
  31 siblings, 0 replies; 69+ messages in thread
From: Benjamin Herrenschmidt @ 2016-07-26 22:21 UTC (permalink / raw)
  To: qemu-ppc; +Cc: qemu-devel, david, Benjamin Herrenschmidt

This is no longer necessary as the helpers will properly retrieve
the return address when needed. Also remove gen_update_current_nip()
which didn't seem to make much sense to me.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
 target-ppc/cpu.h            | 1 -
 target-ppc/misc_helper.c    | 9 +++++----
 target-ppc/translate.c      | 7 -------
 target-ppc/translate_init.c | 2 --
 4 files changed, 5 insertions(+), 14 deletions(-)

diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index 2ee7a5e..0786738 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -1201,7 +1201,6 @@ extern const struct VMStateDescription vmstate_ppc_cpu;
 /*****************************************************************************/
 PowerPCCPU *cpu_ppc_init(const char *cpu_model);
 void ppc_translate_init(void);
-void gen_update_current_nip(void *opaque);
 /* you can call this signal handler from your SIGBUS and SIGSEGV
    signal handlers to inform the virtual CPU of exceptions. non zero
    is returned if the signal was handled by the virtual CPU.  */
diff --git a/target-ppc/misc_helper.c b/target-ppc/misc_helper.c
index cb5ebf5..1e6e705 100644
--- a/target-ppc/misc_helper.c
+++ b/target-ppc/misc_helper.c
@@ -39,7 +39,8 @@ void helper_store_dump_spr(CPUPPCState *env, uint32_t sprn)
 
 #ifdef TARGET_PPC64
 static void raise_fu_exception(CPUPPCState *env, uint32_t bit,
-                               uint32_t sprn, uint32_t cause)
+                               uint32_t sprn, uint32_t cause,
+                               uintptr_t raddr)
 {
     qemu_log("Facility SPR %d is unavailable (SPR FSCR:%d)\n", sprn, bit);
 
@@ -47,7 +48,7 @@ static void raise_fu_exception(CPUPPCState *env, uint32_t bit,
     cause &= FSCR_IC_MASK;
     env->spr[SPR_FSCR] |= (target_ulong)cause << FSCR_IC_POS;
 
-    helper_raise_exception_err(env, POWERPC_EXCP_FU, 0);
+    raise_exception_err_ra(env, POWERPC_EXCP_FU, 0, raddr);
 }
 #endif
 
@@ -59,7 +60,7 @@ void helper_fscr_facility_check(CPUPPCState *env, uint32_t bit,
         /* Facility is enabled, continue */
         return;
     }
-    raise_fu_exception(env, bit, sprn, cause);
+    raise_fu_exception(env, bit, sprn, cause, GETPC());
 #endif
 }
 
@@ -71,7 +72,7 @@ void helper_msr_facility_check(CPUPPCState *env, uint32_t bit,
         /* Facility is enabled, continue */
         return;
     }
-    raise_fu_exception(env, bit, sprn, cause);
+    raise_fu_exception(env, bit, sprn, cause, GETPC());
 #endif
 }
 
diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index f0e0ec6..4577788 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -266,13 +266,6 @@ static inline void gen_update_nip(DisasContext *ctx, target_ulong nip)
     tcg_gen_movi_tl(cpu_nip, nip);
 }
 
-void gen_update_current_nip(void *opaque)
-{
-    DisasContext *ctx = opaque;
-
-    tcg_gen_movi_tl(cpu_nip, ctx->nip);
-}
-
 static void gen_exception_err(DisasContext *ctx, uint32_t excp, uint32_t error)
 {
     TCGv_i32 t0, t1;
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index 5ecafc7..74b1b33 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -7469,7 +7469,6 @@ static void gen_fscr_facility_check(DisasContext *ctx, int facility_sprn,
     TCGv_i32 t2 = tcg_const_i32(sprn);
     TCGv_i32 t3 = tcg_const_i32(cause);
 
-    gen_update_current_nip(ctx);
     gen_helper_fscr_facility_check(cpu_env, t1, t2, t3);
 
     tcg_temp_free_i32(t3);
@@ -7484,7 +7483,6 @@ static void gen_msr_facility_check(DisasContext *ctx, int facility_sprn,
     TCGv_i32 t2 = tcg_const_i32(sprn);
     TCGv_i32 t3 = tcg_const_i32(cause);
 
-    gen_update_current_nip(ctx);
     gen_helper_msr_facility_check(cpu_env, t1, t2, t3);
 
     tcg_temp_free_i32(t3);
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [Qemu-devel] [PATCH 20/32] ppc: Don't update NIP BookE 2.06 tlbwe
  2016-07-26 22:20 [Qemu-devel] [PATCH 01/32] ppc: Fix fault PC reporting for lve*/stve* VMX instructions Benjamin Herrenschmidt
                   ` (17 preceding siblings ...)
  2016-07-26 22:21 ` [Qemu-devel] [PATCH 19/32] ppc: Don't update NIP in facility unavailable interrupts Benjamin Herrenschmidt
@ 2016-07-26 22:21 ` Benjamin Herrenschmidt
  2016-07-26 22:21 ` [Qemu-devel] [PATCH 21/32] ppc: Don't update NIP on conditional trap instructions Benjamin Herrenschmidt
                   ` (12 subsequent siblings)
  31 siblings, 0 replies; 69+ messages in thread
From: Benjamin Herrenschmidt @ 2016-07-26 22:21 UTC (permalink / raw)
  To: qemu-ppc; +Cc: qemu-devel, david, Benjamin Herrenschmidt

This is no longer necessary as the helpers will properly retrieve
the return address when needed.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
 target-ppc/mmu_helper.c | 12 ++++++------
 target-ppc/translate.c  |  1 -
 2 files changed, 6 insertions(+), 7 deletions(-)

diff --git a/target-ppc/mmu_helper.c b/target-ppc/mmu_helper.c
index 80cc262..40aaffa 100644
--- a/target-ppc/mmu_helper.c
+++ b/target-ppc/mmu_helper.c
@@ -2598,9 +2598,9 @@ void helper_booke206_tlbwe(CPUPPCState *env)
     tlb = booke206_cur_tlb(env);
 
     if (!tlb) {
-        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
-                                   POWERPC_EXCP_INVAL |
-                                   POWERPC_EXCP_INVAL_INVAL);
+        raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM,
+                               POWERPC_EXCP_INVAL |
+                               POWERPC_EXCP_INVAL_INVAL, GETPC());
     }
 
     /* check that we support the targeted size */
@@ -2608,9 +2608,9 @@ void helper_booke206_tlbwe(CPUPPCState *env)
     size_ps = booke206_tlbnps(env, tlbn);
     if ((env->spr[SPR_BOOKE_MAS1] & MAS1_VALID) && (tlbncfg & TLBnCFG_AVAIL) &&
         !(size_ps & (1 << size_tlb))) {
-        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
-                                   POWERPC_EXCP_INVAL |
-                                   POWERPC_EXCP_INVAL_INVAL);
+        raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM,
+                               POWERPC_EXCP_INVAL |
+                               POWERPC_EXCP_INVAL_INVAL, GETPC());
     }
 
     if (msr_gs) {
diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index 4577788..8f5afba 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -5613,7 +5613,6 @@ static void gen_tlbwe_booke206(DisasContext *ctx)
     GEN_PRIV;
 #else
     CHK_SV;
-    gen_update_nip(ctx, ctx->nip - 4);
     gen_helper_booke206_tlbwe(cpu_env);
 #endif /* defined(CONFIG_USER_ONLY) */
 }
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [Qemu-devel] [PATCH 21/32] ppc: Don't update NIP on conditional trap instructions
  2016-07-26 22:20 [Qemu-devel] [PATCH 01/32] ppc: Fix fault PC reporting for lve*/stve* VMX instructions Benjamin Herrenschmidt
                   ` (18 preceding siblings ...)
  2016-07-26 22:21 ` [Qemu-devel] [PATCH 20/32] ppc: Don't update NIP BookE 2.06 tlbwe Benjamin Herrenschmidt
@ 2016-07-26 22:21 ` Benjamin Herrenschmidt
  2016-07-27  2:26   ` David Gibson
  2016-07-26 22:21 ` [Qemu-devel] [PATCH 22/32] ppc: Don't update NIP if not taking alignment exceptions Benjamin Herrenschmidt
                   ` (11 subsequent siblings)
  31 siblings, 1 reply; 69+ messages in thread
From: Benjamin Herrenschmidt @ 2016-07-26 22:21 UTC (permalink / raw)
  To: qemu-ppc; +Cc: qemu-devel, david, Benjamin Herrenschmidt

This is no longer necessary as the helpers will properly retrieve
the return address when needed.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
 target-ppc/excp_helper.c | 6 ++++--
 target-ppc/translate.c   | 8 --------
 2 files changed, 4 insertions(+), 10 deletions(-)

diff --git a/target-ppc/excp_helper.c b/target-ppc/excp_helper.c
index 570d188..c31bbad 100644
--- a/target-ppc/excp_helper.c
+++ b/target-ppc/excp_helper.c
@@ -1031,7 +1031,8 @@ void helper_tw(CPUPPCState *env, target_ulong arg1, target_ulong arg2,
                   ((int32_t)arg1 == (int32_t)arg2 && (flags & 0x04)) ||
                   ((uint32_t)arg1 < (uint32_t)arg2 && (flags & 0x02)) ||
                   ((uint32_t)arg1 > (uint32_t)arg2 && (flags & 0x01))))) {
-        raise_exception_err(env, POWERPC_EXCP_PROGRAM, POWERPC_EXCP_TRAP);
+        raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM,
+                               POWERPC_EXCP_TRAP, GETPC());
     }
 }
 
@@ -1044,7 +1045,8 @@ void helper_td(CPUPPCState *env, target_ulong arg1, target_ulong arg2,
                   ((int64_t)arg1 == (int64_t)arg2 && (flags & 0x04)) ||
                   ((uint64_t)arg1 < (uint64_t)arg2 && (flags & 0x02)) ||
                   ((uint64_t)arg1 > (uint64_t)arg2 && (flags & 0x01))))) {
-        raise_exception_err(env, POWERPC_EXCP_PROGRAM, POWERPC_EXCP_TRAP);
+        raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM,
+                               POWERPC_EXCP_TRAP, GETPC());
     }
 }
 #endif
diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index 8f5afba..7163b19 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -3365,8 +3365,6 @@ static void gen_sc(DisasContext *ctx)
 static void gen_tw(DisasContext *ctx)
 {
     TCGv_i32 t0 = tcg_const_i32(TO(ctx->opcode));
-    /* Update the nip since this might generate a trap exception */
-    gen_update_nip(ctx, ctx->nip - 4);
     gen_helper_tw(cpu_env, cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)],
                   t0);
     tcg_temp_free_i32(t0);
@@ -3377,8 +3375,6 @@ static void gen_twi(DisasContext *ctx)
 {
     TCGv t0 = tcg_const_tl(SIMM(ctx->opcode));
     TCGv_i32 t1 = tcg_const_i32(TO(ctx->opcode));
-    /* Update the nip since this might generate a trap exception */
-    gen_update_nip(ctx, ctx->nip - 4);
     gen_helper_tw(cpu_env, cpu_gpr[rA(ctx->opcode)], t0, t1);
     tcg_temp_free(t0);
     tcg_temp_free_i32(t1);
@@ -3389,8 +3385,6 @@ static void gen_twi(DisasContext *ctx)
 static void gen_td(DisasContext *ctx)
 {
     TCGv_i32 t0 = tcg_const_i32(TO(ctx->opcode));
-    /* Update the nip since this might generate a trap exception */
-    gen_update_nip(ctx, ctx->nip - 4);
     gen_helper_td(cpu_env, cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)],
                   t0);
     tcg_temp_free_i32(t0);
@@ -3401,8 +3395,6 @@ static void gen_tdi(DisasContext *ctx)
 {
     TCGv t0 = tcg_const_tl(SIMM(ctx->opcode));
     TCGv_i32 t1 = tcg_const_i32(TO(ctx->opcode));
-    /* Update the nip since this might generate a trap exception */
-    gen_update_nip(ctx, ctx->nip - 4);
     gen_helper_td(cpu_env, cpu_gpr[rA(ctx->opcode)], t0, t1);
     tcg_temp_free(t0);
     tcg_temp_free_i32(t1);
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [Qemu-devel] [PATCH 22/32] ppc: Don't update NIP if not taking alignment exceptions
  2016-07-26 22:20 [Qemu-devel] [PATCH 01/32] ppc: Fix fault PC reporting for lve*/stve* VMX instructions Benjamin Herrenschmidt
                   ` (19 preceding siblings ...)
  2016-07-26 22:21 ` [Qemu-devel] [PATCH 21/32] ppc: Don't update NIP on conditional trap instructions Benjamin Herrenschmidt
@ 2016-07-26 22:21 ` Benjamin Herrenschmidt
  2016-07-26 22:21 ` [Qemu-devel] [PATCH 23/32] ppc: Don't update NIP in dcbz and lscbx Benjamin Herrenschmidt
                   ` (10 subsequent siblings)
  31 siblings, 0 replies; 69+ messages in thread
From: Benjamin Herrenschmidt @ 2016-07-26 22:21 UTC (permalink / raw)
  To: qemu-ppc; +Cc: qemu-devel, david, Benjamin Herrenschmidt

Move the NIP update to after the conditional branch so that we
don't do it if we aren't going to take the alignment exception

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
 target-ppc/translate.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index 7163b19..8670932 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -2199,12 +2199,11 @@ static inline void gen_check_align(DisasContext *ctx, TCGv EA, int mask)
     TCGLabel *l1 = gen_new_label();
     TCGv t0 = tcg_temp_new();
     TCGv_i32 t1, t2;
-    /* NIP cannot be restored if the memory exception comes from an helper */
-    gen_update_nip(ctx, ctx->nip - 4);
     tcg_gen_andi_tl(t0, EA, mask);
     tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 0, l1);
     t1 = tcg_const_i32(POWERPC_EXCP_ALIGN);
     t2 = tcg_const_i32(0);
+    gen_update_nip(ctx, ctx->nip - 4);
     gen_helper_raise_exception_err(cpu_env, t1, t2);
     tcg_temp_free_i32(t1);
     tcg_temp_free_i32(t2);
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [Qemu-devel] [PATCH 23/32] ppc: Don't update NIP in dcbz and lscbx
  2016-07-26 22:20 [Qemu-devel] [PATCH 01/32] ppc: Fix fault PC reporting for lve*/stve* VMX instructions Benjamin Herrenschmidt
                   ` (20 preceding siblings ...)
  2016-07-26 22:21 ` [Qemu-devel] [PATCH 22/32] ppc: Don't update NIP if not taking alignment exceptions Benjamin Herrenschmidt
@ 2016-07-26 22:21 ` Benjamin Herrenschmidt
  2016-07-26 22:21 ` [Qemu-devel] [PATCH 24/32] ppc: Make alignment exceptions suck less Benjamin Herrenschmidt
                   ` (9 subsequent siblings)
  31 siblings, 0 replies; 69+ messages in thread
From: Benjamin Herrenschmidt @ 2016-07-26 22:21 UTC (permalink / raw)
  To: qemu-ppc; +Cc: qemu-devel, david, Benjamin Herrenschmidt

Instead, pass GETPC() result to the corresponding helpers.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
 target-ppc/mem_helper.c | 9 +++++----
 target-ppc/translate.c  | 4 ----
 2 files changed, 5 insertions(+), 8 deletions(-)

diff --git a/target-ppc/mem_helper.c b/target-ppc/mem_helper.c
index e20a53e..92a594c 100644
--- a/target-ppc/mem_helper.c
+++ b/target-ppc/mem_helper.c
@@ -141,13 +141,14 @@ void helper_stsw(CPUPPCState *env, target_ulong addr, uint32_t nb,
     }
 }
 
-static void do_dcbz(CPUPPCState *env, target_ulong addr, int dcache_line_size)
+static void do_dcbz(CPUPPCState *env, target_ulong addr, int dcache_line_size,
+                    uintptr_t raddr)
 {
     int i;
 
     addr &= ~(dcache_line_size - 1);
     for (i = 0; i < dcache_line_size; i += 4) {
-        cpu_stl_data(env, addr + i, 0);
+        cpu_stl_data_ra(env, addr + i, 0, raddr);
     }
     if (env->reserve_addr == addr) {
         env->reserve_addr = (target_ulong)-1ULL;
@@ -168,7 +169,7 @@ void helper_dcbz(CPUPPCState *env, target_ulong addr, uint32_t is_dcbzl)
 
     /* XXX add e500mc support */
 
-    do_dcbz(env, addr, dcbz_size);
+    do_dcbz(env, addr, dcbz_size, GETPC());
 }
 
 void helper_icbi(CPUPPCState *env, target_ulong addr)
@@ -190,7 +191,7 @@ target_ulong helper_lscbx(CPUPPCState *env, target_ulong addr, uint32_t reg,
 
     d = 24;
     for (i = 0; i < xer_bc; i++) {
-        c = cpu_ldub_data(env, addr);
+        c = cpu_ldub_data_ra(env, addr, GETPC());
         addr = addr_add(env, addr, 1);
         /* ra (if not 0) and rb are never modified */
         if (likely(reg != rb && (ra == 0 || reg != ra))) {
diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index 8670932..ddfec33 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -3819,8 +3819,6 @@ static void gen_dcbz(DisasContext *ctx)
     int is_dcbzl = ctx->opcode & 0x00200000 ? 1 : 0;
 
     gen_set_access_type(ctx, ACCESS_CACHE);
-    /* NIP cannot be restored if the memory exception comes from an helper */
-    gen_update_nip(ctx, ctx->nip - 4);
     tcgv_addr = tcg_temp_new();
     tcgv_is_dcbzl = tcg_const_i32(is_dcbzl);
 
@@ -4348,8 +4346,6 @@ static void gen_lscbx(DisasContext *ctx)
     TCGv_i32 t3 = tcg_const_i32(rB(ctx->opcode));
 
     gen_addr_reg_index(ctx, t0);
-    /* NIP cannot be restored if the memory exception comes from an helper */
-    gen_update_nip(ctx, ctx->nip - 4);
     gen_helper_lscbx(t0, cpu_env, t0, t1, t2, t3);
     tcg_temp_free_i32(t1);
     tcg_temp_free_i32(t2);
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [Qemu-devel] [PATCH 24/32] ppc: Make alignment exceptions suck less
  2016-07-26 22:20 [Qemu-devel] [PATCH 01/32] ppc: Fix fault PC reporting for lve*/stve* VMX instructions Benjamin Herrenschmidt
                   ` (21 preceding siblings ...)
  2016-07-26 22:21 ` [Qemu-devel] [PATCH 23/32] ppc: Don't update NIP in dcbz and lscbx Benjamin Herrenschmidt
@ 2016-07-26 22:21 ` Benjamin Herrenschmidt
  2016-07-27  2:30   ` David Gibson
  2016-07-26 22:21 ` [Qemu-devel] [PATCH 25/32] ppc: Handle unconditional (always/never) traps at translation time Benjamin Herrenschmidt
                   ` (8 subsequent siblings)
  31 siblings, 1 reply; 69+ messages in thread
From: Benjamin Herrenschmidt @ 2016-07-26 22:21 UTC (permalink / raw)
  To: qemu-ppc; +Cc: qemu-devel, david, Benjamin Herrenschmidt

The current alignment exception generation tries to load the opcode
to put in DSISR from a context where a cpu_ldl_code() is really not
a good idea. It might fault and longjmp out and that's not something
we want happening here.

Instead, pass the releavant opcode bits via the error_code.

There are a couple of cases of alignment interrupts that won't set
anything, the ones coming from access to direct store segments, but
that doesn't happen in practice, nobody used direct store segments
and they are gone from newer chips.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
 target-ppc/excp_helper.c | 9 +++++----
 target-ppc/translate.c   | 2 +-
 2 files changed, 6 insertions(+), 5 deletions(-)

diff --git a/target-ppc/excp_helper.c b/target-ppc/excp_helper.c
index c31bbad..9a26578 100644
--- a/target-ppc/excp_helper.c
+++ b/target-ppc/excp_helper.c
@@ -260,11 +260,12 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
         }
         break;
     case POWERPC_EXCP_ALIGN:     /* Alignment exception                      */
-        /* XXX: this is false */
         /* Get rS/rD and rA from faulting opcode */
-        /* Broken for LE mode */
-        env->spr[SPR_DSISR] |= (cpu_ldl_code(env, env->nip)
-                                & 0x03FF0000) >> 16;
+        /* Note: the opcode fields will not be set properly for a direct
+         * store load/store, but nobody cares as nobody actually uses
+         * direct store segments.
+         */
+        env->spr[SPR_DSISR] |= (env->error_code & 0x03FF0000) >> 16;
         break;
     case POWERPC_EXCP_PROGRAM:   /* Program exception                        */
         switch (env->error_code & ~0xF) {
diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index ddfec33..9af3f5f 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -2202,7 +2202,7 @@ static inline void gen_check_align(DisasContext *ctx, TCGv EA, int mask)
     tcg_gen_andi_tl(t0, EA, mask);
     tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 0, l1);
     t1 = tcg_const_i32(POWERPC_EXCP_ALIGN);
-    t2 = tcg_const_i32(0);
+    t2 = tcg_const_i32(ctx->opcode & 0x03FF0000);
     gen_update_nip(ctx, ctx->nip - 4);
     gen_helper_raise_exception_err(cpu_env, t1, t2);
     tcg_temp_free_i32(t1);
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [Qemu-devel] [PATCH 25/32] ppc: Handle unconditional (always/never) traps at translation time
  2016-07-26 22:20 [Qemu-devel] [PATCH 01/32] ppc: Fix fault PC reporting for lve*/stve* VMX instructions Benjamin Herrenschmidt
                   ` (22 preceding siblings ...)
  2016-07-26 22:21 ` [Qemu-devel] [PATCH 24/32] ppc: Make alignment exceptions suck less Benjamin Herrenschmidt
@ 2016-07-26 22:21 ` Benjamin Herrenschmidt
  2016-07-27  2:33   ` David Gibson
  2016-07-26 22:21 ` [Qemu-devel] [PATCH 26/32] ppc: Speed up dcbz Benjamin Herrenschmidt
                   ` (7 subsequent siblings)
  31 siblings, 1 reply; 69+ messages in thread
From: Benjamin Herrenschmidt @ 2016-07-26 22:21 UTC (permalink / raw)
  To: qemu-ppc; +Cc: qemu-devel, david, Benjamin Herrenschmidt

We don't need to call a helper for trap always and trap never
which are used by Linux under some circumstances.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
 target-ppc/translate.c | 48 ++++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 42 insertions(+), 6 deletions(-)

diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index 9af3f5f..57a891b 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -3360,10 +3360,29 @@ static void gen_sc(DisasContext *ctx)
 
 /***                                Trap                                   ***/
 
+/* Check for unconditional traps (always or never) */
+static bool check_unconditional_trap(DisasContext *ctx)
+{
+    /* Trap never */
+    if (TO(ctx->opcode) == 0) {
+        return true;
+    }
+    /* Trap always */
+    if (TO(ctx->opcode) == 31) {
+        gen_exception_err(ctx, POWERPC_EXCP_PROGRAM, POWERPC_EXCP_TRAP);
+    }
+    return false;
+}
+
 /* tw */
 static void gen_tw(DisasContext *ctx)
 {
-    TCGv_i32 t0 = tcg_const_i32(TO(ctx->opcode));
+    TCGv_i32 t0;
+
+    if (check_unconditional_trap(ctx)) {
+        return;
+    }
+    t0 = tcg_const_i32(TO(ctx->opcode));
     gen_helper_tw(cpu_env, cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)],
                   t0);
     tcg_temp_free_i32(t0);
@@ -3372,8 +3391,14 @@ static void gen_tw(DisasContext *ctx)
 /* twi */
 static void gen_twi(DisasContext *ctx)
 {
-    TCGv t0 = tcg_const_tl(SIMM(ctx->opcode));
-    TCGv_i32 t1 = tcg_const_i32(TO(ctx->opcode));
+    TCGv t0;
+    TCGv_i32 t1;
+
+    if (check_unconditional_trap(ctx)) {
+        return;
+    }
+    t0 = tcg_const_tl(SIMM(ctx->opcode));
+    t1 = tcg_const_i32(TO(ctx->opcode));
     gen_helper_tw(cpu_env, cpu_gpr[rA(ctx->opcode)], t0, t1);
     tcg_temp_free(t0);
     tcg_temp_free_i32(t1);
@@ -3383,7 +3408,12 @@ static void gen_twi(DisasContext *ctx)
 /* td */
 static void gen_td(DisasContext *ctx)
 {
-    TCGv_i32 t0 = tcg_const_i32(TO(ctx->opcode));
+    TCGv_i32 t0;
+
+    if (check_unconditional_trap(ctx)) {
+        return;
+    }
+    t0 = tcg_const_i32(TO(ctx->opcode));
     gen_helper_td(cpu_env, cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)],
                   t0);
     tcg_temp_free_i32(t0);
@@ -3392,8 +3422,14 @@ static void gen_td(DisasContext *ctx)
 /* tdi */
 static void gen_tdi(DisasContext *ctx)
 {
-    TCGv t0 = tcg_const_tl(SIMM(ctx->opcode));
-    TCGv_i32 t1 = tcg_const_i32(TO(ctx->opcode));
+    TCGv t0;
+    TCGv_i32 t1;
+
+    if (check_unconditional_trap(ctx)) {
+        return;
+    }
+    t0 = tcg_const_tl(SIMM(ctx->opcode));
+    t1 = tcg_const_i32(TO(ctx->opcode));
     gen_helper_td(cpu_env, cpu_gpr[rA(ctx->opcode)], t0, t1);
     tcg_temp_free(t0);
     tcg_temp_free_i32(t1);
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [Qemu-devel] [PATCH 26/32] ppc: Speed up dcbz
  2016-07-26 22:20 [Qemu-devel] [PATCH 01/32] ppc: Fix fault PC reporting for lve*/stve* VMX instructions Benjamin Herrenschmidt
                   ` (23 preceding siblings ...)
  2016-07-26 22:21 ` [Qemu-devel] [PATCH 25/32] ppc: Handle unconditional (always/never) traps at translation time Benjamin Herrenschmidt
@ 2016-07-26 22:21 ` Benjamin Herrenschmidt
  2016-07-27  2:36   ` David Gibson
  2016-07-26 22:21 ` [Qemu-devel] [PATCH 27/32] ppc: Fix CFAR updates Benjamin Herrenschmidt
                   ` (6 subsequent siblings)
  31 siblings, 1 reply; 69+ messages in thread
From: Benjamin Herrenschmidt @ 2016-07-26 22:21 UTC (permalink / raw)
  To: qemu-ppc; +Cc: qemu-devel, david, Benjamin Herrenschmidt

Use tlb_vaddr_to_host to do a fast path single translate for
the whole cache line. Also make the reservation check match
the entire range.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
 target-ppc/mem_helper.c | 46 +++++++++++++++++++++++++---------------------
 target-ppc/translate.c  | 11 ++++-------
 2 files changed, 29 insertions(+), 28 deletions(-)

diff --git a/target-ppc/mem_helper.c b/target-ppc/mem_helper.c
index 92a594c..6548715 100644
--- a/target-ppc/mem_helper.c
+++ b/target-ppc/mem_helper.c
@@ -141,35 +141,39 @@ void helper_stsw(CPUPPCState *env, target_ulong addr, uint32_t nb,
     }
 }
 
-static void do_dcbz(CPUPPCState *env, target_ulong addr, int dcache_line_size,
-                    uintptr_t raddr)
+void helper_dcbz(CPUPPCState *env, target_ulong addr, uint32_t opcode)
 {
-    int i;
-
-    addr &= ~(dcache_line_size - 1);
-    for (i = 0; i < dcache_line_size; i += 4) {
-        cpu_stl_data_ra(env, addr + i, 0, raddr);
-    }
-    if (env->reserve_addr == addr) {
-        env->reserve_addr = (target_ulong)-1ULL;
-    }
-}
-
-void helper_dcbz(CPUPPCState *env, target_ulong addr, uint32_t is_dcbzl)
-{
-    int dcbz_size = env->dcache_line_size;
+    target_ulong mask, dcbz_size = env->dcache_line_size;
+    uint32_t i;
+    void *haddr;
 
 #if defined(TARGET_PPC64)
-    if (!is_dcbzl &&
-        (env->excp_model == POWERPC_EXCP_970) &&
-        ((env->spr[SPR_970_HID5] >> 7) & 0x3) == 1) {
+    /* Check for dcbz vs dcbzl on 970 */
+    if (env->excp_model == POWERPC_EXCP_970 &&
+        !(opcode & 0x00200000) && ((env->spr[SPR_970_HID5] >> 7) & 0x3) == 1) {
         dcbz_size = 32;
     }
 #endif
 
-    /* XXX add e500mc support */
+    /* Align address */
+    mask = ~(dcbz_size - 1);
+    addr &= mask;
+
+    /* Check reservation */
+    if ((env->reserve_addr & mask) == (addr & mask))  {
+        env->reserve_addr = (target_ulong)-1ULL;
+    }
 
-    do_dcbz(env, addr, dcbz_size, GETPC());
+    /* Try fast path translate */
+    haddr = tlb_vaddr_to_host(env, addr, MMU_DATA_STORE, env->dmmu_idx);
+    if (haddr) {
+        memset(haddr, 0, dcbz_size);
+    } else {
+        /* Slow path */
+        for (i = 0; i < dcbz_size; i += 8) {
+            cpu_stq_data_ra(env, addr + i, 0, GETPC());
+        }
+    }
 }
 
 void helper_icbi(CPUPPCState *env, target_ulong addr)
diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index 57a891b..5288e02 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -3851,18 +3851,15 @@ static void gen_dcbtls(DisasContext *ctx)
 static void gen_dcbz(DisasContext *ctx)
 {
     TCGv tcgv_addr;
-    TCGv_i32 tcgv_is_dcbzl;
-    int is_dcbzl = ctx->opcode & 0x00200000 ? 1 : 0;
+    TCGv_i32 tcgv_op;
 
     gen_set_access_type(ctx, ACCESS_CACHE);
     tcgv_addr = tcg_temp_new();
-    tcgv_is_dcbzl = tcg_const_i32(is_dcbzl);
-
+    tcgv_op = tcg_const_i32(ctx->opcode & 0x03FF000);
     gen_addr_reg_index(ctx, tcgv_addr);
-    gen_helper_dcbz(cpu_env, tcgv_addr, tcgv_is_dcbzl);
-
+    gen_helper_dcbz(cpu_env, tcgv_addr, tcgv_op);
     tcg_temp_free(tcgv_addr);
-    tcg_temp_free_i32(tcgv_is_dcbzl);
+    tcg_temp_free_i32(tcgv_op);
 }
 
 /* dst / dstt */
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [Qemu-devel] [PATCH 27/32] ppc: Fix CFAR updates
  2016-07-26 22:20 [Qemu-devel] [PATCH 01/32] ppc: Fix fault PC reporting for lve*/stve* VMX instructions Benjamin Herrenschmidt
                   ` (24 preceding siblings ...)
  2016-07-26 22:21 ` [Qemu-devel] [PATCH 26/32] ppc: Speed up dcbz Benjamin Herrenschmidt
@ 2016-07-26 22:21 ` Benjamin Herrenschmidt
  2016-07-26 22:21 ` [Qemu-devel] [PATCH 28/32] ppc: Avoid double translation for lvx/lvxl/stvx/stvxl Benjamin Herrenschmidt
                   ` (5 subsequent siblings)
  31 siblings, 0 replies; 69+ messages in thread
From: Benjamin Herrenschmidt @ 2016-07-26 22:21 UTC (permalink / raw)
  To: qemu-ppc; +Cc: qemu-devel, david, Benjamin Herrenschmidt

We were one instruction off

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
 target-ppc/translate.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index 5288e02..57e9a12 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -3131,7 +3131,7 @@ static void gen_b(DisasContext *ctx)
     if (LK(ctx->opcode)) {
         gen_setlr(ctx, ctx->nip);
     }
-    gen_update_cfar(ctx, ctx->nip);
+    gen_update_cfar(ctx, ctx->nip - 4);
     gen_goto_tb(ctx, 0, target);
 }
 
@@ -3196,7 +3196,7 @@ static inline void gen_bcond(DisasContext *ctx, int type)
         }
         tcg_temp_free_i32(temp);
     }
-    gen_update_cfar(ctx, ctx->nip);
+    gen_update_cfar(ctx, ctx->nip - 4);
     if (type == BCOND_IM) {
         target_ulong li = (target_long)((int16_t)(BD(ctx->opcode)));
         if (likely(AA(ctx->opcode) == 0)) {
@@ -3311,7 +3311,7 @@ static void gen_rfi(DisasContext *ctx)
      */
     /* Restore CPU state */
     CHK_SV;
-    gen_update_cfar(ctx, ctx->nip);
+    gen_update_cfar(ctx, ctx->nip - 4);
     gen_helper_rfi(cpu_env);
     gen_sync_exception(ctx);
 #endif
@@ -3325,7 +3325,7 @@ static void gen_rfid(DisasContext *ctx)
 #else
     /* Restore CPU state */
     CHK_SV;
-    gen_update_cfar(ctx, ctx->nip);
+    gen_update_cfar(ctx, ctx->nip - 4);
     gen_helper_rfid(cpu_env);
     gen_sync_exception(ctx);
 #endif
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [Qemu-devel] [PATCH 28/32] ppc: Avoid double translation for lvx/lvxl/stvx/stvxl
  2016-07-26 22:20 [Qemu-devel] [PATCH 01/32] ppc: Fix fault PC reporting for lve*/stve* VMX instructions Benjamin Herrenschmidt
                   ` (25 preceding siblings ...)
  2016-07-26 22:21 ` [Qemu-devel] [PATCH 27/32] ppc: Fix CFAR updates Benjamin Herrenschmidt
@ 2016-07-26 22:21 ` Benjamin Herrenschmidt
  2016-07-29  0:49   ` Richard Henderson
  2016-07-26 22:21 ` [Qemu-devel] [PATCH 29/32] ppc: Don't set access_type on all load/stores on hash64 Benjamin Herrenschmidt
                   ` (4 subsequent siblings)
  31 siblings, 1 reply; 69+ messages in thread
From: Benjamin Herrenschmidt @ 2016-07-26 22:21 UTC (permalink / raw)
  To: qemu-ppc; +Cc: qemu-devel, david, Benjamin Herrenschmidt

Those are always naturally aligned, so cannot cross a page boundary,
thus instead of generating two 8-byte loads with translation on each
(and double swap for LE on LE), we use a helper that will do a single
translation and memcpy the result over (or do appropriate swapping
if needed).

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
 target-ppc/helper.h             |  2 ++
 target-ppc/mem_helper.c         | 60 +++++++++++++++++++++++++++++++++++++++++
 target-ppc/translate/vmx-impl.c | 38 ++++++++------------------
 target-ppc/translate/vmx-ops.c  |  4 +--
 4 files changed, 75 insertions(+), 29 deletions(-)

diff --git a/target-ppc/helper.h b/target-ppc/helper.h
index 1f5cfd0..64f7d2c 100644
--- a/target-ppc/helper.h
+++ b/target-ppc/helper.h
@@ -269,9 +269,11 @@ DEF_HELPER_5(vmsumshm, void, env, avr, avr, avr, avr)
 DEF_HELPER_5(vmsumshs, void, env, avr, avr, avr, avr)
 DEF_HELPER_4(vmladduhm, void, avr, avr, avr, avr)
 DEF_HELPER_2(mtvscr, void, env, avr)
+DEF_HELPER_3(lvx, void, env, i32, tl)
 DEF_HELPER_3(lvebx, void, env, avr, tl)
 DEF_HELPER_3(lvehx, void, env, avr, tl)
 DEF_HELPER_3(lvewx, void, env, avr, tl)
+DEF_HELPER_3(stvx, void, env, i32, tl)
 DEF_HELPER_3(stvebx, void, env, avr, tl)
 DEF_HELPER_3(stvehx, void, env, avr, tl)
 DEF_HELPER_3(stvewx, void, env, avr, tl)
diff --git a/target-ppc/mem_helper.c b/target-ppc/mem_helper.c
index 6548715..da3f973 100644
--- a/target-ppc/mem_helper.c
+++ b/target-ppc/mem_helper.c
@@ -225,6 +225,66 @@ target_ulong helper_lscbx(CPUPPCState *env, target_ulong addr, uint32_t reg,
 #define LO_IDX 0
 #endif
 
+void helper_lvx(CPUPPCState *env, uint32_t vr, target_ulong addr)
+{
+    uintptr_t raddr = GETPC();
+    ppc_avr_t *haddr;
+
+    /* Align address */
+    addr &= ~(target_ulong)0xf;
+
+    /* Try fast path translate */
+    haddr = tlb_vaddr_to_host(env, addr, MMU_DATA_LOAD, env->dmmu_idx);
+    if (haddr) {
+        if (msr_le && HI_IDX) {
+            memcpy(&env->avr[vr], haddr, 16);
+        } else {
+            env->avr[vr].u64[LO_IDX] = bswap64(haddr->u64[HI_IDX]);
+            env->avr[vr].u64[HI_IDX] = bswap64(haddr->u64[LO_IDX]);
+        }
+    } else {
+        if (needs_byteswap(env)) {
+            env->avr[vr].u64[LO_IDX] =
+                bswap64(cpu_ldq_data_ra(env, addr, raddr));
+            env->avr[vr].u64[HI_IDX] =
+                bswap64(cpu_ldq_data_ra(env, addr + 8, raddr));
+        } else {
+            env->avr[vr].u64[HI_IDX] = cpu_ldq_data_ra(env, addr, raddr);
+            env->avr[vr].u64[LO_IDX] = cpu_ldq_data_ra(env, addr + 8, raddr);
+        }
+    }
+}
+
+void helper_stvx(CPUPPCState *env, uint32_t vr, target_ulong addr)
+{
+    uintptr_t raddr = GETPC();
+    ppc_avr_t *haddr;
+
+    /* Align address */
+    addr &= ~(target_ulong)0xf;
+
+    /* Try fast path translate */
+    haddr = tlb_vaddr_to_host(env, addr, MMU_DATA_STORE, env->dmmu_idx);
+    if (haddr) {
+        if (msr_le && HI_IDX) {
+            memcpy(haddr, &env->avr[vr], 16);
+        } else {
+            haddr->u64[LO_IDX] = bswap64(env->avr[vr].u64[HI_IDX]);
+            haddr->u64[HI_IDX] = bswap64(env->avr[vr].u64[LO_IDX]);
+        }
+    } else {
+        if (needs_byteswap(env)) {
+            cpu_stq_data_ra(env, addr,
+                            bswap64(env->avr[vr].u64[LO_IDX]), raddr);
+            cpu_stq_data_ra(env, addr + 8,
+                            bswap64(env->avr[vr].u64[HI_IDX]), raddr);
+        } else {
+            cpu_stq_data_ra(env, addr, env->avr[vr].u64[HI_IDX], raddr);
+            cpu_stq_data_ra(env, addr + 8, env->avr[vr].u64[LO_IDX], raddr);
+        }
+    }
+}
+
 /* We use msr_le to determine index ordering in a vector.  However,
    byteswapping is not simply controlled by msr_le.  We also need to take
    into account endianness of the target.  This is done for the little-endian
diff --git a/target-ppc/translate/vmx-impl.c b/target-ppc/translate/vmx-impl.c
index 110e19c..a58aa0c 100644
--- a/target-ppc/translate/vmx-impl.c
+++ b/target-ppc/translate/vmx-impl.c
@@ -15,55 +15,39 @@ static inline TCGv_ptr gen_avr_ptr(int reg)
 }
 
 #define GEN_VR_LDX(name, opc2, opc3)                                          \
-static void glue(gen_, name)(DisasContext *ctx)                                       \
+static void glue(gen_, name)(DisasContext *ctx)                               \
 {                                                                             \
     TCGv EA;                                                                  \
+    TCGv_i32 t0;                                                              \
     if (unlikely(!ctx->altivec_enabled)) {                                    \
         gen_exception(ctx, POWERPC_EXCP_VPU);                                 \
         return;                                                               \
     }                                                                         \
     gen_set_access_type(ctx, ACCESS_INT);                                     \
     EA = tcg_temp_new();                                                      \
+    t0 = tcg_const_i32(rD(ctx->opcode));                                      \
     gen_addr_reg_index(ctx, EA);                                              \
-    tcg_gen_andi_tl(EA, EA, ~0xf);                                            \
-    /* We only need to swap high and low halves. gen_qemu_ld64 does necessary \
-       64-bit byteswap already. */                                            \
-    if (ctx->le_mode) {                                                       \
-        gen_qemu_ld64(ctx, cpu_avrl[rD(ctx->opcode)], EA);                    \
-        tcg_gen_addi_tl(EA, EA, 8);                                           \
-        gen_qemu_ld64(ctx, cpu_avrh[rD(ctx->opcode)], EA);                    \
-    } else {                                                                  \
-        gen_qemu_ld64(ctx, cpu_avrh[rD(ctx->opcode)], EA);                    \
-        tcg_gen_addi_tl(EA, EA, 8);                                           \
-        gen_qemu_ld64(ctx, cpu_avrl[rD(ctx->opcode)], EA);                    \
-    }                                                                         \
+    gen_helper_lvx(cpu_env, t0, EA);                                          \
     tcg_temp_free(EA);                                                        \
+    tcg_temp_free_i32(t0);                                                    \
 }
 
 #define GEN_VR_STX(name, opc2, opc3)                                          \
 static void gen_st##name(DisasContext *ctx)                                   \
 {                                                                             \
     TCGv EA;                                                                  \
+    TCGv_i32 t0;                                                              \
     if (unlikely(!ctx->altivec_enabled)) {                                    \
         gen_exception(ctx, POWERPC_EXCP_VPU);                                 \
         return;                                                               \
     }                                                                         \
     gen_set_access_type(ctx, ACCESS_INT);                                     \
     EA = tcg_temp_new();                                                      \
+    t0 = tcg_const_i32(rD(ctx->opcode));                                      \
     gen_addr_reg_index(ctx, EA);                                              \
-    tcg_gen_andi_tl(EA, EA, ~0xf);                                            \
-    /* We only need to swap high and low halves. gen_qemu_st64 does necessary \
-       64-bit byteswap already. */                                            \
-    if (ctx->le_mode) {                                                       \
-        gen_qemu_st64(ctx, cpu_avrl[rD(ctx->opcode)], EA);                    \
-        tcg_gen_addi_tl(EA, EA, 8);                                           \
-        gen_qemu_st64(ctx, cpu_avrh[rD(ctx->opcode)], EA);                    \
-    } else {                                                                  \
-        gen_qemu_st64(ctx, cpu_avrh[rD(ctx->opcode)], EA);                    \
-        tcg_gen_addi_tl(EA, EA, 8);                                           \
-        gen_qemu_st64(ctx, cpu_avrl[rD(ctx->opcode)], EA);                    \
-    }                                                                         \
+    gen_helper_stvx(cpu_env, t0, EA);                                         \
     tcg_temp_free(EA);                                                        \
+    tcg_temp_free_i32(t0);                                                    \
 }
 
 #define GEN_VR_LVE(name, opc2, opc3, size)                              \
@@ -116,9 +100,9 @@ GEN_VR_LVE(bx, 0x07, 0x00, 1);
 GEN_VR_LVE(hx, 0x07, 0x01, 2);
 GEN_VR_LVE(wx, 0x07, 0x02, 4);
 
-GEN_VR_STX(svx, 0x07, 0x07);
+GEN_VR_STX(vx, 0x07, 0x07);
 /* As we don't emulate the cache, stvxl is stricly equivalent to stvx */
-GEN_VR_STX(svxl, 0x07, 0x0F);
+GEN_VR_STX(vxl, 0x07, 0x0F);
 
 GEN_VR_STVE(bx, 0x07, 0x04, 1);
 GEN_VR_STVE(hx, 0x07, 0x05, 2);
diff --git a/target-ppc/translate/vmx-ops.c b/target-ppc/translate/vmx-ops.c
index b9c982a..6c7d150 100644
--- a/target-ppc/translate/vmx-ops.c
+++ b/target-ppc/translate/vmx-ops.c
@@ -11,8 +11,8 @@ GEN_VR_LDX(lvxl, 0x07, 0x0B),
 GEN_VR_LVE(bx, 0x07, 0x00),
 GEN_VR_LVE(hx, 0x07, 0x01),
 GEN_VR_LVE(wx, 0x07, 0x02),
-GEN_VR_STX(svx, 0x07, 0x07),
-GEN_VR_STX(svxl, 0x07, 0x0F),
+GEN_VR_STX(vx, 0x07, 0x07),
+GEN_VR_STX(vxl, 0x07, 0x0F),
 GEN_VR_STVE(bx, 0x07, 0x04),
 GEN_VR_STVE(hx, 0x07, 0x05),
 GEN_VR_STVE(wx, 0x07, 0x06),
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [Qemu-devel] [PATCH 29/32] ppc: Don't set access_type on all load/stores on hash64
  2016-07-26 22:20 [Qemu-devel] [PATCH 01/32] ppc: Fix fault PC reporting for lve*/stve* VMX instructions Benjamin Herrenschmidt
                   ` (26 preceding siblings ...)
  2016-07-26 22:21 ` [Qemu-devel] [PATCH 28/32] ppc: Avoid double translation for lvx/lvxl/stvx/stvxl Benjamin Herrenschmidt
@ 2016-07-26 22:21 ` Benjamin Herrenschmidt
  2016-07-26 22:21 ` [Qemu-devel] [PATCH 30/32] ppc: Use a helper to generate "LE unsupported" alignment interrupts Benjamin Herrenschmidt
                   ` (3 subsequent siblings)
  31 siblings, 0 replies; 69+ messages in thread
From: Benjamin Herrenschmidt @ 2016-07-26 22:21 UTC (permalink / raw)
  To: qemu-ppc; +Cc: qemu-devel, david, Benjamin Herrenschmidt

We don't use it so let's not generate the updates.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
 target-ppc/translate.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index 57e9a12..fcff24a 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -195,6 +195,7 @@ struct DisasContext {
     /* Routine used to access memory */
     bool pr, hv, dr, le_mode;
     bool lazy_tlb_flush;
+    bool need_access_type;
     int mem_idx;
     int access_type;
     /* Translation flags */
@@ -252,7 +253,7 @@ struct opc_handler_t {
 
 static inline void gen_set_access_type(DisasContext *ctx, int access_type)
 {
-    if (ctx->access_type != access_type) {
+    if (ctx->need_access_type && ctx->access_type != access_type) {
         tcg_gen_movi_i32(cpu_access_type, access_type);
         ctx->access_type = access_type;
     }
@@ -6638,6 +6639,7 @@ void gen_intermediate_code(CPUPPCState *env, struct TranslationBlock *tb)
     ctx.insns_flags = env->insns_flags;
     ctx.insns_flags2 = env->insns_flags2;
     ctx.access_type = -1;
+    ctx.need_access_type = !(env->mmu_model & POWERPC_MMU_64B);
     ctx.le_mode = !!(env->hflags & (1 << MSR_LE));
     ctx.default_tcg_memop_mask = ctx.le_mode ? MO_LE : MO_BE;
 #if defined(TARGET_PPC64)
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [Qemu-devel] [PATCH 30/32] ppc: Use a helper to generate "LE unsupported" alignment interrupts
  2016-07-26 22:20 [Qemu-devel] [PATCH 01/32] ppc: Fix fault PC reporting for lve*/stve* VMX instructions Benjamin Herrenschmidt
                   ` (27 preceding siblings ...)
  2016-07-26 22:21 ` [Qemu-devel] [PATCH 29/32] ppc: Don't set access_type on all load/stores on hash64 Benjamin Herrenschmidt
@ 2016-07-26 22:21 ` Benjamin Herrenschmidt
  2016-07-26 22:21 ` [Qemu-devel] [PATCH 31/32] ppc: load/store multiple and string insns don't do LE Benjamin Herrenschmidt
                   ` (2 subsequent siblings)
  31 siblings, 0 replies; 69+ messages in thread
From: Benjamin Herrenschmidt @ 2016-07-26 22:21 UTC (permalink / raw)
  To: qemu-ppc; +Cc: qemu-devel, david, Benjamin Herrenschmidt

Some operations aren't allowed in LE mode, use a helper rather than
open coding the exception generation.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
 target-ppc/translate.c | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index fcff24a..df9a5bd 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -2212,6 +2212,12 @@ static inline void gen_check_align(DisasContext *ctx, TCGv EA, int mask)
     tcg_temp_free(t0);
 }
 
+static inline void gen_align_no_le(DisasContext *ctx)
+{
+    gen_exception_err(ctx, POWERPC_EXCP_ALIGN,
+                      (ctx->opcode & 0x03FF0000) | POWERPC_EXCP_ALIGN_LE);
+}
+
 /***                             Integer load                              ***/
 static inline void gen_qemu_ld8u(DisasContext *ctx, TCGv arg1, TCGv arg2)
 {
@@ -2432,10 +2438,9 @@ static void gen_lq(DisasContext *ctx)
     }
 
     if (!le_is_supported && ctx->le_mode) {
-        gen_exception_err(ctx, POWERPC_EXCP_ALIGN, POWERPC_EXCP_ALIGN_LE);
+        gen_align_no_le(ctx);
         return;
     }
-
     ra = rA(ctx->opcode);
     rd = rD(ctx->opcode);
     if (unlikely((rd & 1) || rd == ra)) {
@@ -2566,7 +2571,7 @@ static void gen_std(DisasContext *ctx)
         }
 
         if (!le_is_supported && ctx->le_mode) {
-            gen_exception_err(ctx, POWERPC_EXCP_ALIGN, POWERPC_EXCP_ALIGN_LE);
+            gen_align_no_le(ctx);
             return;
         }
 
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [Qemu-devel] [PATCH 31/32] ppc: load/store multiple and string insns don't do LE
  2016-07-26 22:20 [Qemu-devel] [PATCH 01/32] ppc: Fix fault PC reporting for lve*/stve* VMX instructions Benjamin Herrenschmidt
                   ` (28 preceding siblings ...)
  2016-07-26 22:21 ` [Qemu-devel] [PATCH 30/32] ppc: Use a helper to generate "LE unsupported" alignment interrupts Benjamin Herrenschmidt
@ 2016-07-26 22:21 ` Benjamin Herrenschmidt
  2016-07-26 22:21 ` [Qemu-devel] [PATCH 32/32] ppc: Speed up load/store multiple Benjamin Herrenschmidt
  2016-07-27  1:06 ` [Qemu-devel] [PATCH 01/32] ppc: Fix fault PC reporting for lve*/stve* VMX instructions David Gibson
  31 siblings, 0 replies; 69+ messages in thread
From: Benjamin Herrenschmidt @ 2016-07-26 22:21 UTC (permalink / raw)
  To: qemu-ppc; +Cc: qemu-devel, david, Benjamin Herrenschmidt

Just generate an alignment interrupt

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
 target-ppc/translate.c | 29 +++++++++++++++++++++++++++++
 1 file changed, 29 insertions(+)

diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index df9a5bd..3a6de20 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -2674,6 +2674,11 @@ static void gen_lmw(DisasContext *ctx)
 {
     TCGv t0;
     TCGv_i32 t1;
+
+    if (ctx->le_mode) {
+        gen_align_no_le(ctx);
+        return;
+    }
     gen_set_access_type(ctx, ACCESS_INT);
     t0 = tcg_temp_new();
     t1 = tcg_const_i32(rD(ctx->opcode));
@@ -2688,6 +2693,11 @@ static void gen_stmw(DisasContext *ctx)
 {
     TCGv t0;
     TCGv_i32 t1;
+
+    if (ctx->le_mode) {
+        gen_align_no_le(ctx);
+        return;
+    }
     gen_set_access_type(ctx, ACCESS_INT);
     t0 = tcg_temp_new();
     t1 = tcg_const_i32(rS(ctx->opcode));
@@ -2714,6 +2724,10 @@ static void gen_lswi(DisasContext *ctx)
     int ra = rA(ctx->opcode);
     int nr;
 
+    if (ctx->le_mode) {
+        gen_align_no_le(ctx);
+        return;
+    }
     if (nb == 0)
         nb = 32;
     nr = (nb + 3) / 4;
@@ -2737,6 +2751,11 @@ static void gen_lswx(DisasContext *ctx)
 {
     TCGv t0;
     TCGv_i32 t1, t2, t3;
+
+    if (ctx->le_mode) {
+        gen_align_no_le(ctx);
+        return;
+    }
     gen_set_access_type(ctx, ACCESS_INT);
     t0 = tcg_temp_new();
     gen_addr_reg_index(ctx, t0);
@@ -2756,6 +2775,11 @@ static void gen_stswi(DisasContext *ctx)
     TCGv t0;
     TCGv_i32 t1, t2;
     int nb = NB(ctx->opcode);
+
+    if (ctx->le_mode) {
+        gen_align_no_le(ctx);
+        return;
+    }
     gen_set_access_type(ctx, ACCESS_INT);
     t0 = tcg_temp_new();
     gen_addr_register(ctx, t0);
@@ -2774,6 +2798,11 @@ static void gen_stswx(DisasContext *ctx)
 {
     TCGv t0;
     TCGv_i32 t1, t2;
+
+    if (ctx->le_mode) {
+        gen_align_no_le(ctx);
+        return;
+    }
     gen_set_access_type(ctx, ACCESS_INT);
     t0 = tcg_temp_new();
     gen_addr_reg_index(ctx, t0);
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* [Qemu-devel] [PATCH 32/32] ppc: Speed up load/store multiple
  2016-07-26 22:20 [Qemu-devel] [PATCH 01/32] ppc: Fix fault PC reporting for lve*/stve* VMX instructions Benjamin Herrenschmidt
                   ` (29 preceding siblings ...)
  2016-07-26 22:21 ` [Qemu-devel] [PATCH 31/32] ppc: load/store multiple and string insns don't do LE Benjamin Herrenschmidt
@ 2016-07-26 22:21 ` Benjamin Herrenschmidt
  2016-07-27  2:47   ` David Gibson
  2016-07-27  1:06 ` [Qemu-devel] [PATCH 01/32] ppc: Fix fault PC reporting for lve*/stve* VMX instructions David Gibson
  31 siblings, 1 reply; 69+ messages in thread
From: Benjamin Herrenschmidt @ 2016-07-26 22:21 UTC (permalink / raw)
  To: qemu-ppc; +Cc: qemu-devel, david, Benjamin Herrenschmidt

Use a single translate when not crossing a page boundary and avoid
going through layers of helpers. MacOS uses those instructions
a lot, so does OpenBIOS.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
 target-ppc/mem_helper.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 69 insertions(+)

diff --git a/target-ppc/mem_helper.c b/target-ppc/mem_helper.c
index da3f973..511079b 100644
--- a/target-ppc/mem_helper.c
+++ b/target-ppc/mem_helper.c
@@ -53,8 +53,48 @@ static inline target_ulong addr_add(CPUPPCState *env, target_ulong addr,
     }
 }
 
+/* Reduce the length so that addr + len doesn't cross a page boundary.  */
+static inline uint64_t adj_len_to_page(uint64_t len, uint64_t addr)
+{
+#ifndef CONFIG_USER_ONLY
+    if ((addr & ~TARGET_PAGE_MASK) + len - 1 >= TARGET_PAGE_SIZE) {
+        return -addr & ~TARGET_PAGE_MASK;
+    }
+#endif
+    return len;
+}
+
 void helper_lmw(CPUPPCState *env, target_ulong addr, uint32_t reg)
 {
+    uint32_t *src;
+    uint64_t len, adjlen;
+
+    if ((addr & 3)) {
+        goto fallback;
+    }
+    len = (32 - reg) << 2;
+    while (len) {
+        src = tlb_vaddr_to_host(env, addr, MMU_DATA_LOAD, env->dmmu_idx);
+        if (!src) {
+            goto fallback;
+        }
+        adjlen = adj_len_to_page(len, addr);
+        len -= adjlen;
+#if defined(HOST_WORDS_BIGENDIAN)
+        memcpy(&env->gpr[reg], src, adjlen);
+        reg += (adjlen >> 2);
+        addr = addr_add(env, addr, adjlen);
+#else
+        while(adjlen) {
+            env->gpr[reg++] = bswap32(*(src++));
+            adjlen -= 4;
+            addr = addr_add(env, addr, 4);
+        }
+#endif
+    }
+    return;
+
+ fallback:
     for (; reg < 32; reg++) {
         if (needs_byteswap(env)) {
             env->gpr[reg] = bswap32(cpu_ldl_data_ra(env, addr, GETPC()));
@@ -67,6 +107,35 @@ void helper_lmw(CPUPPCState *env, target_ulong addr, uint32_t reg)
 
 void helper_stmw(CPUPPCState *env, target_ulong addr, uint32_t reg)
 {
+    uint32_t *dst;
+    uint64_t len, adjlen;
+
+    if ((addr & 3)) {
+        goto fallback;
+    }
+    len = (32 - reg) << 2;
+    while (len) {
+        dst = tlb_vaddr_to_host(env, addr, MMU_DATA_STORE, env->dmmu_idx);
+        if (!dst) {
+            goto fallback;
+        }
+        adjlen = adj_len_to_page(len, addr);
+        len -= adjlen;
+#if defined(HOST_WORDS_BIGENDIAN)
+        memcpy(dst, &env->gpr[reg], adjlen);
+        reg += (adjlen >> 2);
+        addr = addr_add(env, addr, adjlen);
+#else
+        while(adjlen) {
+            *(dst++) = bswap32(env->gpr[reg++]);
+            adjlen -= 4;
+            addr = addr_add(env, addr, 4);
+        }
+#endif
+    }
+    return;
+
+ fallback:
     for (; reg < 32; reg++) {
         if (needs_byteswap(env)) {
             cpu_stl_data_ra(env, addr, bswap32((uint32_t)env->gpr[reg]),
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 69+ messages in thread

* Re: [Qemu-devel] [PATCH 01/32] ppc: Fix fault PC reporting for lve*/stve* VMX instructions
  2016-07-26 22:20 [Qemu-devel] [PATCH 01/32] ppc: Fix fault PC reporting for lve*/stve* VMX instructions Benjamin Herrenschmidt
                   ` (30 preceding siblings ...)
  2016-07-26 22:21 ` [Qemu-devel] [PATCH 32/32] ppc: Speed up load/store multiple Benjamin Herrenschmidt
@ 2016-07-27  1:06 ` David Gibson
  31 siblings, 0 replies; 69+ messages in thread
From: David Gibson @ 2016-07-27  1:06 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: qemu-ppc, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 3257 bytes --]

On Wed, Jul 27, 2016 at 08:20:55AM +1000, Benjamin Herrenschmidt wrote:
> We forgot to do gen_update_nip() for these like we do with other
> helpers. Fix this, but in a more efficient way by passing the RA
> to the accessors instead so the overhead is only taken on faults.
> 
> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>

As a bugfix, I've applied this to ppc-for-2.7.

> ---
>  target-ppc/mem_helper.c | 21 +++++++++++----------
>  1 file changed, 11 insertions(+), 10 deletions(-)
> 
> diff --git a/target-ppc/mem_helper.c b/target-ppc/mem_helper.c
> index e4de86b..e4ed377 100644
> --- a/target-ppc/mem_helper.c
> +++ b/target-ppc/mem_helper.c
> @@ -232,16 +232,16 @@ target_ulong helper_lscbx(CPUPPCState *env, target_ulong addr, uint32_t reg,
>                                                                  \
>          if (needs_byteswap(env)) {                              \
>              r->element[LO_IDX ? index : (adjust - index)] =     \
> -                swap(access(env, addr));                        \
> +                swap(access(env, addr, GETPC()));               \
>          } else {                                                \
>              r->element[LO_IDX ? index : (adjust - index)] =     \
> -                access(env, addr);                              \
> +                access(env, addr, GETPC());                     \
>          }                                                       \
>      }
>  #define I(x) (x)
> -LVE(lvebx, cpu_ldub_data, I, u8)
> -LVE(lvehx, cpu_lduw_data, bswap16, u16)
> -LVE(lvewx, cpu_ldl_data, bswap32, u32)
> +LVE(lvebx, cpu_ldub_data_ra, I, u8)
> +LVE(lvehx, cpu_lduw_data_ra, bswap16, u16)
> +LVE(lvewx, cpu_ldl_data_ra, bswap32, u32)
>  #undef I
>  #undef LVE
>  
> @@ -259,16 +259,17 @@ LVE(lvewx, cpu_ldl_data, bswap32, u32)
>                                                                          \
>          if (needs_byteswap(env)) {                                      \
>              access(env, addr, swap(r->element[LO_IDX ? index :          \
> -                                              (adjust - index)]));      \
> +                                              (adjust - index)]),       \
> +                        GETPC());                                       \
>          } else {                                                        \
>              access(env, addr, r->element[LO_IDX ? index :               \
> -                                         (adjust - index)]);            \
> +                                         (adjust - index)], GETPC());   \
>          }                                                               \
>      }
>  #define I(x) (x)
> -STVE(stvebx, cpu_stb_data, I, u8)
> -STVE(stvehx, cpu_stw_data, bswap16, u16)
> -STVE(stvewx, cpu_stl_data, bswap32, u32)
> +STVE(stvebx, cpu_stb_data_ra, I, u8)
> +STVE(stvehx, cpu_stw_data_ra, bswap16, u16)
> +STVE(stvewx, cpu_stl_data_ra, bswap32, u32)
>  #undef I
>  #undef LVE
>  

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Qemu-devel] [PATCH 02/32] ppc: Provide basic raise_exception_* functions
  2016-07-26 22:20 ` [Qemu-devel] [PATCH 02/32] ppc: Provide basic raise_exception_* functions Benjamin Herrenschmidt
@ 2016-07-27  1:50   ` David Gibson
  2016-07-27  3:46     ` Benjamin Herrenschmidt
  0 siblings, 1 reply; 69+ messages in thread
From: David Gibson @ 2016-07-27  1:50 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: qemu-ppc, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 5759 bytes --]

On Wed, Jul 27, 2016 at 08:20:56AM +1000, Benjamin Herrenschmidt wrote:
> Instead of using the same helpers called from translate.c, let's have
> a bunch of functions that take the various argument combinations,
> especially the retaddr which will be needed in subsequent patches,
> and leave the helpers to be just that, helpers for translate.c
> 
> We don't yet convert all users, we'll go through them in subsequent
> patches.
> 
> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> ---
>  target-ppc/cpu.h         |  8 ++++++++
>  target-ppc/excp_helper.c | 51 ++++++++++++++++++++++++++++++++----------------
>  2 files changed, 42 insertions(+), 17 deletions(-)
> 
> diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
> index 5fce1ff..2ee7a5e 100644
> --- a/target-ppc/cpu.h
> +++ b/target-ppc/cpu.h
> @@ -2295,6 +2295,14 @@ static inline void cpu_get_tb_cpu_state(CPUPPCState *env, target_ulong *pc,
>      *flags = env->hflags;
>  }
>  
> +void QEMU_NORETURN raise_exception(CPUPPCState *env, uint32_t exception);
> +void QEMU_NORETURN raise_exception_ra(CPUPPCState *env, uint32_t exception,
> +                                      uintptr_t raddr);
> +void QEMU_NORETURN raise_exception_err(CPUPPCState *env, uint32_t exception,
> +                                       uint32_t error_code);
> +void QEMU_NORETURN raise_exception_err_ra(CPUPPCState *env, uint32_t exception,
> +                                          uint32_t error_code, uintptr_t raddr);
> +
>  #if !defined(CONFIG_USER_ONLY)
>  static inline int booke206_tlbm_id(CPUPPCState *env, ppcmas_tlb_t *tlbm)
>  {
> diff --git a/target-ppc/excp_helper.c b/target-ppc/excp_helper.c
> index d6e1678..f4b115e 100644
> --- a/target-ppc/excp_helper.c
> +++ b/target-ppc/excp_helper.c
> @@ -898,34 +898,53 @@ static void cpu_dump_rfi(target_ulong RA, target_ulong msr)
>  /*****************************************************************************/
>  /* Exceptions processing helpers */
>  
> -void helper_raise_exception_err(CPUPPCState *env, uint32_t exception,
> -                                uint32_t error_code)
> +void raise_exception_err_ra(CPUPPCState *env, uint32_t exception,
> +                            uint32_t error_code, uintptr_t raddr)
>  {
>      CPUState *cs = CPU(ppc_env_get_cpu(env));
>  
> -#if 0
> -    printf("Raise exception %3x code : %d\n", exception, error_code);
> -#endif
>      cs->exception_index = exception;
>      env->error_code = error_code;
> -    cpu_loop_exit(cs);
> +    cpu_loop_exit_restore(cs, raddr);
> +}
> +
> +void raise_exception_err(CPUPPCState *env, uint32_t exception,
> +                         uint32_t error_code)
> +{
> +    raise_exception_err_ra(env, exception, error_code, 0);
> +}
> +
> +void raise_exception(CPUPPCState *env, uint32_t exception)
> +{
> +    raise_exception_err_ra(env, exception, 0, 0);
> +}
> +
> +void raise_exception_ra(CPUPPCState *env, uint32_t exception,
> +                        uintptr_t raddr)
> +{
> +    raise_exception_err_ra(env, exception, 0, 0);

This should pass raddr as the last argument, shouldn't it?

> +}
> +
> +void helper_raise_exception_err(CPUPPCState *env, uint32_t exception,
> +                                uint32_t error_code)
> +{
> +    raise_exception_err_ra(env, exception, error_code, 0);
>  }
>  
>  void helper_raise_exception(CPUPPCState *env, uint32_t exception)
>  {
> -    helper_raise_exception_err(env, exception, 0);
> +    raise_exception_err_ra(env, exception, 0, 0);
>  }
>  
>  #if !defined(CONFIG_USER_ONLY)
>  void helper_store_msr(CPUPPCState *env, target_ulong val)
>  {
> -    CPUState *cs;
> +    uint32_t excp = hreg_store_msr(env, val, 0);
>  
> -    val = hreg_store_msr(env, val, 0);
> -    if (val != 0) {
> -        cs = CPU(ppc_env_get_cpu(env));
> +    if (excp != 0) {
> +        CPUState *cs = CPU(ppc_env_get_cpu(env));
>          cs->interrupt_request |= CPU_INTERRUPT_EXITTB;
> -        helper_raise_exception(env, val);
> +        raise_exception(env, excp);
>      }
>  }
>  
> @@ -951,7 +970,7 @@ void helper_pminsn(CPUPPCState *env, powerpc_pm_insn_t insn)
>       * but this doesn't seem to be a problem.
>       */
>      env->msr |= (1ull << MSR_EE);
> -    helper_raise_exception(env, EXCP_HLT);
> +    raise_exception(env, EXCP_HLT);
>  }
>  #endif /* defined(TARGET_PPC64) */
>  
> @@ -1041,8 +1060,7 @@ void helper_tw(CPUPPCState *env, target_ulong arg1, target_ulong arg2,
>                    ((int32_t)arg1 == (int32_t)arg2 && (flags & 0x04)) ||
>                    ((uint32_t)arg1 < (uint32_t)arg2 && (flags & 0x02)) ||
>                    ((uint32_t)arg1 > (uint32_t)arg2 && (flags & 0x01))))) {
> -        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> -                                   POWERPC_EXCP_TRAP);
> +        raise_exception_err(env, POWERPC_EXCP_PROGRAM, POWERPC_EXCP_TRAP);
>      }
>  }
>  
> @@ -1055,8 +1073,7 @@ void helper_td(CPUPPCState *env, target_ulong arg1, target_ulong arg2,
>                    ((int64_t)arg1 == (int64_t)arg2 && (flags & 0x04)) ||
>                    ((uint64_t)arg1 < (uint64_t)arg2 && (flags & 0x02)) ||
>                    ((uint64_t)arg1 > (uint64_t)arg2 && (flags & 0x01))))) {
> -        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> -                                   POWERPC_EXCP_TRAP);
> +        raise_exception_err(env, POWERPC_EXCP_PROGRAM, POWERPC_EXCP_TRAP);
>      }
>  }
>  #endif

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Qemu-devel] [PATCH 10/32] ppc: Make float_check_status() pass the return address
  2016-07-26 22:21 ` [Qemu-devel] [PATCH 10/32] ppc: Make float_check_status() " Benjamin Herrenschmidt
@ 2016-07-27  1:57   ` David Gibson
  2016-07-27  3:47     ` Benjamin Herrenschmidt
  0 siblings, 1 reply; 69+ messages in thread
From: David Gibson @ 2016-07-27  1:57 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: qemu-ppc, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 13177 bytes --]

On Wed, Jul 27, 2016 at 08:21:04AM +1000, Benjamin Herrenschmidt wrote:
> Instead of relying on NIP having been updated already.
> 
> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> ---
>  target-ppc/fpu_helper.c | 63 +++++++++++++++++++++++++++++--------------------
>  1 file changed, 38 insertions(+), 25 deletions(-)
> 
> diff --git a/target-ppc/fpu_helper.c b/target-ppc/fpu_helper.c
> index 8d881fc..7bab3ff 100644
> --- a/target-ppc/fpu_helper.c
> +++ b/target-ppc/fpu_helper.c
> @@ -209,7 +209,7 @@ static inline uint64_t float_invalid_op_excp(CPUPPCState *env, int op,
>      return ret;
>  }
>  
> -static inline void float_zero_divide_excp(CPUPPCState *env)
> +static inline void float_zero_divide_excp(CPUPPCState *env, uintptr_t raddr)
>  {
>      env->fpscr |= 1 << FPSCR_ZX;
>      env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
> @@ -219,8 +219,9 @@ static inline void float_zero_divide_excp(CPUPPCState *env)
>          /* Update the floating-point enabled exception summary */
>          env->fpscr |= 1 << FPSCR_FEX;
>          if (msr_fe0 != 0 || msr_fe1 != 0) {
> -            helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> -                                       POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX);
> +            raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM,
> +                                   POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX,
> +                                   raddr);
>          }
>      }
>  }
> @@ -493,13 +494,14 @@ void store_fpscr(CPUPPCState *env, uint64_t arg, uint32_t mask)
>      helper_store_fpscr(env, arg, mask);
>  }
>  
> -void helper_float_check_status(CPUPPCState *env)
> +static __attribute__((noinline)) void do_float_check_status(CPUPPCState *env,
> +                                                            uintptr_t raddr)

Why do you need to force this to be non-inline?

>  {
>      CPUState *cs = CPU(ppc_env_get_cpu(env));
>      int status = get_float_exception_flags(&env->fp_status);
>  
>      if (status & float_flag_divbyzero) {
> -        float_zero_divide_excp(env);
> +        float_zero_divide_excp(env, raddr);
>      } else if (status & float_flag_overflow) {
>          float_overflow_excp(env);
>      } else if (status & float_flag_underflow) {
> @@ -512,12 +514,23 @@ void helper_float_check_status(CPUPPCState *env)
>          (env->error_code & POWERPC_EXCP_FP)) {
>          /* Differred floating-point exception after target FPR update */
>          if (msr_fe0 != 0 || msr_fe1 != 0) {
> -            helper_raise_exception_err(env, cs->exception_index,
> -                                       env->error_code);
> +            raise_exception_err_ra(env, cs->exception_index,
> +                                   env->error_code, raddr);
>          }
>      }
>  }
>  
> +static inline void float_check_status(CPUPPCState *env)
> +{
> +    /* GETPC() works here because this is inline */
> +    do_float_check_status(env, GETPC());
> +}
> +
> +void helper_float_check_status(CPUPPCState *env)
> +{
> +    do_float_check_status(env, GETPC());
> +}
> +
>  void helper_reset_fpstatus(CPUPPCState *env)
>  {
>      set_float_exception_flags(0, &env->fp_status);
> @@ -642,7 +655,7 @@ uint64_t helper_##op(CPUPPCState *env, uint64_t arg)                   \
>                     float_flag_invalid) {                               \
>              float_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 1);      \
>          }                                                              \
> -        helper_float_check_status(env);                                \
> +        float_check_status(env);                                       \
>      }                                                                  \
>      return farg.ll;                                                    \
>   }
> @@ -667,7 +680,7 @@ uint64_t helper_##op(CPUPPCState *env, uint64_t arg)       \
>      } else {                                               \
>          farg.d = cvtr(arg, &env->fp_status);               \
>      }                                                      \
> -    helper_float_check_status(env);                        \
> +    float_check_status(env);                               \
>      return farg.ll;                                        \
>  }
>  
> @@ -700,7 +713,7 @@ static inline uint64_t do_fri(CPUPPCState *env, uint64_t arg,
>              env->fp_status.float_exception_flags &= ~float_flag_inexact;
>          }
>      }
> -    helper_float_check_status(env);
> +    float_check_status(env);
>      return farg.ll;
>  }
>  
> @@ -1856,7 +1869,7 @@ void helper_##name(CPUPPCState *env, uint32_t opcode)                        \
>          }                                                                    \
>      }                                                                        \
>      putVSR(xT(opcode), &xt, env);                                            \
> -    helper_float_check_status(env);                                          \
> +    float_check_status(env);                                                 \
>  }
>  
>  VSX_ADD_SUB(xsadddp, add, 1, float64, VsrD(0), 1, 0)
> @@ -1912,7 +1925,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)                          \
>      }                                                                        \
>                                                                               \
>      putVSR(xT(opcode), &xt, env);                                            \
> -    helper_float_check_status(env);                                          \
> +    float_check_status(env);                                                 \
>  }
>  
>  VSX_MUL(xsmuldp, 1, float64, VsrD(0), 1, 0)
> @@ -1966,7 +1979,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)                           \
>      }                                                                         \
>                                                                                \
>      putVSR(xT(opcode), &xt, env);                                             \
> -    helper_float_check_status(env);                                           \
> +    float_check_status(env);                                                  \
>  }
>  
>  VSX_DIV(xsdivdp, 1, float64, VsrD(0), 1, 0)
> @@ -2007,7 +2020,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)                           \
>      }                                                                         \
>                                                                                \
>      putVSR(xT(opcode), &xt, env);                                             \
> -    helper_float_check_status(env);                                           \
> +    float_check_status(env);                                                  \
>  }
>  
>  VSX_RE(xsredp, 1, float64, VsrD(0), 1, 0)
> @@ -2056,7 +2069,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)                          \
>      }                                                                        \
>                                                                               \
>      putVSR(xT(opcode), &xt, env);                                            \
> -    helper_float_check_status(env);                                          \
> +    float_check_status(env);                                                 \
>  }
>  
>  VSX_SQRT(xssqrtdp, 1, float64, VsrD(0), 1, 0)
> @@ -2106,7 +2119,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)                          \
>      }                                                                        \
>                                                                               \
>      putVSR(xT(opcode), &xt, env);                                            \
> -    helper_float_check_status(env);                                          \
> +    float_check_status(env);                                                 \
>  }
>  
>  VSX_RSQRTE(xsrsqrtedp, 1, float64, VsrD(0), 1, 0)
> @@ -2305,7 +2318,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)                           \
>          }                                                                     \
>      }                                                                         \
>      putVSR(xT(opcode), &xt_out, env);                                         \
> -    helper_float_check_status(env);                                           \
> +    float_check_status(env);                                                  \
>  }
>  
>  #define MADD_FLGS 0
> @@ -2383,7 +2396,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)                      \
>      env->fpscr |= cc << FPSCR_FPRF;                                      \
>      env->crf[BF(opcode)] = cc;                                           \
>                                                                           \
> -    helper_float_check_status(env);                                      \
> +    float_check_status(env);                                             \
>  }
>  
>  VSX_SCALAR_CMP(xscmpodp, 1)
> @@ -2415,7 +2428,7 @@ void helper_##name(CPUPPCState *env, uint32_t opcode)                         \
>      }                                                                         \
>                                                                                \
>      putVSR(xT(opcode), &xt, env);                                             \
> -    helper_float_check_status(env);                                           \
> +    float_check_status(env);                                                  \
>  }
>  
>  VSX_MAX_MIN(xsmaxdp, maxnum, 1, float64, VsrD(0))
> @@ -2472,7 +2485,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)                       \
>      if ((opcode >> (31-21)) & 1) {                                        \
>          env->crf[6] = (all_true ? 0x8 : 0) | (all_false ? 0x2 : 0);       \
>      }                                                                     \
> -    helper_float_check_status(env);                                       \
> +    float_check_status(env);                                              \
>   }
>  
>  VSX_CMP(xvcmpeqdp, 2, float64, VsrD(i), eq, 0)
> @@ -2514,7 +2527,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)                \
>      }                                                              \
>                                                                     \
>      putVSR(xT(opcode), &xt, env);                                  \
> -    helper_float_check_status(env);                                \
> +    float_check_status(env);                                       \
>  }
>  
>  VSX_CVT_FP_TO_FP(xscvdpsp, 1, float64, float32, VsrD(0), VsrW(0), 1)
> @@ -2573,7 +2586,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)                          \
>      }                                                                        \
>                                                                               \
>      putVSR(xT(opcode), &xt, env);                                            \
> -    helper_float_check_status(env);                                          \
> +    float_check_status(env);                                                 \
>  }
>  
>  VSX_CVT_FP_TO_INT(xscvdpsxds, 1, float64, int64, VsrD(0), VsrD(0), \
> @@ -2624,7 +2637,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)                     \
>      }                                                                   \
>                                                                          \
>      putVSR(xT(opcode), &xt, env);                                       \
> -    helper_float_check_status(env);                                     \
> +    float_check_status(env);                                            \
>  }
>  
>  VSX_CVT_INT_TO_FP(xscvsxddp, 1, int64, float64, VsrD(0), VsrD(0), 1, 0)
> @@ -2688,7 +2701,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode)                    \
>      }                                                                  \
>                                                                         \
>      putVSR(xT(opcode), &xt, env);                                      \
> -    helper_float_check_status(env);                                    \
> +    float_check_status(env);                                           \
>  }
>  
>  VSX_ROUND(xsrdpi, 1, float64, VsrD(0), float_round_ties_away, 1)
> @@ -2716,6 +2729,6 @@ uint64_t helper_xsrsp(CPUPPCState *env, uint64_t xb)
>      uint64_t xt = helper_frsp(env, xb);
>  
>      helper_compute_fprf(env, xt);
> -    helper_float_check_status(env);
> +    float_check_status(env);
>      return xt;
>  }

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Qemu-devel] [PATCH 12/32] ppc: FP exceptions are always precise
  2016-07-26 22:21 ` [Qemu-devel] [PATCH 12/32] ppc: FP exceptions are always precise Benjamin Herrenschmidt
@ 2016-07-27  2:00   ` David Gibson
  2016-07-27  3:50     ` Benjamin Herrenschmidt
  0 siblings, 1 reply; 69+ messages in thread
From: David Gibson @ 2016-07-27  2:00 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: qemu-ppc, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 2341 bytes --]

On Wed, Jul 27, 2016 at 08:21:06AM +1000, Benjamin Herrenschmidt wrote:
> We don't implement imprecise FP exceptions and using store_current
> which sets SRR1 to the *previous* instruction never makes sense
> for these. So let's be truthful and make them precise, which is
> allowed by the architecture.

I don't see any store_correct in the altered code, so the description
doesn't quite make sense to me.

> 
> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> ---
>  target-ppc/excp_helper.c | 11 ++++++-----
>  target-ppc/translate.c   |  1 -
>  2 files changed, 6 insertions(+), 6 deletions(-)
> 
> diff --git a/target-ppc/excp_helper.c b/target-ppc/excp_helper.c
> index f4b115e..91fdf4b 100644
> --- a/target-ppc/excp_helper.c
> +++ b/target-ppc/excp_helper.c
> @@ -274,12 +274,13 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
>                  env->error_code = 0;
>                  return;
>              }
> +
> +            /* FP exceptions always have NIP pointing to the faulting
> +             * instruction, so always use store_next and claim we are
> +             * precise in the MSR.
> +             */
>              msr |= 0x00100000;
> -            if (msr_fe0 == msr_fe1) {
> -                goto store_next;
> -            }
> -            msr |= 0x00010000;
> -            break;
> +            goto store_next;
>          case POWERPC_EXCP_INVAL:
>              LOG_EXCP("Invalid instruction at " TARGET_FMT_lx "\n", env->nip);
>              msr |= 0x00080000;
> diff --git a/target-ppc/translate.c b/target-ppc/translate.c
> index cb4e313..a05fed7 100644
> --- a/target-ppc/translate.c
> +++ b/target-ppc/translate.c
> @@ -2846,7 +2846,6 @@ static void gen_conditional_store(DisasContext *ctx, TCGv EA,
>                                    int reg, int size)
>  {
>      TCGv t0 = tcg_temp_new();
> -    uint32_t save_exception = ctx->exception;

Also, this appears to be an unrelated change.

>      tcg_gen_st_tl(EA, cpu_env, offsetof(CPUPPCState, reserve_ea));
>      tcg_gen_movi_tl(t0, (size << 5) | reg);

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Qemu-devel] [PATCH 13/32] ppc: Don't update NIP in lswi/lswx/stswi/stswx
  2016-07-26 22:21 ` [Qemu-devel] [PATCH 13/32] ppc: Don't update NIP in lswi/lswx/stswi/stswx Benjamin Herrenschmidt
@ 2016-07-27  2:04   ` David Gibson
  2016-07-27  3:51     ` Benjamin Herrenschmidt
  0 siblings, 1 reply; 69+ messages in thread
From: David Gibson @ 2016-07-27  2:04 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: qemu-ppc, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 8257 bytes --]

On Wed, Jul 27, 2016 at 08:21:07AM +1000, Benjamin Herrenschmidt wrote:
> Instead, pass GETPC() result to the corresponding helpers. This
> requires a bit of fiddling to get the PC (hopefully) right in
> the case where we generate a program check, though the hacks there
> are temporary, a subsequent patch will clean this all up by always
> having the nip already set to the right instruction when taking
> the fault.

Where are cpu_ldub_data() and cpu_ldub_data_ra() defined?  I assume
it's via macro somewhere, since I couldn't find it with a grep.

> 
> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> ---
>  target-ppc/excp_helper.c |  8 ++++++++
>  target-ppc/mem_helper.c  | 26 ++++++++++++++++----------
>  target-ppc/translate.c   | 18 ++++++++----------
>  3 files changed, 32 insertions(+), 20 deletions(-)
> 
> diff --git a/target-ppc/excp_helper.c b/target-ppc/excp_helper.c
> index 91fdf4b..563c7bc 100644
> --- a/target-ppc/excp_helper.c
> +++ b/target-ppc/excp_helper.c
> @@ -285,6 +285,10 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
>              LOG_EXCP("Invalid instruction at " TARGET_FMT_lx "\n", env->nip);
>              msr |= 0x00080000;
>              env->spr[SPR_BOOKE_ESR] = ESR_PIL;
> +            /* Some invalids will have the PC in the right place already */
> +            if (env->error_code & POWERPC_EXCP_INVAL_LSWX) {
> +                goto store_next;
> +            }
>              break;
>          case POWERPC_EXCP_PRIV:
>              msr |= 0x00040000;
> @@ -306,6 +310,10 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
>          srr1 = SPR_HSRR1;
>          new_msr |= (target_ulong)MSR_HVB;
>          new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
> +        /* Some invalids will have the PC in the right place already */
> +        if (env->error_code == (POWERPC_EXCP_INVAL|POWERPC_EXCP_INVAL_LSWX)) {
> +                goto store_next;
> +        }
>          goto store_current;
>      case POWERPC_EXCP_FPU:       /* Floating-point unavailable exception     */
>          goto store_current;
> diff --git a/target-ppc/mem_helper.c b/target-ppc/mem_helper.c
> index e4ed377..de96c91 100644
> --- a/target-ppc/mem_helper.c
> +++ b/target-ppc/mem_helper.c
> @@ -77,23 +77,30 @@ void helper_stmw(CPUPPCState *env, target_ulong addr, uint32_t reg)
>      }
>  }
>  
> -void helper_lsw(CPUPPCState *env, target_ulong addr, uint32_t nb, uint32_t reg)
> +static void do_lsw(CPUPPCState *env, target_ulong addr, uint32_t nb,
> +                   uint32_t reg, uintptr_t raddr)
>  {
>      int sh;
>  
>      for (; nb > 3; nb -= 4) {
> -        env->gpr[reg] = cpu_ldl_data(env, addr);
> +        env->gpr[reg] = cpu_ldl_data_ra(env, addr, raddr);
>          reg = (reg + 1) % 32;
>          addr = addr_add(env, addr, 4);
>      }
>      if (unlikely(nb > 0)) {
>          env->gpr[reg] = 0;
>          for (sh = 24; nb > 0; nb--, sh -= 8) {
> -            env->gpr[reg] |= cpu_ldub_data(env, addr) << sh;
> +            env->gpr[reg] |= cpu_ldub_data_ra(env, addr, raddr) << sh;
>              addr = addr_add(env, addr, 1);
>          }
>      }
>  }
> +
> +void helper_lsw(CPUPPCState *env, target_ulong addr, uint32_t nb, uint32_t reg)
> +{
> +    do_lsw(env, addr, nb, reg, GETPC());
> +}
> +
>  /* PPC32 specification says we must generate an exception if
>   * rA is in the range of registers to be loaded.
>   * In an other hand, IBM says this is valid, but rA won't be loaded.
> @@ -106,12 +113,11 @@ void helper_lswx(CPUPPCState *env, target_ulong addr, uint32_t reg,
>          int num_used_regs = (xer_bc + 3) / 4;
>          if (unlikely((ra != 0 && lsw_reg_in_range(reg, num_used_regs, ra)) ||
>                       lsw_reg_in_range(reg, num_used_regs, rb))) {
> -            env->nip += 4;     /* Compensate the "nip - 4" from gen_lswx() */
> -            helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> -                                       POWERPC_EXCP_INVAL |
> -                                       POWERPC_EXCP_INVAL_LSWX);
> +            raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM,
> +                                   POWERPC_EXCP_INVAL |
> +                                   POWERPC_EXCP_INVAL_LSWX, GETPC());
>          } else {
> -            helper_lsw(env, addr, xer_bc, reg);
> +            do_lsw(env, addr, xer_bc, reg, GETPC());
>          }
>      }
>  }
> @@ -122,13 +128,13 @@ void helper_stsw(CPUPPCState *env, target_ulong addr, uint32_t nb,
>      int sh;
>  
>      for (; nb > 3; nb -= 4) {
> -        cpu_stl_data(env, addr, env->gpr[reg]);
> +        cpu_stl_data_ra(env, addr, env->gpr[reg], GETPC());
>          reg = (reg + 1) % 32;
>          addr = addr_add(env, addr, 4);
>      }
>      if (unlikely(nb > 0)) {
>          for (sh = 24; nb > 0; nb--, sh -= 8) {
> -            cpu_stb_data(env, addr, (env->gpr[reg] >> sh) & 0xFF);
> +            cpu_stb_data_ra(env, addr, (env->gpr[reg] >> sh) & 0xFF, GETPC());
>              addr = addr_add(env, addr, 1);
>          }
>      }
> diff --git a/target-ppc/translate.c b/target-ppc/translate.c
> index a05fed7..9d2e923 100644
> --- a/target-ppc/translate.c
> +++ b/target-ppc/translate.c
> @@ -2701,12 +2701,16 @@ static void gen_lswi(DisasContext *ctx)
>          nb = 32;
>      nr = (nb + 3) / 4;
>      if (unlikely(lsw_reg_in_range(start, nr, ra))) {
> +        /* The handler expects the PC to point to *this* instruction,
> +         * so setting ctx->exception here prevents it from being
> +         * improperly updated again by gen_inval_exception
> +         */
> +        gen_update_nip(ctx, ctx->nip - 4);
> +        ctx->exception = POWERPC_EXCP_HV_EMU;
>          gen_inval_exception(ctx, POWERPC_EXCP_INVAL_LSWX);
>          return;
>      }
>      gen_set_access_type(ctx, ACCESS_INT);
> -    /* NIP cannot be restored if the memory exception comes from an helper */
> -    gen_update_nip(ctx, ctx->nip - 4);
>      t0 = tcg_temp_new();
>      gen_addr_register(ctx, t0);
>      t1 = tcg_const_i32(nb);
> @@ -2723,8 +2727,6 @@ static void gen_lswx(DisasContext *ctx)
>      TCGv t0;
>      TCGv_i32 t1, t2, t3;
>      gen_set_access_type(ctx, ACCESS_INT);
> -    /* NIP cannot be restored if the memory exception comes from an helper */
> -    gen_update_nip(ctx, ctx->nip - 4);
>      t0 = tcg_temp_new();
>      gen_addr_reg_index(ctx, t0);
>      t1 = tcg_const_i32(rD(ctx->opcode));
> @@ -2744,8 +2746,6 @@ static void gen_stswi(DisasContext *ctx)
>      TCGv_i32 t1, t2;
>      int nb = NB(ctx->opcode);
>      gen_set_access_type(ctx, ACCESS_INT);
> -    /* NIP cannot be restored if the memory exception comes from an helper */
> -    gen_update_nip(ctx, ctx->nip - 4);
>      t0 = tcg_temp_new();
>      gen_addr_register(ctx, t0);
>      if (nb == 0)
> @@ -2764,8 +2764,6 @@ static void gen_stswx(DisasContext *ctx)
>      TCGv t0;
>      TCGv_i32 t1, t2;
>      gen_set_access_type(ctx, ACCESS_INT);
> -    /* NIP cannot be restored if the memory exception comes from an helper */
> -    gen_update_nip(ctx, ctx->nip - 4);
>      t0 = tcg_temp_new();
>      gen_addr_reg_index(ctx, t0);
>      t1 = tcg_temp_new_i32();
> @@ -3846,7 +3844,7 @@ static void gen_dcbz(DisasContext *ctx)
>  static void gen_dst(DisasContext *ctx)
>  {
>      if (rA(ctx->opcode) == 0) {
> -        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_LSWX);
> +        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
>      } else {
>          /* interpreted as no-op */
>      }
> @@ -3856,7 +3854,7 @@ static void gen_dst(DisasContext *ctx)
>  static void gen_dstst(DisasContext *ctx)
>  {
>      if (rA(ctx->opcode) == 0) {
> -        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_LSWX);
> +        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
>      } else {
>          /* interpreted as no-op */
>      }

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Qemu-devel] [PATCH 16/32] ppc: Rework NIP updates vs. exception generation
  2016-07-26 22:21 ` [Qemu-devel] [PATCH 16/32] ppc: Rework NIP updates vs. exception generation Benjamin Herrenschmidt
@ 2016-07-27  2:19   ` David Gibson
  2016-07-27  3:54     ` Benjamin Herrenschmidt
  2016-07-27  4:35     ` Benjamin Herrenschmidt
  0 siblings, 2 replies; 69+ messages in thread
From: David Gibson @ 2016-07-27  2:19 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: qemu-ppc, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 26925 bytes --]

On Wed, Jul 27, 2016 at 08:21:10AM +1000, Benjamin Herrenschmidt wrote:
> We make env->nip almost always point to the faulting instruction,
> thus avoiding a mess of "store_current" vs "store_next" in the
> exception handling. The syscall exception knows to move the PC by
> 4 and that's really about it.
> 
> This actually fixes a number of cases where the translator was
> setting env->nip to ctx->nip - 4 (ie. the *current* instruction)
> but the program check exception handler would branch to
> "store_current" which applies another -4 offset.
> 
> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>

I'm having a fair bit of trouble wrapping my head around this.  Still
comments on a couple of small matters.

> ---
>  linux-user/main.c        |  12 ++--
>  target-ppc/excp_helper.c | 148 ++++++++++++++++++-----------------------------
>  target-ppc/translate.c   |  59 +++++++++++--------
>  3 files changed, 96 insertions(+), 123 deletions(-)
> 
> diff --git a/linux-user/main.c b/linux-user/main.c
> index 462e820..1d149dc 100644
> --- a/linux-user/main.c
> +++ b/linux-user/main.c
> @@ -1814,7 +1814,7 @@ void cpu_loop(CPUPPCState *env)
>                            env->error_code);
>                  break;
>              }
> -            info._sifields._sigfault._addr = env->nip - 4;
> +            info._sifields._sigfault._addr = env->nip;
>              queue_signal(env, info.si_signo, &info);
>              break;
>          case POWERPC_EXCP_FPU:      /* Floating-point unavailable exception  */
> @@ -1822,7 +1822,7 @@ void cpu_loop(CPUPPCState *env)
>              info.si_signo = TARGET_SIGILL;
>              info.si_errno = 0;
>              info.si_code = TARGET_ILL_COPROC;
> -            info._sifields._sigfault._addr = env->nip - 4;
> +            info._sifields._sigfault._addr = env->nip;
>              queue_signal(env, info.si_signo, &info);
>              break;
>          case POWERPC_EXCP_SYSCALL:  /* System call exception                 */
> @@ -1834,7 +1834,7 @@ void cpu_loop(CPUPPCState *env)
>              info.si_signo = TARGET_SIGILL;
>              info.si_errno = 0;
>              info.si_code = TARGET_ILL_COPROC;
> -            info._sifields._sigfault._addr = env->nip - 4;
> +            info._sifields._sigfault._addr = env->nip;
>              queue_signal(env, info.si_signo, &info);
>              break;
>          case POWERPC_EXCP_DECR:     /* Decrementer exception                 */
> @@ -1862,7 +1862,7 @@ void cpu_loop(CPUPPCState *env)
>              info.si_signo = TARGET_SIGILL;
>              info.si_errno = 0;
>              info.si_code = TARGET_ILL_COPROC;
> -            info._sifields._sigfault._addr = env->nip - 4;
> +            info._sifields._sigfault._addr = env->nip;
>              queue_signal(env, info.si_signo, &info);
>              break;
>          case POWERPC_EXCP_EFPDI:    /* Embedded floating-point data IRQ      */
> @@ -1926,7 +1926,7 @@ void cpu_loop(CPUPPCState *env)
>              info.si_signo = TARGET_SIGILL;
>              info.si_errno = 0;
>              info.si_code = TARGET_ILL_COPROC;
> -            info._sifields._sigfault._addr = env->nip - 4;
> +            info._sifields._sigfault._addr = env->nip;
>              queue_signal(env, info.si_signo, &info);
>              break;
>          case POWERPC_EXCP_PIT:      /* Programmable interval timer IRQ       */
> @@ -2001,9 +2001,9 @@ void cpu_loop(CPUPPCState *env)
>                               env->gpr[5], env->gpr[6], env->gpr[7],
>                               env->gpr[8], 0, 0);
>              if (ret == -TARGET_ERESTARTSYS) {
> -                env->nip -= 4;
>                  break;
>              }
> +            env->nip += 4;
>              if (ret == (target_ulong)(-TARGET_QEMU_ESIGRETURN)) {
>                  /* Returning from a successful sigreturn syscall.
>                     Avoid corrupting register state.  */
> diff --git a/target-ppc/excp_helper.c b/target-ppc/excp_helper.c
> index 563c7bc..570d188 100644
> --- a/target-ppc/excp_helper.c
> +++ b/target-ppc/excp_helper.c
> @@ -198,7 +198,7 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
>          default:
>              goto excp_invalid;
>          }
> -        goto store_next;
> +        break;
>      case POWERPC_EXCP_MCHECK:    /* Machine check exception                  */
>          if (msr_me == 0) {
>              /* Machine check exception is not enabled.
> @@ -209,7 +209,7 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
>              if (qemu_log_separate()) {
>                  qemu_log("Machine check while not allowed. "
>                          "Entering checkstop state\n");
> -            }
> +             }

Looks like an accidental whitespace change.

>              cs->halted = 1;
>              cs->interrupt_request |= CPU_INTERRUPT_EXITTB;
>          }
> @@ -235,16 +235,16 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
>          default:
>              break;
>          }
> -        goto store_next;
> +        break;
>      case POWERPC_EXCP_DSI:       /* Data storage exception                   */
>          LOG_EXCP("DSI exception: DSISR=" TARGET_FMT_lx" DAR=" TARGET_FMT_lx
>                   "\n", env->spr[SPR_DSISR], env->spr[SPR_DAR]);
> -        goto store_next;
> +        break;
>      case POWERPC_EXCP_ISI:       /* Instruction storage exception            */
>          LOG_EXCP("ISI exception: msr=" TARGET_FMT_lx ", nip=" TARGET_FMT_lx
>                   "\n", msr, env->nip);
>          msr |= env->error_code;
> -        goto store_next;
> +        break;
>      case POWERPC_EXCP_EXTERNAL:  /* External input                           */
>          cs = CPU(cpu);
>  
> @@ -258,13 +258,14 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
>              /* IACK the IRQ on delivery */
>              env->spr[SPR_BOOKE_EPR] = ldl_phys(cs->as, env->mpic_iack);
>          }
> -        goto store_next;
> +        break;
>      case POWERPC_EXCP_ALIGN:     /* Alignment exception                      */
>          /* XXX: this is false */
>          /* Get rS/rD and rA from faulting opcode */
> -        env->spr[SPR_DSISR] |= (cpu_ldl_code(env, (env->nip - 4))
> +        /* Broken for LE mode */
> +        env->spr[SPR_DSISR] |= (cpu_ldl_code(env, env->nip)
>                                  & 0x03FF0000) >> 16;
> -        goto store_next;
> +        break;
>      case POWERPC_EXCP_PROGRAM:   /* Program exception                        */
>          switch (env->error_code & ~0xF) {
>          case POWERPC_EXCP_FP:
> @@ -280,15 +281,11 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
>               * precise in the MSR.
>               */
>              msr |= 0x00100000;
> -            goto store_next;
> +            break;
>          case POWERPC_EXCP_INVAL:
>              LOG_EXCP("Invalid instruction at " TARGET_FMT_lx "\n", env->nip);
>              msr |= 0x00080000;
>              env->spr[SPR_BOOKE_ESR] = ESR_PIL;
> -            /* Some invalids will have the PC in the right place already */
> -            if (env->error_code & POWERPC_EXCP_INVAL_LSWX) {
> -                goto store_next;
> -            }
>              break;
>          case POWERPC_EXCP_PRIV:
>              msr |= 0x00040000;
> @@ -304,23 +301,16 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
>                        env->error_code);
>              break;
>          }
> -        goto store_current;
> -    case POWERPC_EXCP_HV_EMU:
> -        srr0 = SPR_HSRR0;
> -        srr1 = SPR_HSRR1;
> -        new_msr |= (target_ulong)MSR_HVB;
> -        new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
> -        /* Some invalids will have the PC in the right place already */
> -        if (env->error_code == (POWERPC_EXCP_INVAL|POWERPC_EXCP_INVAL_LSWX)) {
> -                goto store_next;
> -        }
> -        goto store_current;
> -    case POWERPC_EXCP_FPU:       /* Floating-point unavailable exception     */
> -        goto store_current;
> +        break;
>      case POWERPC_EXCP_SYSCALL:   /* System call exception                    */
>          dump_syscall(env);
>          lev = env->error_code;
>  
> +        /* We need to correct the NIP which in this case is supposed
> +         * to point to the next instruction
> +         */
> +        env->nip += 4;
> +
>          /* "PAPR mode" built-in hypercall emulation */
>          if ((lev == 1) && cpu_ppc_hypercall) {
>              cpu_ppc_hypercall(cpu);
> @@ -329,15 +319,15 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
>          if (lev == 1) {
>              new_msr |= (target_ulong)MSR_HVB;
>          }
> -        goto store_next;
> +        break;
> +    case POWERPC_EXCP_FPU:       /* Floating-point unavailable exception     */
>      case POWERPC_EXCP_APU:       /* Auxiliary processor unavailable          */
> -        goto store_current;
>      case POWERPC_EXCP_DECR:      /* Decrementer exception                    */
> -        goto store_next;
> +        break;
>      case POWERPC_EXCP_FIT:       /* Fixed-interval timer interrupt           */
>          /* FIT on 4xx */
>          LOG_EXCP("FIT exception\n");
> -        goto store_next;
> +        break;
>      case POWERPC_EXCP_WDT:       /* Watchdog timer interrupt                 */
>          LOG_EXCP("WDT exception\n");
>          switch (excp_model) {
> @@ -348,11 +338,10 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
>          default:
>              break;
>          }
> -        goto store_next;
> +        break;
>      case POWERPC_EXCP_DTLB:      /* Data TLB error                           */
> -        goto store_next;
>      case POWERPC_EXCP_ITLB:      /* Instruction TLB error                    */
> -        goto store_next;
> +        break;
>      case POWERPC_EXCP_DEBUG:     /* Debug interrupt                          */
>          switch (excp_model) {
>          case POWERPC_EXCP_BOOKE:
> @@ -367,33 +356,33 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
>          }
>          /* XXX: TODO */
>          cpu_abort(cs, "Debug exception is not implemented yet !\n");
> -        goto store_next;
> +        break;
>      case POWERPC_EXCP_SPEU:      /* SPE/embedded floating-point unavailable  */
>          env->spr[SPR_BOOKE_ESR] = ESR_SPV;
> -        goto store_current;
> +        break;
>      case POWERPC_EXCP_EFPDI:     /* Embedded floating-point data interrupt   */
>          /* XXX: TODO */
>          cpu_abort(cs, "Embedded floating point data exception "
>                    "is not implemented yet !\n");
>          env->spr[SPR_BOOKE_ESR] = ESR_SPV;
> -        goto store_next;
> +        break;
>      case POWERPC_EXCP_EFPRI:     /* Embedded floating-point round interrupt  */
>          /* XXX: TODO */
>          cpu_abort(cs, "Embedded floating point round exception "
>                    "is not implemented yet !\n");
>          env->spr[SPR_BOOKE_ESR] = ESR_SPV;
> -        goto store_next;
> +        break;
>      case POWERPC_EXCP_EPERFM:    /* Embedded performance monitor interrupt   */
>          /* XXX: TODO */
>          cpu_abort(cs,
>                    "Performance counter exception is not implemented yet !\n");
> -        goto store_next;
> +        break;
>      case POWERPC_EXCP_DOORI:     /* Embedded doorbell interrupt              */
> -        goto store_next;
> +        break;
>      case POWERPC_EXCP_DOORCI:    /* Embedded doorbell critical interrupt     */
>          srr0 = SPR_BOOKE_CSRR0;
>          srr1 = SPR_BOOKE_CSRR1;
> -        goto store_next;
> +        break;
>      case POWERPC_EXCP_RESET:     /* System reset exception                   */
>          if (msr_pow) {
>              /* indicate that we resumed from power save mode */
> @@ -404,65 +393,42 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
>  
>          new_msr |= (target_ulong)MSR_HVB;
>          ail = 0;
> -        goto store_next;
> +        break;
>      case POWERPC_EXCP_DSEG:      /* Data segment exception                   */
> -        goto store_next;
>      case POWERPC_EXCP_ISEG:      /* Instruction segment exception            */
> -        goto store_next;
> -    case POWERPC_EXCP_HDECR:     /* Hypervisor decrementer exception         */
> -        srr0 = SPR_HSRR0;
> -        srr1 = SPR_HSRR1;
> -        new_msr |= (target_ulong)MSR_HVB;
> -        new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
> -        goto store_next;
>      case POWERPC_EXCP_TRACE:     /* Trace exception                          */
> -        goto store_next;
> +        break;
> +    case POWERPC_EXCP_HDECR:     /* Hypervisor decrementer exception         */
>      case POWERPC_EXCP_HDSI:      /* Hypervisor data storage exception        */
> -        srr0 = SPR_HSRR0;
> -        srr1 = SPR_HSRR1;
> -        new_msr |= (target_ulong)MSR_HVB;
> -        new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
> -        goto store_next;
>      case POWERPC_EXCP_HISI:      /* Hypervisor instruction storage exception */
> -        srr0 = SPR_HSRR0;
> -        srr1 = SPR_HSRR1;
> -        new_msr |= (target_ulong)MSR_HVB;
> -        new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
> -        goto store_next;
>      case POWERPC_EXCP_HDSEG:     /* Hypervisor data segment exception        */
> -        srr0 = SPR_HSRR0;
> -        srr1 = SPR_HSRR1;
> -        new_msr |= (target_ulong)MSR_HVB;
> -        new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
> -        goto store_next;
>      case POWERPC_EXCP_HISEG:     /* Hypervisor instruction segment exception */
> +    case POWERPC_EXCP_HV_EMU:
>          srr0 = SPR_HSRR0;
>          srr1 = SPR_HSRR1;
>          new_msr |= (target_ulong)MSR_HVB;
>          new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
> -        goto store_next;
> +        break;
>      case POWERPC_EXCP_VPU:       /* Vector unavailable exception             */
> -        goto store_current;
>      case POWERPC_EXCP_VSXU:       /* VSX unavailable exception               */
> -        goto store_current;
>      case POWERPC_EXCP_FU:         /* Facility unavailable exception          */
> -        goto store_current;
> +        break;
>      case POWERPC_EXCP_PIT:       /* Programmable interval timer interrupt    */
>          LOG_EXCP("PIT exception\n");
> -        goto store_next;
> +        break;
>      case POWERPC_EXCP_IO:        /* IO error exception                       */
>          /* XXX: TODO */
>          cpu_abort(cs, "601 IO error exception is not implemented yet !\n");
> -        goto store_next;
> +        break;
>      case POWERPC_EXCP_RUNM:      /* Run mode exception                       */
>          /* XXX: TODO */
>          cpu_abort(cs, "601 run mode exception is not implemented yet !\n");
> -        goto store_next;
> +        break;
>      case POWERPC_EXCP_EMUL:      /* Emulation trap exception                 */
>          /* XXX: TODO */
>          cpu_abort(cs, "602 emulation trap exception "
>                    "is not implemented yet !\n");
> -        goto store_next;
> +        break;
>      case POWERPC_EXCP_IFTLB:     /* Instruction fetch TLB error              */
>          switch (excp_model) {
>          case POWERPC_EXCP_602:
> @@ -577,71 +543,67 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
>              cpu_abort(cs, "Invalid data store TLB miss exception\n");
>              break;
>          }
> -        goto store_next;
> +        break;
>      case POWERPC_EXCP_FPA:       /* Floating-point assist exception          */
>          /* XXX: TODO */
>          cpu_abort(cs, "Floating point assist exception "
>                    "is not implemented yet !\n");
> -        goto store_next;
> +        break;
>      case POWERPC_EXCP_DABR:      /* Data address breakpoint                  */
>          /* XXX: TODO */
>          cpu_abort(cs, "DABR exception is not implemented yet !\n");
> -        goto store_next;
> +        break;
>      case POWERPC_EXCP_IABR:      /* Instruction address breakpoint           */
>          /* XXX: TODO */
>          cpu_abort(cs, "IABR exception is not implemented yet !\n");
> -        goto store_next;
> +        break;
>      case POWERPC_EXCP_SMI:       /* System management interrupt              */
>          /* XXX: TODO */
>          cpu_abort(cs, "SMI exception is not implemented yet !\n");
> -        goto store_next;
> +        break;
>      case POWERPC_EXCP_THERM:     /* Thermal interrupt                        */
>          /* XXX: TODO */
>          cpu_abort(cs, "Thermal management exception "
>                    "is not implemented yet !\n");
> -        goto store_next;
> +        break;
>      case POWERPC_EXCP_PERFM:     /* Embedded performance monitor interrupt   */
>          /* XXX: TODO */
>          cpu_abort(cs,
>                    "Performance counter exception is not implemented yet !\n");
> -        goto store_next;
> +        break;
>      case POWERPC_EXCP_VPUA:      /* Vector assist exception                  */
>          /* XXX: TODO */
>          cpu_abort(cs, "VPU assist exception is not implemented yet !\n");
> -        goto store_next;
> +        break;
>      case POWERPC_EXCP_SOFTP:     /* Soft patch exception                     */
>          /* XXX: TODO */
>          cpu_abort(cs,
>                    "970 soft-patch exception is not implemented yet !\n");
> -        goto store_next;
> +        break;
>      case POWERPC_EXCP_MAINT:     /* Maintenance exception                    */
>          /* XXX: TODO */
>          cpu_abort(cs,
>                    "970 maintenance exception is not implemented yet !\n");
> -        goto store_next;
> +        break;
>      case POWERPC_EXCP_MEXTBR:    /* Maskable external breakpoint             */
>          /* XXX: TODO */
>          cpu_abort(cs, "Maskable external exception "
>                    "is not implemented yet !\n");
> -        goto store_next;
> +        break;
>      case POWERPC_EXCP_NMEXTBR:   /* Non maskable external breakpoint         */
>          /* XXX: TODO */
>          cpu_abort(cs, "Non maskable external exception "
>                    "is not implemented yet !\n");
> -        goto store_next;
> +        break;
>      default:
>      excp_invalid:
>          cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp);
>          break;
> -    store_current:
> -        /* save current instruction location */
> -        env->spr[srr0] = env->nip - 4;
> -        break;
> -    store_next:
> -        /* save next instruction location */
> -        env->spr[srr0] = env->nip;
> -        break;
>      }
> +
> +    /* Save PC */
> +    env->spr[srr0] = env->nip;
> +
>      /* Save MSR */
>      env->spr[srr1] = msr;
>  
> diff --git a/target-ppc/translate.c b/target-ppc/translate.c
> index c4f8916..84bcb09 100644
> --- a/target-ppc/translate.c
> +++ b/target-ppc/translate.c
> @@ -276,8 +276,12 @@ void gen_update_current_nip(void *opaque)
>  static void gen_exception_err(DisasContext *ctx, uint32_t excp, uint32_t error)
>  {
>      TCGv_i32 t0, t1;
> +
> +    /* These are all synchronous exceptions, we set the PC back to
> +     * the faulting instruction
> +     */
>      if (ctx->exception == POWERPC_EXCP_NONE) {
> -        gen_update_nip(ctx, ctx->nip);
> +        gen_update_nip(ctx, ctx->nip - 4);
>      }
>      t0 = tcg_const_i32(excp);
>      t1 = tcg_const_i32(error);
> @@ -290,8 +294,12 @@ static void gen_exception_err(DisasContext *ctx, uint32_t excp, uint32_t error)
>  static void gen_exception(DisasContext *ctx, uint32_t excp)
>  {
>      TCGv_i32 t0;
> +
> +    /* These are all synchronous exceptions, we set the PC back to
> +     * the faulting instruction
> +     */
>      if (ctx->exception == POWERPC_EXCP_NONE) {
> -        gen_update_nip(ctx, ctx->nip);
> +        gen_update_nip(ctx, ctx->nip - 4);
>      }
>      t0 = tcg_const_i32(excp);
>      gen_helper_raise_exception(cpu_env, t0);
> @@ -299,13 +307,28 @@ static void gen_exception(DisasContext *ctx, uint32_t excp)
>      ctx->exception = (excp);
>  }
>  
> +static void gen_exception_nip(DisasContext *ctx, uint32_t excp,
> +                              target_ulong nip)
> +{
> +    TCGv_i32 t0;
> +
> +    gen_update_nip(ctx, nip);
> +    t0 = tcg_const_i32(excp);
> +    gen_helper_raise_exception(cpu_env, t0);
> +    tcg_temp_free_i32(t0);
> +    ctx->exception = (excp);
> +}
> +
>  static void gen_debug_exception(DisasContext *ctx)
>  {
>      TCGv_i32 t0;
>  
> +    /* These are all synchronous exceptions, we set the PC back to
> +     * the faulting instruction
> +     */
>      if ((ctx->exception != POWERPC_EXCP_BRANCH) &&
>          (ctx->exception != POWERPC_EXCP_SYNC)) {
> -        gen_update_nip(ctx, ctx->nip);
> +        gen_update_nip(ctx, ctx->nip - 4);
>      }
>      t0 = tcg_const_i32(EXCP_DEBUG);
>      gen_helper_raise_exception(cpu_env, t0);
> @@ -1437,7 +1460,7 @@ static void gen_pause(DisasContext *ctx)
>      tcg_temp_free_i32(t0);
>  
>      /* Stop translation, this gives other CPUs a chance to run */
> -    gen_exception_err(ctx, EXCP_HLT, 1);
> +    gen_exception_nip(ctx, EXCP_HLT, ctx->nip);
>  }
>  #endif /* defined(TARGET_PPC64) */
>  
> @@ -2697,12 +2720,6 @@ static void gen_lswi(DisasContext *ctx)
>          nb = 32;
>      nr = (nb + 3) / 4;
>      if (unlikely(lsw_reg_in_range(start, nr, ra))) {
> -        /* The handler expects the PC to point to *this* instruction,
> -         * so setting ctx->exception here prevents it from being
> -         * improperly updated again by gen_inval_exception
> -         */
> -        gen_update_nip(ctx, ctx->nip - 4);
> -        ctx->exception = POWERPC_EXCP_HV_EMU;
>          gen_inval_exception(ctx, POWERPC_EXCP_INVAL_LSWX);
>          return;
>      }
> @@ -2845,10 +2862,7 @@ static void gen_conditional_store(DisasContext *ctx, TCGv EA,
>      tcg_gen_movi_tl(t0, (size << 5) | reg);
>      tcg_gen_st_tl(t0, cpu_env, offsetof(CPUPPCState, reserve_info));
>      tcg_temp_free(t0);
> -    gen_update_nip(ctx, ctx->nip-4);
> -    ctx->exception = POWERPC_EXCP_BRANCH;
> -    gen_exception(ctx, POWERPC_EXCP_STCX);
> -    ctx->exception = save_exception;
> +    gen_exception_err(ctx, POWERPC_EXCP_STCX, 0);
>  }
>  #else
>  static void gen_conditional_store(DisasContext *ctx, TCGv EA,
> @@ -2987,7 +3001,7 @@ static void gen_wait(DisasContext *ctx)
>                     -offsetof(PowerPCCPU, env) + offsetof(CPUState, halted));
>      tcg_temp_free_i32(t0);
>      /* Stop translation, as the CPU is supposed to sleep from now */
> -    gen_exception_err(ctx, EXCP_HLT, 1);
> +    gen_exception_nip(ctx, EXCP_HLT, ctx->nip);
>  }
>  
>  #if defined(TARGET_PPC64)
> @@ -3090,10 +3104,7 @@ static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
>                  (CPU_BRANCH_STEP | CPU_SINGLE_STEP)) &&
>                  (ctx->exception == POWERPC_EXCP_BRANCH ||
>                   ctx->exception == POWERPC_EXCP_TRACE)) {
> -                target_ulong tmp = ctx->nip;
> -                ctx->nip = dest;
> -                gen_exception(ctx, POWERPC_EXCP_TRACE);
> -                ctx->nip = tmp;
> +                gen_exception_nip(ctx, POWERPC_EXCP_TRACE, dest);
>              }
>              if (ctx->singlestep_enabled & GDBSTUB_SINGLE_STEP) {
>                  gen_debug_exception(ctx);
> @@ -3362,7 +3373,7 @@ static void gen_tw(DisasContext *ctx)
>  {
>      TCGv_i32 t0 = tcg_const_i32(TO(ctx->opcode));
>      /* Update the nip since this might generate a trap exception */
> -    gen_update_nip(ctx, ctx->nip);
> +    gen_update_nip(ctx, ctx->nip - 4);

twi etc will generally resume from the next instruction if they trap,
yes?  In which case I'm a bit confused by the nip - 4.  But possibly I
just haven't correctly followed all the nip update logic changed by
this patch.

>      gen_helper_tw(cpu_env, cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)],
>                    t0);
>      tcg_temp_free_i32(t0);
> @@ -3374,7 +3385,7 @@ static void gen_twi(DisasContext *ctx)
>      TCGv t0 = tcg_const_tl(SIMM(ctx->opcode));
>      TCGv_i32 t1 = tcg_const_i32(TO(ctx->opcode));
>      /* Update the nip since this might generate a trap exception */
> -    gen_update_nip(ctx, ctx->nip);
> +    gen_update_nip(ctx, ctx->nip - 4);
>      gen_helper_tw(cpu_env, cpu_gpr[rA(ctx->opcode)], t0, t1);
>      tcg_temp_free(t0);
>      tcg_temp_free_i32(t1);
> @@ -3386,7 +3397,7 @@ static void gen_td(DisasContext *ctx)
>  {
>      TCGv_i32 t0 = tcg_const_i32(TO(ctx->opcode));
>      /* Update the nip since this might generate a trap exception */
> -    gen_update_nip(ctx, ctx->nip);
> +    gen_update_nip(ctx, ctx->nip - 4);
>      gen_helper_td(cpu_env, cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)],
>                    t0);
>      tcg_temp_free_i32(t0);
> @@ -3398,7 +3409,7 @@ static void gen_tdi(DisasContext *ctx)
>      TCGv t0 = tcg_const_tl(SIMM(ctx->opcode));
>      TCGv_i32 t1 = tcg_const_i32(TO(ctx->opcode));
>      /* Update the nip since this might generate a trap exception */
> -    gen_update_nip(ctx, ctx->nip);
> +    gen_update_nip(ctx, ctx->nip - 4);
>      gen_helper_td(cpu_env, cpu_gpr[rA(ctx->opcode)], t0, t1);
>      tcg_temp_free(t0);
>      tcg_temp_free_i32(t1);
> @@ -6757,7 +6768,7 @@ void gen_intermediate_code(CPUPPCState *env, struct TranslationBlock *tb)
>                       ctx.exception != POWERPC_SYSCALL &&
>                       ctx.exception != POWERPC_EXCP_TRAP &&
>                       ctx.exception != POWERPC_EXCP_BRANCH)) {
> -            gen_exception(ctxp, POWERPC_EXCP_TRACE);
> +            gen_exception_nip(ctxp, POWERPC_EXCP_TRACE, ctx.nip);
>          } else if (unlikely(((ctx.nip & (TARGET_PAGE_SIZE - 1)) == 0) ||
>                              (cs->singlestep_enabled) ||
>                              singlestep ||

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Qemu-devel] [PATCH 18/32] ppc: Don't update NIP in DCR access routines
  2016-07-26 22:21 ` [Qemu-devel] [PATCH 18/32] ppc: Don't update NIP in DCR access routines Benjamin Herrenschmidt
@ 2016-07-27  2:21   ` David Gibson
  2016-07-27  3:55     ` Benjamin Herrenschmidt
  0 siblings, 1 reply; 69+ messages in thread
From: David Gibson @ 2016-07-27  2:21 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: qemu-ppc, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 6308 bytes --]

On Wed, Jul 27, 2016 at 08:21:12AM +1000, Benjamin Herrenschmidt wrote:
> This is no longer necessary as the helpers will properly retrieve
> the return address when needed

Well, the helpers are only fixed in this patch IIUC.

> 
> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> ---
>  target-ppc/timebase_helper.c | 23 +++++++++++++----------
>  target-ppc/translate.c       | 12 ------------
>  2 files changed, 13 insertions(+), 22 deletions(-)
> 
> diff --git a/target-ppc/timebase_helper.c b/target-ppc/timebase_helper.c
> index a07faa4..73363e0 100644
> --- a/target-ppc/timebase_helper.c
> +++ b/target-ppc/timebase_helper.c
> @@ -19,6 +19,7 @@
>  #include "qemu/osdep.h"
>  #include "cpu.h"
>  #include "exec/helper-proto.h"
> +#include "exec/exec-all.h"
>  #include "qemu/log.h"
>  
>  /*****************************************************************************/
> @@ -143,15 +144,16 @@ target_ulong helper_load_dcr(CPUPPCState *env, target_ulong dcrn)
>  
>      if (unlikely(env->dcr_env == NULL)) {
>          qemu_log_mask(LOG_GUEST_ERROR, "No DCR environment\n");
> -        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> -                                   POWERPC_EXCP_INVAL |
> -                                   POWERPC_EXCP_INVAL_INVAL);
> +        raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM,
> +                               POWERPC_EXCP_INVAL |
> +                               POWERPC_EXCP_INVAL_INVAL, GETPC());
>      } else if (unlikely(ppc_dcr_read(env->dcr_env,
>                                       (uint32_t)dcrn, &val) != 0)) {
>          qemu_log_mask(LOG_GUEST_ERROR, "DCR read error %d %03x\n",
>                        (uint32_t)dcrn, (uint32_t)dcrn);
> -        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> -                                   POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG);
> +        raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM,
> +                               POWERPC_EXCP_INVAL |
> +                               POWERPC_EXCP_PRIV_REG, GETPC());
>      }
>      return val;
>  }
> @@ -160,14 +162,15 @@ void helper_store_dcr(CPUPPCState *env, target_ulong dcrn, target_ulong val)
>  {
>      if (unlikely(env->dcr_env == NULL)) {
>          qemu_log_mask(LOG_GUEST_ERROR, "No DCR environment\n");
> -        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> -                                   POWERPC_EXCP_INVAL |
> -                                   POWERPC_EXCP_INVAL_INVAL);
> +        raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM,
> +                               POWERPC_EXCP_INVAL |
> +                               POWERPC_EXCP_INVAL_INVAL, GETPC());
>      } else if (unlikely(ppc_dcr_write(env->dcr_env, (uint32_t)dcrn,
>                                        (uint32_t)val) != 0)) {
>          qemu_log_mask(LOG_GUEST_ERROR, "DCR write error %d %03x\n",
>                        (uint32_t)dcrn, (uint32_t)dcrn);
> -        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> -                                   POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG);
> +        raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM,
> +                               POWERPC_EXCP_INVAL |
> +                               POWERPC_EXCP_PRIV_REG, GETPC());
>      }
>  }
> diff --git a/target-ppc/translate.c b/target-ppc/translate.c
> index 84bcb09..f0e0ec6 100644
> --- a/target-ppc/translate.c
> +++ b/target-ppc/translate.c
> @@ -5262,8 +5262,6 @@ static void gen_mfdcr(DisasContext *ctx)
>      TCGv dcrn;
>  
>      CHK_SV;
> -    /* NIP cannot be restored if the memory exception comes from an helper */
> -    gen_update_nip(ctx, ctx->nip - 4);
>      dcrn = tcg_const_tl(SPR(ctx->opcode));
>      gen_helper_load_dcr(cpu_gpr[rD(ctx->opcode)], cpu_env, dcrn);
>      tcg_temp_free(dcrn);
> @@ -5279,8 +5277,6 @@ static void gen_mtdcr(DisasContext *ctx)
>      TCGv dcrn;
>  
>      CHK_SV;
> -    /* NIP cannot be restored if the memory exception comes from an helper */
> -    gen_update_nip(ctx, ctx->nip - 4);
>      dcrn = tcg_const_tl(SPR(ctx->opcode));
>      gen_helper_store_dcr(cpu_env, dcrn, cpu_gpr[rS(ctx->opcode)]);
>      tcg_temp_free(dcrn);
> @@ -5295,8 +5291,6 @@ static void gen_mfdcrx(DisasContext *ctx)
>      GEN_PRIV;
>  #else
>      CHK_SV;
> -    /* NIP cannot be restored if the memory exception comes from an helper */
> -    gen_update_nip(ctx, ctx->nip - 4);
>      gen_helper_load_dcr(cpu_gpr[rD(ctx->opcode)], cpu_env,
>                          cpu_gpr[rA(ctx->opcode)]);
>      /* Note: Rc update flag set leads to undefined state of Rc0 */
> @@ -5311,8 +5305,6 @@ static void gen_mtdcrx(DisasContext *ctx)
>      GEN_PRIV;
>  #else
>      CHK_SV;
> -    /* NIP cannot be restored if the memory exception comes from an helper */
> -    gen_update_nip(ctx, ctx->nip - 4);
>      gen_helper_store_dcr(cpu_env, cpu_gpr[rA(ctx->opcode)],
>                           cpu_gpr[rS(ctx->opcode)]);
>      /* Note: Rc update flag set leads to undefined state of Rc0 */
> @@ -5322,8 +5314,6 @@ static void gen_mtdcrx(DisasContext *ctx)
>  /* mfdcrux (PPC 460) : user-mode access to DCR */
>  static void gen_mfdcrux(DisasContext *ctx)
>  {
> -    /* NIP cannot be restored if the memory exception comes from an helper */
> -    gen_update_nip(ctx, ctx->nip - 4);
>      gen_helper_load_dcr(cpu_gpr[rD(ctx->opcode)], cpu_env,
>                          cpu_gpr[rA(ctx->opcode)]);
>      /* Note: Rc update flag set leads to undefined state of Rc0 */
> @@ -5332,8 +5322,6 @@ static void gen_mfdcrux(DisasContext *ctx)
>  /* mtdcrux (PPC 460) : user-mode access to DCR */
>  static void gen_mtdcrux(DisasContext *ctx)
>  {
> -    /* NIP cannot be restored if the memory exception comes from an helper */
> -    gen_update_nip(ctx, ctx->nip - 4);
>      gen_helper_store_dcr(cpu_env, cpu_gpr[rA(ctx->opcode)],
>                           cpu_gpr[rS(ctx->opcode)]);
>      /* Note: Rc update flag set leads to undefined state of Rc0 */

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Qemu-devel] [PATCH 21/32] ppc: Don't update NIP on conditional trap instructions
  2016-07-26 22:21 ` [Qemu-devel] [PATCH 21/32] ppc: Don't update NIP on conditional trap instructions Benjamin Herrenschmidt
@ 2016-07-27  2:26   ` David Gibson
  2016-07-27  3:56     ` Benjamin Herrenschmidt
  0 siblings, 1 reply; 69+ messages in thread
From: David Gibson @ 2016-07-27  2:26 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: qemu-ppc, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 3817 bytes --]

On Wed, Jul 27, 2016 at 08:21:15AM +1000, Benjamin Herrenschmidt wrote:
> This is no longer necessary as the helpers will properly retrieve
> the return address when needed.

Is this right?  Don't the tw etc. instructions continue on rather than
retrying if an exception occurs?

> 
> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> ---
>  target-ppc/excp_helper.c | 6 ++++--
>  target-ppc/translate.c   | 8 --------
>  2 files changed, 4 insertions(+), 10 deletions(-)
> 
> diff --git a/target-ppc/excp_helper.c b/target-ppc/excp_helper.c
> index 570d188..c31bbad 100644
> --- a/target-ppc/excp_helper.c
> +++ b/target-ppc/excp_helper.c
> @@ -1031,7 +1031,8 @@ void helper_tw(CPUPPCState *env, target_ulong arg1, target_ulong arg2,
>                    ((int32_t)arg1 == (int32_t)arg2 && (flags & 0x04)) ||
>                    ((uint32_t)arg1 < (uint32_t)arg2 && (flags & 0x02)) ||
>                    ((uint32_t)arg1 > (uint32_t)arg2 && (flags & 0x01))))) {
> -        raise_exception_err(env, POWERPC_EXCP_PROGRAM, POWERPC_EXCP_TRAP);
> +        raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM,
> +                               POWERPC_EXCP_TRAP, GETPC());
>      }
>  }
>  
> @@ -1044,7 +1045,8 @@ void helper_td(CPUPPCState *env, target_ulong arg1, target_ulong arg2,
>                    ((int64_t)arg1 == (int64_t)arg2 && (flags & 0x04)) ||
>                    ((uint64_t)arg1 < (uint64_t)arg2 && (flags & 0x02)) ||
>                    ((uint64_t)arg1 > (uint64_t)arg2 && (flags & 0x01))))) {
> -        raise_exception_err(env, POWERPC_EXCP_PROGRAM, POWERPC_EXCP_TRAP);
> +        raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM,
> +                               POWERPC_EXCP_TRAP, GETPC());
>      }
>  }
>  #endif
> diff --git a/target-ppc/translate.c b/target-ppc/translate.c
> index 8f5afba..7163b19 100644
> --- a/target-ppc/translate.c
> +++ b/target-ppc/translate.c
> @@ -3365,8 +3365,6 @@ static void gen_sc(DisasContext *ctx)
>  static void gen_tw(DisasContext *ctx)
>  {
>      TCGv_i32 t0 = tcg_const_i32(TO(ctx->opcode));
> -    /* Update the nip since this might generate a trap exception */
> -    gen_update_nip(ctx, ctx->nip - 4);
>      gen_helper_tw(cpu_env, cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)],
>                    t0);
>      tcg_temp_free_i32(t0);
> @@ -3377,8 +3375,6 @@ static void gen_twi(DisasContext *ctx)
>  {
>      TCGv t0 = tcg_const_tl(SIMM(ctx->opcode));
>      TCGv_i32 t1 = tcg_const_i32(TO(ctx->opcode));
> -    /* Update the nip since this might generate a trap exception */
> -    gen_update_nip(ctx, ctx->nip - 4);
>      gen_helper_tw(cpu_env, cpu_gpr[rA(ctx->opcode)], t0, t1);
>      tcg_temp_free(t0);
>      tcg_temp_free_i32(t1);
> @@ -3389,8 +3385,6 @@ static void gen_twi(DisasContext *ctx)
>  static void gen_td(DisasContext *ctx)
>  {
>      TCGv_i32 t0 = tcg_const_i32(TO(ctx->opcode));
> -    /* Update the nip since this might generate a trap exception */
> -    gen_update_nip(ctx, ctx->nip - 4);
>      gen_helper_td(cpu_env, cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)],
>                    t0);
>      tcg_temp_free_i32(t0);
> @@ -3401,8 +3395,6 @@ static void gen_tdi(DisasContext *ctx)
>  {
>      TCGv t0 = tcg_const_tl(SIMM(ctx->opcode));
>      TCGv_i32 t1 = tcg_const_i32(TO(ctx->opcode));
> -    /* Update the nip since this might generate a trap exception */
> -    gen_update_nip(ctx, ctx->nip - 4);
>      gen_helper_td(cpu_env, cpu_gpr[rA(ctx->opcode)], t0, t1);
>      tcg_temp_free(t0);
>      tcg_temp_free_i32(t1);

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Qemu-devel] [PATCH 24/32] ppc: Make alignment exceptions suck less
  2016-07-26 22:21 ` [Qemu-devel] [PATCH 24/32] ppc: Make alignment exceptions suck less Benjamin Herrenschmidt
@ 2016-07-27  2:30   ` David Gibson
  2016-07-27  3:59     ` Benjamin Herrenschmidt
  0 siblings, 1 reply; 69+ messages in thread
From: David Gibson @ 2016-07-27  2:30 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: qemu-ppc, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 2859 bytes --]

On Wed, Jul 27, 2016 at 08:21:18AM +1000, Benjamin Herrenschmidt wrote:
> The current alignment exception generation tries to load the opcode
> to put in DSISR from a context where a cpu_ldl_code() is really not
> a good idea. It might fault and longjmp out and that's not something
> we want happening here.
> 
> Instead, pass the releavant opcode bits via the error_code.
> 
> There are a couple of cases of alignment interrupts that won't set
> anything, the ones coming from access to direct store segments, but
> that doesn't happen in practice, nobody used direct store segments
> and they are gone from newer chips.

Do I understand correctly that this isn't actually new?  This was
already wrong for direct store segments, you've just noted it?

> 
> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> ---
>  target-ppc/excp_helper.c | 9 +++++----
>  target-ppc/translate.c   | 2 +-
>  2 files changed, 6 insertions(+), 5 deletions(-)
> 
> diff --git a/target-ppc/excp_helper.c b/target-ppc/excp_helper.c
> index c31bbad..9a26578 100644
> --- a/target-ppc/excp_helper.c
> +++ b/target-ppc/excp_helper.c
> @@ -260,11 +260,12 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
>          }
>          break;
>      case POWERPC_EXCP_ALIGN:     /* Alignment exception                      */
> -        /* XXX: this is false */
>          /* Get rS/rD and rA from faulting opcode */
> -        /* Broken for LE mode */
> -        env->spr[SPR_DSISR] |= (cpu_ldl_code(env, env->nip)
> -                                & 0x03FF0000) >> 16;
> +        /* Note: the opcode fields will not be set properly for a direct
> +         * store load/store, but nobody cares as nobody actually uses
> +         * direct store segments.
> +         */
> +        env->spr[SPR_DSISR] |= (env->error_code & 0x03FF0000) >> 16;
>          break;
>      case POWERPC_EXCP_PROGRAM:   /* Program exception                        */
>          switch (env->error_code & ~0xF) {
> diff --git a/target-ppc/translate.c b/target-ppc/translate.c
> index ddfec33..9af3f5f 100644
> --- a/target-ppc/translate.c
> +++ b/target-ppc/translate.c
> @@ -2202,7 +2202,7 @@ static inline void gen_check_align(DisasContext *ctx, TCGv EA, int mask)
>      tcg_gen_andi_tl(t0, EA, mask);
>      tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 0, l1);
>      t1 = tcg_const_i32(POWERPC_EXCP_ALIGN);
> -    t2 = tcg_const_i32(0);
> +    t2 = tcg_const_i32(ctx->opcode & 0x03FF0000);
>      gen_update_nip(ctx, ctx->nip - 4);
>      gen_helper_raise_exception_err(cpu_env, t1, t2);
>      tcg_temp_free_i32(t1);

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Qemu-devel] [PATCH 25/32] ppc: Handle unconditional (always/never) traps at translation time
  2016-07-26 22:21 ` [Qemu-devel] [PATCH 25/32] ppc: Handle unconditional (always/never) traps at translation time Benjamin Herrenschmidt
@ 2016-07-27  2:33   ` David Gibson
  2016-07-27  4:00     ` Benjamin Herrenschmidt
  0 siblings, 1 reply; 69+ messages in thread
From: David Gibson @ 2016-07-27  2:33 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: qemu-ppc, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 3518 bytes --]

On Wed, Jul 27, 2016 at 08:21:19AM +1000, Benjamin Herrenschmidt wrote:
> We don't need to call a helper for trap always and trap never
> which are used by Linux under some circumstances.
> 
> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> ---
>  target-ppc/translate.c | 48 ++++++++++++++++++++++++++++++++++++++++++------
>  1 file changed, 42 insertions(+), 6 deletions(-)
> 
> diff --git a/target-ppc/translate.c b/target-ppc/translate.c
> index 9af3f5f..57a891b 100644
> --- a/target-ppc/translate.c
> +++ b/target-ppc/translate.c
> @@ -3360,10 +3360,29 @@ static void gen_sc(DisasContext *ctx)
>  
>  /***                                Trap                                   ***/
>  
> +/* Check for unconditional traps (always or never) */
> +static bool check_unconditional_trap(DisasContext *ctx)
> +{
> +    /* Trap never */
> +    if (TO(ctx->opcode) == 0) {
> +        return true;
> +    }
> +    /* Trap always */
> +    if (TO(ctx->opcode) == 31) {
> +        gen_exception_err(ctx, POWERPC_EXCP_PROGRAM, POWERPC_EXCP_TRAP);

Should you be returning true here?

Without it, IIUC, the functions below will generate the unconditional
trap, then generate more code to actually test the condition and trap
again.

> +    }
> +    return false;
> +}
> +
>  /* tw */
>  static void gen_tw(DisasContext *ctx)
>  {
> -    TCGv_i32 t0 = tcg_const_i32(TO(ctx->opcode));
> +    TCGv_i32 t0;
> +
> +    if (check_unconditional_trap(ctx)) {
> +        return;
> +    }
> +    t0 = tcg_const_i32(TO(ctx->opcode));
>      gen_helper_tw(cpu_env, cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)],
>                    t0);
>      tcg_temp_free_i32(t0);
> @@ -3372,8 +3391,14 @@ static void gen_tw(DisasContext *ctx)
>  /* twi */
>  static void gen_twi(DisasContext *ctx)
>  {
> -    TCGv t0 = tcg_const_tl(SIMM(ctx->opcode));
> -    TCGv_i32 t1 = tcg_const_i32(TO(ctx->opcode));
> +    TCGv t0;
> +    TCGv_i32 t1;
> +
> +    if (check_unconditional_trap(ctx)) {
> +        return;
> +    }
> +    t0 = tcg_const_tl(SIMM(ctx->opcode));
> +    t1 = tcg_const_i32(TO(ctx->opcode));
>      gen_helper_tw(cpu_env, cpu_gpr[rA(ctx->opcode)], t0, t1);
>      tcg_temp_free(t0);
>      tcg_temp_free_i32(t1);
> @@ -3383,7 +3408,12 @@ static void gen_twi(DisasContext *ctx)
>  /* td */
>  static void gen_td(DisasContext *ctx)
>  {
> -    TCGv_i32 t0 = tcg_const_i32(TO(ctx->opcode));
> +    TCGv_i32 t0;
> +
> +    if (check_unconditional_trap(ctx)) {
> +        return;
> +    }
> +    t0 = tcg_const_i32(TO(ctx->opcode));
>      gen_helper_td(cpu_env, cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)],
>                    t0);
>      tcg_temp_free_i32(t0);
> @@ -3392,8 +3422,14 @@ static void gen_td(DisasContext *ctx)
>  /* tdi */
>  static void gen_tdi(DisasContext *ctx)
>  {
> -    TCGv t0 = tcg_const_tl(SIMM(ctx->opcode));
> -    TCGv_i32 t1 = tcg_const_i32(TO(ctx->opcode));
> +    TCGv t0;
> +    TCGv_i32 t1;
> +
> +    if (check_unconditional_trap(ctx)) {
> +        return;
> +    }
> +    t0 = tcg_const_tl(SIMM(ctx->opcode));
> +    t1 = tcg_const_i32(TO(ctx->opcode));
>      gen_helper_td(cpu_env, cpu_gpr[rA(ctx->opcode)], t0, t1);
>      tcg_temp_free(t0);
>      tcg_temp_free_i32(t1);

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Qemu-devel] [PATCH 26/32] ppc: Speed up dcbz
  2016-07-26 22:21 ` [Qemu-devel] [PATCH 26/32] ppc: Speed up dcbz Benjamin Herrenschmidt
@ 2016-07-27  2:36   ` David Gibson
  2016-07-27  4:02     ` Benjamin Herrenschmidt
  0 siblings, 1 reply; 69+ messages in thread
From: David Gibson @ 2016-07-27  2:36 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: qemu-ppc, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 3953 bytes --]

On Wed, Jul 27, 2016 at 08:21:20AM +1000, Benjamin Herrenschmidt wrote:
> Use tlb_vaddr_to_host to do a fast path single translate for
> the whole cache line. Also make the reservation check match
> the entire range.
> 
> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> ---
>  target-ppc/mem_helper.c | 46 +++++++++++++++++++++++++---------------------
>  target-ppc/translate.c  | 11 ++++-------
>  2 files changed, 29 insertions(+), 28 deletions(-)
> 
> diff --git a/target-ppc/mem_helper.c b/target-ppc/mem_helper.c
> index 92a594c..6548715 100644
> --- a/target-ppc/mem_helper.c
> +++ b/target-ppc/mem_helper.c
> @@ -141,35 +141,39 @@ void helper_stsw(CPUPPCState *env, target_ulong addr, uint32_t nb,
>      }
>  }
>  
> -static void do_dcbz(CPUPPCState *env, target_ulong addr, int dcache_line_size,
> -                    uintptr_t raddr)
> +void helper_dcbz(CPUPPCState *env, target_ulong addr, uint32_t opcode)
>  {
> -    int i;
> -
> -    addr &= ~(dcache_line_size - 1);
> -    for (i = 0; i < dcache_line_size; i += 4) {
> -        cpu_stl_data_ra(env, addr + i, 0, raddr);
> -    }
> -    if (env->reserve_addr == addr) {
> -        env->reserve_addr = (target_ulong)-1ULL;
> -    }
> -}
> -
> -void helper_dcbz(CPUPPCState *env, target_ulong addr, uint32_t is_dcbzl)
> -{
> -    int dcbz_size = env->dcache_line_size;
> +    target_ulong mask, dcbz_size = env->dcache_line_size;
> +    uint32_t i;
> +    void *haddr;
>  
>  #if defined(TARGET_PPC64)
> -    if (!is_dcbzl &&
> -        (env->excp_model == POWERPC_EXCP_970) &&
> -        ((env->spr[SPR_970_HID5] >> 7) & 0x3) == 1) {
> +    /* Check for dcbz vs dcbzl on 970 */
> +    if (env->excp_model == POWERPC_EXCP_970 &&
> +        !(opcode & 0x00200000) && ((env->spr[SPR_970_HID5] >> 7) & 0x3) == 1) {
>          dcbz_size = 32;
>      }
>  #endif
>  
> -    /* XXX add e500mc support */
> +    /* Align address */
> +    mask = ~(dcbz_size - 1);
> +    addr &= mask;
> +
> +    /* Check reservation */
> +    if ((env->reserve_addr & mask) == (addr & mask))  {
> +        env->reserve_addr = (target_ulong)-1ULL;
> +    }
>  
> -    do_dcbz(env, addr, dcbz_size, GETPC());
> +    /* Try fast path translate */
> +    haddr = tlb_vaddr_to_host(env, addr, MMU_DATA_STORE, env->dmmu_idx);

It worries me slightly that this doesn't take any length to verify.  I
guess it's ok in practice, because memory blocks will always be at
least cache line size aligned.

> +    if (haddr) {
> +        memset(haddr, 0, dcbz_size);
> +    } else {
> +        /* Slow path */
> +        for (i = 0; i < dcbz_size; i += 8) {
> +            cpu_stq_data_ra(env, addr + i, 0, GETPC());
> +        }
> +    }
>  }
>  
>  void helper_icbi(CPUPPCState *env, target_ulong addr)
> diff --git a/target-ppc/translate.c b/target-ppc/translate.c
> index 57a891b..5288e02 100644
> --- a/target-ppc/translate.c
> +++ b/target-ppc/translate.c
> @@ -3851,18 +3851,15 @@ static void gen_dcbtls(DisasContext *ctx)
>  static void gen_dcbz(DisasContext *ctx)
>  {
>      TCGv tcgv_addr;
> -    TCGv_i32 tcgv_is_dcbzl;
> -    int is_dcbzl = ctx->opcode & 0x00200000 ? 1 : 0;
> +    TCGv_i32 tcgv_op;
>  
>      gen_set_access_type(ctx, ACCESS_CACHE);
>      tcgv_addr = tcg_temp_new();
> -    tcgv_is_dcbzl = tcg_const_i32(is_dcbzl);
> -
> +    tcgv_op = tcg_const_i32(ctx->opcode & 0x03FF000);
>      gen_addr_reg_index(ctx, tcgv_addr);
> -    gen_helper_dcbz(cpu_env, tcgv_addr, tcgv_is_dcbzl);
> -
> +    gen_helper_dcbz(cpu_env, tcgv_addr, tcgv_op);
>      tcg_temp_free(tcgv_addr);
> -    tcg_temp_free_i32(tcgv_is_dcbzl);
> +    tcg_temp_free_i32(tcgv_op);
>  }
>  
>  /* dst / dstt */

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Qemu-devel] [PATCH 32/32] ppc: Speed up load/store multiple
  2016-07-26 22:21 ` [Qemu-devel] [PATCH 32/32] ppc: Speed up load/store multiple Benjamin Herrenschmidt
@ 2016-07-27  2:47   ` David Gibson
  2016-07-27  4:04     ` Benjamin Herrenschmidt
  0 siblings, 1 reply; 69+ messages in thread
From: David Gibson @ 2016-07-27  2:47 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: qemu-ppc, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 3563 bytes --]

On Wed, Jul 27, 2016 at 08:21:26AM +1000, Benjamin Herrenschmidt wrote:
> Use a single translate when not crossing a page boundary and avoid
> going through layers of helpers. MacOS uses those instructions
> a lot, so does OpenBIOS.
> 
> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> ---
>  target-ppc/mem_helper.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 69 insertions(+)
> 
> diff --git a/target-ppc/mem_helper.c b/target-ppc/mem_helper.c
> index da3f973..511079b 100644
> --- a/target-ppc/mem_helper.c
> +++ b/target-ppc/mem_helper.c
> @@ -53,8 +53,48 @@ static inline target_ulong addr_add(CPUPPCState *env, target_ulong addr,
>      }
>  }
>  
> +/* Reduce the length so that addr + len doesn't cross a page boundary.  */
> +static inline uint64_t adj_len_to_page(uint64_t len, uint64_t addr)
> +{
> +#ifndef CONFIG_USER_ONLY
> +    if ((addr & ~TARGET_PAGE_MASK) + len - 1 >= TARGET_PAGE_SIZE) {
> +        return -addr & ~TARGET_PAGE_MASK;
> +    }
> +#endif
> +    return len;
> +}
> +
>  void helper_lmw(CPUPPCState *env, target_ulong addr, uint32_t reg)
>  {
> +    uint32_t *src;
> +    uint64_t len, adjlen;
> +
> +    if ((addr & 3)) {
> +        goto fallback;
> +    }
> +    len = (32 - reg) << 2;
> +    while (len) {
> +        src = tlb_vaddr_to_host(env, addr, MMU_DATA_LOAD, env->dmmu_idx);
> +        if (!src) {
> +            goto fallback;
> +        }
> +        adjlen = adj_len_to_page(len, addr);
> +        len -= adjlen;
> +#if defined(HOST_WORDS_BIGENDIAN)
> +        memcpy(&env->gpr[reg], src, adjlen);
> +        reg += (adjlen >> 2);
> +        addr = addr_add(env, addr, adjlen);
> +#else
> +        while(adjlen) {
> +            env->gpr[reg++] = bswap32(*(src++));
> +            adjlen -= 4;
> +            addr = addr_add(env, addr, 4);
> +        }
> +#endif

Would it improve this any further to do the memcpy() unconditionally,
then byteswap the GPRs in-place for the LE host case?

> +    }
> +    return;
> +
> + fallback:
>      for (; reg < 32; reg++) {
>          if (needs_byteswap(env)) {
>              env->gpr[reg] = bswap32(cpu_ldl_data_ra(env, addr, GETPC()));
> @@ -67,6 +107,35 @@ void helper_lmw(CPUPPCState *env, target_ulong addr, uint32_t reg)
>  
>  void helper_stmw(CPUPPCState *env, target_ulong addr, uint32_t reg)
>  {
> +    uint32_t *dst;
> +    uint64_t len, adjlen;
> +
> +    if ((addr & 3)) {
> +        goto fallback;
> +    }
> +    len = (32 - reg) << 2;
> +    while (len) {
> +        dst = tlb_vaddr_to_host(env, addr, MMU_DATA_STORE, env->dmmu_idx);
> +        if (!dst) {
> +            goto fallback;
> +        }
> +        adjlen = adj_len_to_page(len, addr);
> +        len -= adjlen;
> +#if defined(HOST_WORDS_BIGENDIAN)
> +        memcpy(dst, &env->gpr[reg], adjlen);
> +        reg += (adjlen >> 2);
> +        addr = addr_add(env, addr, adjlen);
> +#else
> +        while(adjlen) {
> +            *(dst++) = bswap32(env->gpr[reg++]);
> +            adjlen -= 4;
> +            addr = addr_add(env, addr, 4);
> +        }
> +#endif
> +    }
> +    return;
> +
> + fallback:
>      for (; reg < 32; reg++) {
>          if (needs_byteswap(env)) {
>              cpu_stl_data_ra(env, addr, bswap32((uint32_t)env->gpr[reg]),

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Qemu-devel] [PATCH 02/32] ppc: Provide basic raise_exception_* functions
  2016-07-27  1:50   ` David Gibson
@ 2016-07-27  3:46     ` Benjamin Herrenschmidt
  0 siblings, 0 replies; 69+ messages in thread
From: Benjamin Herrenschmidt @ 2016-07-27  3:46 UTC (permalink / raw)
  To: David Gibson; +Cc: qemu-ppc, qemu-devel

On Wed, 2016-07-27 at 11:50 +1000, David Gibson wrote:
> 
> > +void raise_exception_err(CPUPPCState *env, uint32_t exception,
> > +                         uint32_t error_code)
> > +{
> > +    raise_exception_err_ra(env, exception, error_code, 0);
> > +}
> > +
> > +void raise_exception(CPUPPCState *env, uint32_t exception)
> > +{
> > +    raise_exception_err_ra(env, exception, 0, 0);
> > +}
> > +
> > +void raise_exception_ra(CPUPPCState *env, uint32_t exception,
> > +                        uintptr_t raddr)
> > +{
> > +    raise_exception_err_ra(env, exception, 0, 0);
> 
> This should pass raddr as the last argument, shouldn't it?

Yes. The fact that I didn't notice the breakage shows how few things
actually care about those exceptions being precise ;-) I'll respin the
patch. Thanks.

Cheers,
Ben.


^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Qemu-devel] [PATCH 10/32] ppc: Make float_check_status() pass the return address
  2016-07-27  1:57   ` David Gibson
@ 2016-07-27  3:47     ` Benjamin Herrenschmidt
  0 siblings, 0 replies; 69+ messages in thread
From: Benjamin Herrenschmidt @ 2016-07-27  3:47 UTC (permalink / raw)
  To: David Gibson; +Cc: qemu-ppc, qemu-devel

On Wed, 2016-07-27 at 11:57 +1000, David Gibson wrote:
> > -void helper_float_check_status(CPUPPCState *env)
> > +static __attribute__((noinline)) void
> do_float_check_status(CPUPPCState *env,
> > +                                                           
> uintptr_t raddr)
> 
> Why do you need to force this to be non-inline?

I don't. It just that gcc inlines too much shit :-)

In fact I had a patch at some point that made a whole pile of stuff in
translate.c non-inline and that reduced the size of it by about 100K

But yeah, I can drop it for now, it's irrelevant to the point of the
patch.

Cheers,
ben.


^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Qemu-devel] [PATCH 12/32] ppc: FP exceptions are always precise
  2016-07-27  2:00   ` David Gibson
@ 2016-07-27  3:50     ` Benjamin Herrenschmidt
  0 siblings, 0 replies; 69+ messages in thread
From: Benjamin Herrenschmidt @ 2016-07-27  3:50 UTC (permalink / raw)
  To: David Gibson; +Cc: qemu-ppc, qemu-devel

On Wed, 2016-07-27 at 12:00 +1000, David Gibson wrote:
> On Wed, Jul 27, 2016 at 08:21:06AM +1000, Benjamin Herrenschmidt
> wrote:
> > 
> > We don't implement imprecise FP exceptions and using store_current
> > which sets SRR1 to the *previous* instruction never makes sense
> > for these. So let's be truthful and make them precise, which is
> > allowed by the architecture.
> 
> I don't see any store_correct in the altered code, so the description
> doesn't quite make sense to me.

The existing program check default to store_current. We want
store_next.

The labels are misnamed, I fix that in a subsequent patch.
store_current means use the "current" ctx->nip which is usually
pointing to the *next* instruction ;-) (though not always).

It's all very messy and fixing that is  what a susequent patch in the
series does.

> > 
> > 
> > Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> > ---
> >  target-ppc/excp_helper.c | 11 ++++++-----
> >  target-ppc/translate.c   |  1 -
> >  2 files changed, 6 insertions(+), 6 deletions(-)
> > 
> > diff --git a/target-ppc/excp_helper.c b/target-ppc/excp_helper.c
> > index f4b115e..91fdf4b 100644
> > --- a/target-ppc/excp_helper.c
> > +++ b/target-ppc/excp_helper.c
> > @@ -274,12 +274,13 @@ static inline void powerpc_excp(PowerPCCPU
> > *cpu, int excp_model, int excp)
> >                  env->error_code = 0;
> >                  return;
> >              }
> > +
> > +            /* FP exceptions always have NIP pointing to the
> > faulting
> > +             * instruction, so always use store_next and claim we
> > are
> > +             * precise in the MSR.
> > +             */
> >              msr |= 0x00100000;
> > -            if (msr_fe0 == msr_fe1) {
> > -                goto store_next;
> > -            }
> > -            msr |= 0x00010000;
> > -            break;
> > +            goto store_next;
> >          case POWERPC_EXCP_INVAL:
> >              LOG_EXCP("Invalid instruction at " TARGET_FMT_lx "\n",
> > env->nip);
> >              msr |= 0x00080000;
> > diff --git a/target-ppc/translate.c b/target-ppc/translate.c
> > index cb4e313..a05fed7 100644
> > --- a/target-ppc/translate.c
> > +++ b/target-ppc/translate.c
> > @@ -2846,7 +2846,6 @@ static void
> > gen_conditional_store(DisasContext *ctx, TCGv EA,
> >                                    int reg, int size)
> >  {
> >      TCGv t0 = tcg_temp_new();
> > -    uint32_t save_exception = ctx->exception;
> 
> Also, this appears to be an unrelated change.
> 
> > 
> >      tcg_gen_st_tl(EA, cpu_env, offsetof(CPUPPCState, reserve_ea));
> >      tcg_gen_movi_tl(t0, (size << 5) | reg);
> 

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Qemu-devel] [PATCH 13/32] ppc: Don't update NIP in lswi/lswx/stswi/stswx
  2016-07-27  2:04   ` David Gibson
@ 2016-07-27  3:51     ` Benjamin Herrenschmidt
  0 siblings, 0 replies; 69+ messages in thread
From: Benjamin Herrenschmidt @ 2016-07-27  3:51 UTC (permalink / raw)
  To: David Gibson; +Cc: qemu-ppc, qemu-devel

On Wed, 2016-07-27 at 12:04 +1000, David Gibson wrote:
> On Wed, Jul 27, 2016 at 08:21:07AM +1000, Benjamin Herrenschmidt
> wrote:
> > Instead, pass GETPC() result to the corresponding helpers. This
> > requires a bit of fiddling to get the PC (hopefully) right in
> > the case where we generate a program check, though the hacks there
> > are temporary, a subsequent patch will clean this all up by always
> > having the nip already set to the right instruction when taking
> > the fault.
> 
> Where are cpu_ldub_data() and cpu_ldub_data_ra() defined?  I assume
> it's via macro somewhere, since I couldn't find it with a grep.

Yeah all that stuff is defined via macros in

include/exec/cpu_ldst.h and cpu_ldst_template.h

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Qemu-devel] [PATCH 16/32] ppc: Rework NIP updates vs. exception generation
  2016-07-27  2:19   ` David Gibson
@ 2016-07-27  3:54     ` Benjamin Herrenschmidt
  2016-07-27  4:35     ` Benjamin Herrenschmidt
  1 sibling, 0 replies; 69+ messages in thread
From: Benjamin Herrenschmidt @ 2016-07-27  3:54 UTC (permalink / raw)
  To: David Gibson; +Cc: qemu-ppc, qemu-devel

On Wed, 2016-07-27 at 12:19 +1000, David Gibson wrote:
> On Wed, Jul 27, 2016 at 08:21:10AM +1000, Benjamin Herrenschmidt
> wrote:
> > 
> > We make env->nip almost always point to the faulting instruction,
> > thus avoiding a mess of "store_current" vs "store_next" in the
> > exception handling. The syscall exception knows to move the PC by
> > 4 and that's really about it.
> > 
> > This actually fixes a number of cases where the translator was
> > setting env->nip to ctx->nip - 4 (ie. the *current* instruction)
> > but the program check exception handler would branch to
> > "store_current" which applies another -4 offset.
> > 
> > Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashinng.org
> 
> I'm having a fair bit of trouble wrapping my head around this.  Still
> comments on a couple of small matters.

Because the original code was a bloody mess ? :-)

Basically, we make sure that we either don't set env->nip (because the
helper will use the TB scan mechanism based on the return address) or
we set it to the address of the instruction that caused the fault
*always*.

Then, in powerpc_excp, we just put that in SRR1 with one exception, the
syscall, where by spec, it has to be on the next instruction.

To fully understand this, you need to know that when the generator of
an instruction is called, ctx->nip has already been moved to the
next instruction (+4).

Cheers,
Ben.

> > 
> > ---
> >  linux-user/main.c        |  12 ++--
> >  target-ppc/excp_helper.c | 148 ++++++++++++++++++-----------------
> > ------------
> >  target-ppc/translate.c   |  59 +++++++++++--------
> >  3 files changed, 96 insertions(+), 123 deletions(-)
> > 
> > diff --git a/linux-user/main.c b/linux-user/main.c
> > index 462e820..1d149dc 100644
> > --- a/linux-user/main.c
> > +++ b/linux-user/main.c
> > @@ -1814,7 +1814,7 @@ void cpu_loop(CPUPPCState *env)
> >                            env->error_code);
> >                  break;
> >              }
> > -            info._sifields._sigfault._addr = env->nip - 4;
> > +            info._sifields._sigfault._addr = env->nip;
> >              queue_signal(env, info.si_signo, &info);
> >              break;
> >          case POWERPC_EXCP_FPU:      /* Floating-point unavailable
> > exception  */
> > @@ -1822,7 +1822,7 @@ void cpu_loop(CPUPPCState *env)
> >              info.si_signo = TARGET_SIGILL;
> >              info.si_errno = 0;
> >              info.si_code = TARGET_ILL_COPROC;
> > -            info._sifields._sigfault._addr = env->nip - 4;
> > +            info._sifields._sigfault._addr = env->nip;
> >              queue_signal(env, info.si_signo, &info);
> >              break;
> >          case POWERPC_EXCP_SYSCALL:  /* System call
> > exception                 */
> > @@ -1834,7 +1834,7 @@ void cpu_loop(CPUPPCState *env)
> >              info.si_signo = TARGET_SIGILL;
> >              info.si_errno = 0;
> >              info.si_code = TARGET_ILL_COPROC;
> > -            info._sifields._sigfault._addr = env->nip - 4;
> > +            info._sifields._sigfault._addr = env->nip;
> >              queue_signal(env, info.si_signo, &info);
> >              break;
> >          case POWERPC_EXCP_DECR:     /* Decrementer
> > exception                 */
> > @@ -1862,7 +1862,7 @@ void cpu_loop(CPUPPCState *env)
> >              info.si_signo = TARGET_SIGILL;
> >              info.si_errno = 0;
> >              info.si_code = TARGET_ILL_COPROC;
> > -            info._sifields._sigfault._addr = env->nip - 4;
> > +            info._sifields._sigfault._addr = env->nip;
> >              queue_signal(env, info.si_signo, &info);
> >              break;
> >          case POWERPC_EXCP_EFPDI:    /* Embedded floating-point
> > data IRQ      */
> > @@ -1926,7 +1926,7 @@ void cpu_loop(CPUPPCState *env)
> >              info.si_signo = TARGET_SIGILL;
> >              info.si_errno = 0;
> >              info.si_code = TARGET_ILL_COPROC;
> > -            info._sifields._sigfault._addr = env->nip - 4;
> > +            info._sifields._sigfault._addr = env->nip;
> >              queue_signal(env, info.si_signo, &info);
> >              break;
> >          case POWERPC_EXCP_PIT:      /* Programmable interval timer
> > IRQ       */
> > @@ -2001,9 +2001,9 @@ void cpu_loop(CPUPPCState *env)
> >                               env->gpr[5], env->gpr[6], env-
> > >gpr[7],
> >                               env->gpr[8], 0, 0);
> >              if (ret == -TARGET_ERESTARTSYS) {
> > -                env->nip -= 4;
> >                  break;
> >              }
> > +            env->nip += 4;
> >              if (ret == (target_ulong)(-TARGET_QEMU_ESIGRETURN)) {
> >                  /* Returning from a successful sigreturn syscall.
> >                     Avoid corrupting register state.  */
> > diff --git a/target-ppc/excp_helper.c b/target-ppc/excp_helper.c
> > index 563c7bc..570d188 100644
> > --- a/target-ppc/excp_helper.c
> > +++ b/target-ppc/excp_helper.c
> > @@ -198,7 +198,7 @@ static inline void powerpc_excp(PowerPCCPU
> > *cpu, int excp_model, int excp)
> >          default:
> >              goto excp_invalid;
> >          }
> > -        goto store_next;
> > +        break;
> >      case POWERPC_EXCP_MCHECK:    /* Machine check
> > exception                  */
> >          if (msr_me == 0) {
> >              /* Machine check exception is not enabled.
> > @@ -209,7 +209,7 @@ static inline void powerpc_excp(PowerPCCPU
> > *cpu, int excp_model, int excp)
> >              if (qemu_log_separate()) {
> >                  qemu_log("Machine check while not allowed. "
> >                          "Entering checkstop state\n");
> > -            }
> > +             }
> 
> Looks like an accidental whitespace change.
> 
> > 
> >              cs->halted = 1;
> >              cs->interrupt_request |= CPU_INTERRUPT_EXITTB;
> >          }
> > @@ -235,16 +235,16 @@ static inline void powerpc_excp(PowerPCCPU
> > *cpu, int excp_model, int excp)
> >          default:
> >              break;
> >          }
> > -        goto store_next;
> > +        break;
> >      case POWERPC_EXCP_DSI:       /* Data storage
> > exception                   */
> >          LOG_EXCP("DSI exception: DSISR=" TARGET_FMT_lx" DAR="
> > TARGET_FMT_lx
> >                   "\n", env->spr[SPR_DSISR], env->spr[SPR_DAR]);
> > -        goto store_next;
> > +        break;
> >      case POWERPC_EXCP_ISI:       /* Instruction storage
> > exception            */
> >          LOG_EXCP("ISI exception: msr=" TARGET_FMT_lx ", nip="
> > TARGET_FMT_lx
> >                   "\n", msr, env->nip);
> >          msr |= env->error_code;
> > -        goto store_next;
> > +        break;
> >      case POWERPC_EXCP_EXTERNAL:  /* External
> > input                           */
> >          cs = CPU(cpu);
> >  
> > @@ -258,13 +258,14 @@ static inline void powerpc_excp(PowerPCCPU
> > *cpu, int excp_model, int excp)
> >              /* IACK the IRQ on delivery */
> >              env->spr[SPR_BOOKE_EPR] = ldl_phys(cs->as, env-
> > >mpic_iack);
> >          }
> > -        goto store_next;
> > +        break;
> >      case POWERPC_EXCP_ALIGN:     /* Alignment
> > exception                      */
> >          /* XXX: this is false */
> >          /* Get rS/rD and rA from faulting opcode */
> > -        env->spr[SPR_DSISR] |= (cpu_ldl_code(env, (env->nip - 4))
> > +        /* Broken for LE mode */
> > +        env->spr[SPR_DSISR] |= (cpu_ldl_code(env, env->nip)
> >                                  & 0x03FF0000) >> 16;
> > -        goto store_next;
> > +        break;
> >      case POWERPC_EXCP_PROGRAM:   /* Program
> > exception                        */
> >          switch (env->error_code & ~0xF) {
> >          case POWERPC_EXCP_FP:
> > @@ -280,15 +281,11 @@ static inline void powerpc_excp(PowerPCCPU
> > *cpu, int excp_model, int excp)
> >               * precise in the MSR.
> >               */
> >              msr |= 0x00100000;
> > -            goto store_next;
> > +            break;
> >          case POWERPC_EXCP_INVAL:
> >              LOG_EXCP("Invalid instruction at " TARGET_FMT_lx "\n",
> > env->nip);
> >              msr |= 0x00080000;
> >              env->spr[SPR_BOOKE_ESR] = ESR_PIL;
> > -            /* Some invalids will have the PC in the right place
> > already */
> > -            if (env->error_code & POWERPC_EXCP_INVAL_LSWX) {
> > -                goto store_next;
> > -            }
> >              break;
> >          case POWERPC_EXCP_PRIV:
> >              msr |= 0x00040000;
> > @@ -304,23 +301,16 @@ static inline void powerpc_excp(PowerPCCPU
> > *cpu, int excp_model, int excp)
> >                        env->error_code);
> >              break;
> >          }
> > -        goto store_current;
> > -    case POWERPC_EXCP_HV_EMU:
> > -        srr0 = SPR_HSRR0;
> > -        srr1 = SPR_HSRR1;
> > -        new_msr |= (target_ulong)MSR_HVB;
> > -        new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
> > -        /* Some invalids will have the PC in the right place
> > already */
> > -        if (env->error_code ==
> > (POWERPC_EXCP_INVAL|POWERPC_EXCP_INVAL_LSWX)) {
> > -                goto store_next;
> > -        }
> > -        goto store_current;
> > -    case POWERPC_EXCP_FPU:       /* Floating-point unavailable
> > exception     */
> > -        goto store_current;
> > +        break;
> >      case POWERPC_EXCP_SYSCALL:   /* System call
> > exception                    */
> >          dump_syscall(env);
> >          lev = env->error_code;
> >  
> > +        /* We need to correct the NIP which in this case is
> > supposed
> > +         * to point to the next instruction
> > +         */
> > +        env->nip += 4;
> > +
> >          /* "PAPR mode" built-in hypercall emulation */
> >          if ((lev == 1) && cpu_ppc_hypercall) {
> >              cpu_ppc_hypercall(cpu);
> > @@ -329,15 +319,15 @@ static inline void powerpc_excp(PowerPCCPU
> > *cpu, int excp_model, int excp)
> >          if (lev == 1) {
> >              new_msr |= (target_ulong)MSR_HVB;
> >          }
> > -        goto store_next;
> > +        break;
> > +    case POWERPC_EXCP_FPU:       /* Floating-point unavailable
> > exception     */
> >      case POWERPC_EXCP_APU:       /* Auxiliary processor
> > unavailable          */
> > -        goto store_current;
> >      case POWERPC_EXCP_DECR:      /* Decrementer
> > exception                    */
> > -        goto store_next;
> > +        break;
> >      case POWERPC_EXCP_FIT:       /* Fixed-interval timer
> > interrupt           */
> >          /* FIT on 4xx */
> >          LOG_EXCP("FIT exception\n");
> > -        goto store_next;
> > +        break;
> >      case POWERPC_EXCP_WDT:       /* Watchdog timer
> > interrupt                 */
> >          LOG_EXCP("WDT exception\n");
> >          switch (excp_model) {
> > @@ -348,11 +338,10 @@ static inline void powerpc_excp(PowerPCCPU
> > *cpu, int excp_model, int excp)
> >          default:
> >              break;
> >          }
> > -        goto store_next;
> > +        break;
> >      case POWERPC_EXCP_DTLB:      /* Data TLB
> > error                           */
> > -        goto store_next;
> >      case POWERPC_EXCP_ITLB:      /* Instruction TLB
> > error                    */
> > -        goto store_next;
> > +        break;
> >      case POWERPC_EXCP_DEBUG:     /* Debug
> > interrupt                          */
> >          switch (excp_model) {
> >          case POWERPC_EXCP_BOOKE:
> > @@ -367,33 +356,33 @@ static inline void powerpc_excp(PowerPCCPU
> > *cpu, int excp_model, int excp)
> >          }
> >          /* XXX: TODO */
> >          cpu_abort(cs, "Debug exception is not implemented yet
> > !\n");
> > -        goto store_next;
> > +        break;
> >      case POWERPC_EXCP_SPEU:      /* SPE/embedded floating-point
> > unavailable  */
> >          env->spr[SPR_BOOKE_ESR] = ESR_SPV;
> > -        goto store_current;
> > +        break;
> >      case POWERPC_EXCP_EFPDI:     /* Embedded floating-point data
> > interrupt   */
> >          /* XXX: TODO */
> >          cpu_abort(cs, "Embedded floating point data exception "
> >                    "is not implemented yet !\n");
> >          env->spr[SPR_BOOKE_ESR] = ESR_SPV;
> > -        goto store_next;
> > +        break;
> >      case POWERPC_EXCP_EFPRI:     /* Embedded floating-point round
> > interrupt  */
> >          /* XXX: TODO */
> >          cpu_abort(cs, "Embedded floating point round exception "
> >                    "is not implemented yet !\n");
> >          env->spr[SPR_BOOKE_ESR] = ESR_SPV;
> > -        goto store_next;
> > +        break;
> >      case POWERPC_EXCP_EPERFM:    /* Embedded performance monitor
> > interrupt   */
> >          /* XXX: TODO */
> >          cpu_abort(cs,
> >                    "Performance counter exception is not
> > implemented yet !\n");
> > -        goto store_next;
> > +        break;
> >      case POWERPC_EXCP_DOORI:     /* Embedded doorbell
> > interrupt              */
> > -        goto store_next;
> > +        break;
> >      case POWERPC_EXCP_DOORCI:    /* Embedded doorbell critical
> > interrupt     */
> >          srr0 = SPR_BOOKE_CSRR0;
> >          srr1 = SPR_BOOKE_CSRR1;
> > -        goto store_next;
> > +        break;
> >      case POWERPC_EXCP_RESET:     /* System reset
> > exception                   */
> >          if (msr_pow) {
> >              /* indicate that we resumed from power save mode */
> > @@ -404,65 +393,42 @@ static inline void powerpc_excp(PowerPCCPU
> > *cpu, int excp_model, int excp)
> >  
> >          new_msr |= (target_ulong)MSR_HVB;
> >          ail = 0;
> > -        goto store_next;
> > +        break;
> >      case POWERPC_EXCP_DSEG:      /* Data segment
> > exception                   */
> > -        goto store_next;
> >      case POWERPC_EXCP_ISEG:      /* Instruction segment
> > exception            */
> > -        goto store_next;
> > -    case POWERPC_EXCP_HDECR:     /* Hypervisor decrementer
> > exception         */
> > -        srr0 = SPR_HSRR0;
> > -        srr1 = SPR_HSRR1;
> > -        new_msr |= (target_ulong)MSR_HVB;
> > -        new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
> > -        goto store_next;
> >      case POWERPC_EXCP_TRACE:     /* Trace
> > exception                          */
> > -        goto store_next;
> > +        break;
> > +    case POWERPC_EXCP_HDECR:     /* Hypervisor decrementer
> > exception         */
> >      case POWERPC_EXCP_HDSI:      /* Hypervisor data storage
> > exception        */
> > -        srr0 = SPR_HSRR0;
> > -        srr1 = SPR_HSRR1;
> > -        new_msr |= (target_ulong)MSR_HVB;
> > -        new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
> > -        goto store_next;
> >      case POWERPC_EXCP_HISI:      /* Hypervisor instruction storage
> > exception */
> > -        srr0 = SPR_HSRR0;
> > -        srr1 = SPR_HSRR1;
> > -        new_msr |= (target_ulong)MSR_HVB;
> > -        new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
> > -        goto store_next;
> >      case POWERPC_EXCP_HDSEG:     /* Hypervisor data segment
> > exception        */
> > -        srr0 = SPR_HSRR0;
> > -        srr1 = SPR_HSRR1;
> > -        new_msr |= (target_ulong)MSR_HVB;
> > -        new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
> > -        goto store_next;
> >      case POWERPC_EXCP_HISEG:     /* Hypervisor instruction segment
> > exception */
> > +    case POWERPC_EXCP_HV_EMU:
> >          srr0 = SPR_HSRR0;
> >          srr1 = SPR_HSRR1;
> >          new_msr |= (target_ulong)MSR_HVB;
> >          new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
> > -        goto store_next;
> > +        break;
> >      case POWERPC_EXCP_VPU:       /* Vector unavailable
> > exception             */
> > -        goto store_current;
> >      case POWERPC_EXCP_VSXU:       /* VSX unavailable
> > exception               */
> > -        goto store_current;
> >      case POWERPC_EXCP_FU:         /* Facility unavailable
> > exception          */
> > -        goto store_current;
> > +        break;
> >      case POWERPC_EXCP_PIT:       /* Programmable interval timer
> > interrupt    */
> >          LOG_EXCP("PIT exception\n");
> > -        goto store_next;
> > +        break;
> >      case POWERPC_EXCP_IO:        /* IO error
> > exception                       */
> >          /* XXX: TODO */
> >          cpu_abort(cs, "601 IO error exception is not implemented
> > yet !\n");
> > -        goto store_next;
> > +        break;
> >      case POWERPC_EXCP_RUNM:      /* Run mode
> > exception                       */
> >          /* XXX: TODO */
> >          cpu_abort(cs, "601 run mode exception is not implemented
> > yet !\n");
> > -        goto store_next;
> > +        break;
> >      case POWERPC_EXCP_EMUL:      /* Emulation trap
> > exception                 */
> >          /* XXX: TODO */
> >          cpu_abort(cs, "602 emulation trap exception "
> >                    "is not implemented yet !\n");
> > -        goto store_next;
> > +        break;
> >      case POWERPC_EXCP_IFTLB:     /* Instruction fetch TLB
> > error              */
> >          switch (excp_model) {
> >          case POWERPC_EXCP_602:
> > @@ -577,71 +543,67 @@ static inline void powerpc_excp(PowerPCCPU
> > *cpu, int excp_model, int excp)
> >              cpu_abort(cs, "Invalid data store TLB miss
> > exception\n");
> >              break;
> >          }
> > -        goto store_next;
> > +        break;
> >      case POWERPC_EXCP_FPA:       /* Floating-point assist
> > exception          */
> >          /* XXX: TODO */
> >          cpu_abort(cs, "Floating point assist exception "
> >                    "is not implemented yet !\n");
> > -        goto store_next;
> > +        break;
> >      case POWERPC_EXCP_DABR:      /* Data address
> > breakpoint                  */
> >          /* XXX: TODO */
> >          cpu_abort(cs, "DABR exception is not implemented yet
> > !\n");
> > -        goto store_next;
> > +        break;
> >      case POWERPC_EXCP_IABR:      /* Instruction address
> > breakpoint           */
> >          /* XXX: TODO */
> >          cpu_abort(cs, "IABR exception is not implemented yet
> > !\n");
> > -        goto store_next;
> > +        break;
> >      case POWERPC_EXCP_SMI:       /* System management
> > interrupt              */
> >          /* XXX: TODO */
> >          cpu_abort(cs, "SMI exception is not implemented yet !\n");
> > -        goto store_next;
> > +        break;
> >      case POWERPC_EXCP_THERM:     /* Thermal
> > interrupt                        */
> >          /* XXX: TODO */
> >          cpu_abort(cs, "Thermal management exception "
> >                    "is not implemented yet !\n");
> > -        goto store_next;
> > +        break;
> >      case POWERPC_EXCP_PERFM:     /* Embedded performance monitor
> > interrupt   */
> >          /* XXX: TODO */
> >          cpu_abort(cs,
> >                    "Performance counter exception is not
> > implemented yet !\n");
> > -        goto store_next;
> > +        break;
> >      case POWERPC_EXCP_VPUA:      /* Vector assist
> > exception                  */
> >          /* XXX: TODO */
> >          cpu_abort(cs, "VPU assist exception is not implemented yet
> > !\n");
> > -        goto store_next;
> > +        break;
> >      case POWERPC_EXCP_SOFTP:     /* Soft patch
> > exception                     */
> >          /* XXX: TODO */
> >          cpu_abort(cs,
> >                    "970 soft-patch exception is not implemented yet
> > !\n");
> > -        goto store_next;
> > +        break;
> >      case POWERPC_EXCP_MAINT:     /* Maintenance
> > exception                    */
> >          /* XXX: TODO */
> >          cpu_abort(cs,
> >                    "970 maintenance exception is not implemented
> > yet !\n");
> > -        goto store_next;
> > +        break;
> >      case POWERPC_EXCP_MEXTBR:    /* Maskable external
> > breakpoint             */
> >          /* XXX: TODO */
> >          cpu_abort(cs, "Maskable external exception "
> >                    "is not implemented yet !\n");
> > -        goto store_next;
> > +        break;
> >      case POWERPC_EXCP_NMEXTBR:   /* Non maskable external
> > breakpoint         */
> >          /* XXX: TODO */
> >          cpu_abort(cs, "Non maskable external exception "
> >                    "is not implemented yet !\n");
> > -        goto store_next;
> > +        break;
> >      default:
> >      excp_invalid:
> >          cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n",
> > excp);
> >          break;
> > -    store_current:
> > -        /* save current instruction location */
> > -        env->spr[srr0] = env->nip - 4;
> > -        break;
> > -    store_next:
> > -        /* save next instruction location */
> > -        env->spr[srr0] = env->nip;
> > -        break;
> >      }
> > +
> > +    /* Save PC */
> > +    env->spr[srr0] = env->nip;
> > +
> >      /* Save MSR */
> >      env->spr[srr1] = msr;
> >  
> > diff --git a/target-ppc/translate.c b/target-ppc/translate.c
> > index c4f8916..84bcb09 100644
> > --- a/target-ppc/translate.c
> > +++ b/target-ppc/translate.c
> > @@ -276,8 +276,12 @@ void gen_update_current_nip(void *opaque)
> >  static void gen_exception_err(DisasContext *ctx, uint32_t excp,
> > uint32_t error)
> >  {
> >      TCGv_i32 t0, t1;
> > +
> > +    /* These are all synchronous exceptions, we set the PC back to
> > +     * the faulting instruction
> > +     */
> >      if (ctx->exception == POWERPC_EXCP_NONE) {
> > -        gen_update_nip(ctx, ctx->nip);
> > +        gen_update_nip(ctx, ctx->nip - 4);
> >      }
> >      t0 = tcg_const_i32(excp);
> >      t1 = tcg_const_i32(error);
> > @@ -290,8 +294,12 @@ static void gen_exception_err(DisasContext
> > *ctx, uint32_t excp, uint32_t error)
> >  static void gen_exception(DisasContext *ctx, uint32_t excp)
> >  {
> >      TCGv_i32 t0;
> > +
> > +    /* These are all synchronous exceptions, we set the PC back to
> > +     * the faulting instruction
> > +     */
> >      if (ctx->exception == POWERPC_EXCP_NONE) {
> > -        gen_update_nip(ctx, ctx->nip);
> > +        gen_update_nip(ctx, ctx->nip - 4);
> >      }
> >      t0 = tcg_const_i32(excp);
> >      gen_helper_raise_exception(cpu_env, t0);
> > @@ -299,13 +307,28 @@ static void gen_exception(DisasContext *ctx,
> > uint32_t excp)
> >      ctx->exception = (excp);
> >  }
> >  
> > +static void gen_exception_nip(DisasContext *ctx, uint32_t excp,
> > +                              target_ulong nip)
> > +{
> > +    TCGv_i32 t0;
> > +
> > +    gen_update_nip(ctx, nip);
> > +    t0 = tcg_const_i32(excp);
> > +    gen_helper_raise_exception(cpu_env, t0);
> > +    tcg_temp_free_i32(t0);
> > +    ctx->exception = (excp);
> > +}
> > +
> >  static void gen_debug_exception(DisasContext *ctx)
> >  {
> >      TCGv_i32 t0;
> >  
> > +    /* These are all synchronous exceptions, we set the PC back to
> > +     * the faulting instruction
> > +     */
> >      if ((ctx->exception != POWERPC_EXCP_BRANCH) &&
> >          (ctx->exception != POWERPC_EXCP_SYNC)) {
> > -        gen_update_nip(ctx, ctx->nip);
> > +        gen_update_nip(ctx, ctx->nip - 4);
> >      }
> >      t0 = tcg_const_i32(EXCP_DEBUG);
> >      gen_helper_raise_exception(cpu_env, t0);
> > @@ -1437,7 +1460,7 @@ static void gen_pause(DisasContext *ctx)
> >      tcg_temp_free_i32(t0);
> >  
> >      /* Stop translation, this gives other CPUs a chance to run */
> > -    gen_exception_err(ctx, EXCP_HLT, 1);
> > +    gen_exception_nip(ctx, EXCP_HLT, ctx->nip);
> >  }
> >  #endif /* defined(TARGET_PPC64) */
> >  
> > @@ -2697,12 +2720,6 @@ static void gen_lswi(DisasContext *ctx)
> >          nb = 32;
> >      nr = (nb + 3) / 4;
> >      if (unlikely(lsw_reg_in_range(start, nr, ra))) {
> > -        /* The handler expects the PC to point to *this*
> > instruction,
> > -         * so setting ctx->exception here prevents it from being
> > -         * improperly updated again by gen_inval_exception
> > -         */
> > -        gen_update_nip(ctx, ctx->nip - 4);
> > -        ctx->exception = POWERPC_EXCP_HV_EMU;
> >          gen_inval_exception(ctx, POWERPC_EXCP_INVAL_LSWX);
> >          return;
> >      }
> > @@ -2845,10 +2862,7 @@ static void
> > gen_conditional_store(DisasContext *ctx, TCGv EA,
> >      tcg_gen_movi_tl(t0, (size << 5) | reg);
> >      tcg_gen_st_tl(t0, cpu_env, offsetof(CPUPPCState,
> > reserve_info));
> >      tcg_temp_free(t0);
> > -    gen_update_nip(ctx, ctx->nip-4);
> > -    ctx->exception = POWERPC_EXCP_BRANCH;
> > -    gen_exception(ctx, POWERPC_EXCP_STCX);
> > -    ctx->exception = save_exception;
> > +    gen_exception_err(ctx, POWERPC_EXCP_STCX, 0);
> >  }
> >  #else
> >  static void gen_conditional_store(DisasContext *ctx, TCGv EA,
> > @@ -2987,7 +3001,7 @@ static void gen_wait(DisasContext *ctx)
> >                     -offsetof(PowerPCCPU, env) + offsetof(CPUState,
> > halted));
> >      tcg_temp_free_i32(t0);
> >      /* Stop translation, as the CPU is supposed to sleep from now
> > */
> > -    gen_exception_err(ctx, EXCP_HLT, 1);
> > +    gen_exception_nip(ctx, EXCP_HLT, ctx->nip);
> >  }
> >  
> >  #if defined(TARGET_PPC64)
> > @@ -3090,10 +3104,7 @@ static inline void gen_goto_tb(DisasContext
> > *ctx, int n, target_ulong dest)
> >                  (CPU_BRANCH_STEP | CPU_SINGLE_STEP)) &&
> >                  (ctx->exception == POWERPC_EXCP_BRANCH ||
> >                   ctx->exception == POWERPC_EXCP_TRACE)) {
> > -                target_ulong tmp = ctx->nip;
> > -                ctx->nip = dest;
> > -                gen_exception(ctx, POWERPC_EXCP_TRACE);
> > -                ctx->nip = tmp;
> > +                gen_exception_nip(ctx, POWERPC_EXCP_TRACE, dest);
> >              }
> >              if (ctx->singlestep_enabled & GDBSTUB_SINGLE_STEP) {
> >                  gen_debug_exception(ctx);
> > @@ -3362,7 +3373,7 @@ static void gen_tw(DisasContext *ctx)
> >  {
> >      TCGv_i32 t0 = tcg_const_i32(TO(ctx->opcode));
> >      /* Update the nip since this might generate a trap exception
> > */
> > -    gen_update_nip(ctx, ctx->nip);
> > +    gen_update_nip(ctx, ctx->nip - 4);
> 
> twi etc will generally resume from the next instruction if they trap,
> yes?  In which case I'm a bit confused by the nip - 4.  But possibly
> I
> just haven't correctly followed all the nip update logic changed by
> this patch.
> 
> > 
> >      gen_helper_tw(cpu_env, cpu_gpr[rA(ctx->opcode)],
> > cpu_gpr[rB(ctx->opcode)],
> >                    t0);
> >      tcg_temp_free_i32(t0);
> > @@ -3374,7 +3385,7 @@ static void gen_twi(DisasContext *ctx)
> >      TCGv t0 = tcg_const_tl(SIMM(ctx->opcode));
> >      TCGv_i32 t1 = tcg_const_i32(TO(ctx->opcode));
> >      /* Update the nip since this might generate a trap exception
> > */
> > -    gen_update_nip(ctx, ctx->nip);
> > +    gen_update_nip(ctx, ctx->nip - 4);
> >      gen_helper_tw(cpu_env, cpu_gpr[rA(ctx->opcode)], t0, t1);
> >      tcg_temp_free(t0);
> >      tcg_temp_free_i32(t1);
> > @@ -3386,7 +3397,7 @@ static void gen_td(DisasContext *ctx)
> >  {
> >      TCGv_i32 t0 = tcg_const_i32(TO(ctx->opcode));
> >      /* Update the nip since this might generate a trap exception
> > */
> > -    gen_update_nip(ctx, ctx->nip);
> > +    gen_update_nip(ctx, ctx->nip - 4);
> >      gen_helper_td(cpu_env, cpu_gpr[rA(ctx->opcode)],
> > cpu_gpr[rB(ctx->opcode)],
> >                    t0);
> >      tcg_temp_free_i32(t0);
> > @@ -3398,7 +3409,7 @@ static void gen_tdi(DisasContext *ctx)
> >      TCGv t0 = tcg_const_tl(SIMM(ctx->opcode));
> >      TCGv_i32 t1 = tcg_const_i32(TO(ctx->opcode));
> >      /* Update the nip since this might generate a trap exception
> > */
> > -    gen_update_nip(ctx, ctx->nip);
> > +    gen_update_nip(ctx, ctx->nip - 4);
> >      gen_helper_td(cpu_env, cpu_gpr[rA(ctx->opcode)], t0, t1);
> >      tcg_temp_free(t0);
> >      tcg_temp_free_i32(t1);
> > @@ -6757,7 +6768,7 @@ void gen_intermediate_code(CPUPPCState *env,
> > struct TranslationBlock *tb)
> >                       ctx.exception != POWERPC_SYSCALL &&
> >                       ctx.exception != POWERPC_EXCP_TRAP &&
> >                       ctx.exception != POWERPC_EXCP_BRANCH)) {
> > -            gen_exception(ctxp, POWERPC_EXCP_TRACE);
> > +            gen_exception_nip(ctxp, POWERPC_EXCP_TRACE, ctx.nip);
> >          } else if (unlikely(((ctx.nip & (TARGET_PAGE_SIZE - 1)) ==
> > 0) ||
> >                              (cs->singlestep_enabled) ||
> >                              singlestep ||
> 

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Qemu-devel] [PATCH 18/32] ppc: Don't update NIP in DCR access routines
  2016-07-27  2:21   ` David Gibson
@ 2016-07-27  3:55     ` Benjamin Herrenschmidt
  0 siblings, 0 replies; 69+ messages in thread
From: Benjamin Herrenschmidt @ 2016-07-27  3:55 UTC (permalink / raw)
  To: David Gibson; +Cc: qemu-ppc, qemu-devel

On Wed, 2016-07-27 at 12:21 +1000, David Gibson wrote:
> On Wed, Jul 27, 2016 at 08:21:12AM +1000, Benjamin Herrenschmidt
> wrote:
> > 
> > This is no longer necessary as the helpers will properly retrieve
> > the return address when needed
> 
> Well, the helpers are only fixed in this patch IIUC.

Yes, all these "Don't update NIP" patches do both the helper and the
removal of the NIP fixup. I can reword the messages if you have a
better wording.
> > 
> > 
> > Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> > ---
> >  target-ppc/timebase_helper.c | 23 +++++++++++++----------
> >  target-ppc/translate.c       | 12 ------------
> >  2 files changed, 13 insertions(+), 22 deletions(-)
> > 
> > diff --git a/target-ppc/timebase_helper.c b/target-
> > ppc/timebase_helper.c
> > index a07faa4..73363e0 100644
> > --- a/target-ppc/timebase_helper.c
> > +++ b/target-ppc/timebase_helper.c
> > @@ -19,6 +19,7 @@
> >  #include "qemu/osdep.h"
> >  #include "cpu.h"
> >  #include "exec/helper-proto.h"
> > +#include "exec/exec-all.h"
> >  #include "qemu/log.h"
> >  
> >  /*****************************************************************
> > ************/
> > @@ -143,15 +144,16 @@ target_ulong helper_load_dcr(CPUPPCState
> > *env, target_ulong dcrn)
> >  
> >      if (unlikely(env->dcr_env == NULL)) {
> >          qemu_log_mask(LOG_GUEST_ERROR, "No DCR environment\n");
> > -        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > -                                   POWERPC_EXCP_INVAL |
> > -                                   POWERPC_EXCP_INVAL_INVAL);
> > +        raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM,
> > +                               POWERPC_EXCP_INVAL |
> > +                               POWERPC_EXCP_INVAL_INVAL, GETPC());
> >      } else if (unlikely(ppc_dcr_read(env->dcr_env,
> >                                       (uint32_t)dcrn, &val) != 0))
> > {
> >          qemu_log_mask(LOG_GUEST_ERROR, "DCR read error %d %03x\n",
> >                        (uint32_t)dcrn, (uint32_t)dcrn);
> > -        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > -                                   POWERPC_EXCP_INVAL |
> > POWERPC_EXCP_PRIV_REG);
> > +        raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM,
> > +                               POWERPC_EXCP_INVAL |
> > +                               POWERPC_EXCP_PRIV_REG, GETPC());
> >      }
> >      return val;
> >  }
> > @@ -160,14 +162,15 @@ void helper_store_dcr(CPUPPCState *env,
> > target_ulong dcrn, target_ulong val)
> >  {
> >      if (unlikely(env->dcr_env == NULL)) {
> >          qemu_log_mask(LOG_GUEST_ERROR, "No DCR environment\n");
> > -        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > -                                   POWERPC_EXCP_INVAL |
> > -                                   POWERPC_EXCP_INVAL_INVAL);
> > +        raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM,
> > +                               POWERPC_EXCP_INVAL |
> > +                               POWERPC_EXCP_INVAL_INVAL, GETPC());
> >      } else if (unlikely(ppc_dcr_write(env->dcr_env,
> > (uint32_t)dcrn,
> >                                        (uint32_t)val) != 0)) {
> >          qemu_log_mask(LOG_GUEST_ERROR, "DCR write error %d
> > %03x\n",
> >                        (uint32_t)dcrn, (uint32_t)dcrn);
> > -        helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > -                                   POWERPC_EXCP_INVAL |
> > POWERPC_EXCP_PRIV_REG);
> > +        raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM,
> > +                               POWERPC_EXCP_INVAL |
> > +                               POWERPC_EXCP_PRIV_REG, GETPC());
> >      }
> >  }
> > diff --git a/target-ppc/translate.c b/target-ppc/translate.c
> > index 84bcb09..f0e0ec6 100644
> > --- a/target-ppc/translate.c
> > +++ b/target-ppc/translate.c
> > @@ -5262,8 +5262,6 @@ static void gen_mfdcr(DisasContext *ctx)
> >      TCGv dcrn;
> >  
> >      CHK_SV;
> > -    /* NIP cannot be restored if the memory exception comes from
> > an helper */
> > -    gen_update_nip(ctx, ctx->nip - 4);
> >      dcrn = tcg_const_tl(SPR(ctx->opcode));
> >      gen_helper_load_dcr(cpu_gpr[rD(ctx->opcode)], cpu_env, dcrn);
> >      tcg_temp_free(dcrn);
> > @@ -5279,8 +5277,6 @@ static void gen_mtdcr(DisasContext *ctx)
> >      TCGv dcrn;
> >  
> >      CHK_SV;
> > -    /* NIP cannot be restored if the memory exception comes from
> > an helper */
> > -    gen_update_nip(ctx, ctx->nip - 4);
> >      dcrn = tcg_const_tl(SPR(ctx->opcode));
> >      gen_helper_store_dcr(cpu_env, dcrn, cpu_gpr[rS(ctx->opcode)]);
> >      tcg_temp_free(dcrn);
> > @@ -5295,8 +5291,6 @@ static void gen_mfdcrx(DisasContext *ctx)
> >      GEN_PRIV;
> >  #else
> >      CHK_SV;
> > -    /* NIP cannot be restored if the memory exception comes from
> > an helper */
> > -    gen_update_nip(ctx, ctx->nip - 4);
> >      gen_helper_load_dcr(cpu_gpr[rD(ctx->opcode)], cpu_env,
> >                          cpu_gpr[rA(ctx->opcode)]);
> >      /* Note: Rc update flag set leads to undefined state of Rc0 */
> > @@ -5311,8 +5305,6 @@ static void gen_mtdcrx(DisasContext *ctx)
> >      GEN_PRIV;
> >  #else
> >      CHK_SV;
> > -    /* NIP cannot be restored if the memory exception comes from
> > an helper */
> > -    gen_update_nip(ctx, ctx->nip - 4);
> >      gen_helper_store_dcr(cpu_env, cpu_gpr[rA(ctx->opcode)],
> >                           cpu_gpr[rS(ctx->opcode)]);
> >      /* Note: Rc update flag set leads to undefined state of Rc0 */
> > @@ -5322,8 +5314,6 @@ static void gen_mtdcrx(DisasContext *ctx)
> >  /* mfdcrux (PPC 460) : user-mode access to DCR */
> >  static void gen_mfdcrux(DisasContext *ctx)
> >  {
> > -    /* NIP cannot be restored if the memory exception comes from
> > an helper */
> > -    gen_update_nip(ctx, ctx->nip - 4);
> >      gen_helper_load_dcr(cpu_gpr[rD(ctx->opcode)], cpu_env,
> >                          cpu_gpr[rA(ctx->opcode)]);
> >      /* Note: Rc update flag set leads to undefined state of Rc0 */
> > @@ -5332,8 +5322,6 @@ static void gen_mfdcrux(DisasContext *ctx)
> >  /* mtdcrux (PPC 460) : user-mode access to DCR */
> >  static void gen_mtdcrux(DisasContext *ctx)
> >  {
> > -    /* NIP cannot be restored if the memory exception comes from
> > an helper */
> > -    gen_update_nip(ctx, ctx->nip - 4);
> >      gen_helper_store_dcr(cpu_env, cpu_gpr[rA(ctx->opcode)],
> >                           cpu_gpr[rS(ctx->opcode)]);
> >      /* Note: Rc update flag set leads to undefined state of Rc0 */
> 

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Qemu-devel] [PATCH 21/32] ppc: Don't update NIP on conditional trap instructions
  2016-07-27  2:26   ` David Gibson
@ 2016-07-27  3:56     ` Benjamin Herrenschmidt
  0 siblings, 0 replies; 69+ messages in thread
From: Benjamin Herrenschmidt @ 2016-07-27  3:56 UTC (permalink / raw)
  To: David Gibson; +Cc: qemu-ppc, qemu-devel

On Wed, 2016-07-27 at 12:26 +1000, David Gibson wrote:
> On Wed, Jul 27, 2016 at 08:21:15AM +1000, Benjamin Herrenschmidt
> wrote:
> > 
> > This is no longer necessary as the helpers will properly retrieve
> > the return address when needed.
> 
> Is this right?  Don't the tw etc. instructions continue on rather
> than retrying if an exception occurs?

What do you mean ? I'm not sure I understand...

Cheers,
Ben.

> > 
> > 
> > Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> > ---
> >  target-ppc/excp_helper.c | 6 ++++--
> >  target-ppc/translate.c   | 8 --------
> >  2 files changed, 4 insertions(+), 10 deletions(-)
> > 
> > diff --git a/target-ppc/excp_helper.c b/target-ppc/excp_helper.c
> > index 570d188..c31bbad 100644
> > --- a/target-ppc/excp_helper.c
> > +++ b/target-ppc/excp_helper.c
> > @@ -1031,7 +1031,8 @@ void helper_tw(CPUPPCState *env, target_ulong
> > arg1, target_ulong arg2,
> >                    ((int32_t)arg1 == (int32_t)arg2 && (flags &
> > 0x04)) ||
> >                    ((uint32_t)arg1 < (uint32_t)arg2 && (flags &
> > 0x02)) ||
> >                    ((uint32_t)arg1 > (uint32_t)arg2 && (flags &
> > 0x01))))) {
> > -        raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > POWERPC_EXCP_TRAP);
> > +        raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM,
> > +                               POWERPC_EXCP_TRAP, GETPC());
> >      }
> >  }
> >  
> > @@ -1044,7 +1045,8 @@ void helper_td(CPUPPCState *env, target_ulong
> > arg1, target_ulong arg2,
> >                    ((int64_t)arg1 == (int64_t)arg2 && (flags &
> > 0x04)) ||
> >                    ((uint64_t)arg1 < (uint64_t)arg2 && (flags &
> > 0x02)) ||
> >                    ((uint64_t)arg1 > (uint64_t)arg2 && (flags &
> > 0x01))))) {
> > -        raise_exception_err(env, POWERPC_EXCP_PROGRAM,
> > POWERPC_EXCP_TRAP);
> > +        raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM,
> > +                               POWERPC_EXCP_TRAP, GETPC());
> >      }
> >  }
> >  #endif
> > diff --git a/target-ppc/translate.c b/target-ppc/translate.c
> > index 8f5afba..7163b19 100644
> > --- a/target-ppc/translate.c
> > +++ b/target-ppc/translate.c
> > @@ -3365,8 +3365,6 @@ static void gen_sc(DisasContext *ctx)
> >  static void gen_tw(DisasContext *ctx)
> >  {
> >      TCGv_i32 t0 = tcg_const_i32(TO(ctx->opcode));
> > -    /* Update the nip since this might generate a trap exception
> > */
> > -    gen_update_nip(ctx, ctx->nip - 4);
> >      gen_helper_tw(cpu_env, cpu_gpr[rA(ctx->opcode)],
> > cpu_gpr[rB(ctx->opcode)],
> >                    t0);
> >      tcg_temp_free_i32(t0);
> > @@ -3377,8 +3375,6 @@ static void gen_twi(DisasContext *ctx)
> >  {
> >      TCGv t0 = tcg_const_tl(SIMM(ctx->opcode));
> >      TCGv_i32 t1 = tcg_const_i32(TO(ctx->opcode));
> > -    /* Update the nip since this might generate a trap exception
> > */
> > -    gen_update_nip(ctx, ctx->nip - 4);
> >      gen_helper_tw(cpu_env, cpu_gpr[rA(ctx->opcode)], t0, t1);
> >      tcg_temp_free(t0);
> >      tcg_temp_free_i32(t1);
> > @@ -3389,8 +3385,6 @@ static void gen_twi(DisasContext *ctx)
> >  static void gen_td(DisasContext *ctx)
> >  {
> >      TCGv_i32 t0 = tcg_const_i32(TO(ctx->opcode));
> > -    /* Update the nip since this might generate a trap exception
> > */
> > -    gen_update_nip(ctx, ctx->nip - 4);
> >      gen_helper_td(cpu_env, cpu_gpr[rA(ctx->opcode)],
> > cpu_gpr[rB(ctx->opcode)],
> >                    t0);
> >      tcg_temp_free_i32(t0);
> > @@ -3401,8 +3395,6 @@ static void gen_tdi(DisasContext *ctx)
> >  {
> >      TCGv t0 = tcg_const_tl(SIMM(ctx->opcode));
> >      TCGv_i32 t1 = tcg_const_i32(TO(ctx->opcode));
> > -    /* Update the nip since this might generate a trap exception
> > */
> > -    gen_update_nip(ctx, ctx->nip - 4);
> >      gen_helper_td(cpu_env, cpu_gpr[rA(ctx->opcode)], t0, t1);
> >      tcg_temp_free(t0);
> >      tcg_temp_free_i32(t1);
> 

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Qemu-devel] [PATCH 24/32] ppc: Make alignment exceptions suck less
  2016-07-27  2:30   ` David Gibson
@ 2016-07-27  3:59     ` Benjamin Herrenschmidt
  0 siblings, 0 replies; 69+ messages in thread
From: Benjamin Herrenschmidt @ 2016-07-27  3:59 UTC (permalink / raw)
  To: David Gibson; +Cc: qemu-ppc, qemu-devel

On Wed, 2016-07-27 at 12:30 +1000, David Gibson wrote:
> On Wed, Jul 27, 2016 at 08:21:18AM +1000, Benjamin Herrenschmidt
> wrote:
> > 
> > The current alignment exception generation tries to load the opcode
> > to put in DSISR from a context where a cpu_ldl_code() is really not
> > a good idea. It might fault and longjmp out and that's not
> > something
> > we want happening here.
> > 
> > Instead, pass the releavant opcode bits via the error_code.
> > 
> > There are a couple of cases of alignment interrupts that won't set
> > anything, the ones coming from access to direct store segments, but
> > that doesn't happen in practice, nobody used direct store segments
> > and they are gone from newer chips.
> 
> Do I understand correctly that this isn't actually new?  This was
> already wrong for direct store segments, you've just noted it?

No, it was *supposeldy* working by loading the opcode to set DSISR
but I'm breaking it. It's not safe to try to load the opcode from
the exception helper, it can cause us to longjmp into lalaland.

If we really care, we could fix it differently by making the
translation code load the opcode to pass it up to us like the generated
code does. The translation code is run in a context that can safely
exit via longjmp, so in that case, if the opcode load fails, it will
just generate an ISI and try again.

However I can't find anything that actually uses direct store segments
so can't be bothered.

Cheers,
Ben.

> > 
> > 
> > Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> > ---
> >  target-ppc/excp_helper.c | 9 +++++----
> >  target-ppc/translate.c   | 2 +-
> >  2 files changed, 6 insertions(+), 5 deletions(-)
> > 
> > diff --git a/target-ppc/excp_helper.c b/target-ppc/excp_helper.c
> > index c31bbad..9a26578 100644
> > --- a/target-ppc/excp_helper.c
> > +++ b/target-ppc/excp_helper.c
> > @@ -260,11 +260,12 @@ static inline void powerpc_excp(PowerPCCPU
> > *cpu, int excp_model, int excp)
> >          }
> >          break;
> >      case POWERPC_EXCP_ALIGN:     /* Alignment
> > exception                      */
> > -        /* XXX: this is false */
> >          /* Get rS/rD and rA from faulting opcode */
> > -        /* Broken for LE mode */
> > -        env->spr[SPR_DSISR] |= (cpu_ldl_code(env, env->nip)
> > -                                & 0x03FF0000) >> 16;
> > +        /* Note: the opcode fields will not be set properly for a
> > direct
> > +         * store load/store, but nobody cares as nobody actually
> > uses
> > +         * direct store segments.
> > +         */
> > +        env->spr[SPR_DSISR] |= (env->error_code & 0x03FF0000) >>
> > 16;
> >          break;
> >      case POWERPC_EXCP_PROGRAM:   /* Program
> > exception                        */
> >          switch (env->error_code & ~0xF) {
> > diff --git a/target-ppc/translate.c b/target-ppc/translate.c
> > index ddfec33..9af3f5f 100644
> > --- a/target-ppc/translate.c
> > +++ b/target-ppc/translate.c
> > @@ -2202,7 +2202,7 @@ static inline void
> > gen_check_align(DisasContext *ctx, TCGv EA, int mask)
> >      tcg_gen_andi_tl(t0, EA, mask);
> >      tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 0, l1);
> >      t1 = tcg_const_i32(POWERPC_EXCP_ALIGN);
> > -    t2 = tcg_const_i32(0);
> > +    t2 = tcg_const_i32(ctx->opcode & 0x03FF0000);
> >      gen_update_nip(ctx, ctx->nip - 4);
> >      gen_helper_raise_exception_err(cpu_env, t1, t2);
> >      tcg_temp_free_i32(t1);
> 

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Qemu-devel] [PATCH 25/32] ppc: Handle unconditional (always/never) traps at translation time
  2016-07-27  2:33   ` David Gibson
@ 2016-07-27  4:00     ` Benjamin Herrenschmidt
  0 siblings, 0 replies; 69+ messages in thread
From: Benjamin Herrenschmidt @ 2016-07-27  4:00 UTC (permalink / raw)
  To: David Gibson; +Cc: qemu-ppc, qemu-devel

On Wed, 2016-07-27 at 12:33 +1000, David Gibson wrote:
> 
> Should you be returning true here?
> 
> Without it, IIUC, the functions below will generate the unconditional
> trap, then generate more code to actually test the condition and trap
> again.

You are right, we generate dead code, will fix.

Cheers,
Ben.

> > 
> > +    }
> > +    return false;
> > +}
> > +
> >  /* tw */
> >  static void gen_tw(DisasContext *ctx)
> >  {
> > -    TCGv_i32 t0 = tcg_const_i32(TO(ctx->opcode));
> > +    TCGv_i32 t0;
> > +
> > +    if (check_unconditional_trap(ctx)) {
> > +        return;
> > +    }
> > +    t0 = tcg_const_i32(TO(ctx->opcode));
> >      gen_helper_tw(cpu_env, cpu_gpr[rA(ctx->opcode)],
> > cpu_gpr[rB(ctx->opcode)],
> >                    t0);
> >      tcg_temp_free_i32(t0);
> > @@ -3372,8 +3391,14 @@ static void gen_tw(DisasContext *ctx)
> >  /* twi */
> >  static void gen_twi(DisasContext *ctx)
> >  {
> > -    TCGv t0 = tcg_const_tl(SIMM(ctx->opcode));
> > -    TCGv_i32 t1 = tcg_const_i32(TO(ctx->opcode));
> > +    TCGv t0;
> > +    TCGv_i32 t1;
> > +
> > +    if (check_unconditional_trap(ctx)) {
> > +        return;
> > +    }
> > +    t0 = tcg_const_tl(SIMM(ctx->opcode));
> > +    t1 = tcg_const_i32(TO(ctx->opcode));
> >      gen_helper_tw(cpu_env, cpu_gpr[rA(ctx->opcode)], t0, t1);
> >      tcg_temp_free(t0);
> >      tcg_temp_free_i32(t1);
> > @@ -3383,7 +3408,12 @@ static void gen_twi(DisasContext *ctx)
> >  /* td */
> >  static void gen_td(DisasContext *ctx)
> >  {
> > -    TCGv_i32 t0 = tcg_const_i32(TO(ctx->opcode));
> > +    TCGv_i32 t0;
> > +
> > +    if (check_unconditional_trap(ctx)) {
> > +        return;
> > +    }
> > +    t0 = tcg_const_i32(TO(ctx->opcode));
> >      gen_helper_td(cpu_env, cpu_gpr[rA(ctx->opcode)],
> > cpu_gpr[rB(ctx->opcode)],
> >                    t0);
> >      tcg_temp_free_i32(t0);
> > @@ -3392,8 +3422,14 @@ static void gen_td(DisasContext *ctx)
> >  /* tdi */
> >  static void gen_tdi(DisasContext *ctx)
> >  {
> > -    TCGv t0 = tcg_const_tl(SIMM(ctx->opcode));
> > -    TCGv_i32 t1 = tcg_const_i32(TO(ctx->opcode));
> > +    TCGv t0;
> > +    TCGv_i32 t1;
> > +
> > +    if (check_unconditional_trap(ctx)) {
> > +        return;
> > +    }
> > +    t0 = tcg_const_tl(SIMM(ctx->opcode));
> > +    t1 = tcg_const_i32(TO(ctx->opcode));
> >      gen_helper_td(cpu_env, cpu_gpr[rA(ctx->opcode)], t0, t1);
> >      tcg_temp_free(t0);
> >      tcg_temp_free_i32(t1);
> 

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Qemu-devel] [PATCH 26/32] ppc: Speed up dcbz
  2016-07-27  2:36   ` David Gibson
@ 2016-07-27  4:02     ` Benjamin Herrenschmidt
  0 siblings, 0 replies; 69+ messages in thread
From: Benjamin Herrenschmidt @ 2016-07-27  4:02 UTC (permalink / raw)
  To: David Gibson; +Cc: qemu-ppc, qemu-devel

On Wed, 2016-07-27 at 12:36 +1000, David Gibson wrote:
> > -    do_dcbz(env, addr, dcbz_size, GETPC());
> > +    /* Try fast path translate */
> > +    haddr = tlb_vaddr_to_host(env, addr, MMU_DATA_STORE, env->dmmu_idx);
> 
> It worries me slightly that this doesn't take any length to verify.  I
> guess it's ok in practice, because memory blocks will always be at
> least cache line size aligned.

It's safe ;-)

The translate returns a qemu page size address which is always 4K.

We don't need to verify  because we just aligned the address to the
cache block size which is always smaller than 4k. So we can't
possibly be crossing a page boundary.

(grep for tlb_vaddr_to_host in target-s390 for other examples of use
of tlb_vaddr_to_host).

Cheers,
Ben.

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Qemu-devel] [PATCH 32/32] ppc: Speed up load/store multiple
  2016-07-27  2:47   ` David Gibson
@ 2016-07-27  4:04     ` Benjamin Herrenschmidt
  0 siblings, 0 replies; 69+ messages in thread
From: Benjamin Herrenschmidt @ 2016-07-27  4:04 UTC (permalink / raw)
  To: David Gibson; +Cc: qemu-ppc, qemu-devel

On Wed, 2016-07-27 at 12:47 +1000, David Gibson wrote:
> > +#if defined(HOST_WORDS_BIGENDIAN)
> > +        memcpy(&env->gpr[reg], src, adjlen);
> > +        reg += (adjlen >> 2);
> > +        addr = addr_add(env, addr, adjlen);
> > +#else
> > +        while(adjlen) {
> > +            env->gpr[reg++] = bswap32(*(src++));
> > +            adjlen -= 4;
> > +            addr = addr_add(env, addr, 4);
> > +        }
> > +#endif
> 
> Would it improve this any further to do the memcpy() unconditionally,
> then byteswap the GPRs in-place for the LE host case?

I thought about it and decided probably not. It's not a big enough
memcpy to matter I suspect. And it keeps the code simpler.

Cheers,
Ben.


^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Qemu-devel] [PATCH 16/32] ppc: Rework NIP updates vs. exception generation
  2016-07-27  2:19   ` David Gibson
  2016-07-27  3:54     ` Benjamin Herrenschmidt
@ 2016-07-27  4:35     ` Benjamin Herrenschmidt
  1 sibling, 0 replies; 69+ messages in thread
From: Benjamin Herrenschmidt @ 2016-07-27  4:35 UTC (permalink / raw)
  To: David Gibson; +Cc: qemu-ppc, qemu-devel

On Wed, 2016-07-27 at 12:19 +1000, David Gibson wrote:
> twi etc will generally resume from the next instruction if they trap,
> yes?  In which case I'm a bit confused by the nip - 4.  But possibly I
> just haven't correctly followed all the nip update logic changed by
> this patch.

>From the ISA (Program Check interrupt)

Trap
A Trap type Program interrupt is generated when
any of the
conditions specified in a Trap instruction
is met.

The following registers are set:
SRR0
For all Program interrupts except a Float-
ing-Point Enabled Exception type Program
interrupt, set to the effective address of the
instruction that caused the corresponding
exception.

Cheers,
Ben.

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Qemu-devel] [PATCH 03/32] ppc: Move classic fp ops out of translate.c
  2016-07-26 22:20 ` [Qemu-devel] [PATCH 03/32] ppc: Move classic fp ops out of translate.c Benjamin Herrenschmidt
@ 2016-07-28 16:02   ` Richard Henderson
  2016-07-28 21:56     ` Benjamin Herrenschmidt
  0 siblings, 1 reply; 69+ messages in thread
From: Richard Henderson @ 2016-07-28 16:02 UTC (permalink / raw)
  To: Benjamin Herrenschmidt, qemu-ppc; +Cc: qemu-devel, david

On 07/27/2016 03:50 AM, Benjamin Herrenschmidt wrote:
> Makes things a bit more manageable
>
> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> ---
>  target-ppc/translate.c         | 1205 +---------------------------------------
>  target-ppc/translate/fp-impl.c | 1098 ++++++++++++++++++++++++++++++++++++
>  target-ppc/translate/fp-ops.c  |  111 ++++
>  3 files changed, 1213 insertions(+), 1201 deletions(-)
>  create mode 100644 target-ppc/translate/fp-impl.c
>  create mode 100644 target-ppc/translate/fp-ops.c

For the benefit of Peter's ./scripts/clean-includes and friends, please name 
these with *.inc.c, like in tcg/*/.


r~

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Qemu-devel] [PATCH 09/32] ppc: Make float_invalid_op_excp() pass the return address
  2016-07-26 22:21 ` [Qemu-devel] [PATCH 09/32] ppc: Make float_invalid_op_excp() pass the return address Benjamin Herrenschmidt
@ 2016-07-28 16:06   ` Richard Henderson
  2016-07-28 21:57     ` Benjamin Herrenschmidt
  0 siblings, 1 reply; 69+ messages in thread
From: Richard Henderson @ 2016-07-28 16:06 UTC (permalink / raw)
  To: Benjamin Herrenschmidt, qemu-ppc; +Cc: qemu-devel, david

On 07/27/2016 03:51 AM, Benjamin Herrenschmidt wrote:
> +            /* GETPC() works here because this is inline */
> +            raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM,
> +                                   POWERPC_EXCP_FP | op, GETPC());

It doesn't, with --enable-debug, aka -O0.


r~

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Qemu-devel] [PATCH 03/32] ppc: Move classic fp ops out of translate.c
  2016-07-28 16:02   ` Richard Henderson
@ 2016-07-28 21:56     ` Benjamin Herrenschmidt
  0 siblings, 0 replies; 69+ messages in thread
From: Benjamin Herrenschmidt @ 2016-07-28 21:56 UTC (permalink / raw)
  To: Richard Henderson, qemu-ppc; +Cc: qemu-devel, david

On Thu, 2016-07-28 at 21:32 +0530, Richard Henderson wrote:
> For the benefit of Peter's ./scripts/clean-includes and friends,
> please name these with *.inc.c, like in tcg/*/.

Ok. David merged the series in for-2.8 but I will send a subsequent
patch to fix them up.

Cheers,
Ben.

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Qemu-devel] [PATCH 09/32] ppc: Make float_invalid_op_excp() pass the return address
  2016-07-28 16:06   ` Richard Henderson
@ 2016-07-28 21:57     ` Benjamin Herrenschmidt
  2016-07-28 22:10       ` Benjamin Herrenschmidt
  0 siblings, 1 reply; 69+ messages in thread
From: Benjamin Herrenschmidt @ 2016-07-28 21:57 UTC (permalink / raw)
  To: Richard Henderson, qemu-ppc; +Cc: qemu-devel, david

On Thu, 2016-07-28 at 21:36 +0530, Richard Henderson wrote:
> On 07/27/2016 03:51 AM, Benjamin Herrenschmidt wrote:
> > 
> > +            /* GETPC() works here because this is inline */
> > +            raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM,
> > +                                   POWERPC_EXCP_FP | op, GETPC());
> 
> It doesn't, with --enable-debug, aka -O0.

Will that prevent even an explicit inline statement ? Would
__attribute__((always_inline)) help there ?

Cheers,
Ben.


^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Qemu-devel] [PATCH 09/32] ppc: Make float_invalid_op_excp() pass the return address
  2016-07-28 21:57     ` Benjamin Herrenschmidt
@ 2016-07-28 22:10       ` Benjamin Herrenschmidt
  0 siblings, 0 replies; 69+ messages in thread
From: Benjamin Herrenschmidt @ 2016-07-28 22:10 UTC (permalink / raw)
  To: Richard Henderson, qemu-ppc; +Cc: qemu-devel, david

On Fri, 2016-07-29 at 07:57 +1000, Benjamin Herrenschmidt wrote:
> On Thu, 2016-07-28 at 21:36 +0530, Richard Henderson wrote:
> > 
> > On 07/27/2016 03:51 AM, Benjamin Herrenschmidt wrote:
> > > 
> > > 
> > > +            /* GETPC() works here because this is inline */
> > > +            raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM,
> > > +                                   POWERPC_EXCP_FP | op,
> > > GETPC());
> > 
> > It doesn't, with --enable-debug, aka -O0.
> 
> Will that prevent even an explicit inline statement ? Would
> __attribute__((always_inline)) help there ?

Ah found this in gcc docs:

<<
GCC does not inline any functions when not optimizing unless you
specify the ‘always_inline’ attribute for the function, like this:

     /* Prototype.  */
     inline void foo (const char) __attribute__((always_inline));
>>

I'll add the attribute.

Cheers,
Ben.


^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Qemu-devel] [PATCH 28/32] ppc: Avoid double translation for lvx/lvxl/stvx/stvxl
  2016-07-26 22:21 ` [Qemu-devel] [PATCH 28/32] ppc: Avoid double translation for lvx/lvxl/stvx/stvxl Benjamin Herrenschmidt
@ 2016-07-29  0:49   ` Richard Henderson
  2016-07-29  2:13     ` Benjamin Herrenschmidt
  2016-07-29  9:00     ` Benjamin Herrenschmidt
  0 siblings, 2 replies; 69+ messages in thread
From: Richard Henderson @ 2016-07-29  0:49 UTC (permalink / raw)
  To: Benjamin Herrenschmidt, qemu-ppc; +Cc: qemu-devel, david

On 07/27/2016 03:51 AM, Benjamin Herrenschmidt wrote:
> -    tcg_gen_andi_tl(EA, EA, ~0xf);                                            \
> -    /* We only need to swap high and low halves. gen_qemu_ld64 does necessary \
> -       64-bit byteswap already. */                                            \
> -    if (ctx->le_mode) {                                                       \
> -        gen_qemu_ld64(ctx, cpu_avrl[rD(ctx->opcode)], EA);                    \
> -        tcg_gen_addi_tl(EA, EA, 8);                                           \
> -        gen_qemu_ld64(ctx, cpu_avrh[rD(ctx->opcode)], EA);                    \
> -    } else {                                                                  \
> -        gen_qemu_ld64(ctx, cpu_avrh[rD(ctx->opcode)], EA);                    \
> -        tcg_gen_addi_tl(EA, EA, 8);                                           \
> -        gen_qemu_ld64(ctx, cpu_avrl[rD(ctx->opcode)], EA);                    \
> -    }                                                                         \
> +    gen_helper_lvx(cpu_env, t0, EA);                                          \

This, I'm not so keen on.

(1) The helper, since it writes to registers controlled by tcg, must be 
described to clobber all registers.  Which will noticeably increase memory 
traffic to ENV.  For instance, you won't be able to hold the guest register 
holding the address in a host register across the call.

(2) We're going to have to teach tcg about 16-byte data types soon anyway, for 
the proper emulation of 16-byte atomic operations.


r~

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Qemu-devel] [PATCH 28/32] ppc: Avoid double translation for lvx/lvxl/stvx/stvxl
  2016-07-29  0:49   ` Richard Henderson
@ 2016-07-29  2:13     ` Benjamin Herrenschmidt
  2016-07-29  3:34       ` David Gibson
  2016-07-29  9:00     ` Benjamin Herrenschmidt
  1 sibling, 1 reply; 69+ messages in thread
From: Benjamin Herrenschmidt @ 2016-07-29  2:13 UTC (permalink / raw)
  To: Richard Henderson, qemu-ppc; +Cc: qemu-devel, david

On Fri, 2016-07-29 at 06:19 +0530, Richard Henderson wrote:
> This, I'm not so keen on.
> 
> (1) The helper, since it writes to registers controlled by tcg, must be 
> described to clobber all registers.  Which will noticeably increase memory 
> traffic to ENV.  For instance, you won't be able to hold the guest register 
> holding the address in a host register across the call.

Ah I wasn't aware of this. How do you describe such a clobber ? Can I describe
specifically which one is clobbered ? I didn't think TCG kept track of the vector
halves but I must admit I'm still a bit new with TCG in general.

I noticed other constructs doing that (passing a register number to an opcode),
what do I do to ensure the right clobbers are there ?

> > (2) We're going to have to teach tcg about 16-byte data types soon anyway, for 
> the proper emulation of 16-byte atomic operations.

Is anybody working on this already ? I thought about that approach as
it would definitely make things easier for that and a couple of other
cases such as lq/stq.

Cheers,
Ben.

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Qemu-devel] [PATCH 28/32] ppc: Avoid double translation for lvx/lvxl/stvx/stvxl
  2016-07-29  2:13     ` Benjamin Herrenschmidt
@ 2016-07-29  3:34       ` David Gibson
  2016-07-29  4:40         ` Benjamin Herrenschmidt
  0 siblings, 1 reply; 69+ messages in thread
From: David Gibson @ 2016-07-29  3:34 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: Richard Henderson, qemu-ppc, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 1499 bytes --]

On Fri, Jul 29, 2016 at 12:13:01PM +1000, Benjamin Herrenschmidt wrote:
> On Fri, 2016-07-29 at 06:19 +0530, Richard Henderson wrote:
> > This, I'm not so keen on.
> > 
> > (1) The helper, since it writes to registers controlled by tcg, must be 
> > described to clobber all registers.  Which will noticeably increase memory 
> > traffic to ENV.  For instance, you won't be able to hold the guest register 
> > holding the address in a host register across the call.
> 
> Ah I wasn't aware of this. How do you describe such a clobber ? Can I describe
> specifically which one is clobbered ? I didn't think TCG kept track of the vector
> halves but I must admit I'm still a bit new with TCG in general.
> 
> I noticed other constructs doing that (passing a register number to an opcode),
> what do I do to ensure the right clobbers are there ?
> 
> > > (2) We're going to have to teach tcg about 16-byte data types soon anyway, for 
> > the proper emulation of 16-byte atomic operations.
> 
> Is anybody working on this already ? I thought about that approach as
> it would definitely make things easier for that and a couple of other
> cases such as lq/stq.

What should I do with this in the short term?  Leave it in
ppc-for-2.8, or remove it for now pending possible changes?

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Qemu-devel] [PATCH 28/32] ppc: Avoid double translation for lvx/lvxl/stvx/stvxl
  2016-07-29  3:34       ` David Gibson
@ 2016-07-29  4:40         ` Benjamin Herrenschmidt
  2016-07-29  4:58           ` Benjamin Herrenschmidt
  0 siblings, 1 reply; 69+ messages in thread
From: Benjamin Herrenschmidt @ 2016-07-29  4:40 UTC (permalink / raw)
  To: David Gibson; +Cc: Richard Henderson, qemu-ppc, qemu-devel

On Fri, 2016-07-29 at 13:34 +1000, David Gibson wrote:
> 
> What should I do with this in the short term?  Leave it in
> ppc-for-2.8, or remove it for now pending possible changes?

I think I'm still measuring a performance improvement with this, I'll
test a bit more and will get back to you.

It will definitely better to do it without a helper once Richard's 128-
bit stuff is in.

Cheers,
Ben.

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Qemu-devel] [PATCH 28/32] ppc: Avoid double translation for lvx/lvxl/stvx/stvxl
  2016-07-29  4:40         ` Benjamin Herrenschmidt
@ 2016-07-29  4:58           ` Benjamin Herrenschmidt
  2016-07-29  5:42             ` David Gibson
  0 siblings, 1 reply; 69+ messages in thread
From: Benjamin Herrenschmidt @ 2016-07-29  4:58 UTC (permalink / raw)
  To: David Gibson; +Cc: Richard Henderson, qemu-ppc, qemu-devel

On Fri, 2016-07-29 at 14:40 +1000, Benjamin Herrenschmidt wrote:
> On Fri, 2016-07-29 at 13:34 +1000, David Gibson wrote:
> > 
> >  
> > What should I do with this in the short term?  Leave it in
> > ppc-for-2.8, or remove it for now pending possible changes?
> 
> I think I'm still measuring a performance improvement with this, I'll
> test a bit more and will get back to you.
> 
> It will definitely better to do it without a helper once Richard's 128-
> bit stuff is in.

Ok, after I nice'd myself on top of all the gcc's on that test machine
I confirm that this patch is a loss on qemu-user. It might still be a
win for qemu-system-ppc64 due to the translation but probably not
worth bothering.

So drop this one. I'll use the 128-bit support when it becomes
available.

Cheers,
Ben.

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Qemu-devel] [PATCH 28/32] ppc: Avoid double translation for lvx/lvxl/stvx/stvxl
  2016-07-29  4:58           ` Benjamin Herrenschmidt
@ 2016-07-29  5:42             ` David Gibson
  0 siblings, 0 replies; 69+ messages in thread
From: David Gibson @ 2016-07-29  5:42 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: Richard Henderson, qemu-ppc, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 1113 bytes --]

On Fri, Jul 29, 2016 at 02:58:07PM +1000, Benjamin Herrenschmidt wrote:
> On Fri, 2016-07-29 at 14:40 +1000, Benjamin Herrenschmidt wrote:
> > On Fri, 2016-07-29 at 13:34 +1000, David Gibson wrote:
> > > 
> > >  
> > > What should I do with this in the short term?  Leave it in
> > > ppc-for-2.8, or remove it for now pending possible changes?
> > 
> > I think I'm still measuring a performance improvement with this, I'll
> > test a bit more and will get back to you.
> > 
> > It will definitely better to do it without a helper once Richard's 128-
> > bit stuff is in.
> 
> Ok, after I nice'd myself on top of all the gcc's on that test machine
> I confirm that this patch is a loss on qemu-user. It might still be a
> win for qemu-system-ppc64 due to the translation but probably not
> worth bothering.
> 
> So drop this one. I'll use the 128-bit support when it becomes
> available.

Done.

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Qemu-devel] [PATCH 28/32] ppc: Avoid double translation for lvx/lvxl/stvx/stvxl
  2016-07-29  0:49   ` Richard Henderson
  2016-07-29  2:13     ` Benjamin Herrenschmidt
@ 2016-07-29  9:00     ` Benjamin Herrenschmidt
  2016-07-29 12:43       ` Richard Henderson
  1 sibling, 1 reply; 69+ messages in thread
From: Benjamin Herrenschmidt @ 2016-07-29  9:00 UTC (permalink / raw)
  To: Richard Henderson, qemu-ppc; +Cc: qemu-devel, david

On Fri, 2016-07-29 at 06:19 +0530, Richard Henderson wrote:
> (1) The helper, since it writes to registers controlled by tcg, must be 
> described to clobber all registers.  Which will noticeably increase memory 
> traffic to ENV.  For instance, you won't be able to hold the guest register 
> holding the address in a host register across the call.

So after fixing my test setup, I did observe indeed a small performance
loss using the helper in qemu-user. It might still win us something in
softmmu due to avoiding extra translations but I will leave that aside
as I mentioned separately.

Now out of curosity, I tried this:

--- a/target-ppc/helper.h
+++ b/target-ppc/helper.h
@@ -22,12 +22,12 @@ DEF_HELPER_1(check_tlb_flush, void, env)
 #endif
 
 DEF_HELPER_3(lmw, void, env, tl, i32)
-DEF_HELPER_3(stmw, void, env, tl, i32)
+DEF_HELPER_FLAGS_3(stmw, TCG_CALL_NO_WG, void, env, tl, i32)
 DEF_HELPER_4(lsw, void, env, tl, i32, i32)
 DEF_HELPER_5(lswx, void, env, tl, i32, i32, i32)
-DEF_HELPER_4(stsw, void, env, tl, i32, i32)
-DEF_HELPER_3(dcbz, void, env, tl, i32)
-DEF_HELPER_2(icbi, void, env, tl)
+DEF_HELPER_FLAGS_4(stsw, TCG_CALL_NO_WG, void, env, tl, i32, i32)
+DEF_HELPER_FLAGS_3(dcbz, TCG_CALL_NO_WG, void, env, tl, i32)
+DEF_HELPER_FLAGS_2(icbi, TCG_CALL_NO_WG, void, env, tl)
 DEF_HELPER_5(lscbx, tl, env, tl, i32, i32, i32)
 
 #if defined(TARGET_PPC64)

If my understanding is right, the above is correct, as none of these
instructions will write to the env, though they can read from it and/
or generate faults.

Sadly I haven't observed any performance improvement as a result in
a few micro-benchmarks I cooked up.

Cheers,
Ben
 

^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: [Qemu-devel] [PATCH 28/32] ppc: Avoid double translation for lvx/lvxl/stvx/stvxl
  2016-07-29  9:00     ` Benjamin Herrenschmidt
@ 2016-07-29 12:43       ` Richard Henderson
  0 siblings, 0 replies; 69+ messages in thread
From: Richard Henderson @ 2016-07-29 12:43 UTC (permalink / raw)
  To: Benjamin Herrenschmidt, qemu-ppc; +Cc: qemu-devel, david

On 07/29/2016 02:30 PM, Benjamin Herrenschmidt wrote:
>  DEF_HELPER_3(lmw, void, env, tl, i32)
> -DEF_HELPER_3(stmw, void, env, tl, i32)
> +DEF_HELPER_FLAGS_3(stmw, TCG_CALL_NO_WG, void, env, tl, i32)
>  DEF_HELPER_4(lsw, void, env, tl, i32, i32)
>  DEF_HELPER_5(lswx, void, env, tl, i32, i32, i32)
> -DEF_HELPER_4(stsw, void, env, tl, i32, i32)
> -DEF_HELPER_3(dcbz, void, env, tl, i32)
> -DEF_HELPER_2(icbi, void, env, tl)
> +DEF_HELPER_FLAGS_4(stsw, TCG_CALL_NO_WG, void, env, tl, i32, i32)
> +DEF_HELPER_FLAGS_3(dcbz, TCG_CALL_NO_WG, void, env, tl, i32)
> +DEF_HELPER_FLAGS_2(icbi, TCG_CALL_NO_WG, void, env, tl)
>  DEF_HELPER_5(lscbx, tl, env, tl, i32, i32, i32)
>
>  #if defined(TARGET_PPC64)
>
> If my understanding is right, the above is correct, as none of these
> instructions will write to the env, though they can read from it and/
> or generate faults.
>
> Sadly I haven't observed any performance improvement as a result in
> a few micro-benchmarks I cooked up.

Too bad.

But the changes look correct, so you might as well queue them.  ;-)


r~

^ permalink raw reply	[flat|nested] 69+ messages in thread

end of thread, other threads:[~2016-07-29 12:43 UTC | newest]

Thread overview: 69+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-07-26 22:20 [Qemu-devel] [PATCH 01/32] ppc: Fix fault PC reporting for lve*/stve* VMX instructions Benjamin Herrenschmidt
2016-07-26 22:20 ` [Qemu-devel] [PATCH 02/32] ppc: Provide basic raise_exception_* functions Benjamin Herrenschmidt
2016-07-27  1:50   ` David Gibson
2016-07-27  3:46     ` Benjamin Herrenschmidt
2016-07-26 22:20 ` [Qemu-devel] [PATCH 03/32] ppc: Move classic fp ops out of translate.c Benjamin Herrenschmidt
2016-07-28 16:02   ` Richard Henderson
2016-07-28 21:56     ` Benjamin Herrenschmidt
2016-07-26 22:20 ` [Qemu-devel] [PATCH 04/32] ppc: Move embedded spe " Benjamin Herrenschmidt
2016-07-26 22:20 ` [Qemu-devel] [PATCH 05/32] ppc: Move DFP " Benjamin Herrenschmidt
2016-07-26 22:21 ` [Qemu-devel] [PATCH 06/32] ppc: Move VMX " Benjamin Herrenschmidt
2016-07-26 22:21 ` [Qemu-devel] [PATCH 07/32] ppc: Move VSX " Benjamin Herrenschmidt
2016-07-26 22:21 ` [Qemu-devel] [PATCH 08/32] ppc: Rename fload_invalid_op_excp to float_invalid_op_excp Benjamin Herrenschmidt
2016-07-26 22:21 ` [Qemu-devel] [PATCH 09/32] ppc: Make float_invalid_op_excp() pass the return address Benjamin Herrenschmidt
2016-07-28 16:06   ` Richard Henderson
2016-07-28 21:57     ` Benjamin Herrenschmidt
2016-07-28 22:10       ` Benjamin Herrenschmidt
2016-07-26 22:21 ` [Qemu-devel] [PATCH 10/32] ppc: Make float_check_status() " Benjamin Herrenschmidt
2016-07-27  1:57   ` David Gibson
2016-07-27  3:47     ` Benjamin Herrenschmidt
2016-07-26 22:21 ` [Qemu-devel] [PATCH 11/32] ppc: Don't update the NIP in floating point generated code Benjamin Herrenschmidt
2016-07-26 22:21 ` [Qemu-devel] [PATCH 12/32] ppc: FP exceptions are always precise Benjamin Herrenschmidt
2016-07-27  2:00   ` David Gibson
2016-07-27  3:50     ` Benjamin Herrenschmidt
2016-07-26 22:21 ` [Qemu-devel] [PATCH 13/32] ppc: Don't update NIP in lswi/lswx/stswi/stswx Benjamin Herrenschmidt
2016-07-27  2:04   ` David Gibson
2016-07-27  3:51     ` Benjamin Herrenschmidt
2016-07-26 22:21 ` [Qemu-devel] [PATCH 14/32] ppc: Don't update NIP in lmw/stmw/icbi Benjamin Herrenschmidt
2016-07-26 22:21 ` [Qemu-devel] [PATCH 15/32] ppc: Make tlb_fill() use new exception helper Benjamin Herrenschmidt
2016-07-26 22:21 ` [Qemu-devel] [PATCH 16/32] ppc: Rework NIP updates vs. exception generation Benjamin Herrenschmidt
2016-07-27  2:19   ` David Gibson
2016-07-27  3:54     ` Benjamin Herrenschmidt
2016-07-27  4:35     ` Benjamin Herrenschmidt
2016-07-26 22:21 ` [Qemu-devel] [PATCH 17/32] ppc: Fix source NIP on SLB related interrupts Benjamin Herrenschmidt
2016-07-26 22:21 ` [Qemu-devel] [PATCH 18/32] ppc: Don't update NIP in DCR access routines Benjamin Herrenschmidt
2016-07-27  2:21   ` David Gibson
2016-07-27  3:55     ` Benjamin Herrenschmidt
2016-07-26 22:21 ` [Qemu-devel] [PATCH 19/32] ppc: Don't update NIP in facility unavailable interrupts Benjamin Herrenschmidt
2016-07-26 22:21 ` [Qemu-devel] [PATCH 20/32] ppc: Don't update NIP BookE 2.06 tlbwe Benjamin Herrenschmidt
2016-07-26 22:21 ` [Qemu-devel] [PATCH 21/32] ppc: Don't update NIP on conditional trap instructions Benjamin Herrenschmidt
2016-07-27  2:26   ` David Gibson
2016-07-27  3:56     ` Benjamin Herrenschmidt
2016-07-26 22:21 ` [Qemu-devel] [PATCH 22/32] ppc: Don't update NIP if not taking alignment exceptions Benjamin Herrenschmidt
2016-07-26 22:21 ` [Qemu-devel] [PATCH 23/32] ppc: Don't update NIP in dcbz and lscbx Benjamin Herrenschmidt
2016-07-26 22:21 ` [Qemu-devel] [PATCH 24/32] ppc: Make alignment exceptions suck less Benjamin Herrenschmidt
2016-07-27  2:30   ` David Gibson
2016-07-27  3:59     ` Benjamin Herrenschmidt
2016-07-26 22:21 ` [Qemu-devel] [PATCH 25/32] ppc: Handle unconditional (always/never) traps at translation time Benjamin Herrenschmidt
2016-07-27  2:33   ` David Gibson
2016-07-27  4:00     ` Benjamin Herrenschmidt
2016-07-26 22:21 ` [Qemu-devel] [PATCH 26/32] ppc: Speed up dcbz Benjamin Herrenschmidt
2016-07-27  2:36   ` David Gibson
2016-07-27  4:02     ` Benjamin Herrenschmidt
2016-07-26 22:21 ` [Qemu-devel] [PATCH 27/32] ppc: Fix CFAR updates Benjamin Herrenschmidt
2016-07-26 22:21 ` [Qemu-devel] [PATCH 28/32] ppc: Avoid double translation for lvx/lvxl/stvx/stvxl Benjamin Herrenschmidt
2016-07-29  0:49   ` Richard Henderson
2016-07-29  2:13     ` Benjamin Herrenschmidt
2016-07-29  3:34       ` David Gibson
2016-07-29  4:40         ` Benjamin Herrenschmidt
2016-07-29  4:58           ` Benjamin Herrenschmidt
2016-07-29  5:42             ` David Gibson
2016-07-29  9:00     ` Benjamin Herrenschmidt
2016-07-29 12:43       ` Richard Henderson
2016-07-26 22:21 ` [Qemu-devel] [PATCH 29/32] ppc: Don't set access_type on all load/stores on hash64 Benjamin Herrenschmidt
2016-07-26 22:21 ` [Qemu-devel] [PATCH 30/32] ppc: Use a helper to generate "LE unsupported" alignment interrupts Benjamin Herrenschmidt
2016-07-26 22:21 ` [Qemu-devel] [PATCH 31/32] ppc: load/store multiple and string insns don't do LE Benjamin Herrenschmidt
2016-07-26 22:21 ` [Qemu-devel] [PATCH 32/32] ppc: Speed up load/store multiple Benjamin Herrenschmidt
2016-07-27  2:47   ` David Gibson
2016-07-27  4:04     ` Benjamin Herrenschmidt
2016-07-27  1:06 ` [Qemu-devel] [PATCH 01/32] ppc: Fix fault PC reporting for lve*/stve* VMX instructions David Gibson

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.