From e97c363638b32943afc4bd2845f4081496fabfbc Mon Sep 17 00:00:00 2001 From: David Gibson Date: Thu, 29 Sep 2011 21:39:10 +0000 Subject: pseries: Support SMT systems for KVM Book3S-HV Alex Graf has already made qemu support KVM for the pseries machine when using the Book3S-PR KVM variant (which runs the guest in usermode, emulating supervisor operations). This code allows gets us very close to also working with KVM Book3S-HV (using the hypervisor capabilities of recent POWER CPUs). This patch moves us another step towards Book3S-HV support by correctly handling SMT (multithreaded) POWER CPUs. There are two parts to this: * Querying KVM to check SMT capability, and if present, adjusting the cpu numbers that qemu assigns to cause KVM to assign guest threads to cores in the right way (this isn't automatic, because the POWER HV support has a limitation that different threads on a single core cannot be in different guests at the same time). * Correctly informing the guest OS of the SMT thread to core mappings via the device tree. Signed-off-by: David Gibson Signed-off-by: Alexander Graf --- target-ppc/helper.c | 11 +++++++++++ target-ppc/kvm.c | 8 ++++++++ target-ppc/kvm_ppc.h | 6 ++++++ 3 files changed, 25 insertions(+) (limited to 'target-ppc') diff --git a/target-ppc/helper.c b/target-ppc/helper.c index 6339be3a75..137a494201 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -26,6 +26,8 @@ #include "helper_regs.h" #include "qemu-common.h" #include "kvm.h" +#include "kvm_ppc.h" +#include "cpus.h" //#define DEBUG_MMU //#define DEBUG_BATS @@ -3189,6 +3191,15 @@ CPUPPCState *cpu_ppc_init (const char *cpu_model) if (tcg_enabled()) { ppc_translate_init(); } + /* Adjust cpu index for SMT */ +#if !defined(CONFIG_USER_ONLY) + if (kvm_enabled()) { + int smt = kvmppc_smt_threads(); + + env->cpu_index = (env->cpu_index / smp_threads)*smt + + (env->cpu_index % smp_threads); + } +#endif /* !CONFIG_USER_ONLY */ env->cpu_model_str = cpu_model; cpu_ppc_register_internal(env, def); diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index 75832d83b8..6c7ca6fc50 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -28,6 +28,7 @@ #include "kvm_ppc.h" #include "cpu.h" #include "device_tree.h" +#include "hw/spapr.h" #include "hw/sysbus.h" #include "hw/spapr.h" @@ -53,6 +54,7 @@ static int cap_interrupt_unset = false; static int cap_interrupt_level = false; static int cap_segstate; static int cap_booke_sregs; +static int cap_ppc_smt; /* XXX We have a race condition where we actually have a level triggered * interrupt, but the infrastructure can't expose that yet, so the guest @@ -76,6 +78,7 @@ int kvm_arch_init(KVMState *s) cap_interrupt_level = kvm_check_extension(s, KVM_CAP_PPC_IRQ_LEVEL); cap_segstate = kvm_check_extension(s, KVM_CAP_PPC_SEGSTATE); cap_booke_sregs = kvm_check_extension(s, KVM_CAP_PPC_BOOKE_SREGS); + cap_ppc_smt = kvm_check_extension(s, KVM_CAP_PPC_SMT); if (!cap_interrupt_level) { fprintf(stderr, "KVM: Couldn't find level irq capability. Expect the " @@ -750,6 +753,11 @@ fail: cpu_abort(env, "This KVM version does not support PAPR\n"); } +int kvmppc_smt_threads(void) +{ + return cap_ppc_smt ? cap_ppc_smt : 1; +} + bool kvm_arch_stop_on_emulation_error(CPUState *env) { return true; diff --git a/target-ppc/kvm_ppc.h b/target-ppc/kvm_ppc.h index c484e60bcb..c298411aa8 100644 --- a/target-ppc/kvm_ppc.h +++ b/target-ppc/kvm_ppc.h @@ -18,6 +18,7 @@ uint64_t kvmppc_get_clockfreq(void); int kvmppc_get_hypercall(CPUState *env, uint8_t *buf, int buf_len); int kvmppc_set_interrupt(CPUState *env, int irq, int level); void kvmppc_set_papr(CPUState *env); +int kvmppc_smt_threads(void); #else @@ -45,6 +46,11 @@ static inline void kvmppc_set_papr(CPUState *env) { } +static inline int kvmppc_smt_threads(void) +{ + return 1; +} + #endif #ifndef CONFIG_KVM -- cgit v1.2.3 From 354ac20a36a82a5ee09b0a6c8ba8655358a7597f Mon Sep 17 00:00:00 2001 From: David Gibson Date: Thu, 29 Sep 2011 21:39:11 +0000 Subject: pseries: Allow KVM Book3S-HV on PPC970 CPUS At present, using the hypervisor aware Book3S-HV KVM will only work with qemu on POWER7 CPUs. PPC970 CPUs also have hypervisor capability, but they lack the VRMA feature which makes assigning guest memory easier. In order to allow KVM Book3S-HV on PPC970, we need to specially allocate the first chunk of guest memory (the "Real Mode Area" or RMA), so that it is physically contiguous. Sufficiently recent host kernels allow such contiguous RMAs to be allocated, with a kvm capability advertising whether the feature is available and/or necessary on this hardware. This patch enables qemu to use this support, thus allowing kvm acceleration of pseries qemu machines on PPC970 hardware. Signed-off-by: Paul Mackerras Signed-off-by: David Gibson Signed-off-by: Alexander Graf --- agraf: fix to use memory api --- target-ppc/kvm.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ target-ppc/kvm_ppc.h | 8 ++++++++ 2 files changed, 52 insertions(+) (limited to 'target-ppc') diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index 6c7ca6fc50..fd17d23d2e 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -55,6 +55,7 @@ static int cap_interrupt_level = false; static int cap_segstate; static int cap_booke_sregs; static int cap_ppc_smt; +static int cap_ppc_rma; /* XXX We have a race condition where we actually have a level triggered * interrupt, but the infrastructure can't expose that yet, so the guest @@ -79,6 +80,7 @@ int kvm_arch_init(KVMState *s) cap_segstate = kvm_check_extension(s, KVM_CAP_PPC_SEGSTATE); cap_booke_sregs = kvm_check_extension(s, KVM_CAP_PPC_BOOKE_SREGS); cap_ppc_smt = kvm_check_extension(s, KVM_CAP_PPC_SMT); + cap_ppc_rma = kvm_check_extension(s, KVM_CAP_PPC_RMA); if (!cap_interrupt_level) { fprintf(stderr, "KVM: Couldn't find level irq capability. Expect the " @@ -758,6 +760,48 @@ int kvmppc_smt_threads(void) return cap_ppc_smt ? cap_ppc_smt : 1; } +off_t kvmppc_alloc_rma(const char *name, MemoryRegion *sysmem) +{ + void *rma; + off_t size; + int fd; + struct kvm_allocate_rma ret; + MemoryRegion *rma_region; + + /* If cap_ppc_rma == 0, contiguous RMA allocation is not supported + * if cap_ppc_rma == 1, contiguous RMA allocation is supported, but + * not necessary on this hardware + * if cap_ppc_rma == 2, contiguous RMA allocation is needed on this hardware + * + * FIXME: We should allow the user to force contiguous RMA + * allocation in the cap_ppc_rma==1 case. + */ + if (cap_ppc_rma < 2) { + return 0; + } + + fd = kvm_vm_ioctl(kvm_state, KVM_ALLOCATE_RMA, &ret); + if (fd < 0) { + fprintf(stderr, "KVM: Error on KVM_ALLOCATE_RMA: %s\n", + strerror(errno)); + return -1; + } + + size = MIN(ret.rma_size, 256ul << 20); + + rma = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); + if (rma == MAP_FAILED) { + fprintf(stderr, "KVM: Error mapping RMA: %s\n", strerror(errno)); + return -1; + }; + + rma_region = g_new(MemoryRegion, 1); + memory_region_init_ram_ptr(rma_region, NULL, name, size, rma); + memory_region_add_subregion(sysmem, 0, rma_region); + + return size; +} + bool kvm_arch_stop_on_emulation_error(CPUState *env) { return true; diff --git a/target-ppc/kvm_ppc.h b/target-ppc/kvm_ppc.h index c298411aa8..82f32f449e 100644 --- a/target-ppc/kvm_ppc.h +++ b/target-ppc/kvm_ppc.h @@ -9,6 +9,8 @@ #ifndef __KVM_PPC_H__ #define __KVM_PPC_H__ +#include "memory.h" + void kvmppc_init(void); #ifdef CONFIG_KVM @@ -19,6 +21,7 @@ int kvmppc_get_hypercall(CPUState *env, uint8_t *buf, int buf_len); int kvmppc_set_interrupt(CPUState *env, int irq, int level); void kvmppc_set_papr(CPUState *env); int kvmppc_smt_threads(void); +off_t kvmppc_alloc_rma(const char *name, MemoryRegion *sysmem); #else @@ -51,6 +54,11 @@ static inline int kvmppc_smt_threads(void) return 1; } +static inline off_t kvmppc_alloc_rma(const char *name, MemoryRegion *sysmem) +{ + return 0; +} + #endif #ifndef CONFIG_KVM -- cgit v1.2.3 From 0f5cb2989f33059a70e8da335b62af5f27fabbe2 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Thu, 29 Sep 2011 21:39:12 +0000 Subject: pseries: Use Book3S-HV TCE acceleration capabilities The pseries machine of qemu implements the TCE mechanism used as a virtual IOMMU for the PAPR defined virtual IO devices. Because the PAPR spec only defines a small DMA address space, the guest VIO drivers need to update TCE mappings very frequently - the virtual network device is particularly bad. This means many slow exits to qemu to emulate the H_PUT_TCE hypercall. Sufficiently recent kernels allow this to be mitigated by implementing H_PUT_TCE in the host kernel. To make use of this, however, qemu needs to initialize the necessary TCE tables, and map them into itself so that the VIO device implementations can retrieve the mappings when they access guest memory (which is treated as a virtual DMA operation). This patch adds the necessary calls to use the KVM TCE acceleration. If the kernel does not support acceleration, or there is some other error creating the accelerated TCE table, then it will still fall back to full userspace TCE implementation. Signed-off-by: David Gibson Signed-off-by: Alexander Graf --- target-ppc/kvm.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++ target-ppc/kvm_ppc.h | 14 ++++++++++++++ 2 files changed, 68 insertions(+) (limited to 'target-ppc') diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index fd17d23d2e..06cad41de5 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -28,6 +28,7 @@ #include "kvm_ppc.h" #include "cpu.h" #include "device_tree.h" +#include "hw/sysbus.h" #include "hw/spapr.h" #include "hw/sysbus.h" @@ -56,6 +57,7 @@ static int cap_segstate; static int cap_booke_sregs; static int cap_ppc_smt; static int cap_ppc_rma; +static int cap_spapr_tce; /* XXX We have a race condition where we actually have a level triggered * interrupt, but the infrastructure can't expose that yet, so the guest @@ -81,6 +83,7 @@ int kvm_arch_init(KVMState *s) cap_booke_sregs = kvm_check_extension(s, KVM_CAP_PPC_BOOKE_SREGS); cap_ppc_smt = kvm_check_extension(s, KVM_CAP_PPC_SMT); cap_ppc_rma = kvm_check_extension(s, KVM_CAP_PPC_RMA); + cap_spapr_tce = kvm_check_extension(s, KVM_CAP_SPAPR_TCE); if (!cap_interrupt_level) { fprintf(stderr, "KVM: Couldn't find level irq capability. Expect the " @@ -802,6 +805,57 @@ off_t kvmppc_alloc_rma(const char *name, MemoryRegion *sysmem) return size; } +void *kvmppc_create_spapr_tce(uint32_t liobn, uint32_t window_size, int *pfd) +{ + struct kvm_create_spapr_tce args = { + .liobn = liobn, + .window_size = window_size, + }; + long len; + int fd; + void *table; + + if (!cap_spapr_tce) { + return NULL; + } + + fd = kvm_vm_ioctl(kvm_state, KVM_CREATE_SPAPR_TCE, &args); + if (fd < 0) { + return NULL; + } + + len = (window_size / SPAPR_VIO_TCE_PAGE_SIZE) * sizeof(VIOsPAPR_RTCE); + /* FIXME: round this up to page size */ + + table = mmap(NULL, len, PROT_READ, MAP_SHARED, fd, 0); + if (table == MAP_FAILED) { + close(fd); + return NULL; + } + + *pfd = fd; + return table; +} + +int kvmppc_remove_spapr_tce(void *table, int fd, uint32_t window_size) +{ + long len; + + if (fd < 0) { + return -1; + } + + len = (window_size / SPAPR_VIO_TCE_PAGE_SIZE)*sizeof(VIOsPAPR_RTCE); + if ((munmap(table, len) < 0) || + (close(fd) < 0)) { + fprintf(stderr, "KVM: Unexpected error removing KVM SPAPR TCE " + "table: %s", strerror(errno)); + /* Leak the table */ + } + + return 0; +} + bool kvm_arch_stop_on_emulation_error(CPUState *env) { return true; diff --git a/target-ppc/kvm_ppc.h b/target-ppc/kvm_ppc.h index 82f32f449e..87d1bdd5fd 100644 --- a/target-ppc/kvm_ppc.h +++ b/target-ppc/kvm_ppc.h @@ -22,6 +22,8 @@ int kvmppc_set_interrupt(CPUState *env, int irq, int level); void kvmppc_set_papr(CPUState *env); int kvmppc_smt_threads(void); off_t kvmppc_alloc_rma(const char *name, MemoryRegion *sysmem); +void *kvmppc_create_spapr_tce(uint32_t liobn, uint32_t window_size, int *pfd); +int kvmppc_remove_spapr_tce(void *table, int pfd, uint32_t window_size); #else @@ -59,6 +61,18 @@ static inline off_t kvmppc_alloc_rma(const char *name, MemoryRegion *sysmem) return 0; } +static inline void *kvmppc_create_spapr_tce(uint32_t liobn, + uint32_t window_size, int *fd) +{ + return NULL; +} + +static inline int kvmppc_remove_spapr_tce(void *table, int pfd, + uint32_t window_size) +{ + return -1; +} + #endif #ifndef CONFIG_KVM -- cgit v1.2.3 From 70560da79d5be611bd7867f9c590847702c61fb5 Mon Sep 17 00:00:00 2001 From: Fabien Chouteau Date: Wed, 28 Sep 2011 05:54:05 +0000 Subject: Set an invalid-bits mask for each SPE instructions SPE instructions are defined by pairs. Currently, the invalid-bits mask is set for the first instruction, but the second one can have a different mask. example: GEN_SPE(efdcmpeq, efdcfs, 0x17, 0x0B, 0x00600000, 0x00180000, PPC_SPE_DOUBLE), Signed-off-by: Fabien Chouteau Signed-off-by: Alexander Graf --- target-ppc/translate.c | 500 +++++++++++++++++++++++++++---------------------- 1 file changed, 271 insertions(+), 229 deletions(-) (limited to 'target-ppc') diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 1e362fc238..99e995c7b6 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -205,8 +205,10 @@ typedef struct DisasContext { } DisasContext; struct opc_handler_t { - /* invalid bits */ - uint32_t inval; + /* invalid bits for instruction 1 (Rc(opcode) == 0) */ + uint32_t inval1; + /* invalid bits for instruction 2 (Rc(opcode) == 1) */ + uint32_t inval2; /* instruction type */ uint64_t type; /* extended instruction type */ @@ -478,7 +480,23 @@ static inline target_ulong MASK(uint32_t start, uint32_t end) .opc3 = op3, \ .pad = { 0, }, \ .handler = { \ - .inval = invl, \ + .inval1 = invl, \ + .type = _typ, \ + .type2 = _typ2, \ + .handler = &gen_##name, \ + .oname = stringify(name), \ + }, \ + .oname = stringify(name), \ +} +#define GEN_OPCODE_DUAL(name, op1, op2, op3, invl1, invl2, _typ, _typ2) \ +{ \ + .opc1 = op1, \ + .opc2 = op2, \ + .opc3 = op3, \ + .pad = { 0, }, \ + .handler = { \ + .inval1 = invl1, \ + .inval2 = invl2, \ .type = _typ, \ .type2 = _typ2, \ .handler = &gen_##name, \ @@ -493,7 +511,7 @@ static inline target_ulong MASK(uint32_t start, uint32_t end) .opc3 = op3, \ .pad = { 0, }, \ .handler = { \ - .inval = invl, \ + .inval1 = invl, \ .type = _typ, \ .type2 = _typ2, \ .handler = &gen_##name, \ @@ -509,7 +527,22 @@ static inline target_ulong MASK(uint32_t start, uint32_t end) .opc3 = op3, \ .pad = { 0, }, \ .handler = { \ - .inval = invl, \ + .inval1 = invl, \ + .type = _typ, \ + .type2 = _typ2, \ + .handler = &gen_##name, \ + }, \ + .oname = stringify(name), \ +} +#define GEN_OPCODE_DUAL(name, op1, op2, op3, invl1, invl2, _typ, _typ2) \ +{ \ + .opc1 = op1, \ + .opc2 = op2, \ + .opc3 = op3, \ + .pad = { 0, }, \ + .handler = { \ + .inval1 = invl1, \ + .inval2 = invl2, \ .type = _typ, \ .type2 = _typ2, \ .handler = &gen_##name, \ @@ -523,7 +556,7 @@ static inline target_ulong MASK(uint32_t start, uint32_t end) .opc3 = op3, \ .pad = { 0, }, \ .handler = { \ - .inval = invl, \ + .inval1 = invl, \ .type = _typ, \ .type2 = _typ2, \ .handler = &gen_##name, \ @@ -550,7 +583,8 @@ static void gen_invalid(DisasContext *ctx) } static opc_handler_t invalid_handler = { - .inval = 0xFFFFFFFF, + .inval1 = 0xFFFFFFFF, + .inval2 = 0xFFFFFFFF, .type = PPC_NONE, .type2 = PPC_NONE, .handler = gen_invalid, @@ -6693,7 +6727,7 @@ static inline void gen_store_gpr64(int reg, TCGv_i64 t) #endif } -#define GEN_SPE(name0, name1, opc2, opc3, inval, type) \ +#define GEN_SPE(name0, name1, opc2, opc3, inval0, inval1, type) \ static void glue(gen_, name0##_##name1)(DisasContext *ctx) \ { \ if (Rc(ctx->opcode)) \ @@ -7416,35 +7450,35 @@ static inline void gen_evmwsmiaa(DisasContext *ctx) tcg_temp_free_i64(tmp); } -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(evmra, speundef, 0x02, 0x13, 0x0000F800, 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(evmwumi, evmwsmi, 0x0C, 0x11, 0x00000000, PPC_SPE); -GEN_SPE(evmwumia, evmwsmia, 0x1C, 0x11, 0x00000000, PPC_SPE); -GEN_SPE(evmwumiaa, evmwsmiaa, 0x0C, 0x15, 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); //// +GEN_SPE(evaddw, speundef, 0x00, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE); //// +GEN_SPE(evaddiw, speundef, 0x01, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE); +GEN_SPE(evsubfw, speundef, 0x02, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE); //// +GEN_SPE(evsubifw, speundef, 0x03, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE); +GEN_SPE(evabs, evneg, 0x04, 0x08, 0x0000F800, 0x0000F800, PPC_SPE); //// +GEN_SPE(evextsb, evextsh, 0x05, 0x08, 0x0000F800, 0x0000F800, PPC_SPE); //// +GEN_SPE(evrndw, evcntlzw, 0x06, 0x08, 0x0000F800, 0x0000F800, PPC_SPE); //// +GEN_SPE(evcntlsw, brinc, 0x07, 0x08, 0x0000F800, 0x00000000, PPC_SPE); // +GEN_SPE(evmra, speundef, 0x02, 0x13, 0x0000F800, 0xFFFFFFFF, PPC_SPE); +GEN_SPE(speundef, evand, 0x08, 0x08, 0xFFFFFFFF, 0x00000000, PPC_SPE); //// +GEN_SPE(evandc, speundef, 0x09, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE); //// +GEN_SPE(evxor, evor, 0x0B, 0x08, 0x00000000, 0x00000000, PPC_SPE); //// +GEN_SPE(evnor, eveqv, 0x0C, 0x08, 0x00000000, 0x00000000, PPC_SPE); //// +GEN_SPE(evmwumi, evmwsmi, 0x0C, 0x11, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(evmwumia, evmwsmia, 0x1C, 0x11, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(evmwumiaa, evmwsmiaa, 0x0C, 0x15, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evorc, 0x0D, 0x08, 0xFFFFFFFF, 0x00000000, PPC_SPE); //// +GEN_SPE(evnand, speundef, 0x0F, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE); //// +GEN_SPE(evsrwu, evsrws, 0x10, 0x08, 0x00000000, 0x00000000, PPC_SPE); //// +GEN_SPE(evsrwiu, evsrwis, 0x11, 0x08, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(evslw, speundef, 0x12, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE); //// +GEN_SPE(evslwi, speundef, 0x13, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE); +GEN_SPE(evrlw, evsplati, 0x14, 0x08, 0x00000000, 0x0000F800, PPC_SPE); // +GEN_SPE(evrlwi, evsplatfi, 0x15, 0x08, 0x00000000, 0x0000F800, PPC_SPE); +GEN_SPE(evmergehi, evmergelo, 0x16, 0x08, 0x00000000, 0x00000000, PPC_SPE); //// +GEN_SPE(evmergehilo, evmergelohi, 0x17, 0x08, 0x00000000, 0x00000000, PPC_SPE); //// +GEN_SPE(evcmpgtu, evcmpgts, 0x18, 0x08, 0x00600000, 0x00600000, PPC_SPE); //// +GEN_SPE(evcmpltu, evcmplts, 0x19, 0x08, 0x00600000, 0x00600000, PPC_SPE); //// +GEN_SPE(evcmpeq, speundef, 0x1A, 0x08, 0x00600000, 0xFFFFFFFF, PPC_SPE); //// /* SPE load and stores */ static inline void gen_addr_spe_imm_index(DisasContext *ctx, TCGv EA, int sh) @@ -7803,74 +7837,74 @@ GEN_SPEOP_LDST(evstwwo, 0x1E, 2); /* 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(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(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(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(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); +GEN_SPE(speundef, evmhessf, 0x01, 0x10, 0xFFFFFFFF, 0x00000000, PPC_SPE);// +GEN_SPE(speundef, evmhossf, 0x03, 0x10, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(evmheumi, evmhesmi, 0x04, 0x10, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhesmf, 0x05, 0x10, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(evmhoumi, evmhosmi, 0x06, 0x10, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhosmf, 0x07, 0x10, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhessfa, 0x11, 0x10, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhossfa, 0x13, 0x10, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(evmheumia, evmhesmia, 0x14, 0x10, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhesmfa, 0x15, 0x10, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(evmhoumia, evmhosmia, 0x16, 0x10, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhosmfa, 0x17, 0x10, 0xFFFFFFFF, 0x00000000, PPC_SPE); + +GEN_SPE(speundef, evmwhssf, 0x03, 0x11, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(evmwlumi, speundef, 0x04, 0x11, 0x00000000, 0xFFFFFFFF, PPC_SPE); +GEN_SPE(evmwhumi, evmwhsmi, 0x06, 0x11, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmwhsmf, 0x07, 0x11, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmwssf, 0x09, 0x11, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmwsmf, 0x0D, 0x11, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmwhssfa, 0x13, 0x11, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(evmwlumia, speundef, 0x14, 0x11, 0x00000000, 0xFFFFFFFF, PPC_SPE); +GEN_SPE(evmwhumia, evmwhsmia, 0x16, 0x11, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmwhsmfa, 0x17, 0x11, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmwssfa, 0x19, 0x11, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmwsmfa, 0x1D, 0x11, 0xFFFFFFFF, 0x00000000, PPC_SPE); + +GEN_SPE(evadduiaaw, evaddsiaaw, 0x00, 0x13, 0x0000F800, 0x0000F800, PPC_SPE); +GEN_SPE(evsubfusiaaw, evsubfssiaaw, 0x01, 0x13, 0x0000F800, 0x0000F800, PPC_SPE); +GEN_SPE(evaddumiaaw, evaddsmiaaw, 0x04, 0x13, 0x0000F800, 0x0000F800, PPC_SPE); +GEN_SPE(evsubfumiaaw, evsubfsmiaaw, 0x05, 0x13, 0x0000F800, 0x0000F800, PPC_SPE); +GEN_SPE(evdivws, evdivwu, 0x06, 0x13, 0x00000000, 0x00000000, PPC_SPE); + +GEN_SPE(evmheusiaaw, evmhessiaaw, 0x00, 0x14, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhessfaaw, 0x01, 0x14, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(evmhousiaaw, evmhossiaaw, 0x02, 0x14, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhossfaaw, 0x03, 0x14, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(evmheumiaaw, evmhesmiaaw, 0x04, 0x14, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhesmfaaw, 0x05, 0x14, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(evmhoumiaaw, evmhosmiaaw, 0x06, 0x14, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhosmfaaw, 0x07, 0x14, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(evmhegumiaa, evmhegsmiaa, 0x14, 0x14, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhegsmfaa, 0x15, 0x14, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(evmhogumiaa, evmhogsmiaa, 0x16, 0x14, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhogsmfaa, 0x17, 0x14, 0xFFFFFFFF, 0x00000000, PPC_SPE); + +GEN_SPE(evmwlusiaaw, evmwlssiaaw, 0x00, 0x15, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(evmwlumiaaw, evmwlsmiaaw, 0x04, 0x15, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmwssfaa, 0x09, 0x15, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmwsmfaa, 0x0D, 0x15, 0xFFFFFFFF, 0x00000000, PPC_SPE); + +GEN_SPE(evmheusianw, evmhessianw, 0x00, 0x16, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhessfanw, 0x01, 0x16, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(evmhousianw, evmhossianw, 0x02, 0x16, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhossfanw, 0x03, 0x16, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(evmheumianw, evmhesmianw, 0x04, 0x16, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhesmfanw, 0x05, 0x16, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(evmhoumianw, evmhosmianw, 0x06, 0x16, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhosmfanw, 0x07, 0x16, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(evmhegumian, evmhegsmian, 0x14, 0x16, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhegsmfan, 0x15, 0x16, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(evmhigumian, evmhigsmian, 0x16, 0x16, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmhogsmfan, 0x17, 0x16, 0xFFFFFFFF, 0x00000000, PPC_SPE); + +GEN_SPE(evmwlusianw, evmwlssianw, 0x00, 0x17, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(evmwlumianw, evmwlsmianw, 0x04, 0x17, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmwssfan, 0x09, 0x17, 0xFFFFFFFF, 0x00000000, PPC_SPE); +GEN_SPE(evmwumian, evmwsmian, 0x0C, 0x17, 0x00000000, 0x00000000, PPC_SPE); +GEN_SPE(speundef, evmwsmfan, 0x0D, 0x17, 0xFFFFFFFF, 0x00000000, PPC_SPE); #endif /*** SPE floating-point extension ***/ @@ -8131,20 +8165,20 @@ GEN_SPEFPUOP_COMP_64(evfststlt); GEN_SPEFPUOP_COMP_64(evfststeq); /* Opcodes definitions */ -GEN_SPE(evfsadd, evfssub, 0x00, 0x0A, 0x00000000, PPC_SPE_SINGLE); // -GEN_SPE(evfsabs, evfsnabs, 0x02, 0x0A, 0x0000F800, PPC_SPE_SINGLE); // -GEN_SPE(evfsneg, speundef, 0x03, 0x0A, 0x0000F800, PPC_SPE_SINGLE); // -GEN_SPE(evfsmul, evfsdiv, 0x04, 0x0A, 0x00000000, PPC_SPE_SINGLE); // -GEN_SPE(evfscmpgt, evfscmplt, 0x06, 0x0A, 0x00600000, PPC_SPE_SINGLE); // -GEN_SPE(evfscmpeq, speundef, 0x07, 0x0A, 0x00600000, PPC_SPE_SINGLE); // -GEN_SPE(evfscfui, evfscfsi, 0x08, 0x0A, 0x00180000, PPC_SPE_SINGLE); // -GEN_SPE(evfscfuf, evfscfsf, 0x09, 0x0A, 0x00180000, PPC_SPE_SINGLE); // -GEN_SPE(evfsctui, evfsctsi, 0x0A, 0x0A, 0x00180000, PPC_SPE_SINGLE); // -GEN_SPE(evfsctuf, evfsctsf, 0x0B, 0x0A, 0x00180000, PPC_SPE_SINGLE); // -GEN_SPE(evfsctuiz, speundef, 0x0C, 0x0A, 0x00180000, PPC_SPE_SINGLE); // -GEN_SPE(evfsctsiz, speundef, 0x0D, 0x0A, 0x00180000, PPC_SPE_SINGLE); // -GEN_SPE(evfststgt, evfststlt, 0x0E, 0x0A, 0x00600000, PPC_SPE_SINGLE); // -GEN_SPE(evfststeq, speundef, 0x0F, 0x0A, 0x00600000, PPC_SPE_SINGLE); // +GEN_SPE(evfsadd, evfssub, 0x00, 0x0A, 0x00000000, 0x00000000, PPC_SPE_SINGLE); // +GEN_SPE(evfsabs, evfsnabs, 0x02, 0x0A, 0x0000F800, 0x0000F800, PPC_SPE_SINGLE); // +GEN_SPE(evfsneg, speundef, 0x03, 0x0A, 0x0000F800, 0xFFFFFFFF, PPC_SPE_SINGLE); // +GEN_SPE(evfsmul, evfsdiv, 0x04, 0x0A, 0x00000000, 0x00000000, PPC_SPE_SINGLE); // +GEN_SPE(evfscmpgt, evfscmplt, 0x06, 0x0A, 0x00600000, 0x00600000, PPC_SPE_SINGLE); // +GEN_SPE(evfscmpeq, speundef, 0x07, 0x0A, 0x00600000, 0xFFFFFFFF, PPC_SPE_SINGLE); // +GEN_SPE(evfscfui, evfscfsi, 0x08, 0x0A, 0x00180000, 0x00180000, PPC_SPE_SINGLE); // +GEN_SPE(evfscfuf, evfscfsf, 0x09, 0x0A, 0x00180000, 0x00180000, PPC_SPE_SINGLE); // +GEN_SPE(evfsctui, evfsctsi, 0x0A, 0x0A, 0x00180000, 0x00180000, PPC_SPE_SINGLE); // +GEN_SPE(evfsctuf, evfsctsf, 0x0B, 0x0A, 0x00180000, 0x00180000, PPC_SPE_SINGLE); // +GEN_SPE(evfsctuiz, speundef, 0x0C, 0x0A, 0x00180000, 0xFFFFFFFF, PPC_SPE_SINGLE); // +GEN_SPE(evfsctsiz, speundef, 0x0D, 0x0A, 0x00180000, 0xFFFFFFFF, PPC_SPE_SINGLE); // +GEN_SPE(evfststgt, evfststlt, 0x0E, 0x0A, 0x00600000, 0x00600000, PPC_SPE_SINGLE); // +GEN_SPE(evfststeq, speundef, 0x0F, 0x0A, 0x00600000, 0xFFFFFFFF, PPC_SPE_SINGLE); // /* Single precision floating-point operations */ /* Arithmetic */ @@ -8199,20 +8233,20 @@ GEN_SPEFPUOP_COMP_32(efststlt); GEN_SPEFPUOP_COMP_32(efststeq); /* Opcodes definitions */ -GEN_SPE(efsadd, efssub, 0x00, 0x0B, 0x00000000, PPC_SPE_SINGLE); // -GEN_SPE(efsabs, efsnabs, 0x02, 0x0B, 0x0000F800, PPC_SPE_SINGLE); // -GEN_SPE(efsneg, speundef, 0x03, 0x0B, 0x0000F800, PPC_SPE_SINGLE); // -GEN_SPE(efsmul, efsdiv, 0x04, 0x0B, 0x00000000, PPC_SPE_SINGLE); // -GEN_SPE(efscmpgt, efscmplt, 0x06, 0x0B, 0x00600000, PPC_SPE_SINGLE); // -GEN_SPE(efscmpeq, efscfd, 0x07, 0x0B, 0x00600000, PPC_SPE_SINGLE); // -GEN_SPE(efscfui, efscfsi, 0x08, 0x0B, 0x00180000, PPC_SPE_SINGLE); // -GEN_SPE(efscfuf, efscfsf, 0x09, 0x0B, 0x00180000, PPC_SPE_SINGLE); // -GEN_SPE(efsctui, efsctsi, 0x0A, 0x0B, 0x00180000, PPC_SPE_SINGLE); // -GEN_SPE(efsctuf, efsctsf, 0x0B, 0x0B, 0x00180000, PPC_SPE_SINGLE); // -GEN_SPE(efsctuiz, speundef, 0x0C, 0x0B, 0x00180000, PPC_SPE_SINGLE); // -GEN_SPE(efsctsiz, speundef, 0x0D, 0x0B, 0x00180000, PPC_SPE_SINGLE); // -GEN_SPE(efststgt, efststlt, 0x0E, 0x0B, 0x00600000, PPC_SPE_SINGLE); // -GEN_SPE(efststeq, speundef, 0x0F, 0x0B, 0x00600000, PPC_SPE_SINGLE); // +GEN_SPE(efsadd, efssub, 0x00, 0x0B, 0x00000000, 0x00000000, PPC_SPE_SINGLE); // +GEN_SPE(efsabs, efsnabs, 0x02, 0x0B, 0x0000F800, 0x0000F800, PPC_SPE_SINGLE); // +GEN_SPE(efsneg, speundef, 0x03, 0x0B, 0x0000F800, 0xFFFFFFFF, PPC_SPE_SINGLE); // +GEN_SPE(efsmul, efsdiv, 0x04, 0x0B, 0x00000000, 0x00000000, PPC_SPE_SINGLE); // +GEN_SPE(efscmpgt, efscmplt, 0x06, 0x0B, 0x00600000, 0x00600000, PPC_SPE_SINGLE); // +GEN_SPE(efscmpeq, efscfd, 0x07, 0x0B, 0x00600000, 0x00180000, PPC_SPE_SINGLE); // +GEN_SPE(efscfui, efscfsi, 0x08, 0x0B, 0x00180000, 0x00180000, PPC_SPE_SINGLE); // +GEN_SPE(efscfuf, efscfsf, 0x09, 0x0B, 0x00180000, 0x00180000, PPC_SPE_SINGLE); // +GEN_SPE(efsctui, efsctsi, 0x0A, 0x0B, 0x00180000, 0x00180000, PPC_SPE_SINGLE); // +GEN_SPE(efsctuf, efsctsf, 0x0B, 0x0B, 0x00180000, 0x00180000, PPC_SPE_SINGLE); // +GEN_SPE(efsctuiz, speundef, 0x0C, 0x0B, 0x00180000, 0xFFFFFFFF, PPC_SPE_SINGLE); // +GEN_SPE(efsctsiz, speundef, 0x0D, 0x0B, 0x00180000, 0xFFFFFFFF, PPC_SPE_SINGLE); // +GEN_SPE(efststgt, efststlt, 0x0E, 0x0B, 0x00600000, 0x00600000, PPC_SPE_SINGLE); // +GEN_SPE(efststeq, speundef, 0x0F, 0x0B, 0x00600000, 0xFFFFFFFF, PPC_SPE_SINGLE); // /* Double precision floating-point operations */ /* Arithmetic */ @@ -8286,22 +8320,22 @@ GEN_SPEFPUOP_COMP_64(efdtstlt); GEN_SPEFPUOP_COMP_64(efdtsteq); /* Opcodes definitions */ -GEN_SPE(efdadd, efdsub, 0x10, 0x0B, 0x00000000, PPC_SPE_DOUBLE); // -GEN_SPE(efdcfuid, efdcfsid, 0x11, 0x0B, 0x00180000, PPC_SPE_DOUBLE); // -GEN_SPE(efdabs, efdnabs, 0x12, 0x0B, 0x0000F800, PPC_SPE_DOUBLE); // -GEN_SPE(efdneg, speundef, 0x13, 0x0B, 0x0000F800, PPC_SPE_DOUBLE); // -GEN_SPE(efdmul, efddiv, 0x14, 0x0B, 0x00000000, PPC_SPE_DOUBLE); // -GEN_SPE(efdctuidz, efdctsidz, 0x15, 0x0B, 0x00180000, PPC_SPE_DOUBLE); // -GEN_SPE(efdcmpgt, efdcmplt, 0x16, 0x0B, 0x00600000, PPC_SPE_DOUBLE); // -GEN_SPE(efdcmpeq, efdcfs, 0x17, 0x0B, 0x00600000, PPC_SPE_DOUBLE); // -GEN_SPE(efdcfui, efdcfsi, 0x18, 0x0B, 0x00180000, PPC_SPE_DOUBLE); // -GEN_SPE(efdcfuf, efdcfsf, 0x19, 0x0B, 0x00180000, PPC_SPE_DOUBLE); // -GEN_SPE(efdctui, efdctsi, 0x1A, 0x0B, 0x00180000, PPC_SPE_DOUBLE); // -GEN_SPE(efdctuf, efdctsf, 0x1B, 0x0B, 0x00180000, PPC_SPE_DOUBLE); // -GEN_SPE(efdctuiz, speundef, 0x1C, 0x0B, 0x00180000, PPC_SPE_DOUBLE); // -GEN_SPE(efdctsiz, speundef, 0x1D, 0x0B, 0x00180000, PPC_SPE_DOUBLE); // -GEN_SPE(efdtstgt, efdtstlt, 0x1E, 0x0B, 0x00600000, PPC_SPE_DOUBLE); // -GEN_SPE(efdtsteq, speundef, 0x1F, 0x0B, 0x00600000, PPC_SPE_DOUBLE); // +GEN_SPE(efdadd, efdsub, 0x10, 0x0B, 0x00000000, 0x00000000, PPC_SPE_DOUBLE); // +GEN_SPE(efdcfuid, efdcfsid, 0x11, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE); // +GEN_SPE(efdabs, efdnabs, 0x12, 0x0B, 0x0000F800, 0x0000F800, PPC_SPE_DOUBLE); // +GEN_SPE(efdneg, speundef, 0x13, 0x0B, 0x0000F800, 0xFFFFFFFF, PPC_SPE_DOUBLE); // +GEN_SPE(efdmul, efddiv, 0x14, 0x0B, 0x00000000, 0x00000000, PPC_SPE_DOUBLE); // +GEN_SPE(efdctuidz, efdctsidz, 0x15, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE); // +GEN_SPE(efdcmpgt, efdcmplt, 0x16, 0x0B, 0x00600000, 0x00600000, PPC_SPE_DOUBLE); // +GEN_SPE(efdcmpeq, efdcfs, 0x17, 0x0B, 0x00600000, 0x00180000, PPC_SPE_DOUBLE); // +GEN_SPE(efdcfui, efdcfsi, 0x18, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE); // +GEN_SPE(efdcfuf, efdcfsf, 0x19, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE); // +GEN_SPE(efdctui, efdctsi, 0x1A, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE); // +GEN_SPE(efdctuf, efdctsf, 0x1B, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE); // +GEN_SPE(efdctuiz, speundef, 0x1C, 0x0B, 0x00180000, 0xFFFFFFFF, PPC_SPE_DOUBLE); // +GEN_SPE(efdctsiz, speundef, 0x1D, 0x0B, 0x00180000, 0xFFFFFFFF, PPC_SPE_DOUBLE); // +GEN_SPE(efdtstgt, efdtstlt, 0x1E, 0x0B, 0x00600000, 0x00600000, PPC_SPE_DOUBLE); // +GEN_SPE(efdtsteq, speundef, 0x1F, 0x0B, 0x00600000, 0xFFFFFFFF, PPC_SPE_DOUBLE); // static opcode_t opcodes[] = { GEN_HANDLER(invalid, 0x00, 0x00, 0x00, 0xFFFFFFFF, PPC_NONE), @@ -9070,84 +9104,84 @@ GEN_VAFORM_PAIRED(vsel, vperm, 21), GEN_VAFORM_PAIRED(vmaddfp, vnmsubfp, 23), #undef GEN_SPE -#define GEN_SPE(name0, name1, opc2, opc3, inval, type) \ -GEN_HANDLER(name0##_##name1, 0x04, opc2, opc3, inval, type) -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(evmra, speundef, 0x02, 0x13, 0x0000F800, 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(evmwumi, evmwsmi, 0x0C, 0x11, 0x00000000, PPC_SPE), -GEN_SPE(evmwumia, evmwsmia, 0x1C, 0x11, 0x00000000, PPC_SPE), -GEN_SPE(evmwumiaa, evmwsmiaa, 0x0C, 0x15, 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), - -GEN_SPE(evfsadd, evfssub, 0x00, 0x0A, 0x00000000, PPC_SPE_SINGLE), -GEN_SPE(evfsabs, evfsnabs, 0x02, 0x0A, 0x0000F800, PPC_SPE_SINGLE), -GEN_SPE(evfsneg, speundef, 0x03, 0x0A, 0x0000F800, PPC_SPE_SINGLE), -GEN_SPE(evfsmul, evfsdiv, 0x04, 0x0A, 0x00000000, PPC_SPE_SINGLE), -GEN_SPE(evfscmpgt, evfscmplt, 0x06, 0x0A, 0x00600000, PPC_SPE_SINGLE), -GEN_SPE(evfscmpeq, speundef, 0x07, 0x0A, 0x00600000, PPC_SPE_SINGLE), -GEN_SPE(evfscfui, evfscfsi, 0x08, 0x0A, 0x00180000, PPC_SPE_SINGLE), -GEN_SPE(evfscfuf, evfscfsf, 0x09, 0x0A, 0x00180000, PPC_SPE_SINGLE), -GEN_SPE(evfsctui, evfsctsi, 0x0A, 0x0A, 0x00180000, PPC_SPE_SINGLE), -GEN_SPE(evfsctuf, evfsctsf, 0x0B, 0x0A, 0x00180000, PPC_SPE_SINGLE), -GEN_SPE(evfsctuiz, speundef, 0x0C, 0x0A, 0x00180000, PPC_SPE_SINGLE), -GEN_SPE(evfsctsiz, speundef, 0x0D, 0x0A, 0x00180000, PPC_SPE_SINGLE), -GEN_SPE(evfststgt, evfststlt, 0x0E, 0x0A, 0x00600000, PPC_SPE_SINGLE), -GEN_SPE(evfststeq, speundef, 0x0F, 0x0A, 0x00600000, PPC_SPE_SINGLE), - -GEN_SPE(efsadd, efssub, 0x00, 0x0B, 0x00000000, PPC_SPE_SINGLE), -GEN_SPE(efsabs, efsnabs, 0x02, 0x0B, 0x0000F800, PPC_SPE_SINGLE), -GEN_SPE(efsneg, speundef, 0x03, 0x0B, 0x0000F800, PPC_SPE_SINGLE), -GEN_SPE(efsmul, efsdiv, 0x04, 0x0B, 0x00000000, PPC_SPE_SINGLE), -GEN_SPE(efscmpgt, efscmplt, 0x06, 0x0B, 0x00600000, PPC_SPE_SINGLE), -GEN_SPE(efscmpeq, efscfd, 0x07, 0x0B, 0x00600000, PPC_SPE_SINGLE), -GEN_SPE(efscfui, efscfsi, 0x08, 0x0B, 0x00180000, PPC_SPE_SINGLE), -GEN_SPE(efscfuf, efscfsf, 0x09, 0x0B, 0x00180000, PPC_SPE_SINGLE), -GEN_SPE(efsctui, efsctsi, 0x0A, 0x0B, 0x00180000, PPC_SPE_SINGLE), -GEN_SPE(efsctuf, efsctsf, 0x0B, 0x0B, 0x00180000, PPC_SPE_SINGLE), -GEN_SPE(efsctuiz, speundef, 0x0C, 0x0B, 0x00180000, PPC_SPE_SINGLE), -GEN_SPE(efsctsiz, speundef, 0x0D, 0x0B, 0x00180000, PPC_SPE_SINGLE), -GEN_SPE(efststgt, efststlt, 0x0E, 0x0B, 0x00600000, PPC_SPE_SINGLE), -GEN_SPE(efststeq, speundef, 0x0F, 0x0B, 0x00600000, PPC_SPE_SINGLE), - -GEN_SPE(efdadd, efdsub, 0x10, 0x0B, 0x00000000, PPC_SPE_DOUBLE), -GEN_SPE(efdcfuid, efdcfsid, 0x11, 0x0B, 0x00180000, PPC_SPE_DOUBLE), -GEN_SPE(efdabs, efdnabs, 0x12, 0x0B, 0x0000F800, PPC_SPE_DOUBLE), -GEN_SPE(efdneg, speundef, 0x13, 0x0B, 0x0000F800, PPC_SPE_DOUBLE), -GEN_SPE(efdmul, efddiv, 0x14, 0x0B, 0x00000000, PPC_SPE_DOUBLE), -GEN_SPE(efdctuidz, efdctsidz, 0x15, 0x0B, 0x00180000, PPC_SPE_DOUBLE), -GEN_SPE(efdcmpgt, efdcmplt, 0x16, 0x0B, 0x00600000, PPC_SPE_DOUBLE), -GEN_SPE(efdcmpeq, efdcfs, 0x17, 0x0B, 0x00600000, PPC_SPE_DOUBLE), -GEN_SPE(efdcfui, efdcfsi, 0x18, 0x0B, 0x00180000, PPC_SPE_DOUBLE), -GEN_SPE(efdcfuf, efdcfsf, 0x19, 0x0B, 0x00180000, PPC_SPE_DOUBLE), -GEN_SPE(efdctui, efdctsi, 0x1A, 0x0B, 0x00180000, PPC_SPE_DOUBLE), -GEN_SPE(efdctuf, efdctsf, 0x1B, 0x0B, 0x00180000, PPC_SPE_DOUBLE), -GEN_SPE(efdctuiz, speundef, 0x1C, 0x0B, 0x00180000, PPC_SPE_DOUBLE), -GEN_SPE(efdctsiz, speundef, 0x1D, 0x0B, 0x00180000, PPC_SPE_DOUBLE), -GEN_SPE(efdtstgt, efdtstlt, 0x1E, 0x0B, 0x00600000, PPC_SPE_DOUBLE), -GEN_SPE(efdtsteq, speundef, 0x1F, 0x0B, 0x00600000, PPC_SPE_DOUBLE), +#define GEN_SPE(name0, name1, opc2, opc3, inval0, inval1, type) \ + GEN_OPCODE_DUAL(name0##_##name1, 0x04, opc2, opc3, inval0, inval1, type, PPC_NONE) +GEN_SPE(evaddw, speundef, 0x00, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE), +GEN_SPE(evaddiw, speundef, 0x01, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE), +GEN_SPE(evsubfw, speundef, 0x02, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE), +GEN_SPE(evsubifw, speundef, 0x03, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE), +GEN_SPE(evabs, evneg, 0x04, 0x08, 0x0000F800, 0x0000F800, PPC_SPE), +GEN_SPE(evextsb, evextsh, 0x05, 0x08, 0x0000F800, 0x0000F800, PPC_SPE), +GEN_SPE(evrndw, evcntlzw, 0x06, 0x08, 0x0000F800, 0x0000F800, PPC_SPE), +GEN_SPE(evcntlsw, brinc, 0x07, 0x08, 0x0000F800, 0x00000000, PPC_SPE), +GEN_SPE(evmra, speundef, 0x02, 0x13, 0x0000F800, 0xFFFFFFFF, PPC_SPE), +GEN_SPE(speundef, evand, 0x08, 0x08, 0xFFFFFFFF, 0x00000000, PPC_SPE), +GEN_SPE(evandc, speundef, 0x09, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE), +GEN_SPE(evxor, evor, 0x0B, 0x08, 0x00000000, 0x00000000, PPC_SPE), +GEN_SPE(evnor, eveqv, 0x0C, 0x08, 0x00000000, 0x00000000, PPC_SPE), +GEN_SPE(evmwumi, evmwsmi, 0x0C, 0x11, 0x00000000, 0x00000000, PPC_SPE), +GEN_SPE(evmwumia, evmwsmia, 0x1C, 0x11, 0x00000000, 0x00000000, PPC_SPE), +GEN_SPE(evmwumiaa, evmwsmiaa, 0x0C, 0x15, 0x00000000, 0x00000000, PPC_SPE), +GEN_SPE(speundef, evorc, 0x0D, 0x08, 0xFFFFFFFF, 0x00000000, PPC_SPE), +GEN_SPE(evnand, speundef, 0x0F, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE), +GEN_SPE(evsrwu, evsrws, 0x10, 0x08, 0x00000000, 0x00000000, PPC_SPE), +GEN_SPE(evsrwiu, evsrwis, 0x11, 0x08, 0x00000000, 0x00000000, PPC_SPE), +GEN_SPE(evslw, speundef, 0x12, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE), +GEN_SPE(evslwi, speundef, 0x13, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE), +GEN_SPE(evrlw, evsplati, 0x14, 0x08, 0x00000000, 0x0000F800, PPC_SPE), +GEN_SPE(evrlwi, evsplatfi, 0x15, 0x08, 0x00000000, 0x0000F800, PPC_SPE), +GEN_SPE(evmergehi, evmergelo, 0x16, 0x08, 0x00000000, 0x00000000, PPC_SPE), +GEN_SPE(evmergehilo, evmergelohi, 0x17, 0x08, 0x00000000, 0x00000000, PPC_SPE), +GEN_SPE(evcmpgtu, evcmpgts, 0x18, 0x08, 0x00600000, 0x00600000, PPC_SPE), +GEN_SPE(evcmpltu, evcmplts, 0x19, 0x08, 0x00600000, 0x00600000, PPC_SPE), +GEN_SPE(evcmpeq, speundef, 0x1A, 0x08, 0x00600000, 0xFFFFFFFF, PPC_SPE), + +GEN_SPE(evfsadd, evfssub, 0x00, 0x0A, 0x00000000, 0x00000000, PPC_SPE_SINGLE), +GEN_SPE(evfsabs, evfsnabs, 0x02, 0x0A, 0x0000F800, 0x0000F800, PPC_SPE_SINGLE), +GEN_SPE(evfsneg, speundef, 0x03, 0x0A, 0x0000F800, 0xFFFFFFFF, PPC_SPE_SINGLE), +GEN_SPE(evfsmul, evfsdiv, 0x04, 0x0A, 0x00000000, 0x00000000, PPC_SPE_SINGLE), +GEN_SPE(evfscmpgt, evfscmplt, 0x06, 0x0A, 0x00600000, 0x00600000, PPC_SPE_SINGLE), +GEN_SPE(evfscmpeq, speundef, 0x07, 0x0A, 0x00600000, 0xFFFFFFFF, PPC_SPE_SINGLE), +GEN_SPE(evfscfui, evfscfsi, 0x08, 0x0A, 0x00180000, 0x00180000, PPC_SPE_SINGLE), +GEN_SPE(evfscfuf, evfscfsf, 0x09, 0x0A, 0x00180000, 0x00180000, PPC_SPE_SINGLE), +GEN_SPE(evfsctui, evfsctsi, 0x0A, 0x0A, 0x00180000, 0x00180000, PPC_SPE_SINGLE), +GEN_SPE(evfsctuf, evfsctsf, 0x0B, 0x0A, 0x00180000, 0x00180000, PPC_SPE_SINGLE), +GEN_SPE(evfsctuiz, speundef, 0x0C, 0x0A, 0x00180000, 0xFFFFFFFF, PPC_SPE_SINGLE), +GEN_SPE(evfsctsiz, speundef, 0x0D, 0x0A, 0x00180000, 0xFFFFFFFF, PPC_SPE_SINGLE), +GEN_SPE(evfststgt, evfststlt, 0x0E, 0x0A, 0x00600000, 0x00600000, PPC_SPE_SINGLE), +GEN_SPE(evfststeq, speundef, 0x0F, 0x0A, 0x00600000, 0xFFFFFFFF, PPC_SPE_SINGLE), + +GEN_SPE(efsadd, efssub, 0x00, 0x0B, 0x00000000, 0x00000000, PPC_SPE_SINGLE), +GEN_SPE(efsabs, efsnabs, 0x02, 0x0B, 0x0000F800, 0x0000F800, PPC_SPE_SINGLE), +GEN_SPE(efsneg, speundef, 0x03, 0x0B, 0x0000F800, 0xFFFFFFFF, PPC_SPE_SINGLE), +GEN_SPE(efsmul, efsdiv, 0x04, 0x0B, 0x00000000, 0x00000000, PPC_SPE_SINGLE), +GEN_SPE(efscmpgt, efscmplt, 0x06, 0x0B, 0x00600000, 0x00600000, PPC_SPE_SINGLE), +GEN_SPE(efscmpeq, efscfd, 0x07, 0x0B, 0x00600000, 0x00180000, PPC_SPE_SINGLE), +GEN_SPE(efscfui, efscfsi, 0x08, 0x0B, 0x00180000, 0x00180000, PPC_SPE_SINGLE), +GEN_SPE(efscfuf, efscfsf, 0x09, 0x0B, 0x00180000, 0x00180000, PPC_SPE_SINGLE), +GEN_SPE(efsctui, efsctsi, 0x0A, 0x0B, 0x00180000, 0x00180000, PPC_SPE_SINGLE), +GEN_SPE(efsctuf, efsctsf, 0x0B, 0x0B, 0x00180000, 0x00180000, PPC_SPE_SINGLE), +GEN_SPE(efsctuiz, speundef, 0x0C, 0x0B, 0x00180000, 0xFFFFFFFF, PPC_SPE_SINGLE), +GEN_SPE(efsctsiz, speundef, 0x0D, 0x0B, 0x00180000, 0xFFFFFFFF, PPC_SPE_SINGLE), +GEN_SPE(efststgt, efststlt, 0x0E, 0x0B, 0x00600000, 0x00600000, PPC_SPE_SINGLE), +GEN_SPE(efststeq, speundef, 0x0F, 0x0B, 0x00600000, 0xFFFFFFFF, PPC_SPE_SINGLE), + +GEN_SPE(efdadd, efdsub, 0x10, 0x0B, 0x00000000, 0x00000000, PPC_SPE_DOUBLE), +GEN_SPE(efdcfuid, efdcfsid, 0x11, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE), +GEN_SPE(efdabs, efdnabs, 0x12, 0x0B, 0x0000F800, 0x0000F800, PPC_SPE_DOUBLE), +GEN_SPE(efdneg, speundef, 0x13, 0x0B, 0x0000F800, 0xFFFFFFFF, PPC_SPE_DOUBLE), +GEN_SPE(efdmul, efddiv, 0x14, 0x0B, 0x00000000, 0x00000000, PPC_SPE_DOUBLE), +GEN_SPE(efdctuidz, efdctsidz, 0x15, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE), +GEN_SPE(efdcmpgt, efdcmplt, 0x16, 0x0B, 0x00600000, 0x00600000, PPC_SPE_DOUBLE), +GEN_SPE(efdcmpeq, efdcfs, 0x17, 0x0B, 0x00600000, 0x00180000, PPC_SPE_DOUBLE), +GEN_SPE(efdcfui, efdcfsi, 0x18, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE), +GEN_SPE(efdcfuf, efdcfsf, 0x19, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE), +GEN_SPE(efdctui, efdctsi, 0x1A, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE), +GEN_SPE(efdctuf, efdctsf, 0x1B, 0x0B, 0x00180000, 0x00180000, PPC_SPE_DOUBLE), +GEN_SPE(efdctuiz, speundef, 0x1C, 0x0B, 0x00180000, 0xFFFFFFFF, PPC_SPE_DOUBLE), +GEN_SPE(efdctsiz, speundef, 0x1D, 0x0B, 0x00180000, 0xFFFFFFFF, PPC_SPE_DOUBLE), +GEN_SPE(efdtstgt, efdtstlt, 0x1E, 0x0B, 0x00600000, 0x00600000, PPC_SPE_DOUBLE), +GEN_SPE(efdtsteq, speundef, 0x1F, 0x0B, 0x00600000, 0xFFFFFFFF, PPC_SPE_DOUBLE), #undef GEN_SPEOP_LDST #define GEN_SPEOP_LDST(name, opc2, sh) \ @@ -9484,11 +9518,19 @@ static inline void gen_intermediate_code_internal(CPUState *env, opc3(ctx.opcode), ctx.opcode, ctx.nip - 4, (int)msr_ir); } } else { - if (unlikely((ctx.opcode & handler->inval) != 0)) { + uint32_t inval; + + if (unlikely(handler->type & (PPC_SPE | PPC_SPE_SINGLE | PPC_SPE_DOUBLE) && Rc(ctx.opcode))) { + inval = handler->inval2; + } else { + inval = handler->inval1; + } + + if (unlikely((ctx.opcode & inval) != 0)) { if (qemu_log_enabled()) { qemu_log("invalid bits: %08x for opcode: " "%02x - %02x - %02x (%08x) " TARGET_FMT_lx "\n", - ctx.opcode & handler->inval, opc1(ctx.opcode), + ctx.opcode & inval, opc1(ctx.opcode), opc2(ctx.opcode), opc3(ctx.opcode), ctx.opcode, ctx.nip - 4); } -- cgit v1.2.3 From 9bc884b741d3ab5bc3471a5cbccc38480676bf2b Mon Sep 17 00:00:00 2001 From: David Gibson Date: Mon, 10 Oct 2011 18:31:00 +0000 Subject: ppc: Generalize the kvmppc_get_clockfreq() function Currently the kvmppc_get_clockfreq() function reads the host's clock frequency from /proc/device-tree, which is useful to past to the guest in KVM setups. However, there are some other host properties advertised in the device tree which can also be relevant to the guests. This patch, therefore, replaces kvmppc_get_clockfreq() which can retrieve any named, single integer property from the host device tree's CPU node. Signed-off-by: David Gibson Signed-off-by: Alexander Graf --- target-ppc/kvm.c | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) (limited to 'target-ppc') diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index 06cad41de5..c48cd76b7c 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -650,37 +650,50 @@ static int kvmppc_find_cpu_dt(char *buf, int buf_len) return 0; } -uint64_t kvmppc_get_clockfreq(void) +/* Read a CPU node property from the host device tree that's a single + * integer (32-bit or 64-bit). Returns 0 if anything goes wrong + * (can't find or open the property, or doesn't understand the + * format) */ +static uint64_t kvmppc_read_int_cpu_dt(const char *propname) { - char buf[512]; - uint32_t tb[2]; + char buf[PATH_MAX]; + union { + uint32_t v32; + uint64_t v64; + } u; FILE *f; int len; if (kvmppc_find_cpu_dt(buf, sizeof(buf))) { - return 0; + return -1; } - strncat(buf, "/clock-frequency", sizeof(buf) - strlen(buf)); + strncat(buf, "/", sizeof(buf) - strlen(buf)); + strncat(buf, propname, sizeof(buf) - strlen(buf)); f = fopen(buf, "rb"); if (!f) { return -1; } - len = fread(tb, sizeof(tb[0]), 2, f); + len = fread(&u, 1, sizeof(u), f); fclose(f); switch (len) { - case 1: - /* freq is only a single cell */ - return tb[0]; - case 2: - return *(uint64_t*)tb; + case 4: + /* property is a 32-bit quantity */ + return be32_to_cpu(u.v32); + case 8: + return be64_to_cpu(u.v64); } return 0; } +uint64_t kvmppc_get_clockfreq(void) +{ + return kvmppc_read_int_cpu_dt("clock-frequency"); +} + int kvmppc_get_hypercall(CPUState *env, uint8_t *buf, int buf_len) { uint32_t *hc = (uint32_t*)buf; -- cgit v1.2.3 From 6659394fa1fa20aa640efa42c8fa5ee6994b6286 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Mon, 10 Oct 2011 18:31:01 +0000 Subject: pseries: Add device tree properties for VMX/VSX and DFP under kvm Sufficiently recent PAPR specifications define properties "ibm,vmx" and "ibm,dfp" on the CPU node which advertise whether the VMX vector extensions (or the later VSX version) and/or the Decimal Floating Point operations from IBM's recent POWER CPUs are available. Currently we do not put these in the guest device tree and the guest kernel will consequently assume they are not available. This is good, because they are not supported under TCG. VMX is similar enough to Altivec that it might be trivial to support, but VSX and DFP would both require significant work to support in TCG. However, when running under kvm on a host which supports these instructions, there's no reason not to let the guest use them. This patch, therefore, checks for the relevant support on the host CPU and, if present, advertises them to the guest as well. Signed-off-by: David Gibson Signed-off-by: Alexander Graf --- target-ppc/kvm.c | 10 ++++++++++ target-ppc/kvm_ppc.h | 12 ++++++++++++ 2 files changed, 22 insertions(+) (limited to 'target-ppc') diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index c48cd76b7c..96139acb23 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -694,6 +694,16 @@ uint64_t kvmppc_get_clockfreq(void) return kvmppc_read_int_cpu_dt("clock-frequency"); } +uint32_t kvmppc_get_vmx(void) +{ + return kvmppc_read_int_cpu_dt("ibm,vmx"); +} + +uint32_t kvmppc_get_dfp(void) +{ + return kvmppc_read_int_cpu_dt("ibm,dfp"); +} + int kvmppc_get_hypercall(CPUState *env, uint8_t *buf, int buf_len) { uint32_t *hc = (uint32_t*)buf; diff --git a/target-ppc/kvm_ppc.h b/target-ppc/kvm_ppc.h index 87d1bdd5fd..955729a1cf 100644 --- a/target-ppc/kvm_ppc.h +++ b/target-ppc/kvm_ppc.h @@ -17,6 +17,8 @@ void kvmppc_init(void); uint32_t kvmppc_get_tbfreq(void); uint64_t kvmppc_get_clockfreq(void); +uint32_t kvmppc_get_vmx(void); +uint32_t kvmppc_get_dfp(void); int kvmppc_get_hypercall(CPUState *env, uint8_t *buf, int buf_len); int kvmppc_set_interrupt(CPUState *env, int irq, int level); void kvmppc_set_papr(CPUState *env); @@ -37,6 +39,16 @@ static inline uint64_t kvmppc_get_clockfreq(void) return 0; } +static inline uint32_t kvmppc_get_vmx(void) +{ + return 0; +} + +static inline uint32_t kvmppc_get_dfp(void) +{ + return 0; +} + static inline int kvmppc_get_hypercall(CPUState *env, uint8_t *buf, int buf_len) { return -1; -- cgit v1.2.3 From be40edcd87b8493cdf691dbe77049e0d9644dcc1 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Wed, 12 Oct 2011 22:40:31 +0000 Subject: ppc: Remove broken partial PVR matching The ppc target contains a ppc_find_by_pvr() function, which looks up a CPU spec based on a PVR (that is, based on the value in the target cpu's Processor Version Register). PVR values contain information on both the cpu model (upper 16 bits, usually) and on the precise revision (low 16 bits, usually). ppc_find_by_pvr, as well as making exact PVR matches, attempts to find "close" PVR matches, when we don't have a CPU spec for the exact revision specified. This sounds like a good idea, execpt that the current logic is completely nonsensical. It seems to assume CPU families are subdivided bit by bit in the PVR in a way they just aren't. Specifically, it requires a match on all bits of the specified pvr up to the last non-zero bit. This has the bizarre effect that when the low bits are simply a sequential revision number (a common though not universal pattern), then odd specified revisions must be matched exactly, whereas even specified revisions will also match the next odd revision, likewise for powers of 4, 8 and so forth. To correctly do inexact matching we'd need to re-organize the table of CPU specs to include a mask showing what PVR range the spec is compatible with (similar to the cputable code in the Linux kernel). For now, just remove the bogosity by only permitting exact PVR matches. That at least makes the matching simple and consistent. If we need inexact matching we can add the necessary per-subfamily masks later. Signed-off-by: David Gibson Signed-off-by: Alexander Graf --- target-ppc/translate_init.c | 36 ++++++------------------------------ 1 file changed, 6 insertions(+), 30 deletions(-) (limited to 'target-ppc') diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index ca0d8525c8..73b49cfd6e 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -10043,40 +10043,16 @@ int cpu_ppc_register_internal (CPUPPCState *env, const ppc_def_t *def) static const ppc_def_t *ppc_find_by_pvr (uint32_t pvr) { - const ppc_def_t *ret; - uint32_t pvr_rev; - int i, best, match, best_match, max; + int i; - ret = NULL; - max = ARRAY_SIZE(ppc_defs); - best = -1; - pvr_rev = pvr & 0xFFFF; - /* We want all specified bits to match */ - best_match = 32 - ctz32(pvr_rev); - for (i = 0; i < max; i++) { - /* We check that the 16 higher bits are the same to ensure the CPU - * model will be the choosen one. - */ - if (((pvr ^ ppc_defs[i].pvr) >> 16) == 0) { - /* We want as much as possible of the low-level 16 bits - * to be the same but we allow inexact matches. - */ - match = clz32(pvr_rev ^ (ppc_defs[i].pvr & 0xFFFF)); - /* We check '>=' instead of '>' because the PPC_defs table - * is ordered by increasing revision. - * Then, we will match the higher revision compatible - * with the requested PVR - */ - if (match >= best_match) { - best = i; - best_match = match; - } + for (i = 0; i < ARRAY_SIZE(ppc_defs); i++) { + /* If we have an exact match, we're done */ + if (pvr == ppc_defs[i].pvr) { + return &ppc_defs[i]; } } - if (best != -1) - ret = &ppc_defs[best]; - return ret; + return NULL; } #include -- cgit v1.2.3 From a1e985833cde3208b0f57c4c7e640b60fbc6c54d Mon Sep 17 00:00:00 2001 From: David Gibson Date: Wed, 12 Oct 2011 22:40:32 +0000 Subject: ppc: First cut implementation of -cpu host For convenience with kvm, x86 allows the user to specify -cpu host on the qemu command line, which means make the guest cpu the same as the host cpu. This patch implements the same option for ppc targets. For now, this just read the host PVR (Processor Version Register) and selects one of our existing CPU specs based on it. This means that the option will not work if the host cpu is not supported by TCG, even if that wouldn't matter for use under kvm. In future, we can extend this in future to override parts of the cpu spec based on information obtained from the host (via /proc/cpuinfo, the host device tree, or explicit KVM calls). That will let us handle cases where the real kvm-virtualized CPU doesn't behave exactly like the TCG-emulated CPU. With appropriate annotation of the CPU specs we'll also then be able to use host cpus under kvm even when there isn't a matching full TCG model. Signed-off-by: David Gibson Signed-off-by: Alexander Graf --- target-ppc/cpu.h | 1 + target-ppc/kvm.c | 19 +++++++++++++++++++ target-ppc/kvm_ppc.h | 6 ++++++ target-ppc/translate_init.c | 8 +++++++- 4 files changed, 33 insertions(+), 1 deletion(-) (limited to 'target-ppc') diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 3f77e308a6..8e5c85c28e 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -1107,6 +1107,7 @@ void ppc_store_msr (CPUPPCState *env, target_ulong value); void ppc_cpu_list (FILE *f, fprintf_function cpu_fprintf); +const ppc_def_t *ppc_find_by_pvr(uint32_t pvr); const ppc_def_t *cpu_ppc_find_by_name (const char *name); int cpu_ppc_register_internal (CPUPPCState *env, const ppc_def_t *def); diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index 96139acb23..313c7b2af2 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -879,6 +879,25 @@ int kvmppc_remove_spapr_tce(void *table, int fd, uint32_t window_size) return 0; } +static inline uint32_t mfpvr(void) +{ + uint32_t pvr; + + asm ("mfpvr %0" + : "=r"(pvr)); + return pvr; +} + +const ppc_def_t *kvmppc_host_cpu_def(void) +{ + uint32_t host_pvr = mfpvr(); + const ppc_def_t *base_spec; + + base_spec = ppc_find_by_pvr(host_pvr); + + return base_spec; +} + bool kvm_arch_stop_on_emulation_error(CPUState *env) { return true; diff --git a/target-ppc/kvm_ppc.h b/target-ppc/kvm_ppc.h index 955729a1cf..b0d6fb667e 100644 --- a/target-ppc/kvm_ppc.h +++ b/target-ppc/kvm_ppc.h @@ -26,6 +26,7 @@ int kvmppc_smt_threads(void); off_t kvmppc_alloc_rma(const char *name, MemoryRegion *sysmem); void *kvmppc_create_spapr_tce(uint32_t liobn, uint32_t window_size, int *pfd); int kvmppc_remove_spapr_tce(void *table, int pfd, uint32_t window_size); +const ppc_def_t *kvmppc_host_cpu_def(void); #else @@ -85,6 +86,11 @@ static inline int kvmppc_remove_spapr_tce(void *table, int pfd, return -1; } +static inline const ppc_def_t *kvmppc_host_cpu_def(void) +{ + return NULL; +} + #endif #ifndef CONFIG_KVM diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 73b49cfd6e..62f0a6b867 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -24,6 +24,8 @@ #include "dis-asm.h" #include "gdbstub.h" +#include +#include "kvm_ppc.h" //#define PPC_DUMP_CPU //#define PPC_DEBUG_SPR @@ -10041,7 +10043,7 @@ int cpu_ppc_register_internal (CPUPPCState *env, const ppc_def_t *def) return 0; } -static const ppc_def_t *ppc_find_by_pvr (uint32_t pvr) +const ppc_def_t *ppc_find_by_pvr(uint32_t pvr) { int i; @@ -10063,6 +10065,10 @@ const ppc_def_t *cpu_ppc_find_by_name (const char *name) const char *p; int i, max, len; + if (kvm_enabled() && (strcasecmp(name, "host") == 0)) { + return kvmppc_host_cpu_def(); + } + /* Check if the given name is a PVR */ len = strlen(name); if (len == 10 && name[0] == '0' && name[1] == 'x') { -- cgit v1.2.3 From 37e305ce167279307335b069bff7e254b858fa6b Mon Sep 17 00:00:00 2001 From: David Gibson Date: Wed, 12 Oct 2011 22:40:33 +0000 Subject: ppc: Add cpu defs for POWER7 revisions 2.1 and 2.3 This patch adds cpu specs to the table for POWER7 revisions 2.1 and 2.3. This allows -cpu host to be used on these host cpus. Signed-off-by: David Gibson Signed-off-by: Alexander Graf --- target-ppc/translate_init.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'target-ppc') diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 62f0a6b867..7de097d945 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -7333,6 +7333,8 @@ enum { CPU_POWERPC_POWER6A = 0x0F000002, #define CPU_POWERPC_POWER7 CPU_POWERPC_POWER7_v20 CPU_POWERPC_POWER7_v20 = 0x003F0200, + CPU_POWERPC_POWER7_v21 = 0x003F0201, + CPU_POWERPC_POWER7_v23 = 0x003F0203, CPU_POWERPC_970 = 0x00390202, #define CPU_POWERPC_970FX CPU_POWERPC_970FX_v31 CPU_POWERPC_970FX_v10 = 0x00391100, @@ -9139,6 +9141,8 @@ static const ppc_def_t ppc_defs[] = { /* POWER7 */ POWERPC_DEF("POWER7", CPU_POWERPC_POWER7, POWER7), POWERPC_DEF("POWER7_v2.0", CPU_POWERPC_POWER7_v20, POWER7), + POWERPC_DEF("POWER7_v2.1", CPU_POWERPC_POWER7_v21, POWER7), + POWERPC_DEF("POWER7_v2.3", CPU_POWERPC_POWER7_v23, POWER7), /* PowerPC 970 */ POWERPC_DEF("970", CPU_POWERPC_970, 970), /* PowerPC 970FX (G5) */ -- cgit v1.2.3 From 8b242eba641a6106db2d3b0356687f8e7e08e568 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Tue, 18 Oct 2011 01:46:08 +0200 Subject: PPC: Bump qemu-system-ppc to 64-bit physical address space Some 32-bit PPC CPUs can use up to 36 bit of physical address space. Treat them accordingly in the qemu-system-ppc binary type. Signed-off-by: Alexander Graf --- target-ppc/cpu.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'target-ppc') diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 8e5c85c28e..f36f375596 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -66,7 +66,7 @@ #define TARGET_PAGE_BITS 12 #endif /* defined(TARGET_PPCEMB) */ -#define TARGET_PHYS_ADDR_SPACE_BITS 32 +#define TARGET_PHYS_ADDR_SPACE_BITS 36 #define TARGET_VIRT_ADDR_SPACE_BITS 32 #endif /* defined (TARGET_PPC64) */ -- cgit v1.2.3 From f0ad8c340145b246982885addef1aac183790706 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Tue, 18 Oct 2011 02:00:51 +0200 Subject: PPC: Disable non-440 CPUs for ppcemb target The sole reason we have the ppcemb target is to support MMUs that have less than the usual 4k possible page size. There are very few of these chips and I don't want to add additional QA and testing burden to everyone to ensure that code still works when TARGET_PAGE_SIZE is not 4k. So this patch disables all CPUs except for MMU_BOOKE capable ones from the ppcemb target. Signed-off-by: Alexander Graf --- target-ppc/translate_init.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'target-ppc') diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 7de097d945..f0ae1d1764 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -10047,11 +10047,27 @@ int cpu_ppc_register_internal (CPUPPCState *env, const ppc_def_t *def) return 0; } +static bool ppc_cpu_usable(const ppc_def_t *def) +{ +#if defined(TARGET_PPCEMB) + /* When using the ppcemb target, we only support 440 style cores */ + if (def->mmu_model != POWERPC_MMU_BOOKE) { + return false; + } +#endif + + return true; +} + const ppc_def_t *ppc_find_by_pvr(uint32_t pvr) { int i; for (i = 0; i < ARRAY_SIZE(ppc_defs); i++) { + if (!ppc_cpu_usable(&ppc_defs[i])) { + continue; + } + /* If we have an exact match, we're done */ if (pvr == ppc_defs[i].pvr) { return &ppc_defs[i]; @@ -10091,6 +10107,10 @@ const ppc_def_t *cpu_ppc_find_by_name (const char *name) ret = NULL; max = ARRAY_SIZE(ppc_defs); for (i = 0; i < max; i++) { + if (!ppc_cpu_usable(&ppc_defs[i])) { + continue; + } + if (strcasecmp(name, ppc_defs[i].name) == 0) { ret = &ppc_defs[i]; break; @@ -10106,6 +10126,10 @@ void ppc_cpu_list (FILE *f, fprintf_function cpu_fprintf) max = ARRAY_SIZE(ppc_defs); for (i = 0; i < max; i++) { + if (!ppc_cpu_usable(&ppc_defs[i])) { + continue; + } + (*cpu_fprintf)(f, "PowerPC %-16s PVR %08x\n", ppc_defs[i].name, ppc_defs[i].pvr); } -- cgit v1.2.3 From a7342588c081c7497bc7810431a03fa7b669af40 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Mon, 17 Oct 2011 18:15:41 +0000 Subject: pseries: Correct vmx/dfp handling in both KVM and TCG cases Currently, when KVM is enabled, the pseries machine checks if the host CPU supports VMX, VSX and/or DFP instructions and advertises accordingly in the guest device tree. It does this regardless of what CPU is selected on the command line. On the other hand, when in TCG mode, it never advertises any of these facilities, even basic VMX (Altivec) which is supported in TCG. Now that we have a -cpu host option for ppc, it is fairly straightforward to fix both problems. This patch changes the -cpu host code to override the basic cpu spec derived from the PVR with information queried from the host avout VMX, VSX and DFP capability. The pseries code then uses the instruction availability advertised in the cpu state to set the guest device tree correctly for both the KVM and TCG cases. Signed-off-by: David Gibson Signed-off-by: Alexander Graf --- target-ppc/cpu.h | 20 ++++++++++++++++++++ target-ppc/kvm.c | 23 ++++++++++++++++++++++- target-ppc/translate_init.c | 18 ++---------------- 3 files changed, 44 insertions(+), 17 deletions(-) (limited to 'target-ppc') diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index f36f375596..3ef4eba836 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -858,6 +858,22 @@ enum { /* The whole PowerPC CPU context */ #define NB_MMU_MODES 3 +struct ppc_def_t { + const char *name; + uint32_t pvr; + uint32_t svr; + uint64_t insns_flags; + uint64_t insns_flags2; + uint64_t msr_mask; + powerpc_mmu_t mmu_model; + powerpc_excp_t excp_model; + powerpc_input_t bus_model; + uint32_t flags; + int bfd_mach; + void (*init_proc)(CPUPPCState *env); + int (*check_pow)(CPUPPCState *env); +}; + struct CPUPPCState { /* First are the most commonly used resources * during translated code execution @@ -1844,6 +1860,10 @@ enum { /* BookE 2.06 PowerPC specification */ PPC2_BOOKE206 = 0x0000000000000001ULL, + /* VSX (extensions to Altivec / VMX) */ + PPC2_VSX = 0x0000000000000002ULL, + /* Decimal Floating Point (DFP) */ + PPC2_DFP = 0x0000000000000004ULL, }; /*****************************************************************************/ diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index 313c7b2af2..a090d79ad4 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -888,14 +888,35 @@ static inline uint32_t mfpvr(void) return pvr; } +static void alter_insns(uint64_t *word, uint64_t flags, bool on) +{ + if (on) { + *word |= flags; + } else { + *word &= ~flags; + } +} + const ppc_def_t *kvmppc_host_cpu_def(void) { uint32_t host_pvr = mfpvr(); const ppc_def_t *base_spec; + ppc_def_t *spec; + uint32_t vmx = kvmppc_get_vmx(); + uint32_t dfp = kvmppc_get_dfp(); base_spec = ppc_find_by_pvr(host_pvr); - return base_spec; + spec = g_malloc0(sizeof(*spec)); + memcpy(spec, base_spec, sizeof(*spec)); + + /* Now fix up the spec with information we can query from the host */ + + alter_insns(&spec->insns_flags, PPC_ALTIVEC, vmx > 0); + alter_insns(&spec->insns_flags2, PPC2_VSX, vmx > 1); + alter_insns(&spec->insns_flags2, PPC2_DFP, dfp); + + return spec; } bool kvm_arch_stop_on_emulation_error(CPUState *env) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index f0ae1d1764..4dfd7f3bfb 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -34,22 +34,6 @@ #define TODO_USER_ONLY 1 #endif -struct ppc_def_t { - const char *name; - uint32_t pvr; - uint32_t svr; - uint64_t insns_flags; - uint64_t insns_flags2; - uint64_t msr_mask; - powerpc_mmu_t mmu_model; - powerpc_excp_t excp_model; - powerpc_input_t bus_model; - uint32_t flags; - int bfd_mach; - void (*init_proc)(CPUPPCState *env); - int (*check_pow)(CPUPPCState *env); -}; - /* For user-mode emulation, we don't emulate any IRQ controller */ #if defined(CONFIG_USER_ONLY) #define PPC_IRQ_INIT_FN(name) \ @@ -6535,6 +6519,8 @@ static void init_proc_970MP (CPUPPCState *env) PPC_64B | PPC_ALTIVEC | \ PPC_SEGMENT_64B | PPC_SLBI | \ PPC_POPCNTB | PPC_POPCNTWD) +/* FIXME: Should also have PPC2_VSX and PPC2_DFP, but we don't + * implement those in TCG yet */ #define POWERPC_INSNS2_POWER7 (PPC_NONE) #define POWERPC_MSRM_POWER7 (0x800000000204FF36ULL) #define POWERPC_MMU_POWER7 (POWERPC_MMU_2_06) -- cgit v1.2.3 From 98efaf75282a96ffbe2914f79a9f5cb736a03db4 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Sun, 23 Oct 2011 17:25:04 +0000 Subject: ppc: Fix up usermode only builds The recent usage of MemoryRegion in kvm_ppc.h breaks builds with CONFIG_USER_ONLY=y. This patch fixes it. Signed-off-by: David Gibson Signed-off-by: Alexander Graf --- target-ppc/kvm_ppc.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'target-ppc') diff --git a/target-ppc/kvm_ppc.h b/target-ppc/kvm_ppc.h index b0d6fb667e..f9c0198311 100644 --- a/target-ppc/kvm_ppc.h +++ b/target-ppc/kvm_ppc.h @@ -23,9 +23,11 @@ int kvmppc_get_hypercall(CPUState *env, uint8_t *buf, int buf_len); int kvmppc_set_interrupt(CPUState *env, int irq, int level); void kvmppc_set_papr(CPUState *env); int kvmppc_smt_threads(void); +#ifndef CONFIG_USER_ONLY off_t kvmppc_alloc_rma(const char *name, MemoryRegion *sysmem); void *kvmppc_create_spapr_tce(uint32_t liobn, uint32_t window_size, int *pfd); int kvmppc_remove_spapr_tce(void *table, int pfd, uint32_t window_size); +#endif /* !CONFIG_USER_ONLY */ const ppc_def_t *kvmppc_host_cpu_def(void); #else @@ -69,6 +71,7 @@ static inline int kvmppc_smt_threads(void) return 1; } +#ifndef CONFIG_USER_ONLY static inline off_t kvmppc_alloc_rma(const char *name, MemoryRegion *sysmem) { return 0; @@ -85,6 +88,7 @@ static inline int kvmppc_remove_spapr_tce(void *table, int pfd, { return -1; } +#endif /* !CONFIG_USER_ONLY */ static inline const ppc_def_t *kvmppc_host_cpu_def(void) { -- cgit v1.2.3 From 70bca53ffb811ea59dc090b3ca7825cf0bf346a7 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Mon, 24 Oct 2011 20:43:22 +0200 Subject: KVM: PPC: Override host vmx/vsx/dfp only when information known The -cpu host feature tries to find out the host capabilities based on device tree information. However, we don't always have that available because it's an optional property in dt. So instead of force unsetting values depending on an unreliable source of information, let's just try to be clever about it and not override capabilities when we don't know the device tree pieces. This fixes altivec with -cpu host on YDL PowerStations. Reported-by: Nishanth Aravamudan Acked-by: David Gibson Signed-off-by: Alexander Graf --- target-ppc/kvm.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'target-ppc') diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index a090d79ad4..f3d0861a11 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -912,9 +912,15 @@ const ppc_def_t *kvmppc_host_cpu_def(void) /* Now fix up the spec with information we can query from the host */ - alter_insns(&spec->insns_flags, PPC_ALTIVEC, vmx > 0); - alter_insns(&spec->insns_flags2, PPC2_VSX, vmx > 1); - alter_insns(&spec->insns_flags2, PPC2_DFP, dfp); + if (vmx != -1) { + /* Only override when we know what the host supports */ + alter_insns(&spec->insns_flags, PPC_ALTIVEC, vmx > 0); + alter_insns(&spec->insns_flags2, PPC2_VSX, vmx > 1); + } + if (dfp != -1) { + /* Only override when we know what the host supports */ + alter_insns(&spec->insns_flags2, PPC2_DFP, dfp); + } return spec; } -- cgit v1.2.3 From 74b41e5676568e6560474267bbf1a5a32d3e2c41 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Thu, 27 Oct 2011 15:56:31 +0000 Subject: pseries: Allow writes to KVM accelerated TCE table Sufficiently recent kernels include a KVM call to accelerate use of PAPR TCE tables (IOMMU), which are used by PAPR virtual IO devices. This involves qemu mapping the TCE table in from a kernel obtained fd, which currently we do with PROT_READ only. This is a hangover from early (never released) versions of this kernel interface which only permitted read-only mappings and required us to destroy and recreate the table when we needed to clear it from qemu. Now, the kernel permits read-write mappings, and we rely on this to clear the table in spapr_vio_quiesce_one(). However, due to insufficient testing, I forgot to update the actual mapping of the table in kvmppc_create_spapr_tce() to add PROT_WRITE to the mmap(). This patch corrects the oversight. Signed-off-by: David Gibson Signed-off-by: Alexander Graf --- target-ppc/kvm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'target-ppc') diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index f3d0861a11..429349fb94 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -850,7 +850,7 @@ void *kvmppc_create_spapr_tce(uint32_t liobn, uint32_t window_size, int *pfd) len = (window_size / SPAPR_VIO_TCE_PAGE_SIZE) * sizeof(VIOsPAPR_RTCE); /* FIXME: round this up to page size */ - table = mmap(NULL, len, PROT_READ, MAP_SHARED, fd, 0); + table = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); if (table == MAP_FAILED) { close(fd); return NULL; -- cgit v1.2.3 From 02d4eae4b0be19d84996105cf6e0cc33f41e3833 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Sun, 30 Oct 2011 15:51:24 +0000 Subject: ppc: Alter CPU state to mask out TCG unimplemented instructions as appropriate The CPU state contains two bitmaps, initialized from the CPU spec which describes which instructions are implemented on the CPU. A couple of bits are defined which cover instructions (VSX and DFP) which are not currently implemented in TCG. So far, these are only used to handle the case of -cpu host because a KVM guest can use the instructions when the host CPU supports them. However, it's a mild layering violation to simply not include those bits in the CPU descriptions for those CPUs that do support them, just because we can't handle them in TCG. This patch corrects the situation, so that the instruction bits _are_ shown correctly in the cpu spec table, but are masked out from the cpu state in the non-KVM case. Signed-off-by: David Gibson Signed-off-by: Alexander Graf --- target-ppc/cpu.h | 26 ++++++++++++++++++++++++++ target-ppc/translate_init.c | 20 +++++++++++++++++--- 2 files changed, 43 insertions(+), 3 deletions(-) (limited to 'target-ppc') diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 3ef4eba836..e84108c49a 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -1856,6 +1856,30 @@ enum { /* popcntw and popcntd instructions */ PPC_POPCNTWD = 0x8000000000000000ULL, +#define PPC_TCG_INSNS (PPC_INSNS_BASE | PPC_POWER | PPC_POWER2 \ + | PPC_POWER_RTC | PPC_POWER_BR | PPC_64B \ + | PPC_64BX | PPC_64H | PPC_WAIT | PPC_MFTB \ + | PPC_602_SPEC | PPC_ISEL | PPC_POPCNTB \ + | PPC_STRING | PPC_FLOAT | PPC_FLOAT_EXT \ + | PPC_FLOAT_FSQRT | PPC_FLOAT_FRES \ + | PPC_FLOAT_FRSQRTE | PPC_FLOAT_FRSQRTES \ + | PPC_FLOAT_FSEL | PPC_FLOAT_STFIWX \ + | PPC_ALTIVEC | PPC_SPE | PPC_SPE_SINGLE \ + | PPC_SPE_DOUBLE | PPC_MEM_TLBIA \ + | PPC_MEM_TLBIE | PPC_MEM_TLBSYNC \ + | PPC_MEM_SYNC | PPC_MEM_EIEIO \ + | PPC_CACHE | PPC_CACHE_ICBI \ + | PPC_CACHE_DCBZ | PPC_CACHE_DCBZT \ + | PPC_CACHE_DCBA | PPC_CACHE_LOCK \ + | PPC_EXTERN | PPC_SEGMENT | PPC_6xx_TLB \ + | PPC_74xx_TLB | PPC_40x_TLB | PPC_SEGMENT_64B \ + | PPC_SLBI | PPC_WRTEE | PPC_40x_EXCP \ + | PPC_405_MAC | PPC_440_SPEC | PPC_BOOKE \ + | PPC_MFAPIDI | PPC_TLBIVA | PPC_TLBIVAX \ + | PPC_4xx_COMMON | PPC_40x_ICBT | PPC_RFMCI \ + | PPC_RFDI | PPC_DCR | PPC_DCRX | PPC_DCRUX \ + | PPC_POPCNTWD) + /* extended type values */ /* BookE 2.06 PowerPC specification */ @@ -1864,6 +1888,8 @@ enum { PPC2_VSX = 0x0000000000000002ULL, /* Decimal Floating Point (DFP) */ PPC2_DFP = 0x0000000000000004ULL, + +#define PPC_TCG_INSNS2 (PPC2_BOOKE206) }; /*****************************************************************************/ diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 4dfd7f3bfb..8a7233fc82 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -6519,9 +6519,7 @@ static void init_proc_970MP (CPUPPCState *env) PPC_64B | PPC_ALTIVEC | \ PPC_SEGMENT_64B | PPC_SLBI | \ PPC_POPCNTB | PPC_POPCNTWD) -/* FIXME: Should also have PPC2_VSX and PPC2_DFP, but we don't - * implement those in TCG yet */ -#define POWERPC_INSNS2_POWER7 (PPC_NONE) +#define POWERPC_INSNS2_POWER7 (PPC2_VSX | PPC2_DFP) #define POWERPC_MSRM_POWER7 (0x800000000204FF36ULL) #define POWERPC_MMU_POWER7 (POWERPC_MMU_2_06) #define POWERPC_EXCP_POWER7 (POWERPC_EXCP_POWER7) @@ -9848,6 +9846,22 @@ int cpu_ppc_register_internal (CPUPPCState *env, const ppc_def_t *def) env->bus_model = def->bus_model; env->insns_flags = def->insns_flags; env->insns_flags2 = def->insns_flags2; + if (!kvm_enabled()) { + /* TCG doesn't (yet) emulate some groups of instructions that + * are implemented on some otherwise supported CPUs (e.g. VSX + * and decimal floating point instructions on POWER7). We + * remove unsupported instruction groups from the cpu state's + * instruction masks and hope the guest can cope. For at + * least the pseries machine, the unavailability of these + * instructions can be advertise to the guest via the device + * tree. + * + * FIXME: we should have a similar masking for CPU features + * not accessible under KVM, but so far, there aren't any of + * those. */ + env->insns_flags &= PPC_TCG_INSNS; + env->insns_flags2 &= PPC_TCG_INSNS2; + } env->flags = def->flags; env->bfd_mach = def->bfd_mach; env->check_pow = def->check_pow; -- cgit v1.2.3