PowerPC 2.03 SPE extension - first pass.
authorj_mayer <j_mayer@c046a42c-6fe2-441c-8c8c-71466251a162>
Tue, 20 Mar 2007 22:11:31 +0000 (22:11 +0000)
committerj_mayer <j_mayer@c046a42c-6fe2-441c-8c8c-71466251a162>
Tue, 20 Mar 2007 22:11:31 +0000 (22:11 +0000)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2519 c046a42c-6fe2-441c-8c8c-71466251a162

target-ppc/cpu.h
target-ppc/exec.h
target-ppc/op.c
target-ppc/op_helper.c
target-ppc/op_helper.h
target-ppc/op_mem.h
target-ppc/op_template.h
target-ppc/translate.c
target-ppc/translate_init.c

index 5b1af41..e229413 100644 (file)
 #if defined (TARGET_PPC64)
 typedef uint64_t ppc_gpr_t;
 #define TARGET_LONG_BITS 64
+#define TARGET_GPR_BITS  64
 #define REGX "%016" PRIx64
-#elif defined(TARGET_E500)
+/* We can safely use PowerPC SPE extension when compiling PowerPC 64 */
+#define TARGET_PPCSPE
+#elif defined(TARGET_PPCSPE)
 /* GPR are 64 bits: used by vector extension */
 typedef uint64_t ppc_gpr_t;
 #define TARGET_LONG_BITS 32
+#define TARGET_GPR_BITS  64
 #define REGX "%08" PRIx32
 #else
 typedef uint32_t ppc_gpr_t;
 #define TARGET_LONG_BITS 32
+#define TARGET_GPR_BITS  32
 #define REGX "%08" PRIx32
 #endif
 
@@ -297,7 +302,7 @@ enum {
     /* ld/st with reservation instructions         */
     /* cache control instructions                  */
     /* spr/msr access instructions                 */
-    PPC_INSNS_BASE  = 0x00000001,
+    PPC_INSNS_BASE  = 0x0000000000000001ULL,
 #define PPC_INTEGER PPC_INSNS_BASE
 #define PPC_FLOW    PPC_INSNS_BASE
 #define PPC_MEM     PPC_INSNS_BASE
@@ -305,68 +310,72 @@ enum {
 #define PPC_CACHE   PPC_INSNS_BASE
 #define PPC_MISC    PPC_INSNS_BASE
     /* floating point operations instructions      */
-    PPC_FLOAT       = 0x00000002,
+    PPC_FLOAT       = 0x0000000000000002ULL,
     /* more floating point operations instructions */
-    PPC_FLOAT_EXT   = 0x00000004,
+    PPC_FLOAT_EXT   = 0x0000000000000004ULL,
     /* external control instructions               */
-    PPC_EXTERN      = 0x00000008,
+    PPC_EXTERN      = 0x0000000000000008ULL,
     /* segment register access instructions        */
-    PPC_SEGMENT     = 0x00000010,
+    PPC_SEGMENT     = 0x0000000000000010ULL,
     /* Optional cache control instructions         */
-    PPC_CACHE_OPT   = 0x00000020,
+    PPC_CACHE_OPT   = 0x0000000000000020ULL,
     /* Optional floating point op instructions     */
-    PPC_FLOAT_OPT   = 0x00000040,
+    PPC_FLOAT_OPT   = 0x0000000000000040ULL,
     /* Optional memory control instructions        */
-    PPC_MEM_TLBIA   = 0x00000080,
-    PPC_MEM_TLBIE   = 0x00000100,
-    PPC_MEM_TLBSYNC = 0x00000200,
+    PPC_MEM_TLBIA   = 0x0000000000000080ULL,
+    PPC_MEM_TLBIE   = 0x0000000000000100ULL,
+    PPC_MEM_TLBSYNC = 0x0000000000000200ULL,
     /* eieio & sync                                */
-    PPC_MEM_SYNC    = 0x00000400,
+    PPC_MEM_SYNC    = 0x0000000000000400ULL,
     /* PowerPC 6xx TLB management instructions     */
-    PPC_6xx_TLB     = 0x00000800,
+    PPC_6xx_TLB     = 0x0000000000000800ULL,
     /* Altivec support                             */
-    PPC_ALTIVEC     = 0x00001000,
+    PPC_ALTIVEC     = 0x0000000000001000ULL,
     /* Time base support                           */
-    PPC_TB          = 0x00002000,
+    PPC_TB          = 0x0000000000002000ULL,
     /* Embedded PowerPC dedicated instructions     */
-    PPC_EMB_COMMON  = 0x00004000,
+    PPC_EMB_COMMON  = 0x0000000000004000ULL,
     /* PowerPC 40x exception model                 */
-    PPC_40x_EXCP    = 0x00008000,
+    PPC_40x_EXCP    = 0x0000000000008000ULL,
     /* PowerPC 40x specific instructions           */
-    PPC_40x_SPEC    = 0x00010000,
+    PPC_40x_SPEC    = 0x0000000000010000ULL,
     /* PowerPC 405 Mac instructions                */
-    PPC_405_MAC     = 0x00020000,
+    PPC_405_MAC     = 0x0000000000020000ULL,
     /* PowerPC 440 specific instructions           */
-    PPC_440_SPEC    = 0x00040000,
+    PPC_440_SPEC    = 0x0000000000040000ULL,
     /* Specific extensions */
     /* Power-to-PowerPC bridge (601)               */
-    PPC_POWER_BR    = 0x00080000,
+    PPC_POWER_BR    = 0x0000000000080000ULL,
     /* PowerPC 602 specific */
-    PPC_602_SPEC    = 0x00100000,
+    PPC_602_SPEC    = 0x0000000000100000ULL,
     /* Deprecated instructions                     */
     /* Original POWER instruction set              */
-    PPC_POWER       = 0x00200000,
+    PPC_POWER       = 0x0000000000200000ULL,
     /* POWER2 instruction set extension            */
-    PPC_POWER2      = 0x00400000,
+    PPC_POWER2      = 0x0000000000400000ULL,
     /* Power RTC support */
-    PPC_POWER_RTC   = 0x00800000,
+    PPC_POWER_RTC   = 0x0000000000800000ULL,
     /* 64 bits PowerPC instructions                */
     /* 64 bits PowerPC instruction set             */
-    PPC_64B         = 0x01000000,
+    PPC_64B         = 0x0000000001000000ULL,
     /* 64 bits hypervisor extensions               */
-    PPC_64H         = 0x02000000,
+    PPC_64H         = 0x0000000002000000ULL,
     /* 64 bits PowerPC "bridge" features           */
-    PPC_64_BRIDGE   = 0x04000000,
+    PPC_64_BRIDGE   = 0x0000000004000000ULL,
     /* BookE (embedded) PowerPC specification      */
-    PPC_BOOKE       = 0x08000000,
+    PPC_BOOKE       = 0x0000000008000000ULL,
     /* eieio */
-    PPC_MEM_EIEIO   = 0x10000000,
+    PPC_MEM_EIEIO   = 0x0000000010000000ULL,
     /* e500 vector instructions */
-    PPC_E500_VECTOR = 0x20000000,
+    PPC_E500_VECTOR = 0x0000000020000000ULL,
     /* PowerPC 4xx dedicated instructions     */
-    PPC_4xx_COMMON  = 0x40000000,
+    PPC_4xx_COMMON  = 0x0000000040000000ULL,
     /* PowerPC 2.03 specification extensions */
-    PPC_203         = 0x80000000,
+    PPC_203         = 0x0000000080000000ULL,
+    /* PowerPC 2.03 SPE extension */
+    PPC_SPE         = 0x0000000100000000ULL,
+    /* PowerPC 2.03 SPE floating-point extension */
+    PPC_SPEFPU      = 0x0000000200000000ULL,
 };
 
 /* CPU run-time flags (MMU and exception model) */
@@ -618,10 +627,10 @@ struct CPUPPCState {
     /* First are the most commonly used resources
      * during translated code execution
      */
-#if TARGET_LONG_BITS > HOST_LONG_BITS
+#if TARGET_GPR_BITS > HOST_LONG_BITS
     /* temporary fixed-point registers
      * used to emulate 64 bits target on 32 bits hosts
-     */
+     */ 
     target_ulong t0, t1, t2;
 #endif
     ppc_avr_t t0_avr, t1_avr, t2_avr;
@@ -683,6 +692,7 @@ struct CPUPPCState {
     uint32_t vscr;
     /* SPE registers */
     ppc_gpr_t spe_acc;
+    float_status spe_status;
     uint32_t spe_fscr;
 
     /* Internal devices resources */
@@ -1192,6 +1202,8 @@ enum {
 #define EXCP_970_MAINT     0x1600 /* Maintenance exception                   */
 #define EXCP_970_THRM      0x1800 /* Thermal exception                       */
 #define EXCP_970_VPUA      0x1700 /* VPU assist exception                    */
+/* SPE related exceptions                                                    */
+#define EXCP_NO_SPE        0x0F20 /* SPE unavailable exception               */
 /* End of exception vectors area                                             */
 #define EXCP_PPC_MAX       0x4000
 /* Qemu exceptions: special cases we want to stop translation                */
index f1dde82..a10b62d 100644 (file)
@@ -39,10 +39,10 @@ register unsigned long T1 asm(AREG2);
 register unsigned long T2 asm(AREG3);
 #endif
 /* We may, sometime, need 64 bits registers on 32 bits target */
-#if defined(TARGET_PPC64) || (HOST_LONG_BITS == 64)
+#if defined(TARGET_PPC64) || defined(TARGET_PPCSPE) || (HOST_LONG_BITS == 64)
 #define T0_64 T0
-#define T1_64 T0
-#define T2_64 T0
+#define T1_64 T1
+#define T2_64 T2
 #else
 /* no registers can be used */
 #define T0_64 (env->t0)
index 9531595..0b972c8 100644 (file)
@@ -1326,106 +1326,14 @@ void OPPROTO op_andi_T1 (void)
 /* count leading zero */
 void OPPROTO op_cntlzw (void)
 {
-    int cnt;
-
-    cnt = 0;
-    if (!(T0 & 0xFFFF0000UL)) {
-        cnt += 16;
-        T0 <<= 16;
-    }
-    if (!(T0 & 0xFF000000UL)) {
-        cnt += 8;
-        T0 <<= 8;
-    }
-    if (!(T0 & 0xF0000000UL)) {
-        cnt += 4;
-        T0 <<= 4;
-    }
-    if (!(T0 & 0xC0000000UL)) {
-        cnt += 2;
-        T0 <<= 2;
-    }
-    if (!(T0 & 0x80000000UL)) {
-        cnt++;
-        T0 <<= 1;
-    }
-    if (!(T0 & 0x80000000UL)) {
-        cnt++;
-    }
-    T0 = cnt;
+    T0 = _do_cntlzw(T0);
     RETURN();
 }
 
 #if defined(TARGET_PPC64)
 void OPPROTO op_cntlzd (void)
 {
-#if HOST_LONG_BITS == 64
-    int cnt;
-
-    cnt = 0;
-    if (!(T0 & 0xFFFFFFFF00000000ULL)) {
-        cnt += 32;
-        T0 <<= 32;
-    }
-    if (!(T0 & 0xFFFF000000000000ULL)) {
-        cnt += 16;
-        T0 <<= 16;
-    }
-    if (!(T0 & 0xFF00000000000000ULL)) {
-        cnt += 8;
-        T0 <<= 8;
-    }
-    if (!(T0 & 0xF000000000000000ULL)) {
-        cnt += 4;
-        T0 <<= 4;
-    }
-    if (!(T0 & 0xC000000000000000ULL)) {
-        cnt += 2;
-        T0 <<= 2;
-    }
-    if (!(T0 & 0x8000000000000000ULL)) {
-        cnt++;
-        T0 <<= 1;
-    }
-    if (!(T0 & 0x8000000000000000ULL)) {
-        cnt++;
-    }
-    T0 = cnt;
-#else
-    uint32_t tmp;
-
-    /* Make it easier on 32 bits host machines */
-    if (!(T0 >> 32)) {
-        tmp = T0;
-        T0 = 32;
-    } else {
-        tmp = T0 >> 32;
-        T0 = 0;
-    }
-    if (!(tmp & 0xFFFF0000UL)) {
-        T0 += 16;
-        tmp <<= 16;
-    }
-    if (!(tmp & 0xFF000000UL)) {
-        T0 += 8;
-        tmp <<= 8;
-    }
-    if (!(tmp & 0xF0000000UL)) {
-        T0 += 4;
-        tmp <<= 4;
-    }
-    if (!(tmp & 0xC0000000UL)) {
-        T0 += 2;
-        tmp <<= 2;
-    }
-    if (!(tmp & 0x80000000UL)) {
-        T0++;
-        tmp <<= 1;
-    }
-    if (!(tmp & 0x80000000UL)) {
-        T0++;
-    }
-#endif
+    T0 = _do_cntlzd(T0);
     RETURN();
 }
 #endif
@@ -2462,4 +2370,723 @@ void OPPROTO op_store_booke_tsr (void)
     store_booke_tsr(env, T0);
     RETURN();
 }
+
 #endif /* !defined(CONFIG_USER_ONLY) */
+
+#if defined(TARGET_PPCSPE)
+/* SPE extension */
+void OPPROTO op_splatw_T1_64 (void)
+{
+    T1_64 = (T1_64 << 32) | (T1_64 & 0x00000000FFFFFFFFULL);
+}
+
+void OPPROTO op_splatwi_T0_64 (void)
+{
+    uint64_t tmp = PARAM1;
+
+    T0_64 = (tmp << 32) | tmp;
+}
+
+void OPPROTO op_splatwi_T1_64 (void)
+{
+    uint64_t tmp = PARAM1;
+
+    T1_64 = (tmp << 32) | tmp;
+}
+
+void OPPROTO op_extsh_T1_64 (void)
+{
+    T1_64 = (int32_t)((int16_t)T1_64);
+    RETURN();
+}
+
+void OPPROTO op_sli16_T1_64 (void)
+{
+    T1_64 = T1_64 << 16;
+    RETURN();
+}
+
+void OPPROTO op_sli32_T1_64 (void)
+{
+    T1_64 = T1_64 << 32;
+    RETURN();
+}
+
+void OPPROTO op_srli32_T1_64 (void)
+{
+    T1_64 = T1_64 >> 32;
+    RETURN();
+}
+
+void OPPROTO op_evsel (void)
+{
+    do_evsel();
+    RETURN();
+}
+
+void OPPROTO op_evaddw (void)
+{
+    do_evaddw();
+    RETURN();
+}
+
+void OPPROTO op_evsubfw (void)
+{
+    do_evsubfw();
+    RETURN();
+}
+
+void OPPROTO op_evneg (void)
+{
+    do_evneg();
+    RETURN();
+}
+
+void OPPROTO op_evabs (void)
+{
+    do_evabs();
+    RETURN();
+}
+
+void OPPROTO op_evextsh (void)
+{
+    T0_64 = ((uint64_t)((int32_t)(int16_t)(T0_64 >> 32)) << 32) |
+        (uint64_t)((int32_t)(int16_t)T0_64);
+    RETURN();
+}
+
+void OPPROTO op_evextsb (void)
+{
+    T0_64 = ((uint64_t)((int32_t)(int8_t)(T0_64 >> 32)) << 32) |
+        (uint64_t)((int32_t)(int8_t)T0_64);
+    RETURN();
+}
+
+void OPPROTO op_evcntlzw (void)
+{
+    do_evcntlzw();
+    RETURN();
+}
+
+void OPPROTO op_evrndw (void)
+{
+    do_evrndw();
+    RETURN();
+}
+
+void OPPROTO op_brinc (void)
+{
+    do_brinc();
+    RETURN();
+}
+
+void OPPROTO op_evcntlsw (void)
+{
+    do_evcntlsw();
+    RETURN();
+}
+
+void OPPROTO op_evand (void)
+{
+    T0_64 &= T1_64;
+    RETURN();
+}
+
+void OPPROTO op_evandc (void)
+{
+    T0_64 &= ~T1_64;
+    RETURN();
+}
+
+void OPPROTO op_evor (void)
+{
+    T0_64 |= T1_64;
+    RETURN();
+}
+
+void OPPROTO op_evxor (void)
+{
+    T0_64 ^= T1_64;
+    RETURN();
+}
+
+void OPPROTO op_eveqv (void)
+{
+    T0_64 = ~(T0_64 ^ T1_64);
+    RETURN();
+}
+
+void OPPROTO op_evnor (void)
+{
+    T0_64 = ~(T0_64 | T1_64);
+    RETURN();
+}
+
+void OPPROTO op_evorc (void)
+{
+    T0_64 |= ~T1_64;
+    RETURN();
+}
+
+void OPPROTO op_evnand (void)
+{
+    T0_64 = ~(T0_64 & T1_64);
+    RETURN();
+}
+
+void OPPROTO op_evsrws (void)
+{
+    do_evsrws();
+    RETURN();
+}
+
+void OPPROTO op_evsrwu (void)
+{
+    do_evsrwu();
+    RETURN();
+}
+
+void OPPROTO op_evslw (void)
+{
+    do_evslw();
+    RETURN();
+}
+
+void OPPROTO op_evrlw (void)
+{
+    do_evrlw();
+    RETURN();
+}
+
+void OPPROTO op_evmergelo (void)
+{
+    T0_64 = (T0_64 << 32) | (T1_64 & 0x00000000FFFFFFFFULL);
+    RETURN();
+}
+
+void OPPROTO op_evmergehi (void)
+{
+    T0_64 = (T0_64 & 0xFFFFFFFF00000000ULL) | (T1_64 >> 32);
+    RETURN();
+}
+
+void OPPROTO op_evmergelohi (void)
+{
+    T0_64 = (T0_64 << 32) | (T1_64 >> 32);
+    RETURN();
+}
+
+void OPPROTO op_evmergehilo (void)
+{
+    T0_64 = (T0_64 & 0xFFFFFFFF00000000ULL) | (T1_64 & 0x00000000FFFFFFFFULL);
+    RETURN();
+}
+
+void OPPROTO op_evcmpgts (void)
+{
+    do_evcmpgts();
+    RETURN();
+}
+
+void OPPROTO op_evcmpgtu (void)
+{
+    do_evcmpgtu();
+    RETURN();
+}
+
+void OPPROTO op_evcmplts (void)
+{
+    do_evcmplts();
+    RETURN();
+}
+
+void OPPROTO op_evcmpltu (void)
+{
+    do_evcmpltu();
+    RETURN();
+}
+
+void OPPROTO op_evcmpeq (void)
+{
+    do_evcmpeq();
+    RETURN();
+}
+
+void OPPROTO op_evfssub (void)
+{
+    do_evfssub();
+    RETURN();
+}
+
+void OPPROTO op_evfsadd (void)
+{
+    do_evfsadd();
+    RETURN();
+}
+
+void OPPROTO op_evfsnabs (void)
+{
+    do_evfsnabs();
+    RETURN();
+}
+
+void OPPROTO op_evfsabs (void)
+{
+    do_evfsabs();
+    RETURN();
+}
+
+void OPPROTO op_evfsneg (void)
+{
+    do_evfsneg();
+    RETURN();
+}
+
+void OPPROTO op_evfsdiv (void)
+{
+    do_evfsdiv();
+    RETURN();
+}
+
+void OPPROTO op_evfsmul (void)
+{
+    do_evfsmul();
+    RETURN();
+}
+
+void OPPROTO op_evfscmplt (void)
+{
+    do_evfscmplt();
+    RETURN();
+}
+
+void OPPROTO op_evfscmpgt (void)
+{
+    do_evfscmpgt();
+    RETURN();
+}
+
+void OPPROTO op_evfscmpeq (void)
+{
+    do_evfscmpeq();
+    RETURN();
+}
+
+void OPPROTO op_evfscfsi (void)
+{
+    do_evfscfsi();
+    RETURN();
+}
+
+void OPPROTO op_evfscfui (void)
+{
+    do_evfscfui();
+    RETURN();
+}
+
+void OPPROTO op_evfscfsf (void)
+{
+    do_evfscfsf();
+    RETURN();
+}
+
+void OPPROTO op_evfscfuf (void)
+{
+    do_evfscfuf();
+    RETURN();
+}
+
+void OPPROTO op_evfsctsi (void)
+{
+    do_evfsctsi();
+    RETURN();
+}
+
+void OPPROTO op_evfsctui (void)
+{
+    do_evfsctui();
+    RETURN();
+}
+
+void OPPROTO op_evfsctsf (void)
+{
+    do_evfsctsf();
+    RETURN();
+}
+
+void OPPROTO op_evfsctuf (void)
+{
+    do_evfsctuf();
+    RETURN();
+}
+
+void OPPROTO op_evfsctuiz (void)
+{
+    do_evfsctuiz();
+    RETURN();
+}
+
+void OPPROTO op_evfsctsiz (void)
+{
+    do_evfsctsiz();
+    RETURN();
+}
+
+void OPPROTO op_evfststlt (void)
+{
+    do_evfststlt();
+    RETURN();
+}
+
+void OPPROTO op_evfststgt (void)
+{
+    do_evfststgt();
+    RETURN();
+}
+
+void OPPROTO op_evfststeq (void)
+{
+    do_evfststeq();
+    RETURN();
+}
+
+void OPPROTO op_efssub (void)
+{
+    T0_64 = _do_efssub(T0_64, T1_64);
+    RETURN();
+}
+
+void OPPROTO op_efsadd (void)
+{
+    T0_64 = _do_efsadd(T0_64, T1_64);
+    RETURN();
+}
+
+void OPPROTO op_efsnabs (void)
+{
+    T0_64 = _do_efsnabs(T0_64);
+    RETURN();
+}
+
+void OPPROTO op_efsabs (void)
+{
+    T0_64 = _do_efsabs(T0_64);
+    RETURN();
+}
+
+void OPPROTO op_efsneg (void)
+{
+    T0_64 = _do_efsneg(T0_64);
+    RETURN();
+}
+
+void OPPROTO op_efsdiv (void)
+{
+    T0_64 = _do_efsdiv(T0_64, T1_64);
+    RETURN();
+}
+
+void OPPROTO op_efsmul (void)
+{
+    T0_64 = _do_efsmul(T0_64, T1_64);
+    RETURN();
+}
+
+void OPPROTO op_efscmplt (void)
+{
+    do_efscmplt();
+    RETURN();
+}
+
+void OPPROTO op_efscmpgt (void)
+{
+    do_efscmpgt();
+    RETURN();
+}
+
+void OPPROTO op_efscfd (void)
+{
+    do_efscfd();
+    RETURN();
+}
+
+void OPPROTO op_efscmpeq (void)
+{
+    do_efscmpeq();
+    RETURN();
+}
+
+void OPPROTO op_efscfsi (void)
+{
+    do_efscfsi();
+    RETURN();
+}
+
+void OPPROTO op_efscfui (void)
+{
+    do_efscfui();
+    RETURN();
+}
+
+void OPPROTO op_efscfsf (void)
+{
+    do_efscfsf();
+    RETURN();
+}
+
+void OPPROTO op_efscfuf (void)
+{
+    do_efscfuf();
+    RETURN();
+}
+
+void OPPROTO op_efsctsi (void)
+{
+    do_efsctsi();
+    RETURN();
+}
+
+void OPPROTO op_efsctui (void)
+{
+    do_efsctui();
+    RETURN();
+}
+
+void OPPROTO op_efsctsf (void)
+{
+    do_efsctsf();
+    RETURN();
+}
+
+void OPPROTO op_efsctuf (void)
+{
+    do_efsctuf();
+    RETURN();
+}
+
+void OPPROTO op_efsctsiz (void)
+{
+    do_efsctsiz();
+    RETURN();
+}
+
+void OPPROTO op_efsctuiz (void)
+{
+    do_efsctuiz();
+    RETURN();
+}
+
+void OPPROTO op_efststlt (void)
+{
+    T0 = _do_efststlt(T0_64, T1_64);
+    RETURN();
+}
+
+void OPPROTO op_efststgt (void)
+{
+    T0 = _do_efststgt(T0_64, T1_64);
+    RETURN();
+}
+
+void OPPROTO op_efststeq (void)
+{
+    T0 = _do_efststeq(T0_64, T1_64);
+    RETURN();
+}
+
+void OPPROTO op_efdsub (void)
+{
+    union {
+        uint64_t u;
+        float64 f;
+    } u1, u2;
+    u1.u = T0_64;
+    u2.u = T1_64;
+    u1.f = float64_sub(u1.f, u2.f, &env->spe_status);
+    T0_64 = u1.u;
+    RETURN();
+}
+
+void OPPROTO op_efdadd (void)
+{
+    union {
+        uint64_t u;
+        float64 f;
+    } u1, u2;
+    u1.u = T0_64;
+    u2.u = T1_64;
+    u1.f = float64_add(u1.f, u2.f, &env->spe_status);
+    T0_64 = u1.u;
+    RETURN();
+}
+
+void OPPROTO op_efdcfsid (void)
+{
+    do_efdcfsi();
+    RETURN();
+}
+
+void OPPROTO op_efdcfuid (void)
+{
+    do_efdcfui();
+    RETURN();
+}
+
+void OPPROTO op_efdnabs (void)
+{
+    T0_64 |= 0x8000000000000000ULL;
+    RETURN();
+}
+
+void OPPROTO op_efdabs (void)
+{
+    T0_64 &= ~0x8000000000000000ULL;
+    RETURN();
+}
+
+void OPPROTO op_efdneg (void)
+{
+    T0_64 ^= 0x8000000000000000ULL;
+    RETURN();
+}
+
+void OPPROTO op_efddiv (void)
+{
+    union {
+        uint64_t u;
+        float64 f;
+    } u1, u2;
+    u1.u = T0_64;
+    u2.u = T1_64;
+    u1.f = float64_div(u1.f, u2.f, &env->spe_status);
+    T0_64 = u1.u;
+    RETURN();
+}
+
+void OPPROTO op_efdmul (void)
+{
+    union {
+        uint64_t u;
+        float64 f;
+    } u1, u2;
+    u1.u = T0_64;
+    u2.u = T1_64;
+    u1.f = float64_mul(u1.f, u2.f, &env->spe_status);
+    T0_64 = u1.u;
+    RETURN();
+}
+
+void OPPROTO op_efdctsidz (void)
+{
+    do_efdctsiz();
+    RETURN();
+}
+
+void OPPROTO op_efdctuidz (void)
+{
+    do_efdctuiz();
+    RETURN();
+}
+
+void OPPROTO op_efdcmplt (void)
+{
+    do_efdcmplt();
+    RETURN();
+}
+
+void OPPROTO op_efdcmpgt (void)
+{
+    do_efdcmpgt();
+    RETURN();
+}
+
+void OPPROTO op_efdcfs (void)
+{
+    do_efdcfs();
+    RETURN();
+}
+
+void OPPROTO op_efdcmpeq (void)
+{
+    do_efdcmpeq();
+    RETURN();
+}
+
+void OPPROTO op_efdcfsi (void)
+{
+    do_efdcfsi();
+    RETURN();
+}
+
+void OPPROTO op_efdcfui (void)
+{
+    do_efdcfui();
+    RETURN();
+}
+
+void OPPROTO op_efdcfsf (void)
+{
+    do_efdcfsf();
+    RETURN();
+}
+
+void OPPROTO op_efdcfuf (void)
+{
+    do_efdcfuf();
+    RETURN();
+}
+
+void OPPROTO op_efdctsi (void)
+{
+    do_efdctsi();
+    RETURN();
+}
+
+void OPPROTO op_efdctui (void)
+{
+    do_efdctui();
+    RETURN();
+}
+
+void OPPROTO op_efdctsf (void)
+{
+    do_efdctsf();
+    RETURN();
+}
+
+void OPPROTO op_efdctuf (void)
+{
+    do_efdctuf();
+    RETURN();
+}
+
+void OPPROTO op_efdctuiz (void)
+{
+    do_efdctuiz();
+    RETURN();
+}
+
+void OPPROTO op_efdctsiz (void)
+{
+    do_efdctsiz();
+    RETURN();
+}
+
+void OPPROTO op_efdtstlt (void)
+{
+    T0 = _do_efdtstlt(T0_64, T1_64);
+    RETURN();
+}
+
+void OPPROTO op_efdtstgt (void)
+{
+    T0 = _do_efdtstgt(T0_64, T1_64);
+    RETURN();
+}
+
+void OPPROTO op_efdtsteq (void)
+{
+    T0 = _do_efdtsteq(T0_64, T1_64);
+    RETURN();
+}
+#endif /* defined(TARGET_PPCSPE) */
index 7ef06b2..756d164 100644 (file)
  */
 #include "exec.h"
 
+#include "op_helper.h"
+
 #define MEMSUFFIX _raw
+#include "op_helper.h"
 #include "op_helper_mem.h"
 #if !defined(CONFIG_USER_ONLY)
 #define MEMSUFFIX _user
+#include "op_helper.h"
 #include "op_helper_mem.h"
 #define MEMSUFFIX _kernel
+#include "op_helper.h"
 #include "op_helper_mem.h"
 #endif
 
@@ -229,7 +234,7 @@ void do_mul64 (uint64_t *plow, uint64_t *phigh)
     mul64(plow, phigh, T0, T1);
 }
 
-static void imul64(uint64_t *plow, uint64_t *phigh, int64_t a, int64_t b)
+static void imul64 (uint64_t *plow, uint64_t *phigh, int64_t a, int64_t b)
 {
     int sa, sb;
     sa = (a < 0);
@@ -1119,6 +1124,868 @@ void do_440_dlmzb (void)
     T0 = i;
 }
 
+#if defined(TARGET_PPCSPE)
+/* SPE extension helpers */
+/* Use a table to make this quicker */
+static uint8_t hbrev[16] = {
+    0x0, 0x8, 0x4, 0xC, 0x2, 0xA, 0x6, 0xE,
+    0x1, 0x9, 0x5, 0xD, 0x3, 0xB, 0x7, 0xF,
+};
+
+static inline uint8_t byte_reverse (uint8_t val)
+{
+    return hbrev[val >> 4] | (hbrev[val & 0xF] << 4);
+}
+
+static inline uint32_t word_reverse (uint32_t val)
+{
+    return byte_reverse(val >> 24) | (byte_reverse(val >> 16) << 8) |
+        (byte_reverse(val >> 8) << 16) | (byte_reverse(val) << 24);
+}
+
+#define MASKBITS 16 // Random value - to be fixed
+void do_brinc (void)
+{
+    uint32_t a, b, d, mask;
+
+    mask = (uint32_t)(-1UL) >> MASKBITS;
+    b = T1_64 & mask;
+    a = T0_64 & mask;
+    d = word_reverse(1 + word_reverse(a | ~mask));
+    T0_64 = (T0_64 & ~mask) | (d & mask);
+}
+
+#define DO_SPE_OP2(name)                                                      \
+void do_ev##name (void)                                                       \
+{                                                                             \
+    T0_64 = ((uint64_t)_do_e##name(T0_64 >> 32, T1_64 >> 32) << 32) |         \
+        (uint64_t)_do_e##name(T0_64, T1_64);                                  \
+}
+
+#define DO_SPE_OP1(name)                                                      \
+void do_ev##name (void)                                                       \
+{                                                                             \
+    T0_64 = ((uint64_t)_do_e##name(T0_64 >> 32) << 32) |                      \
+        (uint64_t)_do_e##name(T0_64);                                         \
+}
+
+/* Fixed-point vector arithmetic */
+static inline uint32_t _do_eabs (uint32_t val)
+{
+    if (val != 0x80000000)
+        val &= ~0x80000000;
+
+    return val;
+}
+
+static inline uint32_t _do_eaddw (uint32_t op1, uint32_t op2)
+{
+    return op1 + op2;
+}
+
+static inline int _do_ecntlsw (uint32_t val)
+{
+    if (val & 0x80000000)
+        return _do_cntlzw(~val);
+    else
+        return _do_cntlzw(val);
+}
+
+static inline int _do_ecntlzw (uint32_t val)
+{
+    return _do_cntlzw(val);
+}
+
+static inline uint32_t _do_eneg (uint32_t val)
+{
+    if (val != 0x80000000)
+        val ^= 0x80000000;
+
+    return val;
+}
+
+static inline uint32_t _do_erlw (uint32_t op1, uint32_t op2)
+{
+    return rotl32(op1, op2);
+}
+
+static inline uint32_t _do_erndw (uint32_t val)
+{
+    return (val + 0x000080000000) & 0xFFFF0000;
+}
+
+static inline uint32_t _do_eslw (uint32_t op1, uint32_t op2)
+{
+    /* No error here: 6 bits are used */
+    return op1 << (op2 & 0x3F);
+}
+
+static inline int32_t _do_esrws (int32_t op1, uint32_t op2)
+{
+    /* No error here: 6 bits are used */
+    return op1 >> (op2 & 0x3F);
+}
+
+static inline uint32_t _do_esrwu (uint32_t op1, uint32_t op2)
+{
+    /* No error here: 6 bits are used */
+    return op1 >> (op2 & 0x3F);
+}
+
+static inline uint32_t _do_esubfw (uint32_t op1, uint32_t op2)
+{
+    return op2 - op1;
+}
+
+/* evabs */
+DO_SPE_OP1(abs);
+/* evaddw */
+DO_SPE_OP2(addw);
+/* evcntlsw */
+DO_SPE_OP1(cntlsw);
+/* evcntlzw */
+DO_SPE_OP1(cntlzw);
+/* evneg */
+DO_SPE_OP1(neg);
+/* evrlw */
+DO_SPE_OP2(rlw);
+/* evrnd */
+DO_SPE_OP1(rndw);
+/* evslw */
+DO_SPE_OP2(slw);
+/* evsrws */
+DO_SPE_OP2(srws);
+/* evsrwu */
+DO_SPE_OP2(srwu);
+/* evsubfw */
+DO_SPE_OP2(subfw);
+
+/* evsel is a little bit more complicated... */
+static inline uint32_t _do_esel (uint32_t op1, uint32_t op2, int n)
+{
+    if (n)
+        return op1;
+    else
+        return op2;
+}
+
+void do_evsel (void)
+{
+    T0_64 = ((uint64_t)_do_esel(T0_64 >> 32, T1_64 >> 32, T0 >> 3) << 32) |
+        (uint64_t)_do_esel(T0_64, T1_64, (T0 >> 2) & 1);
+}
+
+/* Fixed-point vector comparisons */
+#define DO_SPE_CMP(name)                                                      \
+void do_ev##name (void)                                                       \
+{                                                                             \
+    T0 = _do_evcmp_merge((uint64_t)_do_e##name(T0_64 >> 32,                   \
+                                               T1_64 >> 32) << 32,            \
+                         _do_e##name(T0_64, T1_64));                          \
+}
+
+static inline uint32_t _do_evcmp_merge (int t0, int t1)
+{
+    return (t0 << 3) | (t1 << 2) | ((t0 | t1) << 1) | (t0 & t1);
+}
+static inline int _do_ecmpeq (uint32_t op1, uint32_t op2)
+{
+    return op1 == op2 ? 1 : 0;
+}
+
+static inline int _do_ecmpgts (int32_t op1, int32_t op2)
+{
+    return op1 > op2 ? 1 : 0;
+}
+
+static inline int _do_ecmpgtu (uint32_t op1, uint32_t op2)
+{
+    return op1 > op2 ? 1 : 0;
+}
+
+static inline int _do_ecmplts (int32_t op1, int32_t op2)
+{
+    return op1 < op2 ? 1 : 0;
+}
+
+static inline int _do_ecmpltu (uint32_t op1, uint32_t op2)
+{
+    return op1 < op2 ? 1 : 0;
+}
+
+/* evcmpeq */
+DO_SPE_CMP(cmpeq);
+/* evcmpgts */
+DO_SPE_CMP(cmpgts);
+/* evcmpgtu */
+DO_SPE_CMP(cmpgtu);
+/* evcmplts */
+DO_SPE_CMP(cmplts);
+/* evcmpltu */
+DO_SPE_CMP(cmpltu);
+
+/* Single precision floating-point conversions from/to integer */
+static inline uint32_t _do_efscfsi (int32_t val)
+{
+    union {
+        uint32_t u;
+        float32 f;
+    } u;
+
+    u.f = int32_to_float32(val, &env->spe_status);
+
+    return u.u;
+}
+
+static inline uint32_t _do_efscfui (uint32_t val)
+{
+    union {
+        uint32_t u;
+        float32 f;
+    } u;
+
+    u.f = uint32_to_float32(val, &env->spe_status);
+
+    return u.u;
+}
+
+static inline int32_t _do_efsctsi (uint32_t val)
+{
+    union {
+        int32_t u;
+        float32 f;
+    } u;
+
+    u.u = val;
+    /* NaN are not treated the same way IEEE 754 does */
+    if (unlikely(isnan(u.f)))
+        return 0;
+
+    return float32_to_int32(u.f, &env->spe_status);
+}
+
+static inline uint32_t _do_efsctui (uint32_t val)
+{
+    union {
+        int32_t u;
+        float32 f;
+    } u;
+
+    u.u = val;
+    /* NaN are not treated the same way IEEE 754 does */
+    if (unlikely(isnan(u.f)))
+        return 0;
+
+    return float32_to_uint32(u.f, &env->spe_status);
+}
+
+static inline int32_t _do_efsctsiz (uint32_t val)
+{
+    union {
+        int32_t u;
+        float32 f;
+    } u;
+
+    u.u = val;
+    /* NaN are not treated the same way IEEE 754 does */
+    if (unlikely(isnan(u.f)))
+        return 0;
+
+    return float32_to_int32_round_to_zero(u.f, &env->spe_status);
+}
+
+static inline uint32_t _do_efsctuiz (uint32_t val)
+{
+    union {
+        int32_t u;
+        float32 f;
+    } u;
+
+    u.u = val;
+    /* NaN are not treated the same way IEEE 754 does */
+    if (unlikely(isnan(u.f)))
+        return 0;
+
+    return float32_to_uint32_round_to_zero(u.f, &env->spe_status);
+}
+
+void do_efscfsi (void)
+{
+    T0_64 = _do_efscfsi(T0_64);
+}
+
+void do_efscfui (void)
+{
+    T0_64 = _do_efscfui(T0_64);
+}
+
+void do_efsctsi (void)
+{
+    T0_64 = _do_efsctsi(T0_64);
+}
+
+void do_efsctui (void)
+{
+    T0_64 = _do_efsctui(T0_64);
+}
+
+void do_efsctsiz (void)
+{
+    T0_64 = _do_efsctsiz(T0_64);
+}
+
+void do_efsctuiz (void)
+{
+    T0_64 = _do_efsctuiz(T0_64);
+}
+
+/* Single precision floating-point conversion to/from fractional */
+static inline uint32_t _do_efscfsf (uint32_t val)
+{
+    union {
+        uint32_t u;
+        float32 f;
+    } u;
+    float32 tmp;
+
+    u.f = int32_to_float32(val, &env->spe_status);
+    tmp = int64_to_float32(1ULL << 32, &env->spe_status);
+    u.f = float32_div(u.f, tmp, &env->spe_status);
+
+    return u.u;
+}
+
+static inline uint32_t _do_efscfuf (uint32_t val)
+{
+    union {
+        uint32_t u;
+        float32 f;
+    } u;
+    float32 tmp;
+
+    u.f = uint32_to_float32(val, &env->spe_status);
+    tmp = uint64_to_float32(1ULL << 32, &env->spe_status);
+    u.f = float32_div(u.f, tmp, &env->spe_status);
+
+    return u.u;
+}
+
+static inline int32_t _do_efsctsf (uint32_t val)
+{
+    union {
+        int32_t u;
+        float32 f;
+    } u;
+    float32 tmp;
+
+    u.u = val;
+    /* NaN are not treated the same way IEEE 754 does */
+    if (unlikely(isnan(u.f)))
+        return 0;
+    tmp = uint64_to_float32(1ULL << 32, &env->spe_status);
+    u.f = float32_mul(u.f, tmp, &env->spe_status);
+
+    return float32_to_int32(u.f, &env->spe_status);
+}
+
+static inline uint32_t _do_efsctuf (uint32_t val)
+{
+    union {
+        int32_t u;
+        float32 f;
+    } u;
+    float32 tmp;
+
+    u.u = val;
+    /* NaN are not treated the same way IEEE 754 does */
+    if (unlikely(isnan(u.f)))
+        return 0;
+    tmp = uint64_to_float32(1ULL << 32, &env->spe_status);
+    u.f = float32_mul(u.f, tmp, &env->spe_status);
+
+    return float32_to_uint32(u.f, &env->spe_status);
+}
+
+static inline int32_t _do_efsctsfz (uint32_t val)
+{
+    union {
+        int32_t u;
+        float32 f;
+    } u;
+    float32 tmp;
+
+    u.u = val;
+    /* NaN are not treated the same way IEEE 754 does */
+    if (unlikely(isnan(u.f)))
+        return 0;
+    tmp = uint64_to_float32(1ULL << 32, &env->spe_status);
+    u.f = float32_mul(u.f, tmp, &env->spe_status);
+
+    return float32_to_int32_round_to_zero(u.f, &env->spe_status);
+}
+
+static inline uint32_t _do_efsctufz (uint32_t val)
+{
+    union {
+        int32_t u;
+        float32 f;
+    } u;
+    float32 tmp;
+
+    u.u = val;
+    /* NaN are not treated the same way IEEE 754 does */
+    if (unlikely(isnan(u.f)))
+        return 0;
+    tmp = uint64_to_float32(1ULL << 32, &env->spe_status);
+    u.f = float32_mul(u.f, tmp, &env->spe_status);
+
+    return float32_to_uint32_round_to_zero(u.f, &env->spe_status);
+}
+
+void do_efscfsf (void)
+{
+    T0_64 = _do_efscfsf(T0_64);
+}
+
+void do_efscfuf (void)
+{
+    T0_64 = _do_efscfuf(T0_64);
+}
+
+void do_efsctsf (void)
+{
+    T0_64 = _do_efsctsf(T0_64);
+}
+
+void do_efsctuf (void)
+{
+    T0_64 = _do_efsctuf(T0_64);
+}
+
+void do_efsctsfz (void)
+{
+    T0_64 = _do_efsctsfz(T0_64);
+}
+
+void do_efsctufz (void)
+{
+    T0_64 = _do_efsctufz(T0_64);
+}
+
+/* Double precision floating point helpers */
+static inline int _do_efdcmplt (uint64_t op1, uint64_t op2)
+{
+    /* XXX: TODO: test special values (NaN, infinites, ...) */
+    return _do_efdtstlt(op1, op2);
+}
+
+static inline int _do_efdcmpgt (uint64_t op1, uint64_t op2)
+{
+    /* XXX: TODO: test special values (NaN, infinites, ...) */
+    return _do_efdtstgt(op1, op2);
+}
+
+static inline int _do_efdcmpeq (uint64_t op1, uint64_t op2)
+{
+    /* XXX: TODO: test special values (NaN, infinites, ...) */
+    return _do_efdtsteq(op1, op2);
+}
+
+void do_efdcmplt (void)
+{
+    T0 = _do_efdcmplt(T0_64, T1_64);
+}
+
+void do_efdcmpgt (void)
+{
+    T0 = _do_efdcmpgt(T0_64, T1_64);
+}
+
+void do_efdcmpeq (void)
+{
+    T0 = _do_efdcmpeq(T0_64, T1_64);
+}
+
+/* Double precision floating-point conversion to/from integer */
+static inline uint64_t _do_efdcfsi (int64_t val)
+{
+    union {
+        uint64_t u;
+        float64 f;
+    } u;
+
+    u.f = int64_to_float64(val, &env->spe_status);
+
+    return u.u;
+}
+
+static inline uint64_t _do_efdcfui (uint64_t val)
+{
+    union {
+        uint64_t u;
+        float64 f;
+    } u;
+
+    u.f = uint64_to_float64(val, &env->spe_status);
+
+    return u.u;
+}
+
+static inline int64_t _do_efdctsi (uint64_t val)
+{
+    union {
+        int64_t u;
+        float64 f;
+    } u;
+
+    u.u = val;
+    /* NaN are not treated the same way IEEE 754 does */
+    if (unlikely(isnan(u.f)))
+        return 0;
+
+    return float64_to_int64(u.f, &env->spe_status);
+}
+
+static inline uint64_t _do_efdctui (uint64_t val)
+{
+    union {
+        int64_t u;
+        float64 f;
+    } u;
+
+    u.u = val;
+    /* NaN are not treated the same way IEEE 754 does */
+    if (unlikely(isnan(u.f)))
+        return 0;
+
+    return float64_to_uint64(u.f, &env->spe_status);
+}
+
+static inline int64_t _do_efdctsiz (uint64_t val)
+{
+    union {
+        int64_t u;
+        float64 f;
+    } u;
+
+    u.u = val;
+    /* NaN are not treated the same way IEEE 754 does */
+    if (unlikely(isnan(u.f)))
+        return 0;
+
+    return float64_to_int64_round_to_zero(u.f, &env->spe_status);
+}
+
+static inline uint64_t _do_efdctuiz (uint64_t val)
+{
+    union {
+        int64_t u;
+        float64 f;
+    } u;
+
+    u.u = val;
+    /* NaN are not treated the same way IEEE 754 does */
+    if (unlikely(isnan(u.f)))
+        return 0;
+
+    return float64_to_uint64_round_to_zero(u.f, &env->spe_status);
+}
+
+void do_efdcfsi (void)
+{
+    T0_64 = _do_efdcfsi(T0_64);
+}
+
+void do_efdcfui (void)
+{
+    T0_64 = _do_efdcfui(T0_64);
+}
+
+void do_efdctsi (void)
+{
+    T0_64 = _do_efdctsi(T0_64);
+}
+
+void do_efdctui (void)
+{
+    T0_64 = _do_efdctui(T0_64);
+}
+
+void do_efdctsiz (void)
+{
+    T0_64 = _do_efdctsiz(T0_64);
+}
+
+void do_efdctuiz (void)
+{
+    T0_64 = _do_efdctuiz(T0_64);
+}
+
+/* Double precision floating-point conversion to/from fractional */
+static inline uint64_t _do_efdcfsf (int64_t val)
+{
+    union {
+        uint64_t u;
+        float64 f;
+    } u;
+    float64 tmp;
+
+    u.f = int32_to_float64(val, &env->spe_status);
+    tmp = int64_to_float64(1ULL << 32, &env->spe_status);
+    u.f = float64_div(u.f, tmp, &env->spe_status);
+
+    return u.u;
+}
+
+static inline uint64_t _do_efdcfuf (uint64_t val)
+{
+    union {
+        uint64_t u;
+        float64 f;
+    } u;
+    float64 tmp;
+
+    u.f = uint32_to_float64(val, &env->spe_status);
+    tmp = int64_to_float64(1ULL << 32, &env->spe_status);
+    u.f = float64_div(u.f, tmp, &env->spe_status);
+
+    return u.u;
+}
+
+static inline int64_t _do_efdctsf (uint64_t val)
+{
+    union {
+        int64_t u;
+        float64 f;
+    } u;
+    float64 tmp;
+
+    u.u = val;
+    /* NaN are not treated the same way IEEE 754 does */
+    if (unlikely(isnan(u.f)))
+        return 0;
+    tmp = uint64_to_float64(1ULL << 32, &env->spe_status);
+    u.f = float64_mul(u.f, tmp, &env->spe_status);
+
+    return float64_to_int32(u.f, &env->spe_status);
+}
+
+static inline uint64_t _do_efdctuf (uint64_t val)
+{
+    union {
+        int64_t u;
+        float64 f;
+    } u;
+    float64 tmp;
+
+    u.u = val;
+    /* NaN are not treated the same way IEEE 754 does */
+    if (unlikely(isnan(u.f)))
+        return 0;
+    tmp = uint64_to_float64(1ULL << 32, &env->spe_status);
+    u.f = float64_mul(u.f, tmp, &env->spe_status);
+
+    return float64_to_uint32(u.f, &env->spe_status);
+}
+
+static inline int64_t _do_efdctsfz (uint64_t val)
+{
+    union {
+        int64_t u;
+        float64 f;
+    } u;
+    float64 tmp;
+
+    u.u = val;
+    /* NaN are not treated the same way IEEE 754 does */
+    if (unlikely(isnan(u.f)))
+        return 0;
+    tmp = uint64_to_float64(1ULL << 32, &env->spe_status);
+    u.f = float64_mul(u.f, tmp, &env->spe_status);
+
+    return float64_to_int32_round_to_zero(u.f, &env->spe_status);
+}
+
+static inline uint64_t _do_efdctufz (uint64_t val)
+{
+    union {
+        int64_t u;
+        float64 f;
+    } u;
+    float64 tmp;
+
+    u.u = val;
+    /* NaN are not treated the same way IEEE 754 does */
+    if (unlikely(isnan(u.f)))
+        return 0;
+    tmp = uint64_to_float64(1ULL << 32, &env->spe_status);
+    u.f = float64_mul(u.f, tmp, &env->spe_status);
+
+    return float64_to_uint32_round_to_zero(u.f, &env->spe_status);
+}
+
+void do_efdcfsf (void)
+{
+    T0_64 = _do_efdcfsf(T0_64);
+}
+
+void do_efdcfuf (void)
+{
+    T0_64 = _do_efdcfuf(T0_64);
+}
+
+void do_efdctsf (void)
+{
+    T0_64 = _do_efdctsf(T0_64);
+}
+
+void do_efdctuf (void)
+{
+    T0_64 = _do_efdctuf(T0_64);
+}
+
+void do_efdctsfz (void)
+{
+    T0_64 = _do_efdctsfz(T0_64);
+}
+
+void do_efdctufz (void)
+{
+    T0_64 = _do_efdctufz(T0_64);
+}
+
+/* Floating point conversion between single and double precision */
+static inline uint32_t _do_efscfd (uint64_t val)
+{
+    union {
+        uint64_t u;
+        float64 f;
+    } u1;
+    union {
+        uint32_t u;
+        float32 f;
+    } u2;
+
+    u1.u = val;
+    u2.f = float64_to_float32(u1.f, &env->spe_status);
+
+    return u2.u;
+}
+
+static inline uint64_t _do_efdcfs (uint32_t val)
+{
+    union {
+        uint64_t u;
+        float64 f;
+    } u2;
+    union {
+        uint32_t u;
+        float32 f;
+    } u1;
+
+    u1.u = val;
+    u2.f = float32_to_float64(u1.f, &env->spe_status);
+
+    return u2.u;
+}
+
+void do_efscfd (void)
+{
+    T0_64 = _do_efscfd(T0_64);
+}
+
+void do_efdcfs (void)
+{
+    T0_64 = _do_efdcfs(T0_64);
+}
+
+/* Single precision fixed-point vector arithmetic */
+/* evfsabs */
+DO_SPE_OP1(fsabs);
+/* evfsnabs */
+DO_SPE_OP1(fsnabs);
+/* evfsneg */
+DO_SPE_OP1(fsneg);
+/* evfsadd */
+DO_SPE_OP2(fsadd);
+/* evfssub */
+DO_SPE_OP2(fssub);
+/* evfsmul */
+DO_SPE_OP2(fsmul);
+/* evfsdiv */
+DO_SPE_OP2(fsdiv);
+
+/* Single-precision floating-point comparisons */
+static inline int _do_efscmplt (uint32_t op1, uint32_t op2)
+{
+    /* XXX: TODO: test special values (NaN, infinites, ...) */
+    return _do_efststlt(op1, op2);
+}
+
+static inline int _do_efscmpgt (uint32_t op1, uint32_t op2)
+{
+    /* XXX: TODO: test special values (NaN, infinites, ...) */
+    return _do_efststgt(op1, op2);
+}
+
+static inline int _do_efscmpeq (uint32_t op1, uint32_t op2)
+{
+    /* XXX: TODO: test special values (NaN, infinites, ...) */
+    return _do_efststeq(op1, op2);
+}
+
+void do_efscmplt (void)
+{
+    T0 = _do_efscmplt(T0_64, T1_64);
+}
+
+void do_efscmpgt (void)
+{
+    T0 = _do_efscmpgt(T0_64, T1_64);
+}
+
+void do_efscmpeq (void)
+{
+    T0 = _do_efscmpeq(T0_64, T1_64);
+}
+
+/* Single-precision floating-point vector comparisons */
+/* evfscmplt */
+DO_SPE_CMP(fscmplt);
+/* evfscmpgt */
+DO_SPE_CMP(fscmpgt);
+/* evfscmpeq */
+DO_SPE_CMP(fscmpeq);
+/* evfststlt */
+DO_SPE_CMP(fststlt);
+/* evfststgt */
+DO_SPE_CMP(fststgt);
+/* evfststeq */
+DO_SPE_CMP(fststeq);
+
+/* Single-precision floating-point vector conversions */
+/* evfscfsi */
+DO_SPE_OP1(fscfsi);
+/* evfscfui */
+DO_SPE_OP1(fscfui);
+/* evfscfuf */
+DO_SPE_OP1(fscfuf);
+/* evfscfsf */
+DO_SPE_OP1(fscfsf);
+/* evfsctsi */
+DO_SPE_OP1(fsctsi);
+/* evfsctui */
+DO_SPE_OP1(fsctui);
+/* evfsctsiz */
+DO_SPE_OP1(fsctsiz);
+/* evfsctuiz */
+DO_SPE_OP1(fsctuiz);
+/* evfsctsf */
+DO_SPE_OP1(fsctsf);
+/* evfsctuf */
+DO_SPE_OP1(fsctuf);
+#endif /* defined(TARGET_PPCSPE) */
+
 /*****************************************************************************/
 /* Softmmu support */
 #if !defined (CONFIG_USER_ONLY)
index 6eaceb3..8a735c1 100644 (file)
@@ -100,6 +100,7 @@ void do_fctiwz (void);
 void do_fcmpu (void);
 void do_fcmpo (void);
 
+/* Misc */
 void do_tw (int flags);
 #if defined(TARGET_PPC64)
 void do_td (int flags);
@@ -157,11 +158,291 @@ void do_4xx_tlbwe_lo (void);
 void do_4xx_tlbwe_hi (void);
 #endif
 
+/* PowerPC 440 specific helpers */
 void do_440_dlmzb (void);
 
+/* PowerPC 403 specific helpers */
 #if !defined(CONFIG_USER_ONLY)
 void do_load_403_pb (int num);
 void do_store_403_pb (int num);
 #endif
 
+#if defined(TARGET_PPCSPE)
+/* SPE extension helpers */
+void do_brinc (void);
+/* Fixed-point vector helpers */
+void do_evabs (void);
+void do_evaddw (void);
+void do_evcntlsw (void);
+void do_evcntlzw (void);
+void do_evneg (void);
+void do_evrlw (void);
+void do_evsel (void);
+void do_evrndw (void);
+void do_evslw (void);
+void do_evsrws (void);
+void do_evsrwu (void);
+void do_evsubfw (void);
+void do_evcmpeq (void);
+void do_evcmpgts (void);
+void do_evcmpgtu (void);
+void do_evcmplts (void);
+void do_evcmpltu (void);
+
+/* Single precision floating-point helpers */
+void do_efscmplt (void);
+void do_efscmpgt (void);
+void do_efscmpeq (void);
+void do_efscfsf (void);
+void do_efscfuf (void);
+void do_efsctsf (void);
+void do_efsctuf (void);
+
+void do_efscfsi (void);
+void do_efscfui (void);
+void do_efsctsi (void);
+void do_efsctui (void);
+void do_efsctsiz (void);
+void do_efsctuiz (void);
+
+/* Double precision floating-point helpers */
+void do_efdcmplt (void);
+void do_efdcmpgt (void);
+void do_efdcmpeq (void);
+void do_efdcfsf (void);
+void do_efdcfuf (void);
+void do_efdctsf (void);
+void do_efdctuf (void);
+
+void do_efdcfsi (void);
+void do_efdcfui (void);
+void do_efdctsi (void);
+void do_efdctui (void);
+void do_efdctsiz (void);
+void do_efdctuiz (void);
+
+void do_efdcfs (void);
+void do_efscfd (void);
+
+/* Floating-point vector helpers */
+void do_evfsabs (void);
+void do_evfsnabs (void);
+void do_evfsneg (void);
+void do_evfsadd (void);
+void do_evfssub (void);
+void do_evfsmul (void);
+void do_evfsdiv (void);
+void do_evfscmplt (void);
+void do_evfscmpgt (void);
+void do_evfscmpeq (void);
+void do_evfststlt (void);
+void do_evfststgt (void);
+void do_evfststeq (void);
+void do_evfscfsi (void);
+void do_evfscfui (void);
+void do_evfscfsf (void);
+void do_evfscfuf (void);
+void do_evfsctsf (void);
+void do_evfsctuf (void);
+void do_evfsctsi (void);
+void do_evfsctui (void);
+void do_evfsctsiz (void);
+void do_evfsctuiz (void);
+#endif /* defined(TARGET_PPCSPE) */
+
+/* Inlined helpers: used in micro-operation as well as helpers */
+/* Generic fixed-point helpers */
+static inline int _do_cntlzw (uint32_t val)
+{
+    int cnt = 0;
+    if (!(val & 0xFFFF0000UL)) {
+        cnt += 16;
+        val <<= 16;
+    }
+    if (!(val & 0xFF000000UL)) {
+        cnt += 8;
+        val <<= 8;
+    }
+    if (!(val & 0xF0000000UL)) {
+        cnt += 4;
+        val <<= 4;
+    }
+    if (!(val & 0xC0000000UL)) {
+        cnt += 2;
+        val <<= 2;
+    }
+    if (!(val & 0x80000000UL)) {
+        cnt++;
+        val <<= 1;
+    }
+    if (!(val & 0x80000000UL)) {
+        cnt++;
+    }
+    return cnt;
+}
+
+static inline int _do_cntlzd (uint64_t val)
+{
+    int cnt = 0;
+#if HOST_LONG_BITS == 64
+    if (!(val & 0xFFFFFFFF00000000ULL)) {
+        cnt += 32;
+        val <<= 32;
+    }
+    if (!(val & 0xFFFF000000000000ULL)) {
+        cnt += 16;
+        val <<= 16;
+    }
+    if (!(val & 0xFF00000000000000ULL)) {
+        cnt += 8;
+        val <<= 8;
+    }
+    if (!(val & 0xF000000000000000ULL)) {
+        cnt += 4;
+        val <<= 4;
+    }
+    if (!(val & 0xC000000000000000ULL)) {
+        cnt += 2;
+        val <<= 2;
+    }
+    if (!(val & 0x8000000000000000ULL)) {
+        cnt++;
+        val <<= 1;
+    }
+    if (!(val & 0x8000000000000000ULL)) {
+        cnt++;
+    }
+#else
+    uint32_t tmp;
+    /* Make it easier on 32 bits host machines */
+    if (!(val >> 32))
+        cnt = cntlzw(val) + 32;
+    else
+        cnt = cntlzw(val >> 32);
+#endif
+    return cnt;
+}
+
+#if defined(TARGET_PPCSPE)
+/* SPE extension */
+/* Single precision floating-point helpers */
+static inline uint32_t _do_efsabs (uint32_t val)
+{
+    return val & ~0x80000000;
+}
+static inline uint32_t _do_efsnabs (uint32_t val)
+{
+    return val | 0x80000000;
+}
+static inline uint32_t _do_efsneg (uint32_t val)
+{
+    return val ^ 0x80000000;
+}
+static inline uint32_t _do_efsadd (uint32_t op1, uint32_t op2)
+{
+    union {
+        uint32_t u;
+        float32 f;
+    } u1, u2;
+    u1.u = op1;
+    u2.u = op2;
+    u1.f = float32_add(u1.f, u2.f, &env->spe_status);
+    return u1.u;
+}
+static inline uint32_t _do_efssub (uint32_t op1, uint32_t op2)
+{
+    union {
+        uint32_t u;
+        float32 f;
+    } u1, u2;
+    u1.u = op1;
+    u2.u = op2;
+    u1.f = float32_sub(u1.f, u2.f, &env->spe_status);
+    return u1.u;
+}
+static inline uint32_t _do_efsmul (uint32_t op1, uint32_t op2)
+{
+    union {
+        uint32_t u;
+        float32 f;
+    } u1, u2;
+    u1.u = op1;
+    u2.u = op2;
+    u1.f = float32_mul(u1.f, u2.f, &env->spe_status);
+    return u1.u;
+}
+static inline uint32_t _do_efsdiv (uint32_t op1, uint32_t op2)
+{
+    union {
+        uint32_t u;
+        float32 f;
+    } u1, u2;
+    u1.u = op1;
+    u2.u = op2;
+    u1.f = float32_div(u1.f, u2.f, &env->spe_status);
+    return u1.u;
+}
+
+static inline int _do_efststlt (uint32_t op1, uint32_t op2)
+{
+    union {
+        uint32_t u;
+        float32 f;
+    } u1, u2;
+    u1.u = op1;
+    u2.u = op2;
+    return float32_lt(u1.f, u2.f, &env->spe_status) ? 1 : 0;
+}
+static inline int _do_efststgt (uint32_t op1, uint32_t op2)
+{
+    union {
+        uint32_t u;
+        float32 f;
+    } u1, u2;
+    u1.u = op1;
+    u2.u = op2;
+    return float32_le(u1.f, u2.f, &env->spe_status) ? 0 : 1;
+}
+static inline int _do_efststeq (uint32_t op1, uint32_t op2)
+{
+    union {
+        uint32_t u;
+        float32 f;
+    } u1, u2;
+    u1.u = op1;
+    u2.u = op2;
+    return float32_eq(u1.f, u2.f, &env->spe_status) ? 1 : 0;
+}
+/* Double precision floating-point helpers */
+static inline int _do_efdtstlt (uint64_t op1, uint64_t op2)
+{
+    union {
+        uint64_t u;
+        float64 f;
+    } u1, u2;
+    u1.u = op1;
+    u2.u = op2;
+    return float64_lt(u1.f, u2.f, &env->spe_status) ? 1 : 0;
+}
+static inline int _do_efdtstgt (uint64_t op1, uint64_t op2)
+{
+    union {
+        uint64_t u;
+        float64 f;
+    } u1, u2;
+    u1.u = op1;
+    u2.u = op2;
+    return float64_le(u1.f, u2.f, &env->spe_status) ? 0 : 1;
+}
+static inline int _do_efdtsteq (uint64_t op1, uint64_t op2)
+{
+    union {
+        uint64_t u;
+        float64 f;
+    } u1, u2;
+    u1.u = op1;
+    u2.u = op2;
+    return float64_eq(u1.f, u2.f, &env->spe_status) ? 1 : 0;
+}
+#endif /* defined(TARGET_PPCSPE) */
 #endif
index f5a8c4b..f080abc 100644 (file)
@@ -37,12 +37,7 @@ static inline uint32_t glue(ld32r, MEMSUFFIX) (target_ulong EA)
         ((tmp & 0x0000FF00) << 8) | ((tmp & 0x000000FF) << 24);
 }
 
-#if defined(TARGET_PPC64)
-static inline int64_t glue(ldsl, MEMSUFFIX) (target_ulong EA)
-{
-    return (int32_t)glue(ldl, MEMSUFFIX)(EA);
-}
-
+#if defined(TARGET_PPC64) || defined(TARGET_PPCSPE)
 static inline uint64_t glue(ld64r, MEMSUFFIX) (target_ulong EA)
 {
     uint64_t tmp = glue(ldq, MEMSUFFIX)(EA);
@@ -55,6 +50,13 @@ static inline uint64_t glue(ld64r, MEMSUFFIX) (target_ulong EA)
         ((tmp & 0x000000000000FF00ULL) << 40) |
         ((tmp & 0x00000000000000FFULL) << 54);
 }
+#endif
+
+#if defined(TARGET_PPC64)
+static inline int64_t glue(ldsl, MEMSUFFIX) (target_ulong EA)
+{
+    return (int32_t)glue(ldl, MEMSUFFIX)(EA);
+}
 
 static inline int64_t glue(ld32rs, MEMSUFFIX) (target_ulong EA)
 {
@@ -77,7 +79,7 @@ static inline void glue(st32r, MEMSUFFIX) (target_ulong EA, uint32_t data)
     glue(stl, MEMSUFFIX)(EA, tmp);
 }
 
-#if defined(TARGET_PPC64)
+#if defined(TARGET_PPC64) || defined(TARGET_PPCSPE)
 static inline void glue(st64r, MEMSUFFIX) (target_ulong EA, uint64_t data)
 {
     uint64_t tmp = ((data & 0xFF00000000000000ULL) >> 56) |
@@ -839,4 +841,262 @@ void OPPROTO glue(op_POWER2_stfq_le, MEMSUFFIX) (void)
     RETURN();
 }
 
+#if defined(TARGET_PPCSPE)
+/* SPE extension */
+#define _PPC_SPE_LD_OP(name, op)                                              \
+void OPPROTO glue(glue(op_spe_l, name), MEMSUFFIX) (void)                     \
+{                                                                             \
+    T1_64 = glue(op, MEMSUFFIX)((uint32_t)T0);                                \
+    RETURN();                                                                 \
+}
+
+#if defined(TARGET_PPC64)
+#define _PPC_SPE_LD_OP_64(name, op)                                           \
+void OPPROTO glue(glue(glue(op_spe_l, name), _64), MEMSUFFIX) (void)          \
+{                                                                             \
+    T1_64 = glue(op, MEMSUFFIX)((uint64_t)T0);                                \
+    RETURN();                                                                 \
+}
+#define PPC_SPE_LD_OP(name, op)                                               \
+_PPC_SPE_LD_OP(name, op);                                                     \
+_PPC_SPE_LD_OP_64(name, op)
+#else
+#define PPC_SPE_LD_OP(name, op)                                               \
+_PPC_SPE_LD_OP(name, op)
+#endif
+
+
+#define _PPC_SPE_ST_OP(name, op)                                              \
+void OPPROTO glue(glue(op_spe_st, name), MEMSUFFIX) (void)                    \
+{                                                                             \
+    glue(op, MEMSUFFIX)((uint32_t)T0, T1_64);                                 \
+    RETURN();                                                                 \
+}
+
+#if defined(TARGET_PPC64)
+#define _PPC_SPE_ST_OP_64(name, op)                                           \
+void OPPROTO glue(glue(glue(op_spe_st, name), _64), MEMSUFFIX) (void)         \
+{                                                                             \
+    glue(op, MEMSUFFIX)((uint64_t)T0, T1_64);                                 \
+    RETURN();                                                                 \
+}
+#define PPC_SPE_ST_OP(name, op)                                               \
+_PPC_SPE_ST_OP(name, op);                                                     \
+_PPC_SPE_ST_OP_64(name, op)
+#else
+#define PPC_SPE_ST_OP(name, op)                                               \
+_PPC_SPE_ST_OP(name, op)
+#endif
+
+#if !defined(TARGET_PPC64)
+PPC_SPE_LD_OP(dd, ldq);
+PPC_SPE_ST_OP(dd, stq);
+PPC_SPE_LD_OP(dd_le, ld64r);
+PPC_SPE_ST_OP(dd_le, st64r);
+#endif
+static inline uint64_t glue(spe_ldw, MEMSUFFIX) (target_ulong EA)
+{
+    uint64_t ret;
+    ret = (uint64_t)glue(ldl, MEMSUFFIX)(EA) << 32;
+    ret |= (uint64_t)glue(ldl, MEMSUFFIX)(EA + 4);
+    return ret;
+}
+PPC_SPE_LD_OP(dw, spe_ldw);
+static inline void glue(spe_stdw, MEMSUFFIX) (target_ulong EA, uint64_t data)
+{
+    glue(stl, MEMSUFFIX)(EA, data >> 32);
+    glue(stl, MEMSUFFIX)(EA + 4, data);
+}
+PPC_SPE_ST_OP(dw, spe_stdw);
+static inline uint64_t glue(spe_ldw_le, MEMSUFFIX) (target_ulong EA)
+{
+    uint64_t ret;
+    ret = (uint64_t)glue(ld32r, MEMSUFFIX)(EA) << 32;
+    ret |= (uint64_t)glue(ld32r, MEMSUFFIX)(EA + 4);
+    return ret;
+}
+PPC_SPE_LD_OP(dw_le, spe_ldw_le);
+static inline void glue(spe_stdw_le, MEMSUFFIX) (target_ulong EA,
+                                                 uint64_t data)
+{
+    glue(st32r, MEMSUFFIX)(EA, data >> 32);
+    glue(st32r, MEMSUFFIX)(EA + 4, data);
+}
+PPC_SPE_ST_OP(dw_le, spe_stdw_le);
+static inline uint64_t glue(spe_ldh, MEMSUFFIX) (target_ulong EA)
+{
+    uint64_t ret;
+    ret = (uint64_t)glue(lduw, MEMSUFFIX)(EA) << 48;
+    ret |= (uint64_t)glue(lduw, MEMSUFFIX)(EA + 2) << 32;
+    ret |= (uint64_t)glue(lduw, MEMSUFFIX)(EA + 4) << 16;
+    ret |= (uint64_t)glue(lduw, MEMSUFFIX)(EA + 6);
+    return ret;
+}
+PPC_SPE_LD_OP(dh, spe_ldh);
+static inline void glue(spe_stdh, MEMSUFFIX) (target_ulong EA, uint64_t data)
+{
+    glue(stw, MEMSUFFIX)(EA, data >> 48);
+    glue(stw, MEMSUFFIX)(EA + 2, data >> 32);
+    glue(stw, MEMSUFFIX)(EA + 4, data >> 16);
+    glue(stw, MEMSUFFIX)(EA + 6, data);
+}
+PPC_SPE_ST_OP(dh, spe_stdh);
+static inline uint64_t glue(spe_ldh_le, MEMSUFFIX) (target_ulong EA)
+{
+    uint64_t ret;
+    ret = (uint64_t)glue(ld16r, MEMSUFFIX)(EA) << 48;
+    ret |= (uint64_t)glue(ld16r, MEMSUFFIX)(EA + 2) << 32;
+    ret |= (uint64_t)glue(ld16r, MEMSUFFIX)(EA + 4) << 16;
+    ret |= (uint64_t)glue(ld16r, MEMSUFFIX)(EA + 6);
+    return ret;
+}
+PPC_SPE_LD_OP(dh_le, spe_ldh_le);
+static inline void glue(spe_stdh_le, MEMSUFFIX) (target_ulong EA,
+                                                 uint64_t data)
+{
+    glue(st16r, MEMSUFFIX)(EA, data >> 48);
+    glue(st16r, MEMSUFFIX)(EA + 2, data >> 32);
+    glue(st16r, MEMSUFFIX)(EA + 4, data >> 16);
+    glue(st16r, MEMSUFFIX)(EA + 6, data);
+}
+PPC_SPE_ST_OP(dh_le, spe_stdh_le);
+static inline uint64_t glue(spe_lwhe, MEMSUFFIX) (target_ulong EA)
+{
+    uint64_t ret;
+    ret = (uint64_t)glue(lduw, MEMSUFFIX)(EA) << 48;
+    ret |= (uint64_t)glue(lduw, MEMSUFFIX)(EA + 2) << 16;
+    return ret;
+}
+PPC_SPE_LD_OP(whe, spe_lwhe);
+static inline void glue(spe_stwhe, MEMSUFFIX) (target_ulong EA, uint64_t data)
+{
+    glue(stw, MEMSUFFIX)(EA, data >> 48);
+    glue(stw, MEMSUFFIX)(EA + 2, data >> 16);
+}
+PPC_SPE_ST_OP(whe, spe_stwhe);
+static inline uint64_t glue(spe_lwhe_le, MEMSUFFIX) (target_ulong EA)
+{
+    uint64_t ret;
+    ret = (uint64_t)glue(ld16r, MEMSUFFIX)(EA) << 48;
+    ret |= (uint64_t)glue(ld16r, MEMSUFFIX)(EA + 2) << 16;
+    return ret;
+}
+PPC_SPE_LD_OP(whe_le, spe_lwhe_le);
+static inline void glue(spe_stwhe_le, MEMSUFFIX) (target_ulong EA,
+                                                  uint64_t data)
+{
+    glue(st16r, MEMSUFFIX)(EA, data >> 48);
+    glue(st16r, MEMSUFFIX)(EA + 2, data >> 16);
+}
+PPC_SPE_ST_OP(whe_le, spe_stwhe_le);
+static inline uint64_t glue(spe_lwhou, MEMSUFFIX) (target_ulong EA)
+{
+    uint64_t ret;
+    ret = (uint64_t)glue(lduw, MEMSUFFIX)(EA) << 32;
+    ret |= (uint64_t)glue(lduw, MEMSUFFIX)(EA + 2);
+    return ret;
+}
+PPC_SPE_LD_OP(whou, spe_lwhou);
+static inline uint64_t glue(spe_lwhos, MEMSUFFIX) (target_ulong EA)
+{
+    uint64_t ret;
+    ret = ((uint64_t)((int32_t)glue(ldsw, MEMSUFFIX)(EA))) << 32;
+    ret |= (uint64_t)((int32_t)glue(ldsw, MEMSUFFIX)(EA + 2));
+    return ret;
+}
+PPC_SPE_LD_OP(whos, spe_lwhos);
+static inline void glue(spe_stwho, MEMSUFFIX) (target_ulong EA, uint64_t data)
+{
+    glue(stw, MEMSUFFIX)(EA, data >> 32);
+    glue(stw, MEMSUFFIX)(EA + 2, data);
+}
+PPC_SPE_ST_OP(who, spe_stwho);
+static inline uint64_t glue(spe_lwhou_le, MEMSUFFIX) (target_ulong EA)
+{
+    uint64_t ret;
+    ret = (uint64_t)glue(ld16r, MEMSUFFIX)(EA) << 32;
+    ret |= (uint64_t)glue(ld16r, MEMSUFFIX)(EA + 2);
+    return ret;
+}
+PPC_SPE_LD_OP(whou_le, spe_lwhou_le);
+static inline uint64_t glue(spe_lwhos_le, MEMSUFFIX) (target_ulong EA)
+{
+    uint64_t ret;
+    ret = ((uint64_t)((int32_t)glue(ld16rs, MEMSUFFIX)(EA))) << 32;
+    ret |= (uint64_t)((int32_t)glue(ld16rs, MEMSUFFIX)(EA + 2));
+    return ret;
+}
+PPC_SPE_LD_OP(whos_le, spe_lwhos_le);
+static inline void glue(spe_stwho_le, MEMSUFFIX) (target_ulong EA,
+                                                  uint64_t data)
+{
+    glue(st16r, MEMSUFFIX)(EA, data >> 32);
+    glue(st16r, MEMSUFFIX)(EA + 2, data);
+}
+PPC_SPE_ST_OP(who_le, spe_stwho_le);
+#if !defined(TARGET_PPC64)
+static inline void glue(spe_stwwo, MEMSUFFIX) (target_ulong EA, uint64_t data)
+{
+    glue(stl, MEMSUFFIX)(EA, data);
+}
+PPC_SPE_ST_OP(wwo, spe_stwwo);
+static inline void glue(spe_stwwo_le, MEMSUFFIX) (target_ulong EA,
+                                                 uint64_t data)
+{
+    glue(st32r, MEMSUFFIX)(EA, data);
+}
+PPC_SPE_ST_OP(wwo_le, spe_stwwo_le);
+#endif
+static inline uint64_t glue(spe_lh, MEMSUFFIX) (target_ulong EA)
+{
+    uint16_t tmp;
+    tmp = glue(lduw, MEMSUFFIX)(EA);
+    return ((uint64_t)tmp << 48) | ((uint64_t)tmp << 16);
+}
+PPC_SPE_LD_OP(h, spe_lh);
+static inline uint64_t glue(spe_lh_le, MEMSUFFIX) (target_ulong EA)
+{
+    uint16_t tmp;
+    tmp = glue(ld16r, MEMSUFFIX)(EA);
+    return ((uint64_t)tmp << 48) | ((uint64_t)tmp << 16);
+}
+PPC_SPE_LD_OP(h_le, spe_lh_le);
+static inline uint64_t glue(spe_lwwsplat, MEMSUFFIX) (target_ulong EA)
+{
+    uint32_t tmp;
+    tmp = glue(ldl, MEMSUFFIX)(EA);
+    return ((uint64_t)tmp << 32) | (uint64_t)tmp;
+}
+PPC_SPE_LD_OP(wwsplat, spe_lwwsplat);
+static inline uint64_t glue(spe_lwwsplat_le, MEMSUFFIX) (target_ulong EA)
+{
+    uint32_t tmp;
+    tmp = glue(ld32r, MEMSUFFIX)(EA);
+    return ((uint64_t)tmp << 32) | (uint64_t)tmp;
+}
+PPC_SPE_LD_OP(wwsplat_le, spe_lwwsplat_le);
+static inline uint64_t glue(spe_lwhsplat, MEMSUFFIX) (target_ulong EA)
+{
+    uint64_t ret;
+    uint16_t tmp;
+    tmp = glue(lduw, MEMSUFFIX)(EA);
+    ret = ((uint64_t)tmp << 48) | ((uint64_t)tmp << 32);
+    tmp = glue(lduw, MEMSUFFIX)(EA + 2);
+    ret |= ((uint64_t)tmp << 16) | (uint64_t)tmp;
+    return ret;
+}
+PPC_SPE_LD_OP(whsplat, spe_lwhsplat);
+static inline uint64_t glue(spe_lwhsplat_le, MEMSUFFIX) (target_ulong EA)
+{
+    uint64_t ret;
+    uint16_t tmp;
+    tmp = glue(ld16r, MEMSUFFIX)(EA);
+    ret = ((uint64_t)tmp << 48) | ((uint64_t)tmp << 32);
+    tmp = glue(ld16r, MEMSUFFIX)(EA + 2);
+    ret |= ((uint64_t)tmp << 16) | (uint64_t)tmp;
+    return ret;
+}
+PPC_SPE_LD_OP(whsplat_le, spe_lwhsplat_le);
+#endif /* defined(TARGET_PPCSPE) */
+
 #undef MEMSUFFIX
index 511d065..bcef1a5 100644 (file)
@@ -57,6 +57,48 @@ void OPPROTO glue(op_store_T2_gpr_gpr, REG) (void)
 }
 #endif
 
+#if defined(TARGET_PPCSPE)
+void OPPROTO glue(op_load_gpr64_T0_gpr, REG) (void)
+{
+    T0_64 = regs->gpr[REG];
+    RETURN();
+}
+
+void OPPROTO glue(op_load_gpr64_T1_gpr, REG) (void)
+{
+    T1_64 = regs->gpr[REG];
+    RETURN();
+}
+
+#if 0 // unused
+void OPPROTO glue(op_load_gpr64_T2_gpr, REG) (void)
+{
+    T2_64 = regs->gpr[REG];
+    RETURN();
+}
+#endif
+
+void OPPROTO glue(op_store_T0_gpr64_gpr, REG) (void)
+{
+    regs->gpr[REG] = T0_64;
+    RETURN();
+}
+
+void OPPROTO glue(op_store_T1_gpr64_gpr, REG) (void)
+{
+    regs->gpr[REG] = T1_64;
+    RETURN();
+}
+
+#if 0 // unused
+void OPPROTO glue(op_store_T2_gpr64_gpr, REG) (void)
+{
+    regs->gpr[REG] = T2_64;
+    RETURN();
+}
+#endif
+#endif /* defined(TARGET_PPCSPE) */
+
 #if REG <= 7
 /* Condition register moves */
 void OPPROTO glue(op_load_crf_T0_crf, REG) (void)
index d9be35d..90a9fc9 100644 (file)
@@ -160,6 +160,9 @@ typedef struct DisasContext {
     int sf_mode;
 #endif
     int fpu_enabled;
+#if defined(TARGET_PPCSPE)
+    int spe_enabled;
+#endif
     ppc_spr_t *spr_cb; /* Needed to check rights for mfspr/mtspr */
     int singlestep_enabled;
 } DisasContext;
@@ -168,7 +171,7 @@ struct opc_handler_t {
     /* invalid bits */
     uint32_t inval;
     /* instruction type */
-    uint32_t type;
+    uint64_t type;
     /* handler */
     void (*handler)(DisasContext *ctx);
 #if defined(DO_PPC_STATISTICS)
@@ -4468,6 +4471,814 @@ GEN_HANDLER(icbt_440, 0x1F, 0x16, 0x00, 0x03E00001, PPC_BOOKE)
      */
 }
 
+#if defined(TARGET_PPCSPE)
+/***                           SPE extension                               ***/
+
+/* Register moves */
+GEN32(gen_op_load_gpr64_T0, gen_op_load_gpr64_T0_gpr);
+GEN32(gen_op_load_gpr64_T1, gen_op_load_gpr64_T1_gpr);
+#if 0 // unused
+GEN32(gen_op_load_gpr64_T2, gen_op_load_gpr64_T2_gpr);
+#endif
+
+GEN32(gen_op_store_T0_gpr64, gen_op_store_T0_gpr64_gpr);
+GEN32(gen_op_store_T1_gpr64, gen_op_store_T1_gpr64_gpr);
+#if 0 // unused
+GEN32(gen_op_store_T2_gpr64, gen_op_store_T2_gpr64_gpr);
+#endif
+
+#define GEN_SPE(name0, name1, opc2, opc3, inval, type)                        \
+GEN_HANDLER(name0##_##name1, 0x04, opc2, opc3, inval, type)                   \
+{                                                                             \
+    if (Rc(ctx->opcode))                                                      \
+        gen_##name1(ctx);                                                     \
+    else                                                                      \
+        gen_##name0(ctx);                                                     \
+}
+
+/* Handler for undefined SPE opcodes */
+static inline void gen_speundef (DisasContext *ctx)
+{
+    RET_INVAL(ctx);
+}
+
+/* SPE load and stores */
+static inline void gen_addr_spe_imm_index (DisasContext *ctx, int sh)
+{
+    target_long simm = rB(ctx->opcode);
+
+    if (rA(ctx->opcode) == 0) {
+        gen_set_T0(simm << sh);
+    } else {
+        gen_op_load_gpr_T0(rA(ctx->opcode));
+        if (likely(simm != 0))
+            gen_op_addi(simm << sh);
+    }
+}
+
+#define op_spe_ldst(name)        (*gen_op_##name[ctx->mem_idx])()
+#if defined(CONFIG_USER_ONLY)
+#if defined(TARGET_PPC64)
+#define OP_SPE_LD_TABLE(name)                                                 \
+static GenOpFunc *gen_op_spe_l##name[] = {                                    \
+    &gen_op_spe_l##name##_raw,                                                \
+    &gen_op_spe_l##name##_le_raw,                                             \
+    &gen_op_spe_l##name##_64_raw,                                             \
+    &gen_op_spe_l##name##_le_64_raw,                                          \
+};
+#define OP_SPE_ST_TABLE(name)                                                 \
+static GenOpFunc *gen_op_spe_st##name[] = {                                   \
+    &gen_op_spe_st##name##_raw,                                               \
+    &gen_op_spe_st##name##_le_raw,                                            \
+    &gen_op_spe_st##name##_64_raw,                                            \
+    &gen_op_spe_st##name##_le_64_raw,                                         \
+};
+#else /* defined(TARGET_PPC64) */
+#define OP_SPE_LD_TABLE(name)                                                 \
+static GenOpFunc *gen_op_spe_l##name[] = {                                    \
+    &gen_op_spe_l##name##_raw,                                                \
+    &gen_op_spe_l##name##_le_raw,                                             \
+};
+#define OP_SPE_ST_TABLE(name)                                                 \
+static GenOpFunc *gen_op_spe_st##name[] = {                                   \
+    &gen_op_spe_st##name##_raw,                                               \
+    &gen_op_spe_st##name##_le_raw,                                            \
+};
+#endif /* defined(TARGET_PPC64) */
+#else /* defined(CONFIG_USER_ONLY) */
+#if defined(TARGET_PPC64)
+#define OP_SPE_LD_TABLE(name)                                                 \
+static GenOpFunc *gen_op_spe_l##name[] = {                                    \
+    &gen_op_spe_l##name##_user,                                               \
+    &gen_op_spe_l##name##_le_user,                                            \
+    &gen_op_spe_l##name##_kernel,                                             \
+    &gen_op_spe_l##name##_le_kernel,                                          \
+    &gen_op_spe_l##name##_64_user,                                            \
+    &gen_op_spe_l##name##_le_64_user,                                         \
+    &gen_op_spe_l##name##_64_kernel,                                          \
+    &gen_op_spe_l##name##_le_64_kernel,                                       \
+};
+#define OP_SPE_ST_TABLE(name)                                                 \
+static GenOpFunc *gen_op_spe_st##name[] = {                                   \
+    &gen_op_spe_st##name##_user,                                              \
+    &gen_op_spe_st##name##_le_user,                                           \
+    &gen_op_spe_st##name##_kernel,                                            \
+    &gen_op_spe_st##name##_le_kernel,                                         \
+    &gen_op_spe_st##name##_64_user,                                           \
+    &gen_op_spe_st##name##_le_64_user,                                        \
+    &gen_op_spe_st##name##_64_kernel,                                         \
+    &gen_op_spe_st##name##_le_64_kernel,                                      \
+};
+#else /* defined(TARGET_PPC64) */
+#define OP_SPE_LD_TABLE(name)                                                 \
+static GenOpFunc *gen_op_spe_l##name[] = {                                    \
+    &gen_op_spe_l##name##_user,                                               \
+    &gen_op_spe_l##name##_le_user,                                            \
+    &gen_op_spe_l##name##_kernel,                                             \
+    &gen_op_spe_l##name##_le_kernel,                                          \
+};
+#define OP_SPE_ST_TABLE(name)                                                 \
+static GenOpFunc *gen_op_spe_st##name[] = {                                   \
+    &gen_op_spe_st##name##_user,                                              \
+    &gen_op_spe_st##name##_le_user,                                           \
+    &gen_op_spe_st##name##_kernel,                                            \
+    &gen_op_spe_st##name##_le_kernel,                                         \
+};
+#endif /* defined(TARGET_PPC64) */
+#endif /* defined(CONFIG_USER_ONLY) */
+
+#define GEN_SPE_LD(name, sh)                                                  \
+static inline void gen_evl##name (DisasContext *ctx)                          \
+{                                                                             \
+    if (unlikely(!ctx->spe_enabled)) {                                        \
+        RET_EXCP(ctx, EXCP_NO_SPE, 0);                                        \
+        return;                                                               \
+    }                                                                         \
+    gen_addr_spe_imm_index(ctx, sh);                                          \
+    op_spe_ldst(spe_l##name);                                                 \
+    gen_op_store_T1_gpr64(rD(ctx->opcode));                                   \
+}
+
+#define GEN_SPE_LDX(name)                                                     \
+static inline void gen_evl##name##x (DisasContext *ctx)                       \
+{                                                                             \
+    if (unlikely(!ctx->spe_enabled)) {                                        \
+        RET_EXCP(ctx, EXCP_NO_SPE, 0);                                        \
+        return;                                                               \
+    }                                                                         \
+    gen_addr_reg_index(ctx);                                                  \
+    op_spe_ldst(spe_l##name);                                                 \
+    gen_op_store_T1_gpr64(rD(ctx->opcode));                                   \
+}
+
+#define GEN_SPEOP_LD(name, sh)                                                \
+OP_SPE_LD_TABLE(name);                                                        \
+GEN_SPE_LD(name, sh);                                                         \
+GEN_SPE_LDX(name)
+
+#define GEN_SPE_ST(name, sh)                                                  \
+static inline void gen_evst##name (DisasContext *ctx)                         \
+{                                                                             \
+    if (unlikely(!ctx->spe_enabled)) {                                        \
+        RET_EXCP(ctx, EXCP_NO_SPE, 0);                                        \
+        return;                                                               \
+    }                                                                         \
+    gen_addr_spe_imm_index(ctx, sh);                                          \
+    gen_op_load_gpr64_T1(rS(ctx->opcode));                                    \
+    op_spe_ldst(spe_st##name);                                                \
+}
+
+#define GEN_SPE_STX(name)                                                     \
+static inline void gen_evst##name##x (DisasContext *ctx)                      \
+{                                                                             \
+    if (unlikely(!ctx->spe_enabled)) {                                        \
+        RET_EXCP(ctx, EXCP_NO_SPE, 0);                                        \
+        return;                                                               \
+    }                                                                         \
+    gen_addr_reg_index(ctx);                                                  \
+    gen_op_load_gpr64_T1(rS(ctx->opcode));                                    \
+    op_spe_ldst(spe_st##name);                                                \
+}
+
+#define GEN_SPEOP_ST(name, sh)                                                \
+OP_SPE_ST_TABLE(name);                                                        \
+GEN_SPE_ST(name, sh);                                                         \
+GEN_SPE_STX(name)
+
+#define GEN_SPEOP_LDST(name, sh)                                              \
+GEN_SPEOP_LD(name, sh);                                                       \
+GEN_SPEOP_ST(name, sh)
+
+/* SPE arithmetic and logic */
+#define GEN_SPEOP_ARITH2(name)                                                \
+static inline void gen_##name (DisasContext *ctx)                             \
+{                                                                             \
+    if (unlikely(!ctx->spe_enabled)) {                                        \
+        RET_EXCP(ctx, EXCP_NO_SPE, 0);                                        \
+        return;                                                               \
+    }                                                                         \
+    gen_op_load_gpr64_T0(rA(ctx->opcode));                                    \
+    gen_op_load_gpr64_T1(rB(ctx->opcode));                                    \
+    gen_op_##name();                                                          \
+    gen_op_store_T0_gpr64(rD(ctx->opcode));                                   \
+}
+
+#define GEN_SPEOP_ARITH1(name)                                                \
+static inline void gen_##name (DisasContext *ctx)                             \
+{                                                                             \
+    if (unlikely(!ctx->spe_enabled)) {                                        \
+        RET_EXCP(ctx, EXCP_NO_SPE, 0);                                        \
+        return;                                                               \
+    }                                                                         \
+    gen_op_load_gpr64_T0(rA(ctx->opcode));                                    \
+    gen_op_##name();                                                          \
+    gen_op_store_T0_gpr64(rD(ctx->opcode));                                   \
+}
+
+#define GEN_SPEOP_COMP(name)                                                  \
+static inline void gen_##name (DisasContext *ctx)                             \
+{                                                                             \
+    if (unlikely(!ctx->spe_enabled)) {                                        \
+        RET_EXCP(ctx, EXCP_NO_SPE, 0);                                        \
+        return;                                                               \
+    }                                                                         \
+    gen_op_load_gpr64_T0(rA(ctx->opcode));                                    \
+    gen_op_load_gpr64_T1(rB(ctx->opcode));                                    \
+    gen_op_##name();                                                          \
+    gen_op_store_T0_crf(crfD(ctx->opcode));                                   \
+}
+
+/* Logical */
+GEN_SPEOP_ARITH2(evand);
+GEN_SPEOP_ARITH2(evandc);
+GEN_SPEOP_ARITH2(evxor);
+GEN_SPEOP_ARITH2(evor);
+GEN_SPEOP_ARITH2(evnor);
+GEN_SPEOP_ARITH2(eveqv);
+GEN_SPEOP_ARITH2(evorc);
+GEN_SPEOP_ARITH2(evnand);
+GEN_SPEOP_ARITH2(evsrwu);
+GEN_SPEOP_ARITH2(evsrws);
+GEN_SPEOP_ARITH2(evslw);
+GEN_SPEOP_ARITH2(evrlw);
+GEN_SPEOP_ARITH2(evmergehi);
+GEN_SPEOP_ARITH2(evmergelo);
+GEN_SPEOP_ARITH2(evmergehilo);
+GEN_SPEOP_ARITH2(evmergelohi);
+
+/* Arithmetic */
+GEN_SPEOP_ARITH2(evaddw);
+GEN_SPEOP_ARITH2(evsubfw);
+GEN_SPEOP_ARITH1(evabs);
+GEN_SPEOP_ARITH1(evneg);
+GEN_SPEOP_ARITH1(evextsb);
+GEN_SPEOP_ARITH1(evextsh);
+GEN_SPEOP_ARITH1(evrndw);
+GEN_SPEOP_ARITH1(evcntlzw);
+GEN_SPEOP_ARITH1(evcntlsw);
+static inline void gen_brinc (DisasContext *ctx)
+{
+    /* Note: brinc is usable even if SPE is disabled */
+    gen_op_load_gpr64_T0(rA(ctx->opcode));
+    gen_op_load_gpr64_T1(rB(ctx->opcode));
+    gen_op_brinc();
+    gen_op_store_T0_gpr64(rD(ctx->opcode));
+}
+
+#define GEN_SPEOP_ARITH_IMM2(name)                                            \
+static inline void gen_##name##i (DisasContext *ctx)                          \
+{                                                                             \
+    if (unlikely(!ctx->spe_enabled)) {                                        \
+        RET_EXCP(ctx, EXCP_NO_SPE, 0);                                        \
+        return;                                                               \
+    }                                                                         \
+    gen_op_load_gpr64_T0(rB(ctx->opcode));                                    \
+    gen_op_splatwi_T1_64(rA(ctx->opcode));                                    \
+    gen_op_##name();                                                          \
+    gen_op_store_T0_gpr64(rD(ctx->opcode));                                   \
+}
+
+#define GEN_SPEOP_LOGIC_IMM2(name)                                            \
+static inline void gen_##name##i (DisasContext *ctx)                          \
+{                                                                             \
+    if (unlikely(!ctx->spe_enabled)) {                                        \
+        RET_EXCP(ctx, EXCP_NO_SPE, 0);                                        \
+        return;                                                               \
+    }                                                                         \
+    gen_op_load_gpr64_T0(rA(ctx->opcode));                                    \
+    gen_op_splatwi_T1_64(rB(ctx->opcode));                                    \
+    gen_op_##name();                                                          \
+    gen_op_store_T0_gpr64(rD(ctx->opcode));                                   \
+}
+
+GEN_SPEOP_ARITH_IMM2(evaddw);
+#define gen_evaddiw gen_evaddwi
+GEN_SPEOP_ARITH_IMM2(evsubfw);
+#define gen_evsubifw gen_evsubfwi
+GEN_SPEOP_LOGIC_IMM2(evslw);
+GEN_SPEOP_LOGIC_IMM2(evsrwu);
+#define gen_evsrwis gen_evsrwsi
+GEN_SPEOP_LOGIC_IMM2(evsrws);
+#define gen_evsrwiu gen_evsrwui
+GEN_SPEOP_LOGIC_IMM2(evrlw);
+
+static inline void gen_evsplati (DisasContext *ctx)
+{
+    int32_t imm = (int32_t)(rA(ctx->opcode) << 27) >> 27;
+
+    gen_op_splatwi_T0_64(imm);
+    gen_op_store_T0_gpr64(rD(ctx->opcode));
+}
+
+static inline void gen_evsplatfi (DisasContext *ctx)
+{
+    uint32_t imm = rA(ctx->opcode) << 27;
+
+    gen_op_splatwi_T0_64(imm);
+    gen_op_store_T0_gpr64(rD(ctx->opcode));
+}
+
+/* Comparison */
+GEN_SPEOP_COMP(evcmpgtu);
+GEN_SPEOP_COMP(evcmpgts);
+GEN_SPEOP_COMP(evcmpltu);
+GEN_SPEOP_COMP(evcmplts);
+GEN_SPEOP_COMP(evcmpeq);
+
+GEN_SPE(evaddw,         speundef,      0x00, 0x08, 0x00000000, PPC_SPE); ////
+GEN_SPE(evaddiw,        speundef,      0x01, 0x08, 0x00000000, PPC_SPE);
+GEN_SPE(evsubfw,        speundef,      0x02, 0x08, 0x00000000, PPC_SPE); ////
+GEN_SPE(evsubifw,       speundef,      0x03, 0x08, 0x00000000, PPC_SPE);
+GEN_SPE(evabs,          evneg,         0x04, 0x08, 0x0000F800, PPC_SPE); ////
+GEN_SPE(evextsb,        evextsh,       0x05, 0x08, 0x0000F800, PPC_SPE); ////
+GEN_SPE(evrndw,         evcntlzw,      0x06, 0x08, 0x0000F800, PPC_SPE); ////
+GEN_SPE(evcntlsw,       brinc,         0x07, 0x08, 0x00000000, PPC_SPE); //
+GEN_SPE(speundef,       evand,         0x08, 0x08, 0x00000000, PPC_SPE); ////
+GEN_SPE(evandc,         speundef,      0x09, 0x08, 0x00000000, PPC_SPE); ////
+GEN_SPE(evxor,          evor,          0x0B, 0x08, 0x00000000, PPC_SPE); ////
+GEN_SPE(evnor,          eveqv,         0x0C, 0x08, 0x00000000, PPC_SPE); ////
+GEN_SPE(speundef,       evorc,         0x0D, 0x08, 0x00000000, PPC_SPE); ////
+GEN_SPE(evnand,         speundef,      0x0F, 0x08, 0x00000000, PPC_SPE); ////
+GEN_SPE(evsrwu,         evsrws,        0x10, 0x08, 0x00000000, PPC_SPE); ////
+GEN_SPE(evsrwiu,        evsrwis,       0x11, 0x08, 0x00000000, PPC_SPE);
+GEN_SPE(evslw,          speundef,      0x12, 0x08, 0x00000000, PPC_SPE); ////
+GEN_SPE(evslwi,         speundef,      0x13, 0x08, 0x00000000, PPC_SPE);
+GEN_SPE(evrlw,          evsplati,      0x14, 0x08, 0x00000000, PPC_SPE); //
+GEN_SPE(evrlwi,         evsplatfi,     0x15, 0x08, 0x00000000, PPC_SPE);
+GEN_SPE(evmergehi,      evmergelo,     0x16, 0x08, 0x00000000, PPC_SPE); ////
+GEN_SPE(evmergehilo,    evmergelohi,   0x17, 0x08, 0x00000000, PPC_SPE); ////
+GEN_SPE(evcmpgtu,       evcmpgts,      0x18, 0x08, 0x00600000, PPC_SPE); ////
+GEN_SPE(evcmpltu,       evcmplts,      0x19, 0x08, 0x00600000, PPC_SPE); ////
+GEN_SPE(evcmpeq,        speundef,      0x1A, 0x08, 0x00600000, PPC_SPE); ////
+
+static inline void gen_evsel (DisasContext *ctx)
+{
+    if (unlikely(!ctx->spe_enabled)) {
+        RET_EXCP(ctx, EXCP_NO_SPE, 0);
+        return;
+    }
+    gen_op_load_crf_T0(ctx->opcode & 0x7);
+    gen_op_load_gpr64_T0(rA(ctx->opcode));
+    gen_op_load_gpr64_T1(rB(ctx->opcode));
+    gen_op_evsel();
+    gen_op_store_T0_gpr64(rD(ctx->opcode));
+}
+
+GEN_HANDLER(evsel0, 0x04, 0x1c, 0x09, 0x00000000, PPC_SPE)
+{
+    gen_evsel(ctx);
+}
+GEN_HANDLER(evsel1, 0x04, 0x1d, 0x09, 0x00000000, PPC_SPE)
+{
+    gen_evsel(ctx);
+}
+GEN_HANDLER(evsel2, 0x04, 0x1e, 0x09, 0x00000000, PPC_SPE)
+{
+    gen_evsel(ctx);
+}
+GEN_HANDLER(evsel3, 0x04, 0x1f, 0x09, 0x00000000, PPC_SPE)
+{
+    gen_evsel(ctx);
+}
+
+/* Load and stores */
+#if defined(TARGET_PPC64)
+/* In that case, we already have 64 bits load & stores
+ * so, spe_ldd is equivalent to ld and spe_std is equivalent to std
+ */
+#if defined(CONFIG_USER_ONLY)
+#define gen_op_spe_ldd_raw gen_op_ld_raw
+#define gen_op_spe_ldd_64_raw gen_op_ld_64_raw
+#define gen_op_spe_ldd_le_raw gen_op_ld_le_raw
+#define gen_op_spe_ldd_le_64_raw gen_op_ld_le_64_raw
+#define gen_op_spe_stdd_raw gen_op_ld_raw
+#define gen_op_spe_stdd_64_raw gen_op_std_64_raw
+#define gen_op_spe_stdd_le_raw gen_op_std_le_raw
+#define gen_op_spe_stdd_le_64_raw gen_op_std_le_64_raw
+#else /* defined(CONFIG_USER_ONLY) */
+#define gen_op_spe_ldd_kernel gen_op_ld_kernel
+#define gen_op_spe_ldd_64_kernel gen_op_ld_64_kernel
+#define gen_op_spe_ldd_le_kernel gen_op_ld_kernel
+#define gen_op_spe_ldd_le_64_kernel gen_op_ld_64_kernel
+#define gen_op_spe_ldd_user gen_op_ld_user
+#define gen_op_spe_ldd_64_user gen_op_ld_64_user
+#define gen_op_spe_ldd_le_user gen_op_ld_le_user
+#define gen_op_spe_ldd_le_64_user gen_op_ld_le_64_user
+#define gen_op_spe_stdd_kernel gen_op_std_kernel
+#define gen_op_spe_stdd_64_kernel gen_op_std_64_kernel
+#define gen_op_spe_stdd_le_kernel gen_op_std_kernel
+#define gen_op_spe_stdd_le_64_kernel gen_op_std_64_kernel
+#define gen_op_spe_stdd_user gen_op_std_user
+#define gen_op_spe_stdd_64_user gen_op_std_64_user
+#define gen_op_spe_stdd_le_user gen_op_std_le_user
+#define gen_op_spe_stdd_le_64_user gen_op_std_le_64_user
+#endif /* defined(CONFIG_USER_ONLY) */
+#endif /* defined(TARGET_PPC64) */
+GEN_SPEOP_LDST(dd, 3);
+GEN_SPEOP_LDST(dw, 3);
+GEN_SPEOP_LDST(dh, 3);
+GEN_SPEOP_LDST(whe, 2);
+GEN_SPEOP_LD(whou, 2);
+GEN_SPEOP_LD(whos, 2);
+GEN_SPEOP_ST(who, 2);
+
+#if defined(TARGET_PPC64)
+/* In that case, spe_stwwo is equivalent to stw */
+#if defined(CONFIG_USER_ONLY)
+#define gen_op_spe_stwwo_raw gen_op_stw_raw
+#define gen_op_spe_stwwo_le_raw gen_op_stw_le_raw
+#define gen_op_spe_stwwo_64_raw gen_op_stw_64_raw
+#define gen_op_spe_stwwo_le_64_raw gen_op_stw_le_64_raw
+#else
+#define gen_op_spe_stwwo_user gen_op_stw_user
+#define gen_op_spe_stwwo_le_user gen_op_stw_le_user
+#define gen_op_spe_stwwo_64_user gen_op_stw_64_user
+#define gen_op_spe_stwwo_le_64_user gen_op_stw_le_64_user
+#define gen_op_spe_stwwo_kernel gen_op_stw_kernel
+#define gen_op_spe_stwwo_le_kernel gen_op_stw_le_kernel
+#define gen_op_spe_stwwo_64_kernel gen_op_stw_64_kernel
+#define gen_op_spe_stwwo_le_64_kernel gen_op_stw_le_64_kernel
+#endif
+#endif
+#define _GEN_OP_SPE_STWWE(suffix)                                             \
+static inline void gen_op_spe_stwwe_##suffix (void)                           \
+{                                                                             \
+    gen_op_srli32_T1_64();                                                    \
+    gen_op_spe_stwwo_##suffix();                                              \
+}
+#define _GEN_OP_SPE_STWWE_LE(suffix)                                          \
+static inline void gen_op_spe_stwwe_le_##suffix (void)                        \
+{                                                                             \
+    gen_op_srli32_T1_64();                                                    \
+    gen_op_spe_stwwo_le_##suffix();                                           \
+}
+#if defined(TARGET_PPC64)
+#define GEN_OP_SPE_STWWE(suffix)                                              \
+_GEN_OP_SPE_STWWE(suffix);                                                    \
+_GEN_OP_SPE_STWWE_LE(suffix);                                                 \
+static inline void gen_op_spe_stwwe_64_##suffix (void)                        \
+{                                                                             \
+    gen_op_srli32_T1_64();                                                    \
+    gen_op_spe_stwwo_64_##suffix();                                           \
+}                                                                             \
+static inline void gen_op_spe_stwwe_le_64_##suffix (void)                     \
+{                                                                             \
+    gen_op_srli32_T1_64();                                                    \
+    gen_op_spe_stwwo_le_64_##suffix();                                        \
+}
+#else
+#define GEN_OP_SPE_STWWE(suffix)                                              \
+_GEN_OP_SPE_STWWE(suffix);                                                    \
+_GEN_OP_SPE_STWWE_LE(suffix)
+#endif
+#if defined(CONFIG_USER_ONLY)
+GEN_OP_SPE_STWWE(raw);
+#else /* defined(CONFIG_USER_ONLY) */
+GEN_OP_SPE_STWWE(kernel);
+GEN_OP_SPE_STWWE(user);
+#endif /* defined(CONFIG_USER_ONLY) */
+GEN_SPEOP_ST(wwe, 2);
+GEN_SPEOP_ST(wwo, 2);
+
+#define GEN_SPE_LDSPLAT(name, op, suffix)                                     \
+static inline void gen_op_spe_l##name##_##suffix (void)                       \
+{                                                                             \
+    gen_op_##op##_##suffix();                                                 \
+    gen_op_splatw_T1_64();                                                    \
+}
+
+#define GEN_OP_SPE_LHE(suffix)                                                \
+static inline void gen_op_spe_lhe_##suffix (void)                             \
+{                                                                             \
+    gen_op_spe_lh_##suffix();                                                 \
+    gen_op_sli16_T1_64();                                                     \
+}
+
+#define GEN_OP_SPE_LHX(suffix)                                                \
+static inline void gen_op_spe_lhx_##suffix (void)                             \
+{                                                                             \
+    gen_op_spe_lh_##suffix();                                                 \
+    gen_op_extsh_T1_64();                                                     \
+}
+
+#if defined(CONFIG_USER_ONLY)
+GEN_OP_SPE_LHE(raw);
+GEN_SPE_LDSPLAT(hhesplat, spe_lhe, raw);
+GEN_OP_SPE_LHE(le_raw);
+GEN_SPE_LDSPLAT(hhesplat, spe_lhe, le_raw);
+GEN_SPE_LDSPLAT(hhousplat, spe_lh, raw);
+GEN_SPE_LDSPLAT(hhousplat, spe_lh, le_raw);
+GEN_OP_SPE_LHX(raw);
+GEN_SPE_LDSPLAT(hhossplat, spe_lhx, raw);
+GEN_OP_SPE_LHX(le_raw);
+GEN_SPE_LDSPLAT(hhossplat, spe_lhx, le_raw);
+#if defined(TARGET_PPC64)
+GEN_OP_SPE_LHE(64_raw);
+GEN_SPE_LDSPLAT(hhesplat, spe_lhe, 64_raw);
+GEN_OP_SPE_LHE(le_64_raw);
+GEN_SPE_LDSPLAT(hhesplat, spe_lhe, le_64_raw);
+GEN_SPE_LDSPLAT(hhousplat, spe_lh, 64_raw);
+GEN_SPE_LDSPLAT(hhousplat, spe_lh, le_64_raw);
+GEN_OP_SPE_LHX(64_raw);
+GEN_SPE_LDSPLAT(hhossplat, spe_lhx, 64_raw);
+GEN_OP_SPE_LHX(le_64_raw);
+GEN_SPE_LDSPLAT(hhossplat, spe_lhx, le_64_raw);
+#endif
+#else
+GEN_OP_SPE_LHE(kernel);
+GEN_OP_SPE_LHE(user);
+GEN_SPE_LDSPLAT(hhesplat, spe_lhe, kernel);
+GEN_SPE_LDSPLAT(hhesplat, spe_lhe, user);
+GEN_OP_SPE_LHE(le_kernel);
+GEN_OP_SPE_LHE(le_user);
+GEN_SPE_LDSPLAT(hhesplat, spe_lhe, le_kernel);
+GEN_SPE_LDSPLAT(hhesplat, spe_lhe, le_user);
+GEN_SPE_LDSPLAT(hhousplat, spe_lh, kernel);
+GEN_SPE_LDSPLAT(hhousplat, spe_lh, user);
+GEN_SPE_LDSPLAT(hhousplat, spe_lh, le_kernel);
+GEN_SPE_LDSPLAT(hhousplat, spe_lh, le_user);
+GEN_OP_SPE_LHX(kernel);
+GEN_OP_SPE_LHX(user);
+GEN_SPE_LDSPLAT(hhossplat, spe_lhx, kernel);
+GEN_SPE_LDSPLAT(hhossplat, spe_lhx, user);
+GEN_OP_SPE_LHX(le_kernel);
+GEN_OP_SPE_LHX(le_user);
+GEN_SPE_LDSPLAT(hhossplat, spe_lhx, le_kernel);
+GEN_SPE_LDSPLAT(hhossplat, spe_lhx, le_user);
+#if defined(TARGET_PPC64)
+GEN_OP_SPE_LHE(64_kernel);
+GEN_OP_SPE_LHE(64_user);
+GEN_SPE_LDSPLAT(hhesplat, spe_lhe, 64_kernel);
+GEN_SPE_LDSPLAT(hhesplat, spe_lhe, 64_user);
+GEN_OP_SPE_LHE(le_64_kernel);
+GEN_OP_SPE_LHE(le_64_user);
+GEN_SPE_LDSPLAT(hhesplat, spe_lhe, le_64_kernel);
+GEN_SPE_LDSPLAT(hhesplat, spe_lhe, le_64_user);
+GEN_SPE_LDSPLAT(hhousplat, spe_lh, 64_kernel);
+GEN_SPE_LDSPLAT(hhousplat, spe_lh, 64_user);
+GEN_SPE_LDSPLAT(hhousplat, spe_lh, le_64_kernel);
+GEN_SPE_LDSPLAT(hhousplat, spe_lh, le_64_user);
+GEN_OP_SPE_LHX(64_kernel);
+GEN_OP_SPE_LHX(64_user);
+GEN_SPE_LDSPLAT(hhossplat, spe_lhx, 64_kernel);
+GEN_SPE_LDSPLAT(hhossplat, spe_lhx, 64_user);
+GEN_OP_SPE_LHX(le_64_kernel);
+GEN_OP_SPE_LHX(le_64_user);
+GEN_SPE_LDSPLAT(hhossplat, spe_lhx, le_64_kernel);
+GEN_SPE_LDSPLAT(hhossplat, spe_lhx, le_64_user);
+#endif
+#endif
+GEN_SPEOP_LD(hhesplat, 1);
+GEN_SPEOP_LD(hhousplat, 1);
+GEN_SPEOP_LD(hhossplat, 1);
+GEN_SPEOP_LD(wwsplat, 2);
+GEN_SPEOP_LD(whsplat, 2);
+
+GEN_SPE(evlddx,         evldd,         0x00, 0x0C, 0x00000000, PPC_SPE); //
+GEN_SPE(evldwx,         evldw,         0x01, 0x0C, 0x00000000, PPC_SPE); //
+GEN_SPE(evldhx,         evldh,         0x02, 0x0C, 0x00000000, PPC_SPE); //
+GEN_SPE(evlhhesplatx,   evlhhesplat,   0x04, 0x0C, 0x00000000, PPC_SPE); //
+GEN_SPE(evlhhousplatx,  evlhhousplat,  0x06, 0x0C, 0x00000000, PPC_SPE); //
+GEN_SPE(evlhhossplatx,  evlhhossplat,  0x07, 0x0C, 0x00000000, PPC_SPE); //
+GEN_SPE(evlwhex,        evlwhe,        0x08, 0x0C, 0x00000000, PPC_SPE); //
+GEN_SPE(evlwhoux,       evlwhou,       0x0A, 0x0C, 0x00000000, PPC_SPE); //
+GEN_SPE(evlwhosx,       evlwhos,       0x0B, 0x0C, 0x00000000, PPC_SPE); //
+GEN_SPE(evlwwsplatx,    evlwwsplat,    0x0C, 0x0C, 0x00000000, PPC_SPE); //
+GEN_SPE(evlwhsplatx,    evlwhsplat,    0x0E, 0x0C, 0x00000000, PPC_SPE); //
+GEN_SPE(evstddx,        evstdd,        0x10, 0x0C, 0x00000000, PPC_SPE); //
+GEN_SPE(evstdwx,        evstdw,        0x11, 0x0C, 0x00000000, PPC_SPE); //
+GEN_SPE(evstdhx,        evstdh,        0x12, 0x0C, 0x00000000, PPC_SPE); //
+GEN_SPE(evstwhex,       evstwhe,       0x18, 0x0C, 0x00000000, PPC_SPE); //
+GEN_SPE(evstwhox,       evstwho,       0x1A, 0x0C, 0x00000000, PPC_SPE); //
+GEN_SPE(evstwwex,       evstwwe,       0x1C, 0x0C, 0x00000000, PPC_SPE); //
+GEN_SPE(evstwwox,       evstwwo,       0x1E, 0x0C, 0x00000000, PPC_SPE); //
+
+/* Multiply and add - TODO */
+#if 0
+GEN_SPE(speundef,       evmhessf,      0x01, 0x10, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhossf,      0x03, 0x10, 0x00000000, PPC_SPE);
+GEN_SPE(evmheumi,       evmhesmi,      0x04, 0x10, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhesmf,      0x05, 0x10, 0x00000000, PPC_SPE);
+GEN_SPE(evmhoumi,       evmhosmi,      0x06, 0x10, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhosmf,      0x07, 0x10, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhessfa,     0x11, 0x10, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhossfa,     0x13, 0x10, 0x00000000, PPC_SPE);
+GEN_SPE(evmheumia,      evmhesmia,     0x14, 0x10, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhesmfa,     0x15, 0x10, 0x00000000, PPC_SPE);
+GEN_SPE(evmhoumia,      evmhosmia,     0x16, 0x10, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhosmfa,     0x17, 0x10, 0x00000000, PPC_SPE);
+
+GEN_SPE(speundef,       evmwhssf,      0x03, 0x11, 0x00000000, PPC_SPE);
+GEN_SPE(evmwlumi,       speundef,      0x04, 0x11, 0x00000000, PPC_SPE);
+GEN_SPE(evmwhumi,       evmwhsmi,      0x06, 0x11, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmwhsmf,      0x07, 0x11, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmwssf,       0x09, 0x11, 0x00000000, PPC_SPE);
+GEN_SPE(evmwumi,        evmwsmi,       0x0C, 0x11, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmwsmf,       0x0D, 0x11, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmwhssfa,     0x13, 0x11, 0x00000000, PPC_SPE);
+GEN_SPE(evmwlumia,      speundef,      0x14, 0x11, 0x00000000, PPC_SPE);
+GEN_SPE(evmwhumia,      evmwhsmia,     0x16, 0x11, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmwhsmfa,     0x17, 0x11, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmwssfa,      0x19, 0x11, 0x00000000, PPC_SPE);
+GEN_SPE(evmwumia,       evmwsmia,      0x1C, 0x11, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmwsmfa,      0x1D, 0x11, 0x00000000, PPC_SPE);
+
+GEN_SPE(evadduiaaw,     evaddsiaaw,    0x00, 0x13, 0x0000F800, PPC_SPE);
+GEN_SPE(evsubfusiaaw,   evsubfssiaaw,  0x01, 0x13, 0x0000F800, PPC_SPE);
+GEN_SPE(evaddumiaaw,    evaddsmiaaw,   0x04, 0x13, 0x0000F800, PPC_SPE);
+GEN_SPE(evsubfumiaaw,   evsubfsmiaaw,  0x05, 0x13, 0x0000F800, PPC_SPE);
+GEN_SPE(evdivws,        evdivwu,       0x06, 0x13, 0x00000000, PPC_SPE);
+GEN_SPE(evmra,          speundef,      0x07, 0x13, 0x0000F800, PPC_SPE);
+
+GEN_SPE(evmheusiaaw,    evmhessiaaw,   0x00, 0x14, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhessfaaw,   0x01, 0x14, 0x00000000, PPC_SPE);
+GEN_SPE(evmhousiaaw,    evmhossiaaw,   0x02, 0x14, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhossfaaw,   0x03, 0x14, 0x00000000, PPC_SPE);
+GEN_SPE(evmheumiaaw,    evmhesmiaaw,   0x04, 0x14, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhesmfaaw,   0x05, 0x14, 0x00000000, PPC_SPE);
+GEN_SPE(evmhoumiaaw,    evmhosmiaaw,   0x06, 0x14, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhosmfaaw,   0x07, 0x14, 0x00000000, PPC_SPE);
+GEN_SPE(evmhegumiaa,    evmhegsmiaa,   0x14, 0x14, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhegsmfaa,   0x15, 0x14, 0x00000000, PPC_SPE);
+GEN_SPE(evmhogumiaa,    evmhogsmiaa,   0x16, 0x14, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhogsmfaa,   0x17, 0x14, 0x00000000, PPC_SPE);
+
+GEN_SPE(evmwlusiaaw,    evmwlssiaaw,   0x00, 0x15, 0x00000000, PPC_SPE);
+GEN_SPE(evmwlumiaaw,    evmwlsmiaaw,   0x04, 0x15, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmwssfaa,     0x09, 0x15, 0x00000000, PPC_SPE);
+GEN_SPE(evmwumiaa,      evmwsmiaa,     0x0C, 0x15, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmwsmfaa,     0x0D, 0x15, 0x00000000, PPC_SPE);
+
+GEN_SPE(evmheusianw,    evmhessianw,   0x00, 0x16, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhessfanw,   0x01, 0x16, 0x00000000, PPC_SPE);
+GEN_SPE(evmhousianw,    evmhossianw,   0x02, 0x16, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhossfanw,   0x03, 0x16, 0x00000000, PPC_SPE);
+GEN_SPE(evmheumianw,    evmhesmianw,   0x04, 0x16, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhesmfanw,   0x05, 0x16, 0x00000000, PPC_SPE);
+GEN_SPE(evmhoumianw,    evmhosmianw,   0x06, 0x16, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhosmfanw,   0x07, 0x16, 0x00000000, PPC_SPE);
+GEN_SPE(evmhegumian,    evmhegsmian,   0x14, 0x16, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhegsmfan,   0x15, 0x16, 0x00000000, PPC_SPE);
+GEN_SPE(evmhigumian,    evmhigsmian,   0x16, 0x16, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhogsmfan,   0x17, 0x16, 0x00000000, PPC_SPE);
+
+GEN_SPE(evmwlusianw,    evmwlssianw,   0x00, 0x17, 0x00000000, PPC_SPE);
+GEN_SPE(evmwlumianw,    evmwlsmianw,   0x04, 0x17, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmwssfan,     0x09, 0x17, 0x00000000, PPC_SPE);
+GEN_SPE(evmwumian,      evmwsmian,     0x0C, 0x17, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmwsmfan,     0x0D, 0x17, 0x00000000, PPC_SPE);
+#endif
+
+/***                      SPE floating-point extension                     ***/
+#define GEN_SPEFPUOP_CONV(name)                                               \
+static inline void gen_##name (DisasContext *ctx)                             \
+{                                                                             \
+    gen_op_load_gpr64_T0(rB(ctx->opcode));                                    \
+    gen_op_##name();                                                          \
+    gen_op_store_T0_gpr64(rD(ctx->opcode));                                   \
+}
+
+/* Single precision floating-point vectors operations */
+/* Arithmetic */
+GEN_SPEOP_ARITH2(evfsadd);
+GEN_SPEOP_ARITH2(evfssub);
+GEN_SPEOP_ARITH2(evfsmul);
+GEN_SPEOP_ARITH2(evfsdiv);
+GEN_SPEOP_ARITH1(evfsabs);
+GEN_SPEOP_ARITH1(evfsnabs);
+GEN_SPEOP_ARITH1(evfsneg);
+/* Conversion */
+GEN_SPEFPUOP_CONV(evfscfui);
+GEN_SPEFPUOP_CONV(evfscfsi);
+GEN_SPEFPUOP_CONV(evfscfuf);
+GEN_SPEFPUOP_CONV(evfscfsf);
+GEN_SPEFPUOP_CONV(evfsctui);
+GEN_SPEFPUOP_CONV(evfsctsi);
+GEN_SPEFPUOP_CONV(evfsctuf);
+GEN_SPEFPUOP_CONV(evfsctsf);
+GEN_SPEFPUOP_CONV(evfsctuiz);
+GEN_SPEFPUOP_CONV(evfsctsiz);
+/* Comparison */
+GEN_SPEOP_COMP(evfscmpgt);
+GEN_SPEOP_COMP(evfscmplt);
+GEN_SPEOP_COMP(evfscmpeq);
+GEN_SPEOP_COMP(evfststgt);
+GEN_SPEOP_COMP(evfststlt);
+GEN_SPEOP_COMP(evfststeq);
+
+/* Opcodes definitions */
+GEN_SPE(evfsadd,        evfssub,       0x00, 0x0A, 0x00000000, PPC_SPEFPU); //
+GEN_SPE(evfsabs,        evfsnabs,      0x02, 0x0A, 0x0000F800, PPC_SPEFPU); //
+GEN_SPE(evfsneg,        speundef,      0x03, 0x0A, 0x0000F800, PPC_SPEFPU); //
+GEN_SPE(evfsmul,        evfsdiv,       0x04, 0x0A, 0x00000000, PPC_SPEFPU); //
+GEN_SPE(evfscmpgt,      evfscmplt,     0x06, 0x0A, 0x00600000, PPC_SPEFPU); //
+GEN_SPE(evfscmpeq,      speundef,      0x07, 0x0A, 0x00600000, PPC_SPEFPU); //
+GEN_SPE(evfscfui,       evfscfsi,      0x08, 0x0A, 0x00180000, PPC_SPEFPU); //
+GEN_SPE(evfscfuf,       evfscfsf,      0x09, 0x0A, 0x00180000, PPC_SPEFPU); //
+GEN_SPE(evfsctui,       evfsctsi,      0x0A, 0x0A, 0x00180000, PPC_SPEFPU); //
+GEN_SPE(evfsctuf,       evfsctsf,      0x0B, 0x0A, 0x00180000, PPC_SPEFPU); //
+GEN_SPE(evfsctuiz,      speundef,      0x0C, 0x0A, 0x00180000, PPC_SPEFPU); //
+GEN_SPE(evfsctsiz,      speundef,      0x0D, 0x0A, 0x00180000, PPC_SPEFPU); //
+GEN_SPE(evfststgt,      evfststlt,     0x0E, 0x0A, 0x00600000, PPC_SPEFPU); //
+GEN_SPE(evfststeq,      speundef,      0x0F, 0x0A, 0x00600000, PPC_SPEFPU); //
+
+/* Single precision floating-point operations */
+/* Arithmetic */
+GEN_SPEOP_ARITH2(efsadd);
+GEN_SPEOP_ARITH2(efssub);
+GEN_SPEOP_ARITH2(efsmul);
+GEN_SPEOP_ARITH2(efsdiv);
+GEN_SPEOP_ARITH1(efsabs);
+GEN_SPEOP_ARITH1(efsnabs);
+GEN_SPEOP_ARITH1(efsneg);
+/* Conversion */
+GEN_SPEFPUOP_CONV(efscfui);
+GEN_SPEFPUOP_CONV(efscfsi);
+GEN_SPEFPUOP_CONV(efscfuf);
+GEN_SPEFPUOP_CONV(efscfsf);
+GEN_SPEFPUOP_CONV(efsctui);
+GEN_SPEFPUOP_CONV(efsctsi);
+GEN_SPEFPUOP_CONV(efsctuf);
+GEN_SPEFPUOP_CONV(efsctsf);
+GEN_SPEFPUOP_CONV(efsctuiz);
+GEN_SPEFPUOP_CONV(efsctsiz);
+GEN_SPEFPUOP_CONV(efscfd);
+/* Comparison */
+GEN_SPEOP_COMP(efscmpgt);
+GEN_SPEOP_COMP(efscmplt);
+GEN_SPEOP_COMP(efscmpeq);
+GEN_SPEOP_COMP(efststgt);
+GEN_SPEOP_COMP(efststlt);
+GEN_SPEOP_COMP(efststeq);
+
+/* Opcodes definitions */
+GEN_SPE(efsadd,         efssub,        0x00, 0x0A, 0x00000000, PPC_SPEFPU); //
+GEN_SPE(efsabs,         efsnabs,       0x02, 0x0B, 0x0000F800, PPC_SPEFPU); //
+GEN_SPE(efsneg,         speundef,      0x03, 0x0B, 0x0000F800, PPC_SPEFPU); //
+GEN_SPE(efsmul,         efsdiv,        0x04, 0x0B, 0x00000000, PPC_SPEFPU); //
+GEN_SPE(efscmpgt,       efscmplt,      0x06, 0x0B, 0x00600000, PPC_SPEFPU); //
+GEN_SPE(efscmpeq,       efscfd,        0x07, 0x0B, 0x00600000, PPC_SPEFPU); //
+GEN_SPE(efscfui,        efscfsi,       0x08, 0x0B, 0x00180000, PPC_SPEFPU); //
+GEN_SPE(efscfuf,        efscfsf,       0x09, 0x0B, 0x00180000, PPC_SPEFPU); //
+GEN_SPE(efsctui,        efsctsi,       0x0A, 0x0B, 0x00180000, PPC_SPEFPU); //
+GEN_SPE(efsctuf,        efsctsf,       0x0B, 0x0B, 0x00180000, PPC_SPEFPU); //
+GEN_SPE(efsctuiz,       efsctsiz,      0x0C, 0x0B, 0x00180000, PPC_SPEFPU); //
+GEN_SPE(efststgt,       efststlt,      0x0E, 0x0B, 0x00600000, PPC_SPEFPU); //
+GEN_SPE(efststeq,       speundef,      0x0F, 0x0B, 0x00600000, PPC_SPEFPU); //
+
+/* Double precision floating-point operations */
+/* Arithmetic */
+GEN_SPEOP_ARITH2(efdadd);
+GEN_SPEOP_ARITH2(efdsub);
+GEN_SPEOP_ARITH2(efdmul);
+GEN_SPEOP_ARITH2(efddiv);
+GEN_SPEOP_ARITH1(efdabs);
+GEN_SPEOP_ARITH1(efdnabs);
+GEN_SPEOP_ARITH1(efdneg);
+/* Conversion */
+
+GEN_SPEFPUOP_CONV(efdcfui);
+GEN_SPEFPUOP_CONV(efdcfsi);
+GEN_SPEFPUOP_CONV(efdcfuf);
+GEN_SPEFPUOP_CONV(efdcfsf);
+GEN_SPEFPUOP_CONV(efdctui);
+GEN_SPEFPUOP_CONV(efdctsi);
+GEN_SPEFPUOP_CONV(efdctuf);
+GEN_SPEFPUOP_CONV(efdctsf);
+GEN_SPEFPUOP_CONV(efdctuiz);
+GEN_SPEFPUOP_CONV(efdctsiz);
+GEN_SPEFPUOP_CONV(efdcfs);
+GEN_SPEFPUOP_CONV(efdcfuid);
+GEN_SPEFPUOP_CONV(efdcfsid);
+GEN_SPEFPUOP_CONV(efdctuidz);
+GEN_SPEFPUOP_CONV(efdctsidz);
+/* Comparison */
+GEN_SPEOP_COMP(efdcmpgt);
+GEN_SPEOP_COMP(efdcmplt);
+GEN_SPEOP_COMP(efdcmpeq);
+GEN_SPEOP_COMP(efdtstgt);
+GEN_SPEOP_COMP(efdtstlt);
+GEN_SPEOP_COMP(efdtsteq);
+
+/* Opcodes definitions */
+GEN_SPE(efdadd,         efdsub,        0x10, 0x0B, 0x00000000, PPC_SPEFPU); //
+GEN_SPE(efdcfuid,       efdcfsid,      0x11, 0x0B, 0x00180000, PPC_SPEFPU); //
+GEN_SPE(efdabs,         efdnabs,       0x12, 0x0B, 0x0000F800, PPC_SPEFPU); //
+GEN_SPE(efdneg,         speundef,      0x13, 0x0B, 0x0000F800, PPC_SPEFPU); //
+GEN_SPE(efdmul,         efddiv,        0x14, 0x0B, 0x00000000, PPC_SPEFPU); //
+GEN_SPE(efdctuidz,      efdctsidz,     0x15, 0x0B, 0x00180000, PPC_SPEFPU); //
+GEN_SPE(efdcmpgt,       efdcmplt,      0x16, 0x0B, 0x00600000, PPC_SPEFPU); //
+GEN_SPE(efdcmpeq,       efdcfs,        0x17, 0x0B, 0x00600000, PPC_SPEFPU); //
+GEN_SPE(efdcfui,        efdcfsi,       0x18, 0x0B, 0x00180000, PPC_SPEFPU); //
+GEN_SPE(efdcfuf,        efdcfsf,       0x19, 0x0B, 0x00180000, PPC_SPEFPU); //
+GEN_SPE(efdctui,        efdctsi,       0x1A, 0x0B, 0x00180000, PPC_SPEFPU); //
+GEN_SPE(efdctuf,        efdctsf,       0x1B, 0x0B, 0x00180000, PPC_SPEFPU); //
+GEN_SPE(efdctuiz,       speundef,      0x1C, 0x0B, 0x00180000, PPC_SPEFPU); //
+GEN_SPE(efdctsiz,       speundef,      0x1D, 0x0B, 0x00180000, PPC_SPEFPU); //
+GEN_SPE(efdtstgt,       efdtstlt,      0x1E, 0x0B, 0x00600000, PPC_SPEFPU); //
+GEN_SPE(efdtsteq,       speundef,      0x1F, 0x0B, 0x00600000, PPC_SPEFPU); //
+#endif
+
 /* End opcode list */
 GEN_OPCODE_MARK(end);
 
@@ -4604,9 +5415,9 @@ void cpu_dump_statistics (CPUState *env, FILE*f,
 }
 
 /*****************************************************************************/
-static inline int
-gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
-                                int search_pc)
+static inline int gen_intermediate_code_internal (CPUState *env,
+                                                  TranslationBlock *tb,
+                                                  int search_pc)
 {
     DisasContext ctx, *ctxp = &ctx;
     opc_handler_t **table, *handler;
@@ -4639,6 +5450,9 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
     ctx.sf_mode = msr_sf;
 #endif
     ctx.fpu_enabled = msr_fp;
+#if defined(TARGET_PPCSPE)
+    ctx.spe_enabled = msr_spe;
+#endif
     ctx.singlestep_enabled = env->singlestep_enabled;
 #if defined (DO_SINGLE_STEP) && 0
     /* Single step trace mode */
index d4159fa..1778ef1 100644 (file)
@@ -30,7 +30,7 @@ struct ppc_def_t {
     const unsigned char *name;
     uint32_t pvr;
     uint32_t pvr_mask;
-    uint32_t insns_flags;
+    uint64_t insns_flags;
     uint32_t flags;
     uint64_t msr_mask;
 };
@@ -2424,7 +2424,8 @@ static int create_ppc_opcodes (CPUPPCState *env, ppc_def_t *def)
 
     fill_new_table(env->opcodes, 0x40);
 #if defined(PPC_DUMP_CPU)
-    printf("* PowerPC instructions for PVR %08x: %s flags %08x %08x\n",
+    printf("* PowerPC instructions for PVR %08x: %s flags %016 " PRIx64
+           " %08x\n",
            def->pvr, def->name, def->insns_flags, def->flags);
 #endif
     if (&opc_start < &opc_end) {